Browse Source

Merge remote-tracking branch 'origin/master' into feat-network-rebuild

Samuka007 2 weeks ago
parent
commit
6f91133eeb
100 changed files with 1446 additions and 23179 deletions
  1. 2 9
      .github/workflows/doc_translation.yml
  2. 1 1
      .github/workflows/makefile.yml
  3. 7 0
      .gitignore
  4. 0 1
      Makefile
  5. 9 3
      docs/.translation_cache.json
  6. 0 3
      docs/kernel/container/index.rst
  7. 0 14
      docs/kernel/container/namespaces/index.rst
  8. 0 19
      docs/kernel/container/namespaces/mnt_namespace.md
  9. 0 23
      docs/kernel/container/namespaces/pid_namespace.md
  10. 2 0
      docs/kernel/filesystem/vfs/index.rst
  11. 88 0
      docs/kernel/filesystem/vfs/mountable_fs.md
  12. 1 0
      docs/kernel/trace/index.rst
  13. 60 0
      docs/kernel/trace/tracepoint.md
  14. 1 4
      docs/locales/en/kernel/container/index.rst
  15. 0 28
      docs/locales/en/kernel/container/namespaces/index.rst
  16. 0 33
      docs/locales/en/kernel/container/namespaces/mnt_namespace.md
  17. 0 38
      docs/locales/en/kernel/container/namespaces/pid_namespace.md
  18. 20 18
      docs/locales/en/kernel/filesystem/vfs/index.rst
  19. 101 0
      docs/locales/en/kernel/filesystem/vfs/mountable_fs.md
  20. 3 2
      docs/locales/en/kernel/trace/index.rst
  21. 74 0
      docs/locales/en/kernel/trace/tracepoint.md
  22. 25 567
      kernel/Cargo.lock
  23. 7 3
      kernel/Cargo.toml
  24. 1 4
      kernel/Makefile
  25. 2 0
      kernel/crates/bitmap/src/traits.rs
  26. 1 0
      kernel/crates/kdepends/Cargo.toml
  27. 2 0
      kernel/crates/kdepends/src/lib.rs
  28. 0 21
      kernel/crates/rbpf/.appveyor.yml
  29. 0 2
      kernel/crates/rbpf/.gitignore
  30. 0 78
      kernel/crates/rbpf/Cargo.toml
  31. 0 202
      kernel/crates/rbpf/LICENSE-APACHE
  32. 0 25
      kernel/crates/rbpf/LICENSE-MIT
  33. 0 743
      kernel/crates/rbpf/README.md
  34. 0 1
      kernel/crates/rbpf/clippy.toml
  35. 0 26
      kernel/crates/rbpf/examples/disassemble.rs
  36. 0 3
      kernel/crates/rbpf/examples/helper.rs
  37. 0 115
      kernel/crates/rbpf/examples/load_elf.rs
  38. 0 43
      kernel/crates/rbpf/examples/load_elf__block_a_port.c
  39. 0 126
      kernel/crates/rbpf/examples/rbpf_plugin.rs
  40. 0 74
      kernel/crates/rbpf/examples/to_json.rs
  41. 0 78
      kernel/crates/rbpf/examples/uptime.rs
  42. 0 72
      kernel/crates/rbpf/mk/appveyor.bat
  43. 0 3
      kernel/crates/rbpf/rustfmt.toml
  44. 0 642
      kernel/crates/rbpf/src/asm_parser.rs
  45. 0 277
      kernel/crates/rbpf/src/assembler.rs
  46. 0 1230
      kernel/crates/rbpf/src/cranelift.rs
  47. 0 807
      kernel/crates/rbpf/src/disassembler.rs
  48. 0 635
      kernel/crates/rbpf/src/ebpf.rs
  49. 0 488
      kernel/crates/rbpf/src/helpers.rs
  50. 0 2199
      kernel/crates/rbpf/src/insn_builder.rs
  51. 0 708
      kernel/crates/rbpf/src/interpreter.rs
  52. 0 1054
      kernel/crates/rbpf/src/jit.rs
  53. 0 1782
      kernel/crates/rbpf/src/lib.rs
  54. 0 41
      kernel/crates/rbpf/src/no_std_error.rs
  55. 0 75
      kernel/crates/rbpf/src/stack.rs
  56. 0 386
      kernel/crates/rbpf/src/verifier.rs
  57. 0 655
      kernel/crates/rbpf/tests/assembler.rs
  58. 0 97
      kernel/crates/rbpf/tests/common.rs
  59. 0 2257
      kernel/crates/rbpf/tests/cranelift.rs
  60. 0 377
      kernel/crates/rbpf/tests/disassembler.rs
  61. 0 571
      kernel/crates/rbpf/tests/misc.rs
  62. 0 2891
      kernel/crates/rbpf/tests/ubpf_jit_x86_64.rs
  63. 0 177
      kernel/crates/rbpf/tests/ubpf_verifier.rs
  64. 0 2674
      kernel/crates/rbpf/tests/ubpf_vm.rs
  65. 2 1
      kernel/crates/system_error/Cargo.toml
  66. 7 0
      kernel/crates/system_error/src/another_ext4.rs
  67. 2 0
      kernel/crates/system_error/src/lib.rs
  68. 4 0
      kernel/src/arch/loongarch64/mm/mod.rs
  69. 2 2
      kernel/src/arch/loongarch64/process/kthread.rs
  70. 21 302
      kernel/src/arch/riscv64/ipc/signal.rs
  71. 4 0
      kernel/src/arch/riscv64/mm/mod.rs
  72. 2 4
      kernel/src/arch/riscv64/process/kthread.rs
  73. 39 290
      kernel/src/arch/x86_64/ipc/signal.rs
  74. 27 5
      kernel/src/arch/x86_64/mm/fault.rs
  75. 32 4
      kernel/src/arch/x86_64/mm/mod.rs
  76. 3 3
      kernel/src/arch/x86_64/process/kthread.rs
  77. 2 2
      kernel/src/arch/x86_64/process/syscall.rs
  78. 2 2
      kernel/src/arch/x86_64/syscall/mod.rs
  79. 1 0
      kernel/src/bpf/helper/consts.rs
  80. 46 7
      kernel/src/bpf/helper/mod.rs
  81. 2 2
      kernel/src/debug/klog/mm.rs
  82. 7 2
      kernel/src/debug/panic/mod.rs
  83. 23 10
      kernel/src/debug/tracing/mod.rs
  84. 120 3
      kernel/src/debug/tracing/trace_pipe.rs
  85. 106 2
      kernel/src/driver/base/block/gendisk/mod.rs
  86. 68 18
      kernel/src/driver/base/block/manager.rs
  87. 21 0
      kernel/src/driver/base/device/device_number.rs
  88. 5 0
      kernel/src/driver/base/device/mod.rs
  89. 57 3
      kernel/src/driver/block/virtio_blk.rs
  90. 2 1
      kernel/src/driver/disk/ahci/ahcidisk.rs
  91. 6 4
      kernel/src/driver/tty/pty/unix98pty.rs
  92. 45 11
      kernel/src/driver/tty/tty_core.rs
  93. 70 12
      kernel/src/driver/tty/tty_device.rs
  94. 6 0
      kernel/src/driver/tty/tty_driver.rs
  95. 161 54
      kernel/src/driver/tty/tty_job_control.rs
  96. 10 3
      kernel/src/driver/tty/tty_ldisc/ntty.rs
  97. 4 0
      kernel/src/driver/tty/tty_port.rs
  98. 2 2
      kernel/src/driver/tty/virtual_terminal/virtual_console.rs
  99. 4 2
      kernel/src/driver/virtio/virtio.rs
  100. 124 23
      kernel/src/filesystem/devfs/mod.rs

+ 2 - 9
.github/workflows/doc_translation.yml

@@ -36,18 +36,11 @@ jobs:
       - name: Run document translator
         run: python tools/doc_translator.py
         env:
-          MAX_WORKERS: 20
+          MAX_WORKERS: 5
           OPENAI_API_KEY: ${{ secrets.DRAGONOS_OPENAI_API_KEY }}
-          OPENAI_MODEL: Qwen/Qwen3-8B
+          OPENAI_MODEL: hunyuan-turbos-latest
           OPENAI_BASE_URL: ${{ secrets.DRAGONOS_OPENAI_API_BASE }}
 
-      - name: Commit translated files
-        run: |
-          git config --global user.name "dragonosbot"
-          git config --global user.email "bot@dragonos.org"
-          git add docs/locales/
-          git commit -m "Update translated documentation" || echo "No changes to commit"
-
       - name: Create Pull Request
         uses: peter-evans/create-pull-request@v5
         with:

+ 1 - 1
.github/workflows/makefile.yml

@@ -51,7 +51,7 @@ jobs:
         env:
           ARCH: ${{ matrix.arch }}
           HOME: /root
-        run: bash -c "source /root/.cargo/env && cd kernel && make test && make test-rbpf"
+        run: bash -c "source /root/.cargo/env && cd kernel && make test"
 
   build:
     name: Build ${{ matrix.arch }}

+ 7 - 0
.gitignore

@@ -20,3 +20,10 @@ cppcheck.xml
 compile_commands.json
 /logs/
 *.log
+
+# Nix dev files
+/.envrc
+/.direnv/
+/flake.nix
+flake.lock
+/default.nix

+ 0 - 1
Makefile

@@ -167,7 +167,6 @@ log-monitor:
 update-submodules:
 	@echo "更新子模块"
 	@git submodule update --recursive --init
-	@git submodule foreach git pull origin master
 
 .PHONY: update-submodules-by-mirror
 update-submodules-by-mirror:

+ 9 - 3
docs/.translation_cache.json

@@ -69,7 +69,7 @@
     "hash": "1b0b3fe0cc2918cc2c53a5af392a96ff"
   },
   "en:kernel/filesystem/vfs/index.rst": {
-    "hash": "d0de5d78a2105a1ecfe4ef137c18f7f5"
+    "hash": "ab891fde3149c7b4f28cf2197584e1eb"
   },
   "en:kernel/debug/profiling-kernel-with-dadk.md": {
     "hash": "966d07272ad19e1afbdc64bb6cfcea73"
@@ -108,7 +108,7 @@
     "hash": "2eba6973dc429ea15ad6ac8f47bfa187"
   },
   "en:kernel/container/index.rst": {
-    "hash": "624e76dd31081ef9304da582d835992f"
+    "hash": "3c50e38e785710c95cecc85f29e6a762"
   },
   "en:kernel/container/namespaces/mnt_namespace.md": {
     "hash": "19af9b11f162c0e4be4725d8458fd253"
@@ -153,7 +153,7 @@
     "hash": "aa1979d81b79f64b12962f885a6820af"
   },
   "en:kernel/trace/index.rst": {
-    "hash": "944a5b865100258ec7957a4cbedd7251"
+    "hash": "3c466a411a5bd71514f8fa4f15d06241"
   },
   "en:kernel/configuration/config.md": {
     "hash": "dff794c4f3bfb4c3d66e6d0fa8f7c495"
@@ -271,5 +271,11 @@
   },
   "en:questions/build_errors.md": {
     "hash": "76bf24821bab907c28e8c8287d2895d5"
+  },
+  "en:kernel/trace/tracepoint.md": {
+    "hash": "18a5f586ca3e3ffbdec6ceeac34eba9c"
+  },
+  "en:kernel/filesystem/vfs/mountable_fs.md": {
+    "hash": "d2ba6ab80dfbc436408ee23e81bbe2ae"
   }
 }

+ 0 - 3
docs/kernel/container/index.rst

@@ -3,11 +3,8 @@
 ====================================
 
    这里是DragonOS中,与容器化相关的说明文档。
-
-   主要包括namespace,overlayfs和cgroup
    
 .. toctree::
    :maxdepth: 2
 
-   namespaces/index
    ../filesystem/unionfs/index

+ 0 - 14
docs/kernel/container/namespaces/index.rst

@@ -1,14 +0,0 @@
-====================================
-命名空间
-====================================
-
-DragonOS的namespaces目前支持pid_namespace和mnt_namespace 预计之后会继续完善
-namespace是容器化实现过程中的重要组成部分
-
-由于目前os是单用户,user_namespace为全局静态
-
-.. toctree::
-   :maxdepth: 1
-
-   pid_namespace
-   mnt_namespace

+ 0 - 19
docs/kernel/container/namespaces/mnt_namespace.md

@@ -1,19 +0,0 @@
-# 挂载命名空间
-
-## 底层架构
-
-pcb -> nsproxy -> mnt_namespace
-
-每一个挂载文件系统都有自立独立的挂载点,表现在数据结构上是一个挂载的红黑树,每一个命名空间中挂载是独立的,所以文件系统的挂载和卸载不会影响别的
-
-## 系统调用接口
- 
-
-- clone
-    - CLONE_NEWNS用于创建一个新的 MNT 命名空间。提供独立的文件系统挂载点
-- unshare 
-    - 使用 CLONE_NEWPID 标志调用 unshare() 后,后续创建的所有子进程都将在新的命名空间中运行。
-- setns
-    - 将进程加入到指定的命名空间
-- chroot 
-    - 将当前进程的根目录更改为指定的路径,提供文件系统隔离。

+ 0 - 23
docs/kernel/container/namespaces/pid_namespace.md

@@ -1,23 +0,0 @@
-# 进程命名空间
-:::{note} 本文作者:操丰毅 1553389239@qq.com
-
-2024年10月30日
-:::
-
-pid_namespace 是内核中的一种命名空间,用于实现进程隔离,允许在不同的命名空间中运行的进程有独立的pid视图
-
-## 底层架构
-
-pcb -> nsproxy -> pid_namespace
-- pid_namespace 内有独立的一套进程分配器,以及孤儿进程回收器,独立管理内部的pid
-- 不同进程的详细信息都存放在proc文件系统中,里面的找到对应的pid号里面的信息都在pid中,记录的是pid_namespace中的信息
-- pid_namespace等限制由ucount来控制管理
-
-## 系统调用接口
-
-- clone
-    - CLONE_NEWPID用于创建一个新的 PID 命名空间。使用这个标志时,子进程将在新的 PID 命名空间内运行,进程 ID 从 1 开始。
-- unshare 
-    - 使用 CLONE_NEWPID 标志调用 unshare() 后,后续创建的所有子进程都将在新的命名空间中运行。
-- getpid
-    - 在命名空间中调用 getpid() 会返回进程在当前 PID 命名空间中的进程 ID

+ 2 - 0
docs/kernel/filesystem/vfs/index.rst

@@ -12,6 +12,7 @@ VFS是DragonOS文件系统的核心,它提供了一套统一的文件系统接
 - 提供文件系统的抽象(FileSystem)
 - 提供IndexNode抽象
 - 提供文件系统的缓存、同步机制(尚未实现)
+- 支持将硬盘设备挂载到文件系统上(目前支持EXT4和vfat类型的virtio硬盘)
 
 
 .. toctree::
@@ -20,4 +21,5 @@ VFS是DragonOS文件系统的核心,它提供了一套统一的文件系统接
 
    design
    api
+   mountable_fs
 

+ 88 - 0
docs/kernel/filesystem/vfs/mountable_fs.md

@@ -0,0 +1,88 @@
+:::{note}
+本文作者: 庄凯烨
+
+Email: <sparkhhhhhhhhhh@outlook.com>
+:::
+
+# 设计
+
+```mermaid
+    graph TD
+    subgraph 用户层 / 系统调用
+        A[sys_mount] --> B[produce_fs!]
+    end
+
+    subgraph 文件系统注册与创建
+        B --> C{查找 FSMAKER}
+        C -- 找到匹配 --> D[FileSystemMaker::builder && FileSystemMaker::maker]
+        D --> G[FileSystem 实例]
+        G --> H[挂载成功]
+        C -- 未找到 --> I[错误: EINVAL]
+    end
+
+    subgraph 文件系统实现者
+        J[RamFS / 其他文件系统] --> K[实现 MountableFileSystem trait]
+        K --> L[make_mount_data]
+        K --> M[make_fs]
+        L --> N[register_mountable_fs!宏]
+        M --> N
+    end
+
+    N --> O[分布式切片 FSMAKER ]
+    O --> C
+
+    click J "#" "RamFS - 文件系统示例"
+    click B "#" "produce_fs 函数"
+    click O "#" "FSMAKER - 文件系统工厂数组"
+```
+
+## 流程说明:
+
+
+- 具体的文件系统(例如`RamFS`)通过实现`MountableFileSystem trait`,并使用 `register_mountable_fs!` 宏,将自身的创建逻辑注册到 `FSMAKER` 中。
+- 用户通过 `sys_mount` 系统调用请求挂载一个文件系统。
+- `sys_mount` 调用 `produce_fs` 函数,传入文件系统类型、原始挂载数据和源路径。
+- `produce_fs` 遍历全局的 `FSMAKER` 数组,查找与请求的文件系统类型名称匹配的 FileSystemMaker。
+- 如果找到,首先调用 `maker.builder`(它内部会调用具体文件系统的 `make_mount_data` 方法)来处理原始数据,生成一个可选的 `mount_data` 对象。
+- 接着,调用 `maker.build`(它内部会调用具体文件系统的 `make_fs` 方法),并传入上一步生成的 mount_data,从而创建出文件系统实例。
+- 成功创建的文件系统实例(`Arc<dyn FileSystem>`)被返回并用于后续的挂载操作。
+- 如果找不到对应的文件系统类型,则返回错误。
+
+## 其他
+
+目前 DragonOS 支持挂载的文件系统包括 `ramfs`、`ext4` 和 `vfat`。在 DragonOS 中挂载硬盘文件时,要注意:
+
+- 由于系统暂时无法直接查看硬盘的文件系统类型,在挂载前需要提前明确目标分区所使用的文件系统类型。
+- 挂载操作需要指定对应的硬盘设备名称(位于 /dev 下)。
+- 这些硬盘设备文件来源于通过修改 `tools/run-qemu.sh` 启动脚本,将制作好的硬盘镜像文件传入系统。virtio 硬盘设备命名示例如 `vda1`、`vdb1`,硬盘在 DragonOS 内的设备名称是根据 `run-qemu.sh` 中镜像传入的顺序自动分配(a,b,c等等)的,其中的数字表示分区号。
+
+所以目前需要挂载硬盘的话,可以更改`test-mount-ext4`执行程序,将指定的硬盘文件以对应的文件系统格式进行挂载,以下为挂载示例:
+
+
+```Rust
+use core::ffi::{c_char, c_void};
+use libc::{mount, MS_BIND};
+use std::fs;
+use std::path::Path;
+
+fn main() {
+    let ext4_path = Path::new("mnt/ext4");
+    let dir = fs::create_dir_all(ext4_path);
+    if dir.is_err() {
+        panic!("mkdir /mnt/ext4 fail.");
+    }
+
+    // 硬盘名称,由传入顺序决定
+    let source = b"/dev/vdb1\0".as_ptr() as *const c_char;
+    let target = b"/mnt/ext4\0".as_ptr() as *const c_char;
+    // 文件系统类型
+    let fstype = b"ext4\0".as_ptr() as *const c_char;
+    let flags = MS_BIND;
+    let data = std::ptr::null() as *const c_void;
+    let _ = unsafe { mount(source, target, fstype, flags, data) };
+
+    println!("Mount successfully!");
+}
+```
+
+至于硬盘镜像的制作,可以通过运行`sudo bash tools/make_fs_image.sh`来同时制作`ext4`和`fat`的磁盘镜像,进入系统后就可以dev目录下多出两个磁盘文件(`vdb1`和`vdc1`),然后就可以执行`test-mount-ext4`以及`test-mount-fat`测试程序来验证

+ 1 - 0
docs/kernel/trace/index.rst

@@ -9,3 +9,4 @@
 
    eBPF
    kprobe
+   tracepoint

+ 60 - 0
docs/kernel/trace/tracepoint.md

@@ -0,0 +1,60 @@
+# Tracepoints
+
+> 作者: 陈林峰
+>
+> Email: chenlinfeng25@outlook.com
+
+
+## 概述
+Tracepoints 是 Linux 内核提供的一种跟踪机制,允许开发者在内核代码的特定位置插入探测点,以便收集运行时信息。与 kprobes 不同,tracepoints 是预定义的,并且通常用于收集性能数据或调试信息,而不需要修改内核代码。
+
+## 工作流程
+1. **定义 Tracepoint**: 内核开发者在代码中定义 tracepoint,使用宏 `define_event_trace`。
+2. **触发 Tracepoint**: 在代码的其他部分,开发者可以使用 `define_event_trace` 定义的函数来触发已定义的 tracepoint,并传递相关的上下文信息。比如定义的tracepoint名称为`my_tracepoint`,则可以使用 `trace_my_tracepoint()` 来触发它。
+3.  **收集数据**: 当 tracepoint 被触发时,内核会记录相关的数据,这些数据可以通过用户空间工具(如 `trace-cmd` 或 `perf`)进行分析。现在DragonOS中还只能支持查看内核为这些数据创建的文件。
+    1.  读取`/sys/kernel/debug/tracing/trace`文件可以查看tracepoint收集的数据。缓冲区的内容不会被清除。
+    2.  读取`/sys/kernel/debug/tracing/trace_pipe`文件可以查看tracepoint收集的数据。缓冲区的内容会被清除。如果缓冲区没有内容,则会阻塞等待新的数据。
+    3.  读取`/sys/kernel/debug/tracing/events/`目录可以查看所有可用的 tracepoints。
+    4.  读取`/sys/kernel/debug/tracing/events/<event_name>/format`文件可以查看特定 tracepoint 的数据格式。
+    5.  写入`/sys/kernel/debug/tracing/events/<event_name>/enable` 文件可以启用特定的 tracepoint。
+    6.  写入空值到 `/sys/kernel/debug/tracing/trace` 可以清空当前的 trace 数据。
+4. **分析数据**: 用户空间工具可以读取 tracepoint 收集的数据,并生成报告或图表,以帮助开发者理解内核行为。
+
+
+## 接口
+```rust
+define_event_trace!() // 定义一个 tracepoint
+```
+
+```rust
+// example
+define_event_trace!(
+    sys_enter_openat,
+    TP_system(syscalls),
+    TP_PROTO(dfd: i32, path:*const u8, o_flags: u32, mode: u32),
+    TP_STRUCT__entry{
+        dfd: i32,
+        path: u64,
+        o_flags: u32,
+        mode: u32,
+    },
+    TP_fast_assign{
+        dfd: dfd,
+        path: path as u64,
+        o_flags: o_flags,
+        mode: mode,
+    },
+    TP_ident(__entry),
+    TP_printk({
+        format!(
+            "dfd: {}, path: {:#x}, o_flags: {:?}, mode: {:?}",
+            __entry.dfd,
+            __entry.path,
+            __entry.o_flags,
+            __entry.mode
+        )
+    })
+);
+```
+## Tracepoints For eBPF
+在 DragonOS 中,tracepoints 也可以与 eBPF 结合使用,以便在内核中收集更丰富的数据。eBPF 程序可以附加到 tracepoints 上,以便在 tracepoint 被触发时执行自定义的逻辑。

+ 1 - 4
docs/locales/en/kernel/container/index.rst

@@ -4,7 +4,7 @@
 
    - Source document: kernel/container/index.rst
 
-   - Translation time: 2025-05-19 01:41:19
+   - Translation time: 2025-06-28 13:21:05
 
    - Translation model: `Qwen/Qwen3-8B`
 
@@ -17,10 +17,7 @@ Containerization
 
    This is the documentation related to containerization in DragonOS.
 
-   It mainly includes namespace, overlayfs, and cgroup
-
 .. toctree::
    :maxdepth: 2
 
-   namespaces/index
    ../filesystem/unionfs/index

+ 0 - 28
docs/locales/en/kernel/container/namespaces/index.rst

@@ -1,28 +0,0 @@
-.. note:: AI Translation Notice
-
-   This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
-
-   - Source document: kernel/container/namespaces/index.rst
-
-   - Translation time: 2025-05-19 01:41:19
-
-   - Translation model: `Qwen/Qwen3-8B`
-
-
-   Please report issues via `Community Channel <https://github.com/DragonOS-Community/DragonOS/issues>`_
-
-====================================
-Namespaces
-====================================
-
-DragonOS's namespaces currently support pid_namespace and mnt_namespace, and more features are expected to be added in the future.
-
-Namespaces are an important component in the process of containerization.
-
-Since the current OS is single-user, user_namespace is globally static.
-
-.. toctree::
-   :maxdepth: 1
-
-   pid_namespace
-   mnt_namespace

+ 0 - 33
docs/locales/en/kernel/container/namespaces/mnt_namespace.md

@@ -1,33 +0,0 @@
-:::{note}
-**AI Translation Notice**
-
-This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
-
-- Source document: kernel/container/namespaces/mnt_namespace.md
-
-- Translation time: 2025-05-19 01:41:19
-
-- Translation model: `Qwen/Qwen3-8B`
-
-Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
-
-:::
-
-# Mount Namespace
-
-## Underlying Architecture
-
-pcb -> nsproxy -> mnt_namespace
-
-Each mounted file system has its own independent mount point, which is represented in the data structure as a red-black tree of mounts. Each namespace has its own independent mounts, so mounting and unmounting file systems will not affect others.
-
-## System Call Interface
-
-- clone
-    - CLONE_NEWNS is used to create a new MNT namespace. It provides an independent file system mount point.
-- unshare
-    - After calling unshare() with the CLONE_NEWPID flag, all subsequent child processes will run in the new namespace.
-- setns
-    - Adds the process to the specified namespace.
-- chroot
-    - Changes the current process's root directory to the specified path, providing file system isolation.

+ 0 - 38
docs/locales/en/kernel/container/namespaces/pid_namespace.md

@@ -1,38 +0,0 @@
-:::{note}
-**AI Translation Notice**
-
-This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
-
-- Source document: kernel/container/namespaces/pid_namespace.md
-
-- Translation time: 2025-05-19 01:41:31
-
-- Translation model: `Qwen/Qwen3-8B`
-
-Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
-
-:::
-
-# Process Namespace
-:::{note} Author: Cao Fengyi 1553389239@qq.com
-
-October 30, 2024
-:::
-
-`pid_namespace` is a type of namespace in the kernel that is used to achieve process isolation. It allows processes running in different namespaces to have independent views of process IDs (PIDs).
-
-## Underlying Architecture
-
-pcb -> nsproxy -> pid_namespace
-- `pid_namespace` contains an independent set of process allocators and an orphan process reaper, which independently manages PIDs within the namespace.
-- Detailed information about processes is stored in the proc file system. The information corresponding to a specific PID is located within the `pid_namespace`, recording information related to the `pid_namespace`.
-- The limitations imposed by `pid_namespace` are controlled and managed by `ucount`.
-
-## System Call Interface
-
-- `clone`
-    - `CLONE_NEWPID` is used to create a new PID namespace. When this flag is used, the child process will run in the new PID namespace, with the process ID starting from 1.
-- `unshare`
-    - After calling `unshare()` with the `CLONE_NEWPID` flag, all subsequent child processes will run within the new namespace.
-- `getpid`
-    - Calling `getpid()` within a namespace returns the process ID of the process within the current PID namespace.

+ 20 - 18
docs/locales/en/kernel/filesystem/vfs/index.rst

@@ -1,33 +1,35 @@
 .. note:: AI Translation Notice
 
-   This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
+   This document was automatically translated by `hunyuan-turbos-latest` model, for reference only.
 
    - Source document: kernel/filesystem/vfs/index.rst
 
-   - Translation time: 2025-05-19 01:41:14
+   - Translation time: 2025-06-29 09:58:04
 
-   - Translation model: `Qwen/Qwen3-8B`
+   - Translation model: `hunyuan-turbos-latest`
 
 
    Please report issues via `Community Channel <https://github.com/DragonOS-Community/DragonOS/issues>`_
 
-VFS Virtual File System
-====================================
+VFS Virtual File System  
+====================================  
 
-In DragonOS, VFS acts as an adapter, hiding the differences between specific file systems and providing a unified file operation interface abstraction to the outside.
+In DragonOS, VFS acts as an adapter that abstracts the differences between specific file systems, providing a unified file operation interface to the outside.  
 
-VFS is the core of the file system in DragonOS. It provides a set of unified file system interfaces, enabling DragonOS to support various different file systems. The main functions of VFS include:
+VFS is the core of DragonOS's file system, offering a standardized set of file system interfaces that enable DragonOS to support multiple different file systems. The main functions of VFS include:  
 
-- Providing a unified file system interface
-- Providing mount and unmount mechanisms for file systems (MountFS)
-- Providing file abstraction (File)
-- Providing file system abstraction (FileSystem)
-- Providing IndexNode abstraction
-- Providing caching and synchronization mechanisms for file systems (not yet implemented)
+- Providing a unified file system interface  
+- Offering file system mount and unmount mechanisms (MountFS)  
+- Providing file abstraction (File)  
+- Providing file system abstraction (FileSystem)  
+- Offering IndexNode abstraction  
+- Providing file system caching and synchronization mechanisms (not yet implemented)  
+- Supporting the mounting of disk devices onto the file system (currently supports EXT4 and vfat types of virtio disks)  
 
-.. toctree::
-   :maxdepth: 1
-   :caption: Directory
+.. toctree::  
+   :maxdepth: 1  
+   :caption: Table of Contents  
 
-   design
-   api
+   design  
+   api  
+   mountable_fs

+ 101 - 0
docs/locales/en/kernel/filesystem/vfs/mountable_fs.md

@@ -0,0 +1,101 @@
+:::{note}
+**AI Translation Notice**
+
+This document was automatically translated by `hunyuan-turbos-latest` model, for reference only.
+
+- Source document: kernel/filesystem/vfs/mountable_fs.md
+
+- Translation time: 2025-06-29 09:58:15
+
+- Translation model: `hunyuan-turbos-latest`
+
+Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
+
+:::
+
+:::{note}
+Author: Zhuang Kaiye
+
+Email: <sparkhhhhhhhhhh@outlook.com>
+:::
+
+# Design
+
+```mermaid
+    graph TD
+    subgraph 用户层 / 系统调用
+        A[sys_mount] --> B[produce_fs!]
+    end
+
+    subgraph 文件系统注册与创建
+        B --> C{查找 FSMAKER}
+        C -- 找到匹配 --> D[FileSystemMaker::builder && FileSystemMaker::maker]
+        D --> G[FileSystem 实例]
+        G --> H[挂载成功]
+        C -- 未找到 --> I[错误: EINVAL]
+    end
+
+    subgraph 文件系统实现者
+        J[RamFS / 其他文件系统] --> K[实现 MountableFileSystem trait]
+        K --> L[make_mount_data]
+        K --> M[make_fs]
+        L --> N[register_mountable_fs!宏]
+        M --> N
+    end
+
+    N --> O[分布式切片 FSMAKER ]
+    O --> C
+
+    click J "#" "RamFS - 文件系统示例"
+    click B "#" "produce_fs 函数"
+    click O "#" "FSMAKER - 文件系统工厂数组"
+```
+
+## Process Description:
+
+- A specific file system (e.g., `RamFS`) registers its creation logic with `FSMAKER` by implementing `MountableFileSystem trait` and using the `register_mountable_fs!` macro.
+- Users request to mount a file system via the `sys_mount` system call.
+- `sys_mount` calls the `produce_fs` function, passing the file system type, raw mount data, and source path.
+- `produce_fs` traverses the global `FSMAKER` array to find a FileSystemMaker matching the requested file system type name.
+- If found, it first calls `maker.builder` (which internally invokes the specific file system's `make_mount_data` method) to process the raw data and generate an optional `mount_data` object.
+- Next, it calls `maker.build` (which internally invokes the specific file system's `make_fs` method), passing the mount_data generated in the previous step, thereby creating the file system instance.
+- The successfully created file system instance (`Arc<dyn FileSystem>`) is returned and used for subsequent mount operations.
+- If no matching file system type is found, an error is returned.
+
+## Additional Notes
+
+Currently, DragonOS supports mounting the following file systems: `ramfs`, `ext4`, and `vfat`. When mounting disk files in DragonOS, note the following:
+
+- Since the system cannot directly determine the file system type of a disk, the target partition's file system type must be explicitly known before mounting.
+- The mount operation requires specifying the corresponding disk device name (located under /dev).
+- These disk device files are generated by modifying the `tools/run-qemu.sh` startup script to load the prepared disk image files into the system. Examples of virtio disk device naming include `vda1` and `vdb1`. The device names of disks in DragonOS are automatically assigned based on the order in which images are loaded in `run-qemu.sh` (a, b, c, etc.), with numbers indicating partition numbers.
+
+Therefore, to mount a disk currently, you can modify the `test-mount-ext4` executable to mount the specified disk file with the corresponding file system format. Below is an example of the mount operation:
+
+```Rust
+use core::ffi::{c_char, c_void};
+use libc::{mount, MS_BIND};
+use std::fs;
+use std::path::Path;
+
+fn main() {
+    let ext4_path = Path::new("mnt/ext4");
+    let dir = fs::create_dir_all(ext4_path);
+    if dir.is_err() {
+        panic!("mkdir /mnt/ext4 fail.");
+    }
+
+    // 硬盘名称,由传入顺序决定
+    let source = b"/dev/vdb1\0".as_ptr() as *const c_char;
+    let target = b"/mnt/ext4\0".as_ptr() as *const c_char;
+    // 文件系统类型
+    let fstype = b"ext4\0".as_ptr() as *const c_char;
+    let flags = MS_BIND;
+    let data = std::ptr::null() as *const c_void;
+    let _ = unsafe { mount(source, target, fstype, flags, data) };
+
+    println!("Mount successfully!");
+}
+```
+
+As for disk image creation, you can run `sudo bash tools/make_fs_image.sh` to simultaneously create disk images for `ext4` and `fat`. After entering the system, two additional disk files (`vdb1` and `vdc1`) will appear in the dev directory. You can then execute the `test-mount-ext4` and `test-mount-fat` test programs to verify the setup.

+ 3 - 2
docs/locales/en/kernel/trace/index.rst

@@ -4,7 +4,7 @@
 
    - Source document: kernel/trace/index.rst
 
-   - Translation time: 2025-05-19 01:41:20
+   - Translation time: 2025-06-14 09:35:32
 
    - Translation model: `Qwen/Qwen3-8B`
 
@@ -14,7 +14,7 @@
 Kernel Tracing Mechanism
 ====================================
 
-   The kernel tracing mechanism consists of many functionalities, such as kprobe, uprobe, tracepoint, ftrace, and eBPF, which is used to extend the observability of the kernel. The kernel currently supports kprobe and eBPF. This chapter will introduce these two mechanisms.
+   The kernel tracing mechanism consists of many features, such as kprobe, uprobe, tracepoint, and ftrace, as well as eBPF for extending kernel observability. The kernel currently supports kprobe and eBPF, and this chapter will introduce these two mechanisms.
 
 .. toctree::
    :maxdepth: 1
@@ -22,3 +22,4 @@ Kernel Tracing Mechanism
 
    eBPF
    kprobe
+   tracepoint

+ 74 - 0
docs/locales/en/kernel/trace/tracepoint.md

@@ -0,0 +1,74 @@
+:::{note}
+**AI Translation Notice**
+
+This document was automatically translated by `Qwen/Qwen3-8B` model, for reference only.
+
+- Source document: kernel/trace/tracepoint.md
+
+- Translation time: 2025-06-14 09:36:42
+
+- Translation model: `Qwen/Qwen3-8B`
+
+Please report issues via [Community Channel](https://github.com/DragonOS-Community/DragonOS/issues)
+
+:::
+
+# Tracepoints
+
+> Author: Chen Linfeng  
+>
+> Email: chenlinfeng25@outlook.com
+
+## Overview
+Tracepoints are a tracing mechanism provided by the Linux kernel, allowing developers to insert probe points at specific locations in the kernel code to collect runtime information. Unlike kprobes, tracepoints are predefined and are typically used for collecting performance data or debugging information without modifying the kernel code.
+
+## Workflow
+1. **Define Tracepoint**: Kernel developers define tracepoints in the code using the macro ``define_event_trace``.
+2. **Trigger Tracepoint**: Developers can trigger the defined tracepoints from other parts of the code by using the functions defined with ``define_event_trace``, and pass relevant context information. For example, if the defined tracepoint is named ``my_tracepoint``, it can be triggered using ``trace_my_tracepoint()``.
+3. **Collect Data**: When a tracepoint is triggered, the kernel records the related data. This data can be analyzed using user-space tools (such as ``trace-cmd`` or ``perf``). Currently, DragonOS only supports viewing the data files created by the kernel for these data.
+    1. Reading the ``/sys/kernel/debug/tracing/trace`` file can view the tracepoint collected data. The buffer content will not be cleared.
+    2. Reading the ``/sys/kernel/debug/tracing/trace_pipe`` file can view the tracepoint collected data. The buffer content will be cleared. If there is no content in the buffer, it will block until new data is available.
+    3. Reading the ``/sys/kernel/debug/tracing/events/`` directory can view all available tracepoints.
+    4. Reading the ``/sys/kernel/debug/tracing/events/<event_name>/format`` file can view the data format of a specific tracepoint.
+    5. Writing to the ``/sys/kernel/debug/tracing/events/<event_name>/enable`` file can enable a specific tracepoint.
+    6. Writing an empty value to ``/sys/kernel/debug/tracing/trace`` can clear the current trace data.
+4. **Analyze Data**: User-space tools can read the data collected by tracepoints and generate reports or charts to help developers understand kernel behavior.
+
+## Interface
+```rust
+define_event_trace!() // 定义一个 tracepoint
+```
+
+```rust
+// example
+define_event_trace!(
+    sys_enter_openat,
+    TP_system(syscalls),
+    TP_PROTO(dfd: i32, path:*const u8, o_flags: u32, mode: u32),
+    TP_STRUCT__entry{
+        dfd: i32,
+        path: u64,
+        o_flags: u32,
+        mode: u32,
+    },
+    TP_fast_assign{
+        dfd: dfd,
+        path: path as u64,
+        o_flags: o_flags,
+        mode: mode,
+    },
+    TP_ident(__entry),
+    TP_printk({
+        format!(
+            "dfd: {}, path: {:#x}, o_flags: {:?}, mode: {:?}",
+            __entry.dfd,
+            __entry.path,
+            __entry.o_flags,
+            __entry.mode
+        )
+    })
+);
+```
+
+## Tracepoints For eBPF
+In DragonOS, tracepoints can also be used in conjunction with eBPF to collect richer data within the kernel. eBPF programs can be attached to tracepoints to execute custom logic when a tracepoint is triggered.

+ 25 - 567
kernel/Cargo.lock

@@ -40,16 +40,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
-name = "anyhow"
-version = "1.0.97"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
-
-[[package]]
-name = "arbitrary"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+name = "another_ext4"
+version = "0.1.0"
+source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/another_ext4.git?rev=bf782ff294#bf782ff2947b57ba89503824eada5eb3c20a2e2a"
+dependencies = [
+ "bitflags 2.9.0",
+ "log",
+]
 
 [[package]]
 name = "asm_macros"
@@ -83,12 +80,6 @@ version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
-[[package]]
-name = "base-x"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
-
 [[package]]
 name = "bindgen"
 version = "0.61.0"
@@ -144,35 +135,17 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
 name = "bitmap"
 version = "0.1.0"
 
-[[package]]
-name = "bumpalo"
-version = "3.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
-
-[[package]]
-name = "byteorder"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
-
 [[package]]
 name = "byteorder"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
-[[package]]
-name = "bytes"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
-
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
 dependencies = [
  "jobserver",
  "libc",
@@ -221,136 +194,9 @@ version = "4.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
 dependencies = [
- "bytes",
  "memchr",
 ]
 
-[[package]]
-name = "const_fn"
-version = "0.4.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e"
-
-[[package]]
-name = "cranelift-bforest"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a91a1ccf6fb772808742db2f51e2179f25b1ec559cbe39ea080c72ff61caf8f"
-dependencies = [
- "cranelift-entity",
-]
-
-[[package]]
-name = "cranelift-codegen"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "169db1a457791bff4fd1fc585bb5cc515609647e0420a7d5c98d7700c59c2d00"
-dependencies = [
- "bumpalo",
- "cranelift-bforest",
- "cranelift-codegen-meta",
- "cranelift-codegen-shared",
- "cranelift-control",
- "cranelift-entity",
- "cranelift-isle",
- "gimli 0.27.3",
- "hashbrown 0.13.2",
- "log",
- "regalloc2",
- "smallvec",
- "target-lexicon",
-]
-
-[[package]]
-name = "cranelift-codegen-meta"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3486b93751ef19e6d6eef66d2c0e83ed3d2ba01da1919ed2747f2f7bd8ba3419"
-dependencies = [
- "cranelift-codegen-shared",
-]
-
-[[package]]
-name = "cranelift-codegen-shared"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86a1205ab18e7cd25dc4eca5246e56b506ced3feb8d95a8d776195e48d2cd4ef"
-
-[[package]]
-name = "cranelift-control"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b108cae0f724ddfdec1871a0dc193a607e0c2d960f083cfefaae8ccf655eff2"
-dependencies = [
- "arbitrary",
-]
-
-[[package]]
-name = "cranelift-entity"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "720444006240622798665bfc6aa8178e2eed556da342fda62f659c5267c3c659"
-
-[[package]]
-name = "cranelift-frontend"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7a94c4c5508b7407e125af9d5320694b7423322e59a4ac0d07919ae254347ca"
-dependencies = [
- "cranelift-codegen",
- "log",
- "smallvec",
- "target-lexicon",
-]
-
-[[package]]
-name = "cranelift-isle"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef1f888d0845dcd6be4d625b91d9d8308f3d95bed5c5d4072ce38e1917faa505"
-
-[[package]]
-name = "cranelift-jit"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "547845cd12d15167e5458556ee67513bfaff2e05e72eb489edfbabc9f21d9ea2"
-dependencies = [
- "anyhow",
- "cranelift-codegen",
- "cranelift-control",
- "cranelift-entity",
- "cranelift-module",
- "cranelift-native",
- "libc",
- "log",
- "region",
- "target-lexicon",
- "wasmtime-jit-icache-coherence",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "cranelift-module"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c104ed6a4c56c15e1858cc466482373e3c13d022bc1391485769ba384d9b079"
-dependencies = [
- "anyhow",
- "cranelift-codegen",
- "cranelift-control",
-]
-
-[[package]]
-name = "cranelift-native"
-version = "0.99.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ad5966da08f1e96a3ae63be49966a85c9b249fa465f8cf1b66469a82b1004a0"
-dependencies = [
- "cranelift-codegen",
- "libc",
- "target-lexicon",
-]
-
 [[package]]
 name = "crc"
 version = "0.1.0"
@@ -476,12 +322,6 @@ dependencies = [
  "syn 2.0.100",
 ]
 
-[[package]]
-name = "discard"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
-
 [[package]]
 name = "doc-comment"
 version = "0.3.3"
@@ -503,7 +343,7 @@ dependencies = [
  "defer",
  "derive_builder",
  "driver_base_macros",
- "elf 0.7.2",
+ "elf",
  "fdt",
  "hashbrown 0.13.2",
  "ida",
@@ -553,15 +393,6 @@ version = "1.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
 
-[[package]]
-name = "elf"
-version = "0.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4841de15dbe0e49b9b62a417589299e3be0d557e0900d36acb87e6dae47197f5"
-dependencies = [
- "byteorder 0.5.3",
-]
-
 [[package]]
 name = "elf"
 version = "0.7.2"
@@ -600,15 +431,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
 dependencies = [
  "libc",
- "windows-sys 0.59.0",
+ "windows-sys",
 ]
 
-[[package]]
-name = "fallible-iterator"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
-
 [[package]]
 name = "fdt"
 version = "0.2.0-alpha1"
@@ -637,17 +462,6 @@ dependencies = [
  "wasi",
 ]
 
-[[package]]
-name = "gimli"
-version = "0.27.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
-dependencies = [
- "fallible-iterator",
- "indexmap 1.9.3",
- "stable_deref_trait",
-]
-
 [[package]]
 name = "gimli"
 version = "0.31.1"
@@ -666,15 +480,9 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
 dependencies = [
- "byteorder 1.5.0",
+ "byteorder",
 ]
 
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-
 [[package]]
 name = "hashbrown"
 version = "0.13.2"
@@ -714,19 +522,13 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
 [[package]]
 name = "home"
 version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -748,16 +550,6 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
-[[package]]
-name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown 0.12.3",
-]
-
 [[package]]
 name = "indexmap"
 version = "2.8.0"
@@ -817,12 +609,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "json"
-version = "0.11.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92c245af8786f6ac35f95ca14feca9119e71339aaab41e878e7cdd655c97e9e5"
-
 [[package]]
 name = "kcmdline_macros"
 version = "0.1.0"
@@ -831,6 +617,7 @@ version = "0.1.0"
 name = "kdepends"
 version = "0.1.0"
 dependencies = [
+ "another_ext4",
  "crc",
  "memoffset",
  "ringbuffer",
@@ -956,15 +743,6 @@ dependencies = [
  "hashbrown 0.15.2",
 ]
 
-[[package]]
-name = "mach"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa"
-dependencies = [
- "libc",
-]
-
 [[package]]
 name = "mach2"
 version = "0.4.2"
@@ -1192,12 +970,6 @@ dependencies = [
  "syn 2.0.100",
 ]
 
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
 [[package]]
 name = "proc-macro2"
 version = "1.0.94"
@@ -1286,34 +1058,13 @@ dependencies = [
 
 [[package]]
 name = "rbpf"
-version = "0.2.0"
+version = "0.3.0"
+source = "git+https://git.mirrors.dragonos.org.cn/DragonOS-Community/rbpf?rev=f31e471a29#f31e471a29dea9a0c272626f7b762adba755e6cc"
 dependencies = [
- "byteorder 1.5.0",
+ "byteorder",
  "combine",
- "cranelift-codegen",
- "cranelift-frontend",
- "cranelift-jit",
- "cranelift-module",
- "cranelift-native",
- "elf 0.0.10",
- "hex",
- "json",
- "libc",
- "log",
- "time",
-]
-
-[[package]]
-name = "regalloc2"
-version = "0.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6"
-dependencies = [
- "hashbrown 0.13.2",
+ "hashbrown 0.15.2",
  "log",
- "rustc-hash",
- "slice-group-by",
- "smallvec",
 ]
 
 [[package]]
@@ -1345,18 +1096,6 @@ version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
-[[package]]
-name = "region"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0"
-dependencies = [
- "bitflags 1.3.2",
- "libc",
- "mach",
- "winapi",
-]
-
 [[package]]
 name = "ringbuffer"
 version = "0.15.0"
@@ -1378,15 +1117,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
-[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-dependencies = [
- "semver",
-]
-
 [[package]]
 name = "rustix"
 version = "0.38.44"
@@ -1397,7 +1127,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1433,21 +1163,6 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
 [[package]]
 name = "serde"
 version = "1.0.219"
@@ -1489,21 +1204,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "sha1"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
-dependencies = [
- "sha1_smol",
-]
-
-[[package]]
-name = "sha1_smol"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
-
 [[package]]
 name = "shlex"
 version = "1.3.0"
@@ -1520,12 +1220,6 @@ dependencies = [
  "spin 0.9.8",
 ]
 
-[[package]]
-name = "slice-group-by"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
-
 [[package]]
 name = "smallvec"
 version = "1.14.0"
@@ -1539,7 +1233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb"
 dependencies = [
  "bitflags 1.3.2",
- "byteorder 1.5.0",
+ "byteorder",
  "cfg-if",
  "defmt",
  "heapless",
@@ -1567,15 +1261,6 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
 
-[[package]]
-name = "standback"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
-dependencies = [
- "version_check",
-]
-
 [[package]]
 name = "static-keys"
 version = "0.7.0"
@@ -1588,55 +1273,6 @@ dependencies = [
  "windows 0.59.0",
 ]
 
-[[package]]
-name = "stdweb"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
-dependencies = [
- "discard",
- "rustc_version",
- "stdweb-derive",
- "stdweb-internal-macros",
- "stdweb-internal-runtime",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "stdweb-derive"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
-dependencies = [
- "proc-macro2",
- "quote",
- "serde",
- "serde_derive",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "stdweb-internal-macros"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
-dependencies = [
- "base-x",
- "proc-macro2",
- "quote",
- "serde",
- "serde_derive",
- "serde_json",
- "sha1",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "stdweb-internal-runtime"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
-
 [[package]]
 name = "strsim"
 version = "0.11.1"
@@ -1673,16 +1309,11 @@ version = "0.1.0"
 name = "system_error"
 version = "0.1.0"
 dependencies = [
+ "kdepends",
  "num-derive",
  "num-traits 0.2.15",
 ]
 
-[[package]]
-name = "target-lexicon"
-version = "0.12.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
-
 [[package]]
 name = "target-triple"
 version = "0.1.4"
@@ -1727,44 +1358,6 @@ dependencies = [
  "syn 2.0.100",
 ]
 
-[[package]]
-name = "time"
-version = "0.2.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
-dependencies = [
- "const_fn",
- "libc",
- "standback",
- "stdweb",
- "time-macros",
- "version_check",
- "winapi",
-]
-
-[[package]]
-name = "time-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
-dependencies = [
- "proc-macro-hack",
- "time-macros-impl",
-]
-
-[[package]]
-name = "time-macros-impl"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
-dependencies = [
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "standback",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "toml"
 version = "0.8.20"
@@ -1792,7 +1385,7 @@ version = "0.22.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
 dependencies = [
- "indexmap 2.8.0",
+ "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -1900,7 +1493,7 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987"
 dependencies = [
- "gimli 0.31.1",
+ "gimli",
 ]
 
 [[package]]
@@ -1944,75 +1537,6 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
-dependencies = [
- "cfg-if",
- "once_cell",
- "rustversion",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn 2.0.100",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.100",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "wasmtime-jit-icache-coherence"
-version = "12.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b59f94b0409221873565419168e20b5aedf18c4bd64de5c38acf8f0634efeee3"
-dependencies = [
- "cfg-if",
- "libc",
- "windows-sys 0.48.0",
-]
-
 [[package]]
 name = "which"
 version = "4.4.2"
@@ -2047,7 +1571,7 @@ version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -2189,15 +1713,6 @@ dependencies = [
  "windows-link",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
 [[package]]
 name = "windows-sys"
 version = "0.59.0"
@@ -2207,21 +1722,6 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
 [[package]]
 name = "windows-targets"
 version = "0.52.6"
@@ -2254,12 +1754,6 @@ dependencies = [
  "windows_x86_64_msvc 0.53.0",
 ]
 
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
 [[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.52.6"
@@ -2272,12 +1766,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
 
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.52.6"
@@ -2290,12 +1778,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
 
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
 [[package]]
 name = "windows_i686_gnu"
 version = "0.52.6"
@@ -2320,12 +1802,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
 
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
 [[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
@@ -2338,12 +1814,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
 
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.52.6"
@@ -2356,12 +1826,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
 
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.52.6"
@@ -2374,12 +1838,6 @@ version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
 
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.52.6"
@@ -2458,7 +1916,7 @@ version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
- "byteorder 1.5.0",
+ "byteorder",
  "zerocopy-derive 0.7.35",
 ]
 

+ 7 - 3
kernel/Cargo.toml

@@ -25,6 +25,9 @@ driver_ps2_mouse = []
 kprobe_test = []
 static_keys_test = []
 
+# kstack_protect 开启该功能后,会开启内核栈保护功能。用于辅助检测栈溢出。(内核栈占用会*2)
+kstack_protect = []
+
 # 运行时依赖项
 [dependencies]
 acpi = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/acpi-rs.git", rev = "282df2af7b" }
@@ -73,15 +76,16 @@ log = "0.4.21"
 kprobe = { path = "crates/kprobe" }
 lru = "0.12.3"
 
-rbpf = { path = "crates/rbpf" }
+rbpf = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/rbpf", rev = "f31e471a29", default-features = false }
 printf-compat = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/printf-compat", rev = "5f5c9cc363", default-features = false }
 
 static-keys = { version = "=0.7" }
 
 defer = "0.2.1"
 cfg-if = { version = "1.0.0" }
-derive_builder = { version = "0.20.2", default-features = false, features = ["alloc"] }
-
+derive_builder = { version = "0.20.2", default-features = false, features = [
+    "alloc",
+] }
 
 # target为x86_64时,使用下面的依赖
 [target.'cfg(target_arch = "x86_64")'.dependencies]

+ 1 - 4
kernel/Makefile

@@ -41,7 +41,4 @@ check: ECHO
 
 test:
 # 测试内核库
-	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 test --workspace --exclude dragonos_kernel rbpf
-
-test-rbpf:
-	cd crates/rbpf && RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 test --features=std,user,cranelift
+	RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-11-05 test --workspace --exclude dragonos_kernel

+ 2 - 0
kernel/crates/bitmap/src/traits.rs

@@ -284,6 +284,8 @@ pub trait BitMapOps<T: BitOps> {
     fn last_false_index(&self) -> Option<usize>;
 
     /// 获取指定index之后第一个为1的位的index
+    ///
+    /// **注意**: 这个不包含当前的index位(如果index位的值是1,那么它是会跳过这个位的)
     fn next_index(&self, index: usize) -> Option<usize>;
 
     /// 获取指定index之后第一个为0的位的index

+ 1 - 0
kernel/crates/kdepends/Cargo.toml

@@ -11,6 +11,7 @@ crc = { path = "../crc" }
 memoffset = "0.9.0"
 ringbuffer = "0.15.0"
 xarray = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/xarray", rev = "de93b57c34", features = ["slab-friendly"] }
+another_ext4 = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/another_ext4.git", rev = "bf782ff294", default-features = false }
 
 # 一个无锁MPSC队列
 [dependencies.thingbuf]

+ 2 - 0
kernel/crates/kdepends/src/lib.rs

@@ -8,3 +8,5 @@ pub extern crate ringbuffer;
 
 pub extern crate crc;
 pub extern crate xarray;
+
+pub extern crate another_ext4;

+ 0 - 21
kernel/crates/rbpf/.appveyor.yml

@@ -1,21 +0,0 @@
-version: 1.0.{build}
-branches:
-  only:
-    - main
-os:
-  - Visual Studio 2015
-clone_depth: 1
-configuration:
-  - Debug
-platform:
-  - x64
-environment:
-  matrix:
-    - TOOLCHAIN_VERSION: 14.0
-      RUST: 1.76.0
-    - TOOLCHAIN_VERSION: 14.0
-      RUST: beta
-    - TOOLCHAIN_VERSION: 14.0
-      RUST: nightly
-
-build_script: mk/appveyor.bat

+ 0 - 2
kernel/crates/rbpf/.gitignore

@@ -1,2 +0,0 @@
-target
-Cargo.lock

+ 0 - 78
kernel/crates/rbpf/Cargo.toml

@@ -1,78 +0,0 @@
-[package]
-
-# Project metadata
-name = "rbpf"
-version = "0.2.0"
-authors = ["Quentin <quentin@isovalent.com>"]
-
-# Additional metadata for packaging
-description = "Virtual machine and JIT compiler for eBPF programs"
-repository = "https://github.com/qmonnet/rbpf"
-readme = "README.md"
-keywords = ["BPF", "eBPF", "interpreter", "JIT", "filtering"]
-license = "Apache-2.0/MIT"
-edition = "2021"
-
-# Packaging directives
-include = [
-    "src/**",
-    "examples/**",
-    "tests/**",
-    "bench/**",
-    "LICENSE*",
-    "Cargo.toml",
-]
-
-[dependencies]
-
-# Default features (std) are disabled so that the dependencies don't pull in the
-# standard library when the crate is compiled for no_std
-byteorder = { version = "1.2", default-features = false }
-log = {version = "0.4.21", default-features = false }
-combine = { version = "4.6", default-features = false }
-
-# Optional Dependencies when using the standard library
-libc = { version = "0.2", optional = true }
-time = { version = "0.2", optional = true }
-
-# Optional Dependencies for the CraneLift JIT
-cranelift-codegen = { version = "0.99", optional = true }
-cranelift-frontend = { version = "0.99", optional = true }
-cranelift-jit = { version = "0.99", optional = true }
-cranelift-native = { version = "0.99", optional = true }
-cranelift-module = { version = "0.99", optional = true }
-
-[dev-dependencies]
-
-elf = "0.0.10"
-json = "0.11"
-hex = "0.4.3"
-
-[features]
-#default = ["std", "user", "cranelift"]
-cargo-clippy = []
-std = ["dep:time", "dep:libc", "combine/std"]
-cranelift = [
-    "dep:cranelift-codegen",
-    "dep:cranelift-frontend",
-    "dep:cranelift-jit",
-    "dep:cranelift-native",
-    "dep:cranelift-module",
-]
-user = []
-
-# Examples that depend on the standard library should be disabled when
-# testing the `no_std` configuration.
-[[example]]
-name = "disassemble"
-required-features = ["std"]
-
-[[example]]
-name = "uptime"
-required-features = ["std"]
-
-[[example]]
-name = "to_json"
-
-[[example]]
-name = "rbpf_plugin"

+ 0 - 202
kernel/crates/rbpf/LICENSE-APACHE

@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.

+ 0 - 25
kernel/crates/rbpf/LICENSE-MIT

@@ -1,25 +0,0 @@
-Copyright (c) 2016 6WIND S.A.
-
-Permission is hereby granted, free of charge, to any
-person obtaining a copy of this software and associated
-documentation files (the "Software"), to deal in the
-Software without restriction, including without
-limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software
-is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice
-shall be included in all copies or substantial portions
-of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
-ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
-TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
-IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.

+ 0 - 743
kernel/crates/rbpf/README.md

@@ -1,743 +0,0 @@
-# rbpf
-
-<picture>
-  <source media="(prefers-color-scheme: dark)" srcset="misc/rbpf_256_border.png">
-  <img src="misc/rbpf_256.png">
-</picture>
-
-Rust (user-space) virtual machine for eBPF
-
-[![Build Status](https://github.com/qmonnet/rbpf/actions/workflows/test.yaml/badge.svg)](https://github.com/qmonnet/rbpf/actions/workflows/test.yaml)
-[![Build status](https://ci.appveyor.com/api/projects/status/ia74coeuhxtrcvsk/branch/main?svg=true)](https://ci.appveyor.com/project/qmonnet/rbpf/branch/main)
-[![Coverage Status](https://coveralls.io/repos/github/qmonnet/rbpf/badge.svg?branch=main)](https://coveralls.io/github/qmonnet/rbpf?branch=main)
-[![Crates.io](https://img.shields.io/crates/v/rbpf.svg)](https://crates.io/crates/rbpf)
-
-* [Description](#description)
-* [Link to the crate](#link-to-the-crate)
-* [API](#api)
-* [Example uses](#example-uses)
-* [Building eBPF programs](#building-ebpf-programs)
-* [Build Features](#build-features)
-* [Feedback welcome!](#feedback-welcome)
-* [Questions / Answers](#questions--answers)
-* [Caveats](#caveats)
-* [_To do_ list](#to-do-list)
-* [License](#license)
-* [Inspired by](#inspired-by)
-* [Other resources](#other-resources)
-
-## Description
-
-This crate contains a virtual machine for eBPF program execution. BPF, as in
-_Berkeley Packet Filter_, is an assembly-like language initially developed for
-BSD systems, in order to filter packets in the kernel with tools such as
-tcpdump so as to avoid useless copies to user-space. It was ported to Linux,
-where it evolved into eBPF (_extended_ BPF), a faster version with more
-features. While BPF programs are originally intended to run in the kernel, the
-virtual machine of this crate enables running it in user-space applications;
-it contains an interpreter, an x86_64 JIT-compiler for eBPF programs, as well as
-a disassembler.
-
-It is based on Rich Lane's [uBPF software](https://github.com/iovisor/ubpf/),
-which does nearly the same, but is written in C.
-
-The crate is supposed to compile and run on Linux, MacOS X, and Windows,
-although the JIT-compiler does not work with Windows at this time.
-
-## Link to the crate
-
-This crate is available from [crates.io](https://crates.io/crates/rbpf), so it
-should work out of the box by adding it as a dependency in your `Cargo.toml`
-file:
-
-```toml
-[dependencies]
-rbpf = "0.2.0"
-```
-
-You can also use the development version from this GitHub repository. This
-should be as simple as putting this inside your `Cargo.toml`:
-
-```toml
-[dependencies]
-rbpf = { git = "https://github.com/qmonnet/rbpf" }
-```
-
-Of course, if you prefer, you can clone it locally, possibly hack the crate,
-and then indicate the path of your local version in `Cargo.toml`:
-
-```toml
-[dependencies]
-rbpf = { path = "path/to/rbpf" }
-```
-
-Then indicate in your source code that you want to use the crate:
-
-```rust,ignore
-extern crate rbpf;
-```
-
-## API
-
-The API is pretty well documented inside the source code. You should also be
-able to access [an online version of the documentation from
-here](https://docs.rs/rbpf/), automatically generated from the
-[crates.io](https://crates.io/crates/rbpf) version (may not be up-to-date with
-the main branch). [Examples](../../tree/main/examples) and [unit
-tests](../../tree/main/tests) should also prove helpful. Here is a summary of
-how to use the crate.
-
-Here are the steps to follow to run an eBPF program with rbpf:
-
-1. Create a virtual machine. There are several kinds of machines, we will come
-   back on this later. When creating the VM, pass the eBPF program as an
-   argument to the constructor.
-2. If you want to use some helper functions, register them into the virtual
-   machine.
-3. If you want a JIT-compiled program, compile it.
-4. Execute your program: either run the interpreter or call the JIT-compiled
-   function.
-
-eBPF has been initially designed to filter packets (now it has some other hooks
-in the Linux kernel, such as kprobes, but this is not covered by rbpf). As a
-consequence, most of the load and store instructions of the program are
-performed on a memory area representing the packet data. However, in the Linux
-kernel, the eBPF program does not immediately access this data area: initially,
-it has access to a C `struct sk_buff` instead, which is a buffer containing
-metadata about the packet—including memory addresses of the beginning and of
-the end of the packet data area. So the program first loads those pointers from
-the `sk_buff`, and then can access the packet data.
-
-This behavior can be replicated with rbpf, but it is not mandatory. For this
-reason, we have several structs representing different kinds of virtual
-machines:
-
-* `struct EbpfVmMbuffer` mimics the kernel. When the program is run, the
-  address provided to its first eBPF register will be the address of a metadata
-  buffer provided by the user, and that is expected to contain pointers to the
-  start and the end of the packet data memory area.
-
-* `struct EbpfVmFixedMbuff` has one purpose: enabling the execution of programs
-  created to be compatible with the kernel, while saving the effort to manually
-  handle the metadata buffer for the user. In fact, this struct has a static
-  internal buffer that is passed to the program. The user has to indicate the
-  offset values at which the eBPF program expects to find the start and the end
-  of packet data in the buffer. On calling the function that runs the program
-  (JITted or not), the struct automatically updates the addresses in this
-  static buffer, at the appointed offsets, for the start and the end of the
-  packet data the program is called upon.
-
-* `struct EbpfVmRaw` is for programs that want to run directly on packet data.
-  No metadata buffer is involved, the eBPF program directly receives the
-  address of the packet data in its first register. This is the behavior of
-  uBPF.
-
-* `struct EbpfVmNoData` does not take any data. The eBPF program takes no
-  argument whatsoever and its return value is deterministic. Not so sure there
-  is a valid use case for that, but if nothing else, this is very useful for
-  unit tests.
-
-All these structs implement the same public functions:
-
-```rust,ignore
-// called with EbpfVmMbuff:: prefix
-pub fn new(prog: &'a [u8]) -> Result<EbpfVmMbuff<'a>, Error>
-
-// called with EbpfVmFixedMbuff:: prefix
-pub fn new(prog: &'a [u8],
-           data_offset: usize,
-           data_end_offset: usize) -> Result<EbpfVmFixedMbuff<'a>, Error>
-
-// called with EbpfVmRaw:: prefix
-pub fn new(prog: &'a [u8]) -> Result<EbpfVmRaw<'a>, Error>
-
-// called with EbpfVmNoData:: prefix
-pub fn new(prog: &'a [u8]) -> Result<EbpfVmNoData<'a>, Error>
-```
-
-This is used to create a new instance of a VM. The return type is dependent of
-the struct from which the function is called. For instance,
-`rbpf::EbpfVmRaw::new(Some(my_program))` would return an instance of `struct
-rbpf::EbpfVmRaw` (wrapped in a `Result`). When a program is loaded, it is
-checked with a very simple verifier (nothing close to the one for Linux
-kernel). Users are also able to replace it with a custom verifier.
-
-For `struct EbpfVmFixedMbuff`, two additional arguments must be passed to the
-constructor: `data_offset` and `data_end_offset`. They are the offset (byte
-number) at which the pointers to the beginning and to the end, respectively, of
-the memory area of packet data are to be stored in the internal metadata buffer
-each time the program is executed. Other structs do not use this mechanism and
-do not need those offsets.
-
-```rust,ignore
-// for struct EbpfVmMbuff, struct EbpfVmRaw and struct EbpfVmRawData
-pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error>
-
-// for struct EbpfVmFixedMbuff
-pub fn set_program(&mut self, prog: &'a [u8],
-                data_offset: usize,
-                data_end_offset: usize) -> Result<(), Error>
-```
-
-You can use for example `my_vm.set_program(my_program);` to change the loaded
-program after the VM instance creation. This program is checked with the
-verifier attached to the VM. The verifying function of the VM can be changed at
-any moment.
-
-```rust,ignore
-pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;
-
-pub fn set_verifier(&mut self,
-                    verifier: Verifier) -> Result<(), Error>
-```
-
-Note that if a program has already been loaded into the VM, setting a new
-verifier also immediately runs it on the loaded program. However, the verifier
-is not run if no program has been loaded (if `None` was passed to the `new()`
-method when creating the VM).
-
-```rust,ignore
-pub type Helper = fn (u64, u64, u64, u64, u64) -> u64;
-
-pub fn register_helper(&mut self,
-                       key: u32,
-                       function: Helper) -> Result<(), Error>
-```
-
-This function is used to register a helper function. The VM stores its
-registers in a hashmap, so the key can be any `u32` value you want. It may be
-useful for programs that should be compatible with the Linux kernel and
-therefore must use specific helper numbers.
-
-```rust,ignore
-// for struct EbpfVmMbuff
-pub fn execute_program(&self,
-                 mem: &'a mut [u8],
-                 mbuff: &'a mut [u8]) -> Result<(u64), Error>
-
-// for struct EbpfVmFixedMbuff and struct EbpfVmRaw
-pub fn execute_program(&self,
-                 mem: &'a mut [u8]) -> Result<(u64), Error>
-
-// for struct EbpfVmNoData
-pub fn execute_program(&self) -> Result<(u64), Error>
-```
-
-Interprets the loaded program. The function takes a reference to the packet
-data and the metadata buffer, or only to the packet data, or nothing at all,
-depending on the kind of the VM used. The value returned is the result of the
-eBPF program.
-
-```rust,ignore
-pub fn jit_compile(&mut self) -> Result<(), Error>
-```
-
-JIT-compile the loaded program, for x86_64 architecture. If the program is to
-use helper functions, they must be registered into the VM before this function
-is called. The generated assembly function is internally stored in the VM.
-
-```rust,ignore
-// for struct EbpfVmMbuff
-pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8],
-                            mbuff: &'a mut [u8]) -> Result<(u64), Error>
-
-// for struct EbpfVmFixedMbuff and struct EbpfVmRaw
-pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<(u64), Error>
-
-// for struct EbpfVmNoData
-pub unsafe fn execute_program_jit(&self) -> Result<(u64), Error>
-```
-
-Calls the JIT-compiled program. The arguments to provide are the same as for
-`execute_program()`, again depending on the kind of VM that is used. The result of
-the JIT-compiled program should be the same as with the interpreter, but it
-should run faster. Note that if errors occur during the program execution, the
-JIT-compiled version does not handle it as well as the interpreter, and the
-program may crash. For this reason, the functions are marked as `unsafe`.
-
-## Example uses
-
-### Simple example
-
-This comes from the unit test `test_vm_add`.
-
-```rust
-extern crate rbpf;
-
-fn main() {
-
-    // This is the eBPF program, in the form of bytecode instructions.
-    let prog = &[
-        0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov32 r0, 0
-        0xb4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov32 r1, 2
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // add32 r0, 1
-        0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // add32 r0, r1
-        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    ];
-
-    // Instantiate a struct EbpfVmNoData. This is an eBPF VM for programs that
-    // takes no packet data in argument.
-    // The eBPF program is passed to the constructor.
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-
-    // Execute (interpret) the program. No argument required for this VM.
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-```
-
-### With JIT, on packet data
-
-This comes from the unit test `test_jit_ldxh`.
-
-```rust
-extern crate rbpf;
-
-fn main() {
-    let prog = &[
-        0x71, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxh r0, [r1+2]
-        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    ];
-
-    // Let's use some data.
-    let mem = &mut [
-        0xaa, 0xbb, 0x11, 0xcc, 0xdd
-    ];
-
-    // This is an eBPF VM for programs reading from a given memory area (it
-    // directly reads from packet data)
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-
-    #[cfg(any(windows, not(feature = "std")))] {
-        assert_eq!(vm.execute_program(mem).unwrap(), 0x11);
-    }
-    #[cfg(all(not(windows), feature = "std"))] {
-        // This time we JIT-compile the program.
-        vm.jit_compile().unwrap();
-
-        // Then we execute it. For this kind of VM, a reference to the packet
-        // data must be passed to the function that executes the program.
-        unsafe { assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11); }
-    }
-}
-```
-### Using a metadata buffer
-
-This comes from the unit test `test_jit_mbuff` and derives from the unit test
-`test_jit_ldxh`.
-
-```rust
-extern crate rbpf;
-
-fn main() {
-    let prog = &[
-        // Load mem from mbuff at offset 8 into R1
-        0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
-        // ldhx r1[2], r0
-        0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-    ];
-    let mem = &mut [
-        0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    ];
-
-    // Just for the example we create our metadata buffer from scratch, and
-    // we store the pointers to packet data start and end in it.
-    let mut mbuff = &mut [0u8; 32];
-    unsafe {
-        let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
-        let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-        *data     = mem.as_ptr() as u64;
-        *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    }
-
-    // This eBPF VM is for program that use a metadata buffer.
-    let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-
-    #[cfg(any(windows, not(feature = "std")))] {
-        assert_eq!(vm.execute_program(mem, mbuff).unwrap(), 0x2211);
-    }
-    #[cfg(all(not(windows), feature = "std"))] {
-        // Here again we JIT-compile the program.
-        vm.jit_compile().unwrap();
-
-        // Here we must provide both a reference to the packet data, and to the
-        // metadata buffer we use.
-        unsafe {
-            assert_eq!(vm.execute_program_jit(mem, mbuff).unwrap(), 0x2211);
-        }
-    }
-}
-```
-
-### Loading code from an object file; and using a virtual metadata buffer
-
-This comes from unit test `test_vm_block_port`.
-
-This example requires the following additional crates, you may have to add them
-to your `Cargo.toml` file.
-
-```toml
-[dependencies]
-rbpf = "0.2.0"
-elf = "0.0.10"
-```
-
-It also uses a kind of VM that uses an internal buffer used to simulate the
-`sk_buff` used by eBPF programs in the kernel, without having to manually
-create a new buffer for each packet. It may be useful for programs compiled for
-the kernel and that assumes the data they receive is a `sk_buff` pointing to
-the packet data start and end addresses. So here we just provide the offsets at
-which the eBPF program expects to find those pointers, and the VM handles the
-buffer update so that we only have to provide a reference to the packet data
-for each run of the program.
-
-```rust
-extern crate elf;
-use std::path::PathBuf;
-
-extern crate rbpf;
-use rbpf::helpers;
-
-fn main() {
-    // Load a program from an ELF file, e.g. compiled from C to eBPF with
-    // clang/LLVM. Some minor modification to the bytecode may be required.
-    let filename = "examples/load_elf__block_a_port.elf";
-
-    let path = PathBuf::from(filename);
-    let file = match elf::File::open_path(&path) {
-        Ok(f) => f,
-        Err(e) => panic!("Error: {:?}", e),
-    };
-
-    // Here we assume the eBPF program is in the ELF section called
-    // ".classifier".
-    let text_scn = match file.get_section(".classifier") {
-        Some(s) => s,
-        None => panic!("Failed to look up .classifier section"),
-    };
-
-    let prog = &text_scn.data;
-
-    // This is our data: a real packet, starting with Ethernet header
-    let packet = &mut [
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
-        0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
-        0x08, 0x00,             // ethertype
-        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
-        0xa6, 0xab, 0x40, 0x00,
-        0x40, 0x06, 0x96, 0x0f,
-        0x7f, 0x00, 0x00, 0x01,
-        0x7f, 0x00, 0x00, 0x01,
-        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
-        0xd1, 0xe5, 0xc4, 0x9d,
-        0xd4, 0x30, 0xb5, 0xd2,
-        0x80, 0x18, 0x01, 0x56,
-        0xfe, 0x2f, 0x00, 0x00,
-        0x01, 0x01, 0x08, 0x0a, // start data
-        0x00, 0x23, 0x75, 0x89,
-        0x00, 0x23, 0x63, 0x2d,
-        0x71, 0x64, 0x66, 0x73,
-        0x64, 0x66, 0x0a
-    ];
-
-    // This is an eBPF VM for programs using a virtual metadata buffer, similar
-    // to the sk_buff that eBPF programs use with tc and in Linux kernel.
-    // We must provide the offsets at which the pointers to packet data start
-    // and end must be stored: these are the offsets at which the program will
-    // load the packet data from the metadata buffer.
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-
-    // We register a helper function, that can be called by the program, into
-    // the VM. The `bpf_trace_printf` is only available when we have access to
-    // the standard library.
-    #[cfg(feature = "std")] {
-        vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX,
-                           helpers::bpf_trace_printf).unwrap();
-    }
-
-    // This kind of VM takes a reference to the packet data, but does not need
-    // any reference to the metadata buffer: a fixed buffer is handled
-    // internally by the VM.
-    let res = vm.execute_program(packet).unwrap();
-    println!("Program returned: {:?} ({:#x})", res, res);
-}
-```
-
-## Building eBPF programs
-
-Besides passing the raw hexadecimal codes for building eBPF programs, two other
-methods are available.
-
-### Assembler
-
-The first method consists in using the assembler provided by the crate.
-
-```rust
-extern crate rbpf;
-use rbpf::assembler::assemble;
-
-let prog = assemble("add64 r1, 0x605
-                     mov64 r2, 0x32
-                     mov64 r1, r0
-                     be16 r0
-                     neg64 r2
-                     exit").unwrap();
-
-#[cfg(feature = "std")] {
-    println!("{:?}", prog);
-}
-```
-
-The above snippet will produce:
-
-```rust,ignore
-Ok([0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
-    0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
-    0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-    0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
-```
-
-Conversely, a disassembler is also available to dump instruction names from
-bytecode in a human-friendly format.
-
-```rust
-extern crate rbpf;
-use rbpf::disassembler::disassemble;
-
-let prog = &[
-    0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
-    0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
-    0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-    0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-];
-
-disassemble(prog);
-```
-
-This will produce the following output:
-
-```txt
-add64 r1, 0x605
-mov64 r2, 0x32
-mov64 r1, r0
-be16 r0
-neg64 r2
-exit
-```
-
-Please refer to [source code](src/assembler.rs) and [tests](tests/assembler.rs)
-for the syntax and the list of instruction names.
-
-### Building API
-
-The other way to build programs is to chain commands from the instruction
-builder API. It looks less like assembly, maybe more like high-level functions.
-What's sure is that the result is more verbose, but if you prefer to build
-programs this way, it works just as well. If we take again the same sample as
-above, it would be constructed as follows.
-
-```rust
-extern crate rbpf;
-use rbpf::insn_builder::*;
-
-let mut program = BpfCode::new();
-program.add(Source::Imm, Arch::X64).set_dst(1).set_imm(0x605).push()
-       .mov(Source::Imm, Arch::X64).set_dst(2).set_imm(0x32).push()
-       .mov(Source::Reg, Arch::X64).set_src(0).set_dst(1).push()
-       .swap_bytes(Endian::Big).set_dst(0).set_imm(0x10).push()
-       .negate(Arch::X64).set_dst(2).push()
-       .exit().push();
-```
-
-Again, please refer to [the source and related tests](src/insn_builder.rs) to
-get more information and examples on how to use it.
-
-## Build features
-
-### `no_std`
-
-The `rbpf` crate has a Cargo feature named "std" that is enabled by default. To
-use `rbpf` in `no_std` environments this feature needs to be disabled. To do
-this, you need to modify your dependency on `rbpf` in Cargo.toml to disable the
-enabled-by-default features.
-
-```toml
-[dependencies]
-rbpf = { version = "1.0", default-features = false }
-```
-
-Note that when using this crate in `no_std` environments, the `jit` module
-isn't available. This is because it depends on functions provided by `libc`
-(`libc::posix_memalign()`, `libc::mprotect()`) which aren't available on
-`no_std`.
-
-The `assembler` module is available, albeit with reduced debugging features. It
-depends on the `combine` crate providing parser combinators. Under `no_std`
-this crate only provides simple parsers which generate less descriptive error
-messages.
-
-## Feedback welcome!
-
-This is the author's first try at writing Rust code. He learned a lot in the
-process, but there remains a feeling that this crate has a kind of C-ish style
-in some places instead of the Rusty look the author would like it to have. So
-feedback (or PRs) are welcome, including about ways you might see to take
-better advantage of Rust features.
-
-Note that the project expects new commits to be covered by the
-[Developer's Certificate of Origin](https://wiki.linuxfoundation.org/dco).
-When contributing Pull Requests, please sign off your commits accordingly.
-
-## Questions / Answers
-
-### Why implementing an eBPF virtual machine in Rust?
-
-As of this writing, there is no particular use case for this crate at the best
-of the author's knowledge. The author happens to work with BPF on Linux and to
-know how uBPF works, and he wanted to learn and experiment with Rust—no more
-than that.
-
-### What are the differences with uBPF?
-
-Other than the language, obviously? Well, there are some differences:
-
-* Some constants, such as the maximum length for programs or the length for the
-  stack, differs between uBPF and rbpf. The latter uses the same values as the
-  Linux kernel, while uBPF has its own values.
-
-* When an error occurs while a program is run by uBPF, the function running the
-  program silently returns the maximum value as an error code, while rbpf
-  returns Rust type `Error`.
-
-* The registration of helper functions, that can be called from within an eBPF
-  program, is not handled in the same way.
-
-* The distinct structs permitting to run program either on packet data, or with
-  a metadata buffer (simulated or not) is a specificity of rbpf.
-
-* As for performance: theoretically the JITted programs are expected to run at
-  the same speed, while the C interpreter of uBPF should go slightly faster
-  than rbpf. But this has not been asserted yet. Benchmarking both programs
-  would be an interesting thing to do.
-
-### Can I use it with the “classic” BPF (a.k.a cBPF) version?
-
-No. This crate only works with extended BPF (eBPF) programs. For cBPF programs,
-such as used by tcpdump (as of this writing) for example, you may be interested
-in the [bpfjit crate](https://crates.io/crates/bpfjit) written by Alexander
-Polakov instead.
-
-### What functionalities are implemented?
-
-Running and JIT-compiling eBPF programs work. There is also a mechanism to
-register user-defined helper functions. The eBPF implementation of the Linux
-kernel comes with [some additional
-features](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md):
-a high number of helpers, several kinds of maps, tail calls.
-
-* Additional helpers should be easy to add, but very few of the existing Linux
-  helpers have been replicated in rbpf so far.
-
-* Tail calls (“long jumps” from an eBPF program into another) are not
-  implemented. This is probably not trivial to design and implement.
-
-* The interaction with maps is done through the use of specific helpers, so
-  this should not be difficult to add. The maps themselves can reuse the maps
-  in the kernel (if on Linux), to communicate with in-kernel eBPF programs for
-  instance; or they can be handled in user space. Rust has arrays and hashmaps,
-  so their implementation should be pretty straightforward (and may be added to
-  rbpf in the future).
-
-### What about program validation?
-
-The ”verifier” of this crate is very short and has nothing to do with the
-kernel verifier, which means that it accepts programs that may not be safe. On
-the other hand, you probably do not run this in a kernel here, so it will not
-crash your system. Implementing a verifier similar to the one in the kernel is
-not trivial, and we cannot “copy” it since it is under GPL license.
-
-### What about safety then?
-
-Rust has a strong emphasis on safety. Yet to have the eBPF VM work, some
-`unsafe` blocks of code are used. The VM, taken as an eBPF interpreter, can
-return an error but should not crash. Please file an issue otherwise.
-
-As for the JIT-compiler, it is a different story, since runtime memory checks
-are more complicated to implement in assembly. It _will_ crash if your
-JIT-compiled program tries to perform unauthorized memory accesses. Usually, it
-could be a good idea to test your program with the interpreter first.
-
-Oh, and if your program has infinite loops, even with the interpreter, you're
-on your own.
-
-## Caveats
-
-* This crate is **under development** and the API may be subject to change.
-
-* The JIT compiler produces an unsafe program: memory access are not tested at
-  runtime (yet). Use with caution.
-
-* A small number of eBPF instructions have not been implemented yet. This
-  should not be a problem for the majority of eBPF programs.
-
-* Beware of turnips. Turnips are disgusting.
-
-## _To do_ list
-
-* Implement some traits (`Clone`, `Drop`, `Debug` are good candidates).
-* Provide built-in support for user-space array and hash BPF maps.
-* Improve safety of JIT-compiled programs with runtime memory checks.
-* Add helpers (some of those supported in the kernel, such as checksum update,
-  could be helpful).
-* Improve verifier. Could we find a way to directly support programs compiled
-  with clang?
-* Maybe one day, tail calls?
-* JIT-compilers for other architectures?
-* …
-
-## License
-
-Following the effort of the Rust language project itself in order to ease
-integration with other projects, the rbpf crate is distributed under the terms
-of both the MIT license and the Apache License (Version 2.0).
-
-See
-[LICENSE-APACHE](https://github.com/qmonnet/rbpf/blob/main/LICENSE-APACHE)
-and [LICENSE-MIT](https://github.com/qmonnet/rbpf/blob/main/LICENSE-MIT) for
-details.
-
-## Version
-[The last commit](https://github.com/qmonnet/rbpf/commit/fe7021b07b08a43b836743a77796d07ce1f4902e)
-
-
-## Inspired by
-
-* [uBPF](https://github.com/iovisor/ubpf), a C user-space implementation of an
-  eBPF virtual machine, with a JIT-compiler and disassembler (and also
-  including the assembler from the human-readable form of the instructions,
-  such as in `mov r0, 0x1337`), by Rich Lane for Big Switch Networks (2015)
-
-* [_Building a simple JIT in
-  Rust_](https://www.sophiajt.com/building-a-simple-jit-in-rust),
-  by Sophia Turner (2015)
-
-* [bpfjit](https://github.com/polachok/bpfjit) (also [on
-  crates.io](https://crates.io/crates/bpfjit)), a Rust crate exporting the cBPF
-  JIT compiler from FreeBSD 10 tree to Rust, by Alexander Polakov (2016)
-
-## Other resources
-
-* Cilium project documentation about BPF: [_BPF and XDP Reference
-  Guide_](http://docs.cilium.io/en/latest/bpf/)
-
-* [Kernel documentation about BPF](https://docs.kernel.org/bpf/)
-
-* [_Dive into BPF: a list of reading
-  material_](https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf),
-  a blog article listing documentation for BPF and related technologies (2016)
-
-* [The Rust programming language](https://www.rust-lang.org)

+ 0 - 1
kernel/crates/rbpf/clippy.toml

@@ -1 +0,0 @@
-doc-valid-idents = ["eBPF", "uBPF"] 

+ 0 - 26
kernel/crates/rbpf/examples/disassemble.rs

@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
-
-extern crate rbpf;
-use rbpf::disassembler;
-
-// Simply disassemble a program into human-readable instructions.
-fn main() {
-    let prog = &[
-        0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x13, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2d, 0x23, 0x12, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x69, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x10, 0x00,
-        0x08, 0x00, 0x00, 0x00, 0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x0e,
-        0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf,
-        0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-        0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff,
-        0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x21, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x18, 0x02, 0x00, 0x00, 0x00,
-        0x00, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x21, 0x01, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    disassembler::disassemble(prog);
-}

+ 0 - 3
kernel/crates/rbpf/examples/helper.rs

@@ -1,3 +0,0 @@
-fn main() {
-    rbpf::helpers::show_helper();
-}

+ 0 - 115
kernel/crates/rbpf/examples/load_elf.rs

@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-#![allow(clippy::unreadable_literal)]
-
-extern crate elf;
-use std::path::PathBuf;
-
-extern crate rbpf;
-use rbpf::helpers;
-
-// The following example uses an ELF file that has been compiled from the C program available in
-// `load_elf__block_a_port.c` in the same directory.
-//
-// It was compiled with the following command:
-//
-// ```bash
-// clang -O2 -emit-llvm -c load_elf__block_a_port.c -o - | \
-//     llc -march=bpf -filetype=obj -o load_elf__block_a_port.o
-// ```
-//
-// Once compiled, this program can be injected into Linux kernel, with tc for instance. Sadly, we
-// need to bring some modifications to the generated bytecode in order to run it: the three
-// instructions with opcode 0x61 load data from a packet area as 4-byte words, where we need to
-// load it as 8-bytes double words (0x79). The kernel does the same kind of translation before
-// running the program, but rbpf does not implement this.
-//
-// In addition, the offset at which the pointer to the packet data is stored must be changed: since
-// we use 8 bytes instead of 4 for the start and end addresses of the data packet, we cannot use
-// the offsets produced by clang (0x4c and 0x50), the addresses would overlap. Instead we can use,
-// for example, 0x40 and 0x50.
-//
-// These change were applied with the following script:
-//
-// ```bash
-// xxd load_elf__block_a_port.o | sed '
-//     s/6112 5000 0000 0000/7912 5000 0000 0000/ ;
-//     s/6111 4c00 0000 0000/7911 4000 0000 0000/ ;
-//     s/6111 2200 0000 0000/7911 2200 0000 0000/' | xxd -r > load_elf__block_a_port.tmp
-
-// mv load_elf__block_a_port.tmp load_elf__block_a_port.o
-// ```
-//
-// The eBPF program was placed into the `.classifier` ELF section (see C code above), which means
-// that you can retrieve the raw bytecode with `readelf -x .classifier load_elf__block_a_port.o` or
-// with `objdump -s -j .classifier load_elf__block_a_port.o`.
-//
-// Once the bytecode has been edited, we can load the bytecode directly from the ELF object file.
-
-fn main() {
-    let filename = "examples/load_elf__block_a_port.elf";
-
-    let path = PathBuf::from(filename);
-    let file = match elf::File::open_path(path) {
-        Ok(f) => f,
-        Err(e) => panic!("Error: {:?}", e),
-    };
-
-    let text_scn = match file.get_section(".classifier") {
-        Some(s) => s,
-        None => panic!("Failed to look up .classifier section"),
-    };
-
-    let prog = &text_scn.data;
-
-    let packet1 = &mut [
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
-        0x00, // ethertype
-        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
-        0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
-        0x01,
-        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
-        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
-        0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
-        0x00, 0x01, 0x01, 0x08, 0x0a, // start data
-        0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
-    ];
-
-    let packet2 = &mut [
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
-        0x00, // ethertype
-        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
-        0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
-        0x01,
-        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
-        0x98, 0x76, 0xc6, 0xcc, // start tcp_hdr
-        0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
-        0x00, 0x01, 0x01, 0x08, 0x0a, // start data
-        0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
-    ];
-
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
-        .unwrap();
-
-    let res = vm.execute_program(packet1).unwrap();
-    println!("Packet #1, program returned: {res:?} ({res:#x})");
-    assert_eq!(res, 0xffffffff);
-
-    #[cfg(not(windows))]
-    {
-        vm.jit_compile().unwrap();
-
-        let res = unsafe { vm.execute_program_jit(packet2).unwrap() };
-        println!("Packet #2, program returned: {res:?} ({res:#x})");
-        assert_eq!(res, 0);
-    }
-
-    #[cfg(windows)]
-    {
-        let res = vm.execute_program(packet2).unwrap();
-        println!("Packet #2, program returned: {:?} ({:#x})", res, res);
-        assert_eq!(res, 0);
-    }
-}

+ 0 - 43
kernel/crates/rbpf/examples/load_elf__block_a_port.c

@@ -1,43 +0,0 @@
-// SPDX-License-Identifier: (APACHE-2.0 OR MIT)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// Block TCP packets on source or destination port 0x9999.
-
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/bpf.h>
-
-#define ETH_ALEN 6
-#define ETH_P_IP 0x0008 /* htons(0x0800) */
-#define TCP_HDR_LEN 20
-
-#define BLOCKED_TCP_PORT 0x9999
-
-struct eth_hdr {
-    unsigned char   h_dest[ETH_ALEN];
-    unsigned char   h_source[ETH_ALEN];
-    unsigned short  h_proto;
-};
-
-#define SEC(NAME) __attribute__((section(NAME), used))
-SEC(".classifier")
-int handle_ingress(struct __sk_buff *skb)
-{
-    void *data = (void *)(long)skb->data;
-    void *data_end = (void *)(long)skb->data_end;
-    struct eth_hdr *eth = data;
-    struct iphdr *iph = data + sizeof(*eth);
-    struct tcphdr *tcp = data + sizeof(*eth) + sizeof(*iph);
-
-    /* single length check */
-    if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcp) > data_end)
-        return 0;
-    if (eth->h_proto != ETH_P_IP)
-        return 0;
-    if (iph->protocol != IPPROTO_TCP)
-        return 0;
-    if (tcp->source == BLOCKED_TCP_PORT || tcp->dest == BLOCKED_TCP_PORT)
-        return -1;
-    return 0;
-}

+ 0 - 126
kernel/crates/rbpf/examples/rbpf_plugin.rs

@@ -1,126 +0,0 @@
-// Copyright Microsoft Corporation
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-// Path: examples/rbpf_plugin.rs
-use std::io::Read;
-
-// Helper function used by https://github.com/Alan-Jowett/bpf_conformance/blob/main/tests/call_unwind_fail.data
-fn _unwind(a: u64, _b: u64, _c: u64, _d: u64, _e: u64) -> u64 {
-    a
-}
-
-// This is a plugin for the bpf_conformance test suite (https://github.com/Alan-Jowett/bpf_conformance)
-// It accepts a single argument, the memory contents to pass to the VM.
-// It reads the program from stdin.
-fn main() {
-    let mut args: Vec<String> = std::env::args().collect();
-    #[allow(unused_mut)] // In no_std the jit variable isn't mutated.
-    let mut jit: bool = false;
-    let mut cranelift: bool = false;
-    let mut program_text = String::new();
-    let mut memory_text = String::new();
-
-    args.remove(0);
-
-    // Memory is always the first argument.
-    if !args.is_empty() {
-        memory_text.clone_from(&args[0]);
-        // Strip whitespace
-        memory_text.retain(|c| !c.is_whitespace());
-        args.remove(0);
-    }
-
-    // Process the rest of the arguments.
-    while !args.is_empty() {
-        match args[0].as_str() {
-            "--help" => {
-                println!("Usage: rbpf_plugin [memory] < program");
-                return;
-            }
-            "--jit" => {
-                #[cfg(any(windows, not(feature = "std")))]
-                {
-                    println!("JIT not supported");
-                    return;
-                }
-                #[cfg(all(not(windows), feature = "std"))]
-                {
-                    jit = true;
-                }
-            }
-            "--cranelift" => {
-                cranelift = true;
-
-                #[cfg(not(feature = "cranelift"))]
-                {
-                    let _ = cranelift;
-                    println!("Cranelift is not enabled");
-                    return;
-                }
-            }
-            "--program" => {
-                if args.len() < 2 {
-                    println!("Missing argument to --program");
-                    return;
-                }
-                args.remove(0);
-                if !args.is_empty() {
-                    program_text.clone_from(&args[0]);
-                    args.remove(0);
-                }
-            }
-            _ => panic!("Unknown argument {}", args[0]),
-        }
-        args.remove(0);
-    }
-
-    if program_text.is_empty() {
-        // Read program text from stdin
-        std::io::stdin().read_to_string(&mut program_text).unwrap();
-    }
-
-    // Strip whitespace
-    program_text.retain(|c| !c.is_whitespace());
-
-    // Convert program from hex to bytecode
-    let bytecode = hex::decode(program_text).unwrap();
-
-    // Convert memory from hex to bytes
-    let mut memory: Vec<u8> = hex::decode(memory_text).unwrap();
-
-    // Create rbpf vm
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&bytecode)).unwrap();
-
-    // Register the helper function used by call_unwind_fail.data test.
-    vm.register_helper(5, _unwind).unwrap();
-
-    let result: u64;
-    if jit {
-        #[cfg(any(windows, not(feature = "std")))]
-        {
-            println!("JIT not supported");
-            return;
-        }
-        #[cfg(all(not(windows), feature = "std"))]
-        {
-            unsafe {
-                vm.jit_compile().unwrap();
-                result = vm.execute_program_jit(&mut memory).unwrap();
-            }
-        }
-    } else if cranelift {
-        #[cfg(not(feature = "cranelift"))]
-        {
-            println!("Cranelift is not enabled");
-            return;
-        }
-        #[cfg(feature = "cranelift")]
-        {
-            vm.cranelift_compile().unwrap();
-            result = vm.execute_program_cranelift(&mut memory).unwrap();
-        }
-    } else {
-        result = vm.execute_program(&mut memory).unwrap();
-    }
-    println!("{result:x}");
-}

+ 0 - 74
kernel/crates/rbpf/examples/to_json.rs

@@ -1,74 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
-
-#[macro_use]
-extern crate json;
-
-extern crate elf;
-use std::path::PathBuf;
-
-extern crate rbpf;
-use rbpf::disassembler;
-
-// Turn a program into a JSON string.
-//
-// Relies on `json` crate.
-//
-// You may copy this function and adapt it according to your needs. For instance, you may want to:
-//
-// * Remove the "desc" (description) attributes from the output.
-// * Print integers as integers, and not as strings containing their hexadecimal representation
-//   (just replace the relevant `format!()` calls by the commented values.
-fn to_json(prog: &[u8]) -> String {
-    // This call returns a high-level representation of the instructions, with the two parts of
-    // `LD_DW_IMM` instructions merged, and name and descriptions of the instructions.
-    // If you prefer to use a lower-level representation, use `ebpf::to_insn_vec()` function
-    // instead.
-    let insns = disassembler::to_insn_vec(prog);
-    let mut json_insns = vec![];
-    for insn in insns {
-        json_insns.push(object!(
-            "opc"  => format!("{:#x}", insn.opc), // => insn.opc,
-            "dst"  => format!("{:#x}", insn.dst), // => insn.dst,
-            "src"  => format!("{:#x}", insn.src), // => insn.src,
-            "off"  => format!("{:#x}", insn.off), // => insn.off,
-            // Warning: for imm we use a i64 instead of a i32 (to have correct values for
-            // `lddw` operation. If we print a number in the JSON this is not a problem, the
-            // internal i64 has the same value with extended sign on 32 most significant bytes.
-            // If we print the hexadecimal value as a string however, we want to cast as a i32
-            // to prevent all other instructions to print spurious `ffffffff` prefix if the
-            // number is negative. When values takes more than 32 bits with `lddw`, the cast
-            // has no effect and the complete value is printed anyway.
-            "imm"  => format!("{:#x}", insn.imm as i32), // => insn.imm,
-            "desc" => insn.desc
-        ));
-    }
-    json::stringify_pretty(
-        object!(
-        "size"  => json_insns.len(),
-        "insns" => json_insns
-        ),
-        4,
-    )
-}
-
-// Load a program from an object file, and prints it to standard output as a JSON string.
-fn main() {
-    // Let's reuse this file from `load_elf/example`.
-    let filename = "examples/load_elf__block_a_port.elf";
-
-    let path = PathBuf::from(filename);
-    let file = match elf::File::open_path(path) {
-        Ok(f) => f,
-        Err(e) => panic!("Error: {:?}", e),
-    };
-
-    let text_scn = match file.get_section(".classifier") {
-        Some(s) => s,
-        None => panic!("Failed to look up .classifier section"),
-    };
-
-    let prog = &text_scn.data;
-
-    println!("{}", to_json(prog));
-}

+ 0 - 78
kernel/crates/rbpf/examples/uptime.rs

@@ -1,78 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
-
-extern crate rbpf;
-use rbpf::helpers;
-
-// The main objectives of this example is to show:
-//
-// * the use of EbpfVmNoData function,
-// * and the use of a helper.
-//
-// The two eBPF programs are independent and are not related to one another.
-fn main() {
-    let prog1 = &[
-        0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov32 r0, 0
-        0xb4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov32 r1, 2
-        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // add32 r0, 1
-        0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // add32 r0, r1
-        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit and return r0
-    ];
-
-    // We use helper `bpf_time_getns()`, which is similar to helper `bpf_ktime_getns()` from Linux
-    // kernel. Hence rbpf::helpers module provides the index of this in-kernel helper as a
-    // constant, so that we can remain compatible with programs for the kernel. Here we also cast
-    // it to a u8 so as to use it directly in program instructions.
-    let hkey = helpers::BPF_KTIME_GETNS_IDX as u8;
-    let prog2 = &[
-        0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
-        0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
-        0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
-        0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
-        0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
-        0x85, 0x00, 0x00, 0x00, hkey, 0x00, 0x00, 0x00, // call helper <hkey>
-        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit and return r0
-    ];
-
-    // Create a VM: this one takes no data. Load prog1 in it.
-    let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();
-    // Execute prog1.
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-
-    // As struct EbpfVmNoData does not takes any memory area, its return value is mostly
-    // deterministic. So we know prog1 will always return 3. There is an exception: when it uses
-    // helpers, the latter may have non-deterministic values, and all calls may not return the same
-    // value.
-    //
-    // In the following example we use a helper to get the elapsed time since boot time: we
-    // reimplement uptime in eBPF, in Rust. Because why not.
-
-    vm.set_program(prog2).unwrap();
-    vm.register_helper(helpers::BPF_KTIME_GETNS_IDX, helpers::bpf_time_getns)
-        .unwrap();
-
-    let time;
-
-    #[cfg(all(not(windows), feature = "std"))]
-    {
-        vm.jit_compile().unwrap();
-
-        time = unsafe { vm.execute_program_jit().unwrap() };
-    }
-
-    #[cfg(any(windows, not(feature = "std")))]
-    {
-        time = vm.execute_program().unwrap();
-    }
-
-    let days = time / 10u64.pow(9) / 60 / 60 / 24;
-    let hours = (time / 10u64.pow(9) / 60 / 60) % 24;
-    let minutes = (time / 10u64.pow(9) / 60) % 60;
-    let seconds = (time / 10u64.pow(9)) % 60;
-    let nanosec = time % 10u64.pow(9);
-
-    println!(
-        "Uptime: {:#x} ns == {} days {:02}:{:02}:{:02}, {} ns",
-        time, days, hours, minutes, seconds, nanosec
-    );
-}

+ 0 - 72
kernel/crates/rbpf/mk/appveyor.bat

@@ -1,72 +0,0 @@
-echo on
-SetLocal EnableDelayedExpansion
-
-REM This is the recommended way to choose the toolchain version, according to
-REM Appveyor's documentation.
-SET PATH=C:\Program Files (x86)\MSBuild\%TOOLCHAIN_VERSION%\Bin;%PATH%
-
-set VCVARSALL="C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN_VERSION%\VC\vcvarsall.bat"
-
-if [%Platform%] NEQ [x64] goto win32
-set TARGET_ARCH=x86_64
-set TARGET_PROGRAM_FILES=%ProgramFiles%
-call %VCVARSALL% amd64
-if %ERRORLEVEL% NEQ 0 exit 1
-goto download
-
-:win32
-echo on
-if [%Platform%] NEQ [Win32] exit 1
-set TARGET_ARCH=i686
-set TARGET_PROGRAM_FILES=%ProgramFiles(x86)%
-call %VCVARSALL% amd64_x86
-if %ERRORLEVEL% NEQ 0 exit 1
-goto download
-
-:download
-REM vcvarsall turns echo off
-echo on
-
-mkdir windows_build_tools
-mkdir windows_build_tools\
-echo Downloading Yasm...
-powershell -Command "(New-Object Net.WebClient).DownloadFile('http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe', 'windows_build_tools\yasm.exe')"
-if %ERRORLEVEL% NEQ 0 (
-  echo ...downloading Yasm failed.
-  exit 1
-)
-
-set RUST_URL=https://static.rust-lang.org/dist/rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi
-echo Downloading %RUST_URL%...
-mkdir build
-powershell -Command "(New-Object Net.WebClient).DownloadFile('%RUST_URL%', 'build\rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi')"
-if %ERRORLEVEL% NEQ 0 (
-  echo ...downloading Rust failed.
-  exit 1
-)
-
-start /wait msiexec /i build\rust-%RUST%-%TARGET_ARCH%-pc-windows-msvc.msi INSTALLDIR="%TARGET_PROGRAM_FILES%\Rust %RUST%" /quiet /qn /norestart
-if %ERRORLEVEL% NEQ 0 exit 1
-
-set PATH="%TARGET_PROGRAM_FILES%\Rust %RUST%\bin";%cd%\windows_build_tools;%PATH%
-
-if [%Configuration%] == [Release] set CARGO_MODE=--release
-
-set
-
-link /?
-cl /?
-rustc --version
-cargo --version
-
-cargo test --all-features -vv %CARGO_MODE%
-if %ERRORLEVEL% NEQ 0 exit 1
-
-REM Verify that `cargo build`, independent from `cargo test`, works; i.e.
-REM verify that non-test builds aren't trying to use test-only features.
-cargo build -vv %CARGO_MODE%
-if %ERRORLEVEL% NEQ 0 exit 1
-
-REM Verify that we can build with all features
-cargo build --all-features -vv %CARGO_MODE%
-if %ERRORLEVEL% NEQ 0 exit 1

+ 0 - 3
kernel/crates/rbpf/rustfmt.toml

@@ -1,3 +0,0 @@
-group_imports="StdExternalCrate"
-reorder_imports=true
-imports_granularity="Crate"

+ 0 - 642
kernel/crates/rbpf/src/asm_parser.rs

@@ -1,642 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 Rich Lane <lanerl@gmail.com>
-
-// Rust-doc comments were left in the module, but it is no longer publicly exposed from the root
-// file of the crate. Do not expect to find those comments in the documentation of the crate.
-
-//! This module parses eBPF assembly language source code.
-
-use alloc::{
-    string::{String, ToString},
-    vec::Vec,
-};
-
-#[cfg(feature = "std")]
-use combine::EasyParser;
-use combine::{
-    attempt, between, eof, many, many1, one_of, optional,
-    parser::char::{alpha_num, char, digit, hex_digit, spaces, string},
-    sep_by,
-    stream::position::{self},
-    ParseError, Parser, Stream,
-};
-
-/// Operand of an instruction.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum Operand {
-    /// Register number.
-    Register(i64),
-    /// Jump offset or immediate.
-    Integer(i64),
-    /// Register number and offset.
-    Memory(i64, i64),
-    /// Used for pattern matching.
-    Nil,
-}
-
-/// Parsed instruction.
-#[derive(Debug, PartialEq, Eq)]
-pub struct Instruction {
-    /// Instruction name.
-    pub name: String,
-    /// Operands.
-    pub operands: Vec<Operand>,
-}
-
-fn ident<I>() -> impl Parser<I, Output = String>
-where
-    I: Stream<Token = char>,
-    I::Error: ParseError<I::Token, I::Range, I::Position>,
-{
-    many1(alpha_num())
-}
-
-fn integer<I>() -> impl Parser<I, Output = i64>
-where
-    I: Stream<Token = char>,
-    I::Error: ParseError<I::Token, I::Range, I::Position>,
-{
-    let sign = optional(one_of("-+".chars())).map(|x| match x {
-        Some('-') => -1,
-        _ => 1,
-    });
-    let hex = string("0x")
-        .with(many1(hex_digit()))
-        .map(|x: String| u64::from_str_radix(&x, 16).unwrap() as i64);
-    let dec = many1(digit()).map(|x: String| x.parse::<i64>().unwrap());
-    (sign, attempt(hex).or(dec)).map(|(s, x)| s * x)
-}
-
-fn register<I>() -> impl Parser<I, Output = i64>
-where
-    I: Stream<Token = char>,
-    I::Error: ParseError<I::Token, I::Range, I::Position>,
-{
-    char('r')
-        .with(many1(digit()))
-        .map(|x: String| x.parse::<i64>().unwrap())
-}
-
-fn operand<I>() -> impl Parser<I, Output = Operand>
-where
-    I: Stream<Token = char>,
-    I::Error: ParseError<I::Token, I::Range, I::Position>,
-{
-    let register_operand = register().map(Operand::Register);
-    let immediate = integer().map(Operand::Integer);
-    let memory = between(char('['), char(']'), (register(), optional(integer())))
-        .map(|t| Operand::Memory(t.0, t.1.unwrap_or(0)));
-    register_operand.or(immediate).or(memory)
-}
-
-fn instruction<I>() -> impl Parser<I, Output = Instruction>
-where
-    I: Stream<Token = char>,
-    I::Error: ParseError<I::Token, I::Range, I::Position>,
-{
-    let operands = sep_by(operand(), char(',').skip(spaces()));
-    (ident().skip(spaces()), operands, spaces()).map(|t| Instruction {
-        name: t.0,
-        operands: t.1,
-    })
-}
-
-/// Parse a string into a list of instructions.
-///
-/// The instructions are not validated and may have invalid names and operand types.
-pub fn parse(input: &str) -> Result<Vec<Instruction>, String> {
-    let mut with = spaces().with(many(instruction()).skip(eof()));
-
-    #[cfg(feature = "std")]
-    {
-        match with.easy_parse(position::Stream::new(input)) {
-            Ok((insts, _)) => Ok(insts),
-            Err(err) => Err(err.to_string()),
-        }
-    }
-    #[cfg(not(feature = "std"))]
-    {
-        match with.parse(position::Stream::new(input)) {
-            Ok((insts, _)) => Ok(insts),
-            Err(err) => Err(err.to_string()),
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use alloc::{string::ToString, vec};
-
-    use combine::Parser;
-
-    use super::{ident, instruction, integer, operand, parse, register, Instruction, Operand};
-
-    // Unit tests for the different kinds of parsers.
-
-    #[test]
-    fn test_ident() {
-        assert_eq!(ident().parse("nop"), Ok(("nop".to_string(), "")));
-        assert_eq!(ident().parse("add32"), Ok(("add32".to_string(), "")));
-        assert_eq!(ident().parse("add32*"), Ok(("add32".to_string(), "*")));
-    }
-
-    #[test]
-    fn test_integer() {
-        assert_eq!(integer().parse("0"), Ok((0, "")));
-        assert_eq!(integer().parse("42"), Ok((42, "")));
-        assert_eq!(integer().parse("+42"), Ok((42, "")));
-        assert_eq!(integer().parse("-42"), Ok((-42, "")));
-        assert_eq!(integer().parse("0x0"), Ok((0, "")));
-        assert_eq!(
-            integer().parse("0x123456789abcdef0"),
-            Ok((0x123456789abcdef0, ""))
-        );
-        assert_eq!(integer().parse("-0x1f"), Ok((-31, "")));
-    }
-
-    #[test]
-    fn test_register() {
-        assert_eq!(register().parse("r0"), Ok((0, "")));
-        assert_eq!(register().parse("r15"), Ok((15, "")));
-    }
-
-    #[test]
-    fn test_operand() {
-        assert_eq!(operand().parse("r0"), Ok((Operand::Register(0), "")));
-        assert_eq!(operand().parse("r15"), Ok((Operand::Register(15), "")));
-        assert_eq!(operand().parse("0"), Ok((Operand::Integer(0), "")));
-        assert_eq!(operand().parse("42"), Ok((Operand::Integer(42), "")));
-        assert_eq!(operand().parse("[r1]"), Ok((Operand::Memory(1, 0), "")));
-        assert_eq!(operand().parse("[r3+5]"), Ok((Operand::Memory(3, 5), "")));
-        assert_eq!(
-            operand().parse("[r3+0x1f]"),
-            Ok((Operand::Memory(3, 31), ""))
-        );
-        assert_eq!(
-            operand().parse("[r3-0x1f]"),
-            Ok((Operand::Memory(3, -31), ""))
-        );
-    }
-
-    #[test]
-    fn test_instruction() {
-        assert_eq!(
-            instruction().parse("exit"),
-            Ok((
-                Instruction {
-                    name: "exit".to_string(),
-                    operands: vec![],
-                },
-                ""
-            ))
-        );
-
-        assert_eq!(
-            instruction().parse("call 2"),
-            Ok((
-                Instruction {
-                    name: "call".to_string(),
-                    operands: vec![Operand::Integer(2)],
-                },
-                ""
-            ))
-        );
-
-        assert_eq!(
-            instruction().parse("addi r1, 2"),
-            Ok((
-                Instruction {
-                    name: "addi".to_string(),
-                    operands: vec![Operand::Register(1), Operand::Integer(2)],
-                },
-                ""
-            ))
-        );
-
-        assert_eq!(
-            instruction().parse("ldxb r2, [r1+12]"),
-            Ok((
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Memory(1, 12)],
-                },
-                ""
-            ))
-        );
-
-        assert_eq!(
-            instruction().parse("lsh r3, 0x8"),
-            Ok((
-                Instruction {
-                    name: "lsh".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(8)],
-                },
-                ""
-            ))
-        );
-
-        assert_eq!(
-            instruction().parse("jne r3, 0x8, +37"),
-            Ok((
-                Instruction {
-                    name: "jne".to_string(),
-                    operands: vec![
-                        Operand::Register(3),
-                        Operand::Integer(8),
-                        Operand::Integer(37)
-                    ],
-                },
-                ""
-            ))
-        );
-
-        // Whitespace between operands is optional.
-        assert_eq!(
-            instruction().parse("jne r3,0x8,+37"),
-            Ok((
-                Instruction {
-                    name: "jne".to_string(),
-                    operands: vec![
-                        Operand::Register(3),
-                        Operand::Integer(8),
-                        Operand::Integer(37)
-                    ],
-                },
-                ""
-            ))
-        );
-    }
-
-    // Other unit tests: try to parse various set of instructions.
-
-    #[test]
-    fn test_empty() {
-        assert_eq!(parse(""), Ok(vec![]));
-    }
-
-    #[test]
-    fn test_exit() {
-        // No operands.
-        assert_eq!(
-            parse("exit"),
-            Ok(vec![Instruction {
-                name: "exit".to_string(),
-                operands: vec![],
-            }])
-        );
-    }
-
-    #[test]
-    fn test_lsh() {
-        // Register and immediate operands.
-        assert_eq!(
-            parse("lsh r3, 0x20"),
-            Ok(vec![Instruction {
-                name: "lsh".to_string(),
-                operands: vec![Operand::Register(3), Operand::Integer(0x20)],
-            }])
-        );
-    }
-
-    #[test]
-    fn test_ja() {
-        // Jump offset operand.
-        assert_eq!(
-            parse("ja +1"),
-            Ok(vec![Instruction {
-                name: "ja".to_string(),
-                operands: vec![Operand::Integer(1)],
-            }])
-        );
-    }
-
-    #[test]
-    fn test_ldxh() {
-        // Register and memory operands.
-        assert_eq!(
-            parse("ldxh r4, [r1+12]"),
-            Ok(vec![Instruction {
-                name: "ldxh".to_string(),
-                operands: vec![Operand::Register(4), Operand::Memory(1, 12)],
-            }])
-        );
-    }
-
-    #[test]
-    fn test_tcp_sack() {
-        // Sample program from ubpf.
-        // We could technically indent the instructions since the parser support white spaces at
-        // the beginning, but there is another test for that.
-        let src = "\
-ldxb r2, [r1+12]
-ldxb r3, [r1+13]
-lsh r3, 0x8
-or r3, r2
-mov r0, 0x0
-jne r3, 0x8, +37
-ldxb r2, [r1+23]
-jne r2, 0x6, +35
-ldxb r2, [r1+14]
-add r1, 0xe
-and r2, 0xf
-lsh r2, 0x2
-add r1, r2
-mov r0, 0x0
-ldxh r4, [r1+12]
-add r1, 0x14
-rsh r4, 0x2
-and r4, 0x3c
-mov r2, r4
-add r2, 0xffffffec
-mov r5, 0x15
-mov r3, 0x0
-jgt r5, r4, +20
-mov r5, r3
-lsh r5, 0x20
-arsh r5, 0x20
-mov r4, r1
-add r4, r5
-ldxb r5, [r4]
-jeq r5, 0x1, +4
-jeq r5, 0x0, +12
-mov r6, r3
-jeq r5, 0x5, +9
-ja +2
-add r3, 0x1
-mov r6, r3
-ldxb r3, [r4+1]
-add r3, r6
-lsh r3, 0x20
-arsh r3, 0x20
-jsgt r2, r3, -18
-ja +1
-mov r0, 0x1
-exit
-";
-
-        assert_eq!(
-            parse(src),
-            Ok(vec![
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Memory(1, 12)],
-                },
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Memory(1, 13)],
-                },
-                Instruction {
-                    name: "lsh".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(8)],
-                },
-                Instruction {
-                    name: "or".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Register(2)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(0), Operand::Integer(0)],
-                },
-                Instruction {
-                    name: "jne".to_string(),
-                    operands: vec![
-                        Operand::Register(3),
-                        Operand::Integer(8),
-                        Operand::Integer(37)
-                    ],
-                },
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Memory(1, 23)],
-                },
-                Instruction {
-                    name: "jne".to_string(),
-                    operands: vec![
-                        Operand::Register(2),
-                        Operand::Integer(6),
-                        Operand::Integer(35)
-                    ],
-                },
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Memory(1, 14)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(1), Operand::Integer(14)],
-                },
-                Instruction {
-                    name: "and".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Integer(15)],
-                },
-                Instruction {
-                    name: "lsh".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Integer(2)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(1), Operand::Register(2)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(0), Operand::Integer(0)],
-                },
-                Instruction {
-                    name: "ldxh".to_string(),
-                    operands: vec![Operand::Register(4), Operand::Memory(1, 12)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(1), Operand::Integer(20)],
-                },
-                Instruction {
-                    name: "rsh".to_string(),
-                    operands: vec![Operand::Register(4), Operand::Integer(2)],
-                },
-                Instruction {
-                    name: "and".to_string(),
-                    operands: vec![Operand::Register(4), Operand::Integer(60)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Register(4)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(2), Operand::Integer(4294967276)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(5), Operand::Integer(21)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(0)],
-                },
-                Instruction {
-                    name: "jgt".to_string(),
-                    operands: vec![
-                        Operand::Register(5),
-                        Operand::Register(4),
-                        Operand::Integer(20)
-                    ],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(5), Operand::Register(3)],
-                },
-                Instruction {
-                    name: "lsh".to_string(),
-                    operands: vec![Operand::Register(5), Operand::Integer(32)],
-                },
-                Instruction {
-                    name: "arsh".to_string(),
-                    operands: vec![Operand::Register(5), Operand::Integer(32)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(4), Operand::Register(1)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(4), Operand::Register(5)],
-                },
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(5), Operand::Memory(4, 0)],
-                },
-                Instruction {
-                    name: "jeq".to_string(),
-                    operands: vec![
-                        Operand::Register(5),
-                        Operand::Integer(1),
-                        Operand::Integer(4)
-                    ],
-                },
-                Instruction {
-                    name: "jeq".to_string(),
-                    operands: vec![
-                        Operand::Register(5),
-                        Operand::Integer(0),
-                        Operand::Integer(12)
-                    ],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(6), Operand::Register(3)],
-                },
-                Instruction {
-                    name: "jeq".to_string(),
-                    operands: vec![
-                        Operand::Register(5),
-                        Operand::Integer(5),
-                        Operand::Integer(9)
-                    ],
-                },
-                Instruction {
-                    name: "ja".to_string(),
-                    operands: vec![Operand::Integer(2)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(1)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(6), Operand::Register(3)],
-                },
-                Instruction {
-                    name: "ldxb".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Memory(4, 1)],
-                },
-                Instruction {
-                    name: "add".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Register(6)],
-                },
-                Instruction {
-                    name: "lsh".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(32)],
-                },
-                Instruction {
-                    name: "arsh".to_string(),
-                    operands: vec![Operand::Register(3), Operand::Integer(32)],
-                },
-                Instruction {
-                    name: "jsgt".to_string(),
-                    operands: vec![
-                        Operand::Register(2),
-                        Operand::Register(3),
-                        Operand::Integer(-18)
-                    ],
-                },
-                Instruction {
-                    name: "ja".to_string(),
-                    operands: vec![Operand::Integer(1)],
-                },
-                Instruction {
-                    name: "mov".to_string(),
-                    operands: vec![Operand::Register(0), Operand::Integer(1)],
-                },
-                Instruction {
-                    name: "exit".to_string(),
-                    operands: vec![],
-                }
-            ])
-        );
-    }
-
-    /// When running without `std` the `EasyParser` provided by `combine`
-    /// cannot be used. Because of this we need to use the `Parser` and the
-    /// error messages are different.
-    #[test]
-    fn test_error_eof() {
-        let expected_error;
-        #[cfg(feature = "std")]
-        {
-            expected_error = Err(
-                "Parse error at line: 1, column: 6\nUnexpected end of input\nExpected digit\n"
-                    .to_string(),
-            );
-        }
-        #[cfg(not(feature = "std"))]
-        {
-            expected_error = Err("unexpected parse".to_string());
-        }
-        // Unexpected end of input in a register name.
-        assert_eq!(parse("lsh r"), expected_error);
-    }
-
-    /// When running without `std` the `EasyParser` provided by `combine`
-    /// cannot be used. Because of this we need to use the `Parser` and the
-    /// error messages are different.
-    #[test]
-    fn test_error_unexpected_character() {
-        let expected_error;
-        #[cfg(feature = "std")]
-        {
-            expected_error = Err(
-                "Parse error at line: 2, column: 1\nUnexpected `^`\nExpected letter or digit, whitespaces, `r`, `-`, `+`, `[` or end of input\n".to_string()
-            );
-        }
-        #[cfg(not(feature = "std"))]
-        {
-            expected_error = Err("unexpected parse".to_string());
-        }
-        // Unexpected character at end of input.
-        assert_eq!(parse("exit\n^"), expected_error);
-    }
-
-    #[test]
-    fn test_initial_whitespace() {
-        assert_eq!(
-            parse(
-                " 
-                          exit"
-            ),
-            Ok(vec![Instruction {
-                name: "exit".to_string(),
-                operands: vec![],
-            }])
-        );
-    }
-}

+ 0 - 277
kernel/crates/rbpf/src/assembler.rs

@@ -1,277 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 Rich Lane <lanerl@gmail.com>
-
-//! This module translates eBPF assembly language to binary.
-
-use alloc::{
-    collections::BTreeMap,
-    format,
-    string::{String, ToString},
-    vec,
-    vec::Vec,
-};
-
-use self::InstructionType::{
-    AluBinary, AluUnary, Call, Endian, JumpConditional, JumpUnconditional, LoadAbs, LoadImm,
-    LoadInd, LoadReg, NoOperand, StoreImm, StoreReg,
-};
-use crate::{
-    asm_parser::{
-        parse, Instruction, Operand,
-        Operand::{Integer, Memory, Nil, Register},
-    },
-    ebpf::{self, Insn},
-};
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum InstructionType {
-    AluBinary,
-    AluUnary,
-    LoadImm,
-    LoadAbs,
-    LoadInd,
-    LoadReg,
-    StoreImm,
-    StoreReg,
-    JumpUnconditional,
-    JumpConditional,
-    Call,
-    Endian(i64),
-    NoOperand,
-}
-
-fn make_instruction_map() -> BTreeMap<String, (InstructionType, u8)> {
-    let mut result = BTreeMap::new();
-
-    let alu_binary_ops = [
-        ("add", ebpf::BPF_ADD),
-        ("sub", ebpf::BPF_SUB),
-        ("mul", ebpf::BPF_MUL),
-        ("div", ebpf::BPF_DIV),
-        ("or", ebpf::BPF_OR),
-        ("and", ebpf::BPF_AND),
-        ("lsh", ebpf::BPF_LSH),
-        ("rsh", ebpf::BPF_RSH),
-        ("mod", ebpf::BPF_MOD),
-        ("xor", ebpf::BPF_XOR),
-        ("mov", ebpf::BPF_MOV),
-        ("arsh", ebpf::BPF_ARSH),
-    ];
-
-    let mem_sizes = [
-        ("w", ebpf::BPF_W),
-        ("h", ebpf::BPF_H),
-        ("b", ebpf::BPF_B),
-        ("dw", ebpf::BPF_DW),
-    ];
-
-    let jump_conditions = [
-        ("jeq", ebpf::BPF_JEQ),
-        ("jgt", ebpf::BPF_JGT),
-        ("jge", ebpf::BPF_JGE),
-        ("jlt", ebpf::BPF_JLT),
-        ("jle", ebpf::BPF_JLE),
-        ("jset", ebpf::BPF_JSET),
-        ("jne", ebpf::BPF_JNE),
-        ("jsgt", ebpf::BPF_JSGT),
-        ("jsge", ebpf::BPF_JSGE),
-        ("jslt", ebpf::BPF_JSLT),
-        ("jsle", ebpf::BPF_JSLE),
-    ];
-
-    {
-        let mut entry = |name: &str, inst_type: InstructionType, opc: u8| {
-            result.insert(name.to_string(), (inst_type, opc))
-        };
-
-        // Miscellaneous.
-        entry("exit", NoOperand, ebpf::EXIT);
-        entry("ja", JumpUnconditional, ebpf::JA);
-        entry("call", Call, ebpf::CALL);
-        entry("lddw", LoadImm, ebpf::LD_DW_IMM);
-
-        // AluUnary.
-        entry("neg", AluUnary, ebpf::NEG64);
-        entry("neg32", AluUnary, ebpf::NEG32);
-        entry("neg64", AluUnary, ebpf::NEG64);
-
-        // AluBinary.
-        for &(name, opc) in &alu_binary_ops {
-            entry(name, AluBinary, ebpf::BPF_ALU64 | opc);
-            entry(&format!("{name}32"), AluBinary, ebpf::BPF_ALU | opc);
-            entry(&format!("{name}64"), AluBinary, ebpf::BPF_ALU64 | opc);
-        }
-
-        // LoadAbs, LoadInd, LoadReg, StoreImm, and StoreReg.
-        for &(suffix, size) in &mem_sizes {
-            entry(
-                &format!("ldabs{suffix}"),
-                LoadAbs,
-                ebpf::BPF_ABS | ebpf::BPF_LD | size,
-            );
-            entry(
-                &format!("ldind{suffix}"),
-                LoadInd,
-                ebpf::BPF_IND | ebpf::BPF_LD | size,
-            );
-            entry(
-                &format!("ldx{suffix}"),
-                LoadReg,
-                ebpf::BPF_MEM | ebpf::BPF_LDX | size,
-            );
-            entry(
-                &format!("st{suffix}"),
-                StoreImm,
-                ebpf::BPF_MEM | ebpf::BPF_ST | size,
-            );
-            entry(
-                &format!("stx{suffix}"),
-                StoreReg,
-                ebpf::BPF_MEM | ebpf::BPF_STX | size,
-            );
-        }
-
-        // JumpConditional.
-        for &(name, condition) in &jump_conditions {
-            entry(name, JumpConditional, ebpf::BPF_JMP | condition);
-            entry(
-                &format!("{name}32"),
-                JumpConditional,
-                ebpf::BPF_JMP32 | condition,
-            );
-        }
-
-        // Endian.
-        for &size in &[16, 32, 64] {
-            entry(&format!("be{size}"), Endian(size), ebpf::BE);
-            entry(&format!("le{size}"), Endian(size), ebpf::LE);
-        }
-    }
-
-    result
-}
-
-fn insn(opc: u8, dst: i64, src: i64, off: i64, imm: i64) -> Result<Insn, String> {
-    if !(0..16).contains(&dst) {
-        return Err(format!("Invalid destination register {dst}"));
-    }
-    if dst < 0 || src >= 16 {
-        return Err(format!("Invalid source register {src}"));
-    }
-    if !(-32768..32768).contains(&off) {
-        return Err(format!("Invalid offset {off}"));
-    }
-    if !(-2147483648..2147483648).contains(&imm) {
-        return Err(format!("Invalid immediate {imm}"));
-    }
-    Ok(Insn {
-        opc,
-        dst: dst as u8,
-        src: src as u8,
-        off: off as i16,
-        imm: imm as i32,
-    })
-}
-
-// TODO Use slice patterns when available and remove this function.
-fn operands_tuple(operands: &[Operand]) -> Result<(Operand, Operand, Operand), String> {
-    match operands.len() {
-        0 => Ok((Nil, Nil, Nil)),
-        1 => Ok((operands[0], Nil, Nil)),
-        2 => Ok((operands[0], operands[1], Nil)),
-        3 => Ok((operands[0], operands[1], operands[2])),
-        _ => Err("Too many operands".to_string()),
-    }
-}
-
-fn encode(inst_type: InstructionType, opc: u8, operands: &[Operand]) -> Result<Insn, String> {
-    let (a, b, c) = (operands_tuple(operands))?;
-    match (inst_type, a, b, c) {
-        (AluBinary, Register(dst), Register(src), Nil) => insn(opc | ebpf::BPF_X, dst, src, 0, 0),
-        (AluBinary, Register(dst), Integer(imm), Nil) => insn(opc | ebpf::BPF_K, dst, 0, 0, imm),
-        (AluUnary, Register(dst), Nil, Nil) => insn(opc, dst, 0, 0, 0),
-        (LoadAbs, Integer(imm), Nil, Nil) => insn(opc, 0, 0, 0, imm),
-        (LoadInd, Register(src), Integer(imm), Nil) => insn(opc, 0, src, 0, imm),
-        (LoadReg, Register(dst), Memory(src, off), Nil)
-        | (StoreReg, Memory(dst, off), Register(src), Nil) => insn(opc, dst, src, off, 0),
-        (StoreImm, Memory(dst, off), Integer(imm), Nil) => insn(opc, dst, 0, off, imm),
-        (NoOperand, Nil, Nil, Nil) => insn(opc, 0, 0, 0, 0),
-        (JumpUnconditional, Integer(off), Nil, Nil) => insn(opc, 0, 0, off, 0),
-        (JumpConditional, Register(dst), Register(src), Integer(off)) => {
-            insn(opc | ebpf::BPF_X, dst, src, off, 0)
-        }
-        (JumpConditional, Register(dst), Integer(imm), Integer(off)) => {
-            insn(opc | ebpf::BPF_K, dst, 0, off, imm)
-        }
-        (Call, Integer(imm), Nil, Nil) => insn(opc, 0, 0, 0, imm),
-        (Endian(size), Register(dst), Nil, Nil) => insn(opc, dst, 0, 0, size),
-        (LoadImm, Register(dst), Integer(imm), Nil) => insn(opc, dst, 0, 0, (imm << 32) >> 32),
-        _ => Err(format!("Unexpected operands: {operands:?}")),
-    }
-}
-
-fn assemble_internal(parsed: &[Instruction]) -> Result<Vec<Insn>, String> {
-    let instruction_map = make_instruction_map();
-    let mut result: Vec<Insn> = vec![];
-    for instruction in parsed {
-        let name = instruction.name.as_str();
-        match instruction_map.get(name) {
-            Some(&(inst_type, opc)) => {
-                match encode(inst_type, opc, &instruction.operands) {
-                    Ok(insn) => result.push(insn),
-                    Err(msg) => return Err(format!("Failed to encode {name}: {msg}")),
-                }
-                // Special case for lddw.
-                if let LoadImm = inst_type {
-                    if let Integer(imm) = instruction.operands[1] {
-                        result.push(insn(0, 0, 0, 0, imm >> 32).unwrap());
-                    }
-                }
-            }
-            None => return Err(format!("Invalid instruction {name:?}")),
-        }
-    }
-    Ok(result)
-}
-
-/// Parse assembly source and translate to binary.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::assembler::assemble;
-/// let prog = assemble("add64 r1, 0x605
-///                      mov64 r2, 0x32
-///                      mov64 r1, r0
-///                      be16 r0
-///                      neg64 r2
-///                      exit");
-/// println!("{:?}", prog);
-/// # assert_eq!(prog,
-/// #            Ok(vec![0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
-/// #                    0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
-/// #                    0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/// #                    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-/// #                    0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/// #                    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]));
-/// ```
-///
-/// This will produce the following output:
-///
-/// ```test
-/// Ok([0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
-///     0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
-///     0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-///     0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
-/// ```
-pub fn assemble(src: &str) -> Result<Vec<u8>, String> {
-    let parsed = (parse(src))?;
-    let insns = (assemble_internal(&parsed))?;
-    let mut result: Vec<u8> = vec![];
-    for insn in insns {
-        result.extend_from_slice(&insn.to_array());
-    }
-    Ok(result)
-}

+ 0 - 1230
kernel/crates/rbpf/src/cranelift.rs

@@ -1,1230 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-use alloc::{collections::BTreeMap, format, vec, vec::Vec};
-use core::{mem, mem::ManuallyDrop};
-use std::io::ErrorKind;
-
-use cranelift_codegen::{
-    entity::EntityRef,
-    ir::{
-        condcodes::IntCC,
-        types::{I16, I32, I64, I8},
-        AbiParam, Block, Endianness, FuncRef, Function, InstBuilder, MemFlags, Signature,
-        SourceLoc, StackSlotData, StackSlotKind, TrapCode, Type, UserFuncName, Value,
-    },
-    isa::OwnedTargetIsa,
-    settings::{self, Configurable},
-};
-use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
-use cranelift_jit::{JITBuilder, JITModule};
-use cranelift_module::{FuncId, Linkage, Module};
-
-use super::{Error, HashMap, HashSet};
-use crate::ebpf::{
-    self, Insn, BPF_ALU_OP_MASK, BPF_IND, BPF_JEQ, BPF_JGE, BPF_JGT, BPF_JLE, BPF_JLT, BPF_JMP32,
-    BPF_JNE, BPF_JSET, BPF_JSGE, BPF_JSGT, BPF_JSLE, BPF_JSLT, BPF_X, STACK_SIZE,
-};
-
-pub type JittedFunction = extern "C" fn(
-    *mut u8, // mem_ptr
-    usize,   // mem_len
-    *mut u8, // mbuff_ptr
-    usize,   // mbuff_len
-) -> u64;
-
-pub(crate) struct CraneliftCompiler {
-    isa: OwnedTargetIsa,
-    module: JITModule,
-
-    helpers: HashMap<u32, ebpf::Helper>,
-    helper_func_refs: HashMap<u32, FuncRef>,
-
-    /// List of blocks corresponding to each instruction.
-    /// We only store the first instruction that observes a new block
-    insn_blocks: BTreeMap<u32, Block>,
-    /// Map of block targets for each jump/branching instruction.
-    insn_targets: BTreeMap<u32, (Block, Block)>,
-    filled_blocks: HashSet<Block>,
-
-    /// Map of register numbers to Cranelift variables.
-    registers: [Variable; 11],
-    /// Other usefull variables used throughout the program.
-    mem_start: Variable,
-    mem_end: Variable,
-    mbuf_start: Variable,
-    mbuf_end: Variable,
-    stack_start: Variable,
-    stack_end: Variable,
-}
-
-impl CraneliftCompiler {
-    pub(crate) fn new(helpers: HashMap<u32, ebpf::Helper>) -> Self {
-        let mut flag_builder = settings::builder();
-
-        flag_builder.set("opt_level", "speed").unwrap();
-
-        // Enable stack probes
-        flag_builder.enable("enable_probestack").unwrap();
-        flag_builder.set("probestack_strategy", "inline").unwrap();
-
-        let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| {
-            panic!("host machine is not supported: {}", msg);
-        });
-        let isa = isa_builder
-            .finish(settings::Flags::new(flag_builder))
-            .unwrap();
-
-        let mut jit_builder =
-            JITBuilder::with_isa(isa.clone(), cranelift_module::default_libcall_names());
-        // Register all the helpers
-        for (k, v) in helpers.iter() {
-            let name = format!("helper_{}", k);
-            jit_builder.symbol(name, (*v) as usize as *const u8);
-        }
-
-        let mut module = JITModule::new(jit_builder);
-
-        let registers = (0..11)
-            .map(|i| Variable::new(i))
-            .collect::<Vec<_>>()
-            .try_into()
-            .unwrap();
-
-        Self {
-            isa,
-            module,
-            helpers,
-            helper_func_refs: HashMap::new(),
-            insn_blocks: BTreeMap::new(),
-            insn_targets: BTreeMap::new(),
-            filled_blocks: HashSet::new(),
-            registers,
-            mem_start: Variable::new(11),
-            mem_end: Variable::new(12),
-            mbuf_start: Variable::new(13),
-            mbuf_end: Variable::new(14),
-            stack_start: Variable::new(15),
-            stack_end: Variable::new(16),
-        }
-    }
-
-    pub(crate) fn compile_function(mut self, prog: &[u8]) -> Result<CraneliftProgram, Error> {
-        let name = "main";
-        // This is not a standard eBPF function! We use an informal ABI with just 4 parameters.
-        // See [JittedFunction] which is the signature of this function.
-        //
-        // Since this function only serves as the entrypoint for the JITed program, it doesen't
-        // really matter.
-        let sig = Signature {
-            params: vec![
-                AbiParam::new(I64),
-                AbiParam::new(I64),
-                AbiParam::new(I64),
-                AbiParam::new(I64),
-            ],
-            returns: vec![AbiParam::new(I64)],
-            call_conv: self.isa.default_call_conv(),
-        };
-
-        let func_id = self
-            .module
-            .declare_function(name, Linkage::Local, &sig)
-            .unwrap();
-
-        let mut ctx = self.module.make_context();
-        ctx.func = Function::with_name_signature(UserFuncName::testcase(name.as_bytes()), sig);
-        let mut func_ctx = FunctionBuilderContext::new();
-
-        {
-            let mut builder: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
-
-            let entry = builder.create_block();
-            builder.append_block_params_for_function_params(entry);
-            builder.switch_to_block(entry);
-
-            self.build_cfg(&mut builder, prog)?;
-            self.build_function_prelude(&mut builder, entry)?;
-            self.translate_program(&mut builder, prog)?;
-
-            builder.seal_all_blocks();
-            builder.finalize();
-        }
-
-        self.module.define_function(func_id, &mut ctx).unwrap();
-        self.module.finalize_definitions().unwrap();
-        self.module.clear_context(&mut ctx);
-
-        Ok(CraneliftProgram::new(self.module, func_id))
-    }
-
-    fn build_function_prelude(
-        &mut self,
-        bcx: &mut FunctionBuilder,
-        entry: Block,
-    ) -> Result<(), Error> {
-        // Register the VM registers as variables
-        for var in self.registers.iter() {
-            bcx.declare_var(*var, I64);
-        }
-
-        // Register the bounds check variables
-        bcx.declare_var(self.mem_start, I64);
-        bcx.declare_var(self.mem_end, I64);
-        bcx.declare_var(self.mbuf_start, I64);
-        bcx.declare_var(self.mbuf_end, I64);
-        bcx.declare_var(self.stack_start, I64);
-        bcx.declare_var(self.stack_end, I64);
-
-        // Register the helpers
-        for (k, _) in self.helpers.iter() {
-            let name = format!("helper_{}", k);
-            let sig = Signature {
-                params: vec![
-                    AbiParam::new(I64),
-                    AbiParam::new(I64),
-                    AbiParam::new(I64),
-                    AbiParam::new(I64),
-                    AbiParam::new(I64),
-                ],
-                returns: vec![AbiParam::new(I64)],
-                call_conv: self.isa.default_call_conv(),
-            };
-            let func_id = self
-                .module
-                .declare_function(&name, Linkage::Import, &sig)
-                .unwrap();
-
-            let func_ref = self.module.declare_func_in_func(func_id, bcx.func);
-            self.helper_func_refs.insert(*k, func_ref);
-        }
-
-        // Register the stack
-        let ss = bcx.create_sized_stack_slot(StackSlotData {
-            kind: StackSlotKind::ExplicitSlot,
-            size: STACK_SIZE as u32,
-        });
-        let addr_ty = self.isa.pointer_type();
-        let stack_addr = bcx.ins().stack_addr(addr_ty, ss, STACK_SIZE as i32);
-        bcx.def_var(self.registers[10], stack_addr);
-
-        // Initialize the bounds check variables
-        let stack_start = bcx.ins().stack_addr(addr_ty, ss, 0);
-        bcx.def_var(self.stack_start, stack_start);
-        let stack_end = bcx.ins().stack_addr(addr_ty, ss, STACK_SIZE as i32);
-        bcx.def_var(self.stack_end, stack_end);
-
-        // This is our internal ABI where the first 2 params are the memory
-        let mem_start = bcx.block_params(entry)[0];
-        let mem_len = bcx.block_params(entry)[1];
-        let mem_end = bcx.ins().iadd(mem_start, mem_len);
-        bcx.def_var(self.mem_start, mem_start);
-        bcx.def_var(self.mem_end, mem_end);
-
-        // And the next 2 are the mbuf
-        let mbuf_start = bcx.block_params(entry)[2];
-        let mbuf_len = bcx.block_params(entry)[3];
-        let mbuf_end = bcx.ins().iadd(mbuf_start, mbuf_len);
-        bcx.def_var(self.mbuf_start, mbuf_start);
-        bcx.def_var(self.mbuf_end, mbuf_end);
-
-        // The ABI for eBPF specifies that R1 must contain either the memory, or mbuff pointer
-        // If the mbuf length is non-zero, then we use that, otherwise we use the memory pointer
-        let mbuf_exists = bcx.ins().icmp_imm(IntCC::NotEqual, mbuf_len, 0);
-        let mem_or_mbuf = bcx.ins().select(mbuf_exists, mbuf_start, mem_start);
-        bcx.def_var(self.registers[1], mem_or_mbuf);
-
-        // R2 should contain the length of the memory or mbuf
-        // At least ebpf-conformance tests expect this
-        let mem_or_mbuf_len = bcx.ins().select(mbuf_exists, mbuf_len, mem_len);
-        bcx.def_var(self.registers[2], mem_or_mbuf_len);
-
-        // Insert the *actual* initial block
-        let program_entry = bcx.create_block();
-        bcx.ins().jump(program_entry, &[]);
-        self.filled_blocks.insert(bcx.current_block().unwrap());
-        self.insn_blocks.insert(0, program_entry);
-
-        Ok(())
-    }
-
-    fn translate_program(&mut self, bcx: &mut FunctionBuilder, prog: &[u8]) -> Result<(), Error> {
-        let mut insn_ptr: usize = 0;
-        while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-            let insn = ebpf::get_insn(prog, insn_ptr);
-
-            // If this instruction is on a new block switch to it.
-            if let Some(block) = self.insn_blocks.get(&(insn_ptr as u32)) {
-                // Blocks must have a terminator instruction at the end before we switch away from them
-                let current_block = bcx.current_block().unwrap();
-                if !self.filled_blocks.contains(&current_block) {
-                    bcx.ins().jump(*block, &[]);
-                }
-
-                bcx.switch_to_block(*block);
-            }
-
-            // Set the source location for the instruction
-            bcx.set_srcloc(SourceLoc::new(insn_ptr as u32));
-
-            match insn.opc {
-                // BPF_LD class
-                // LD_ABS_* and LD_IND_* are supposed to load pointer to data from metadata buffer.
-                // Since this pointer is constant, and since we already know it (mem), do not
-                // bother re-fetching it, just use mem already.
-                ebpf::LD_ABS_B
-                | ebpf::LD_ABS_H
-                | ebpf::LD_ABS_W
-                | ebpf::LD_ABS_DW
-                | ebpf::LD_IND_B
-                | ebpf::LD_IND_H
-                | ebpf::LD_IND_W
-                | ebpf::LD_IND_DW => {
-                    let ty = match insn.opc {
-                        ebpf::LD_ABS_B | ebpf::LD_IND_B => I8,
-                        ebpf::LD_ABS_H | ebpf::LD_IND_H => I16,
-                        ebpf::LD_ABS_W | ebpf::LD_IND_W => I32,
-                        ebpf::LD_ABS_DW | ebpf::LD_IND_DW => I64,
-                        _ => unreachable!(),
-                    };
-
-                    // Both instructions add the imm part of the instruction to the pointer
-                    let ptr = bcx.use_var(self.mem_start);
-                    let offset = bcx
-                        .ins()
-                        .iconst(self.isa.pointer_type(), insn.imm as u32 as i64);
-                    let addr = bcx.ins().iadd(ptr, offset);
-
-                    // IND instructions additionally add the value of the source register
-                    let is_ind = (insn.opc & BPF_IND) != 0;
-                    let addr = if is_ind {
-                        let src_reg = self.insn_src(bcx, &insn);
-                        bcx.ins().iadd(addr, src_reg)
-                    } else {
-                        addr
-                    };
-
-                    // The offset here has already been added to the pointer, so we pass 0
-                    let loaded = self.reg_load(bcx, ty, addr, 0);
-
-                    let ext = if ty != I64 {
-                        bcx.ins().uextend(I64, loaded)
-                    } else {
-                        loaded
-                    };
-
-                    self.set_dst(bcx, &insn, ext);
-                }
-                ebpf::LD_DW_IMM => {
-                    insn_ptr += 1;
-                    let next_insn = ebpf::get_insn(prog, insn_ptr);
-
-                    let imm = (((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32)) as i64;
-                    let iconst = bcx.ins().iconst(I64, imm);
-                    self.set_dst(bcx, &insn, iconst);
-                }
-
-                // BPF_LDX class
-                ebpf::LD_B_REG | ebpf::LD_H_REG | ebpf::LD_W_REG | ebpf::LD_DW_REG => {
-                    let ty = match insn.opc {
-                        ebpf::LD_B_REG => I8,
-                        ebpf::LD_H_REG => I16,
-                        ebpf::LD_W_REG => I32,
-                        ebpf::LD_DW_REG => I64,
-                        _ => unreachable!(),
-                    };
-
-                    let base = self.insn_src(bcx, &insn);
-                    let loaded = self.reg_load(bcx, ty, base, insn.off);
-
-                    let ext = if ty != I64 {
-                        bcx.ins().uextend(I64, loaded)
-                    } else {
-                        loaded
-                    };
-
-                    self.set_dst(bcx, &insn, ext);
-                }
-
-                // BPF_ST and BPF_STX class
-                ebpf::ST_B_IMM
-                | ebpf::ST_H_IMM
-                | ebpf::ST_W_IMM
-                | ebpf::ST_DW_IMM
-                | ebpf::ST_B_REG
-                | ebpf::ST_H_REG
-                | ebpf::ST_W_REG
-                | ebpf::ST_DW_REG => {
-                    let ty = match insn.opc {
-                        ebpf::ST_B_IMM | ebpf::ST_B_REG => I8,
-                        ebpf::ST_H_IMM | ebpf::ST_H_REG => I16,
-                        ebpf::ST_W_IMM | ebpf::ST_W_REG => I32,
-                        ebpf::ST_DW_IMM | ebpf::ST_DW_REG => I64,
-                        _ => unreachable!(),
-                    };
-                    let is_imm = match insn.opc {
-                        ebpf::ST_B_IMM | ebpf::ST_H_IMM | ebpf::ST_W_IMM | ebpf::ST_DW_IMM => true,
-                        ebpf::ST_B_REG | ebpf::ST_H_REG | ebpf::ST_W_REG | ebpf::ST_DW_REG => false,
-                        _ => unreachable!(),
-                    };
-
-                    let value = if is_imm {
-                        self.insn_imm64(bcx, &insn)
-                    } else {
-                        self.insn_src(bcx, &insn)
-                    };
-
-                    let narrow = if ty != I64 {
-                        bcx.ins().ireduce(ty, value)
-                    } else {
-                        value
-                    };
-
-                    let base = self.insn_dst(bcx, &insn);
-                    self.reg_store(bcx, ty, base, insn.off, narrow);
-                }
-
-                ebpf::ST_W_XADD => unimplemented!(),
-                ebpf::ST_DW_XADD => unimplemented!(),
-
-                // BPF_ALU class
-                // TODO Check how overflow works in kernel. Should we &= U32MAX all src register value
-                // before we do the operation?
-                // Cf ((0x11 << 32) - (0x1 << 32)) as u32 VS ((0x11 << 32) as u32 - (0x1 << 32) as u32
-                ebpf::ADD32_IMM => {
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().iadd(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::ADD32_REG => {
-                    //((reg[_dst] & U32MAX) + (reg[_src] & U32MAX)) & U32MAX,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().iadd(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::SUB32_IMM => {
-                    // reg[_dst] = (reg[_dst] as i32).wrapping_sub(insn.imm)         as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().isub(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::SUB32_REG => {
-                    // reg[_dst] = (reg[_dst] as i32).wrapping_sub(reg[_src] as i32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().isub(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::MUL32_IMM => {
-                    // reg[_dst] = (reg[_dst] as i32).wrapping_mul(insn.imm)         as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().imul(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::MUL32_REG => {
-                    // reg[_dst] = (reg[_dst] as i32).wrapping_mul(reg[_src] as i32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().imul(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::DIV32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32 / insn.imm              as u32) as u64,
-                    let res = if insn.imm == 0 {
-                        bcx.ins().iconst(I32, 0)
-                    } else {
-                        let imm = self.insn_imm32(bcx, &insn);
-                        let src = self.insn_dst32(bcx, &insn);
-                        bcx.ins().udiv(src, imm)
-                    };
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::DIV32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32 / reg[_src]             as u32) as u64,
-                    let zero = bcx.ins().iconst(I32, 0);
-                    let one = bcx.ins().iconst(I32, 1);
-
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-
-                    let rhs_is_zero = bcx.ins().icmp(IntCC::Equal, rhs, zero);
-                    let safe_rhs = bcx.ins().select(rhs_is_zero, one, rhs);
-                    let div_res = bcx.ins().udiv(lhs, safe_rhs);
-
-                    let res = bcx.ins().select(rhs_is_zero, zero, div_res);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::OR32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32             | insn.imm  as u32) as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().bor(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::OR32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32             | reg[_src] as u32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().bor(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::AND32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32             & insn.imm  as u32) as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().band(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::AND32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32             & reg[_src] as u32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().band(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::LSH32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32).wrapping_shl(insn.imm  as u32) as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().ishl(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::LSH32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32).wrapping_shl(reg[_src] as u32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().ishl(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::RSH32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32).wrapping_shr(insn.imm  as u32) as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().ushr(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::RSH32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32).wrapping_shr(reg[_src] as u32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().ushr(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::NEG32 => {
-                    // { reg[_dst] = (reg[_dst] as i32).wrapping_neg()                 as u64; reg[_dst] &= U32MAX; },
-                    let src = self.insn_dst32(bcx, &insn);
-                    let res = bcx.ins().ineg(src);
-                    // TODO: Do we need to mask the result?
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::MOD32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32             % insn.imm  as u32) as u64,
-
-                    if insn.imm != 0 {
-                        let imm = self.insn_imm32(bcx, &insn);
-                        let src = self.insn_dst32(bcx, &insn);
-                        let res = bcx.ins().urem(src, imm);
-                        self.set_dst32(bcx, &insn, res);
-                    }
-                }
-                ebpf::MOD32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32 % reg[_src]             as u32) as u64,
-                    let zero = bcx.ins().iconst(I32, 0);
-                    let one = bcx.ins().iconst(I32, 1);
-
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-
-                    let rhs_is_zero = bcx.ins().icmp(IntCC::Equal, rhs, zero);
-                    let safe_rhs = bcx.ins().select(rhs_is_zero, one, rhs);
-                    let div_res = bcx.ins().urem(lhs, safe_rhs);
-
-                    let res = bcx.ins().select(rhs_is_zero, lhs, div_res);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::XOR32_IMM => {
-                    // reg[_dst] = (reg[_dst] as u32             ^ insn.imm  as u32) as u64,
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().bxor(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::XOR32_REG => {
-                    // reg[_dst] = (reg[_dst] as u32             ^ reg[_src] as u32) as u64,
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().bxor(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::MOV32_IMM => {
-                    let imm = self.insn_imm32(bcx, &insn);
-                    self.set_dst32(bcx, &insn, imm);
-                }
-                ebpf::MOV32_REG => {
-                    // reg[_dst] = (reg[_src] as u32)                                as u64,
-                    let src = self.insn_src32(bcx, &insn);
-                    self.set_dst32(bcx, &insn, src);
-                }
-                ebpf::ARSH32_IMM => {
-                    // { reg[_dst] = (reg[_dst] as i32).wrapping_shr(insn.imm  as u32) as u64; reg[_dst] &= U32MAX; },
-                    let src = self.insn_dst32(bcx, &insn);
-                    let imm = self.insn_imm32(bcx, &insn);
-                    let res = bcx.ins().sshr(src, imm);
-                    self.set_dst32(bcx, &insn, res);
-                }
-                ebpf::ARSH32_REG => {
-                    // { reg[_dst] = (reg[_dst] as i32).wrapping_shr(reg[_src] as u32) as u64; reg[_dst] &= U32MAX; },
-                    let lhs = self.insn_dst32(bcx, &insn);
-                    let rhs = self.insn_src32(bcx, &insn);
-                    let res = bcx.ins().sshr(lhs, rhs);
-                    self.set_dst32(bcx, &insn, res);
-                }
-
-                ebpf::BE | ebpf::LE => {
-                    let should_swap = match insn.opc {
-                        ebpf::BE => self.isa.endianness() == Endianness::Little,
-                        ebpf::LE => self.isa.endianness() == Endianness::Big,
-                        _ => unreachable!(),
-                    };
-
-                    let ty: Type = match insn.imm {
-                        16 => I16,
-                        32 => I32,
-                        64 => I64,
-                        _ => unreachable!(),
-                    };
-
-                    if should_swap {
-                        let src = self.insn_dst(bcx, &insn);
-                        let src_narrow = if ty != I64 {
-                            bcx.ins().ireduce(ty, src)
-                        } else {
-                            src
-                        };
-
-                        let res = bcx.ins().bswap(src_narrow);
-                        let res_wide = if ty != I64 {
-                            bcx.ins().uextend(I64, res)
-                        } else {
-                            res
-                        };
-
-                        self.set_dst(bcx, &insn, res_wide);
-                    }
-                }
-
-                // BPF_ALU64 class
-                ebpf::ADD64_IMM => {
-                    // reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().iadd(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::ADD64_REG => {
-                    // reg[_dst] = reg[_dst].wrapping_add(reg[_src]),
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().iadd(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::SUB64_IMM => {
-                    // reg[_dst] = reg[_dst].wrapping_sub(insn.imm as u64),
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().isub(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::SUB64_REG => {
-                    // reg[_dst] = reg[_dst].wrapping_sub(reg[_src]),
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().isub(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::MUL64_IMM => {
-                    // reg[_dst] = reg[_dst].wrapping_mul(insn.imm as u64),
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().imul(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::MUL64_REG => {
-                    // reg[_dst] = reg[_dst].wrapping_mul(reg[_src]),
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().imul(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::DIV64_IMM => {
-                    // reg[_dst] /= insn.imm as u64,
-                    let res = if insn.imm == 0 {
-                        bcx.ins().iconst(I64, 0)
-                    } else {
-                        let imm = self.insn_imm64(bcx, &insn);
-                        let src = self.insn_dst(bcx, &insn);
-                        bcx.ins().udiv(src, imm)
-                    };
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::DIV64_REG => {
-                    // reg[_dst] /= reg[_src], if reg[_src] != 0
-                    // reg[_dst] = 0, if reg[_src] == 0
-                    let zero = bcx.ins().iconst(I64, 0);
-                    let one = bcx.ins().iconst(I64, 1);
-
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-
-                    let rhs_is_zero = bcx.ins().icmp(IntCC::Equal, rhs, zero);
-                    let safe_rhs = bcx.ins().select(rhs_is_zero, one, rhs);
-                    let div_res = bcx.ins().udiv(lhs, safe_rhs);
-
-                    let res = bcx.ins().select(rhs_is_zero, zero, div_res);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::MOD64_IMM => {
-                    // reg[_dst] %= insn.imm as u64,
-
-                    if insn.imm != 0 {
-                        let imm = self.insn_imm64(bcx, &insn);
-                        let src = self.insn_dst(bcx, &insn);
-                        let res = bcx.ins().urem(src, imm);
-                        self.set_dst(bcx, &insn, res);
-                    };
-                }
-                ebpf::MOD64_REG => {
-                    // reg[_dst] %= reg[_src], if reg[_src] != 0
-
-                    let zero = bcx.ins().iconst(I64, 0);
-                    let one = bcx.ins().iconst(I64, 1);
-
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-
-                    let rhs_is_zero = bcx.ins().icmp(IntCC::Equal, rhs, zero);
-                    let safe_rhs = bcx.ins().select(rhs_is_zero, one, rhs);
-                    let div_res = bcx.ins().urem(lhs, safe_rhs);
-
-                    let res = bcx.ins().select(rhs_is_zero, lhs, div_res);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::OR64_IMM => {
-                    // reg[_dst] |= insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().bor(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::OR64_REG => {
-                    // reg[_dst] |= reg[_src],
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().bor(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::AND64_IMM => {
-                    // reg[_dst] &= insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().band(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::AND64_REG => {
-                    // reg[_dst] &= reg[_src],
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().band(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::LSH64_IMM => {
-                    // reg[_dst] <<= insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().ishl(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::LSH64_REG => {
-                    // reg[_dst] <<= reg[_src],
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().ishl(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::RSH64_IMM => {
-                    // reg[_dst] >>= insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().ushr(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::RSH64_REG => {
-                    // reg[_dst] >>= reg[_src],
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().ushr(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::NEG64 => {
-                    // reg[_dst] = -(reg[_dst] as i64) as u64,
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().ineg(src);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::XOR64_IMM => {
-                    // reg[_dst] ^= insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().bxor(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::XOR64_REG => {
-                    // reg[_dst] ^= reg[_src],
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().bxor(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::MOV64_IMM => {
-                    // reg[_dst] = insn.imm as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    bcx.def_var(self.registers[insn.dst as usize], imm);
-                }
-                ebpf::MOV64_REG => {
-                    // reg[_dst] = reg[_src],
-                    let src = self.insn_src(bcx, &insn);
-                    bcx.def_var(self.registers[insn.dst as usize], src);
-                }
-                ebpf::ARSH64_IMM => {
-                    // reg[_dst] = (reg[_dst] as i64 >> insn.imm) as u64,
-                    let imm = self.insn_imm64(bcx, &insn);
-                    let src = self.insn_dst(bcx, &insn);
-                    let res = bcx.ins().sshr(src, imm);
-                    self.set_dst(bcx, &insn, res);
-                }
-                ebpf::ARSH64_REG => {
-                    // reg[_dst] = (reg[_dst] as i64 >> reg[_src]) as u64,
-                    let lhs = self.insn_dst(bcx, &insn);
-                    let rhs = self.insn_src(bcx, &insn);
-                    let res = bcx.ins().sshr(lhs, rhs);
-                    self.set_dst(bcx, &insn, res);
-                }
-
-                // BPF_JMP & BPF_JMP32 class
-                ebpf::JA => {
-                    let (_, target_block) = self.insn_targets[&(insn_ptr as u32)];
-
-                    bcx.ins().jump(target_block, &[]);
-                    self.filled_blocks.insert(bcx.current_block().unwrap());
-                }
-                ebpf::JEQ_IMM
-                | ebpf::JEQ_REG
-                | ebpf::JGT_IMM
-                | ebpf::JGT_REG
-                | ebpf::JGE_IMM
-                | ebpf::JGE_REG
-                | ebpf::JLT_IMM
-                | ebpf::JLT_REG
-                | ebpf::JLE_IMM
-                | ebpf::JLE_REG
-                | ebpf::JNE_IMM
-                | ebpf::JNE_REG
-                | ebpf::JSGT_IMM
-                | ebpf::JSGT_REG
-                | ebpf::JSGE_IMM
-                | ebpf::JSGE_REG
-                | ebpf::JSLT_IMM
-                | ebpf::JSLT_REG
-                | ebpf::JSLE_IMM
-                | ebpf::JSLE_REG
-                | ebpf::JSET_IMM
-                | ebpf::JSET_REG
-                | ebpf::JEQ_IMM32
-                | ebpf::JEQ_REG32
-                | ebpf::JGT_IMM32
-                | ebpf::JGT_REG32
-                | ebpf::JGE_IMM32
-                | ebpf::JGE_REG32
-                | ebpf::JLT_IMM32
-                | ebpf::JLT_REG32
-                | ebpf::JLE_IMM32
-                | ebpf::JLE_REG32
-                | ebpf::JNE_IMM32
-                | ebpf::JNE_REG32
-                | ebpf::JSGT_IMM32
-                | ebpf::JSGT_REG32
-                | ebpf::JSGE_IMM32
-                | ebpf::JSGE_REG32
-                | ebpf::JSLT_IMM32
-                | ebpf::JSLT_REG32
-                | ebpf::JSLE_IMM32
-                | ebpf::JSLE_REG32
-                | ebpf::JSET_IMM32
-                | ebpf::JSET_REG32 => {
-                    let (fallthrough, target) = self.insn_targets[&(insn_ptr as u32)];
-
-                    let is_reg = (insn.opc & BPF_X) != 0;
-                    let is_32 = (insn.opc & BPF_JMP32) != 0;
-                    let intcc = match insn.opc {
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JEQ => IntCC::Equal,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JNE => IntCC::NotEqual,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JGT => IntCC::UnsignedGreaterThan,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JGE => IntCC::UnsignedGreaterThanOrEqual,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JLT => IntCC::UnsignedLessThan,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JLE => IntCC::UnsignedLessThanOrEqual,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JSGT => IntCC::SignedGreaterThan,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JSGE => IntCC::SignedGreaterThanOrEqual,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JSLT => IntCC::SignedLessThan,
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JSLE => IntCC::SignedLessThanOrEqual,
-                        // JSET is handled specially below
-                        c if (c & BPF_ALU_OP_MASK) == BPF_JSET => IntCC::NotEqual,
-                        _ => unreachable!(),
-                    };
-
-                    let lhs = if is_32 {
-                        self.insn_dst32(bcx, &insn)
-                    } else {
-                        self.insn_dst(bcx, &insn)
-                    };
-                    let rhs = match (is_reg, is_32) {
-                        (true, false) => self.insn_src(bcx, &insn),
-                        (true, true) => self.insn_src32(bcx, &insn),
-                        (false, false) => self.insn_imm64(bcx, &insn),
-                        (false, true) => self.insn_imm32(bcx, &insn),
-                    };
-
-                    let cmp_res = if (insn.opc & BPF_ALU_OP_MASK) == BPF_JSET {
-                        bcx.ins().band(lhs, rhs)
-                    } else {
-                        bcx.ins().icmp(intcc, lhs, rhs)
-                    };
-                    bcx.ins().brif(cmp_res, target, &[], fallthrough, &[]);
-                    self.filled_blocks.insert(bcx.current_block().unwrap());
-                }
-
-                // Do not delegate the check to the verifier, since registered functions can be
-                // changed after the program has been verified.
-                ebpf::CALL => {
-                    let func_ref = self
-                        .helper_func_refs
-                        .get(&(insn.imm as u32))
-                        .copied()
-                        .ok_or_else(|| {
-                            Error::new(
-                                ErrorKind::Other,
-                                format!(
-                                    "[CRANELIFT] Error: unknown helper function (id: {:#x})",
-                                    insn.imm as u32
-                                ),
-                            )
-                        })?;
-
-                    let arg0 = bcx.use_var(self.registers[1]);
-                    let arg1 = bcx.use_var(self.registers[2]);
-                    let arg2 = bcx.use_var(self.registers[3]);
-                    let arg3 = bcx.use_var(self.registers[4]);
-                    let arg4 = bcx.use_var(self.registers[5]);
-
-                    let call = bcx.ins().call(func_ref, &[arg0, arg1, arg2, arg3, arg4]);
-                    let ret = bcx.inst_results(call)[0];
-                    self.set_dst(bcx, &insn, ret);
-                }
-                ebpf::TAIL_CALL => unimplemented!(),
-                ebpf::EXIT => {
-                    let ret = bcx.use_var(self.registers[0]);
-                    bcx.ins().return_(&[ret]);
-                    self.filled_blocks.insert(bcx.current_block().unwrap());
-                }
-                _ => unimplemented!("inst: {:?}", insn),
-            }
-
-            insn_ptr += 1;
-        }
-
-        Ok(())
-    }
-
-    fn insn_imm64(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        bcx.ins().iconst(I64, insn.imm as u64 as i64)
-    }
-    fn insn_imm32(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        bcx.ins().iconst(I32, insn.imm as u32 as u64 as i64)
-    }
-
-    fn insn_dst(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        bcx.use_var(self.registers[insn.dst as usize])
-    }
-    fn insn_dst32(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        let dst = self.insn_dst(bcx, insn);
-        bcx.ins().ireduce(I32, dst)
-    }
-
-    fn insn_src(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        bcx.use_var(self.registers[insn.src as usize])
-    }
-    fn insn_src32(&mut self, bcx: &mut FunctionBuilder, insn: &Insn) -> Value {
-        let src = self.insn_src(bcx, insn);
-        bcx.ins().ireduce(I32, src)
-    }
-
-    fn set_dst(&mut self, bcx: &mut FunctionBuilder, insn: &Insn, val: Value) {
-        bcx.def_var(self.registers[insn.dst as usize], val);
-    }
-    fn set_dst32(&mut self, bcx: &mut FunctionBuilder, insn: &Insn, val: Value) {
-        let val32 = bcx.ins().uextend(I64, val);
-        self.set_dst(bcx, insn, val32);
-    }
-
-    fn reg_load(&mut self, bcx: &mut FunctionBuilder, ty: Type, base: Value, offset: i16) -> Value {
-        self.insert_bounds_check(bcx, ty, base, offset);
-
-        let mut flags = MemFlags::new();
-        flags.set_endianness(Endianness::Little);
-
-        bcx.ins().load(ty, flags, base, offset as i32)
-    }
-    fn reg_store(
-        &mut self,
-        bcx: &mut FunctionBuilder,
-        ty: Type,
-        base: Value,
-        offset: i16,
-        val: Value,
-    ) {
-        self.insert_bounds_check(bcx, ty, base, offset);
-
-        let mut flags = MemFlags::new();
-        flags.set_endianness(Endianness::Little);
-
-        bcx.ins().store(flags, val, base, offset as i32);
-    }
-
-    /// Inserts a bounds check for a memory access
-    ///
-    /// This emits a conditional trap if the access is out of bounds for any of the known
-    /// valid memory regions. These are the stack, the memory, and the mbuf.
-    fn insert_bounds_check(
-        &mut self,
-        bcx: &mut FunctionBuilder,
-        ty: Type,
-        base: Value,
-        offset: i16,
-    ) {
-        let access_size = bcx.ins().iconst(I64, ty.bytes() as i64);
-
-        let offset = bcx.ins().iconst(I64, offset as i64);
-        let start_addr = bcx.ins().iadd(base, offset);
-        let end_addr = bcx.ins().iadd(start_addr, access_size);
-
-        let does_not_overflow =
-            bcx.ins()
-                .icmp(IntCC::UnsignedGreaterThanOrEqual, end_addr, start_addr);
-
-        // Check if it's a valid stack access
-        let stack_start = bcx.use_var(self.stack_start);
-        let stack_end = bcx.use_var(self.stack_end);
-        let stack_start_valid =
-            bcx.ins()
-                .icmp(IntCC::UnsignedGreaterThanOrEqual, start_addr, stack_start);
-        let stack_end_valid = bcx
-            .ins()
-            .icmp(IntCC::UnsignedLessThanOrEqual, end_addr, stack_end);
-        let stack_valid = bcx.ins().band(stack_start_valid, stack_end_valid);
-
-        // Check if it's a valid memory access
-        let mem_start = bcx.use_var(self.mem_start);
-        let mem_end = bcx.use_var(self.mem_end);
-        let has_mem = bcx.ins().icmp_imm(IntCC::NotEqual, mem_start, 0);
-        let mem_start_valid =
-            bcx.ins()
-                .icmp(IntCC::UnsignedGreaterThanOrEqual, start_addr, mem_start);
-        let mem_end_valid = bcx
-            .ins()
-            .icmp(IntCC::UnsignedLessThanOrEqual, end_addr, mem_end);
-
-        let mem_valid = bcx.ins().band(mem_start_valid, mem_end_valid);
-        let mem_valid = bcx.ins().band(mem_valid, has_mem);
-
-        // Check if it's a valid mbuf access
-        let mbuf_start = bcx.use_var(self.mbuf_start);
-        let mbuf_end = bcx.use_var(self.mbuf_end);
-        let has_mbuf = bcx.ins().icmp_imm(IntCC::NotEqual, mbuf_start, 0);
-        let mbuf_start_valid =
-            bcx.ins()
-                .icmp(IntCC::UnsignedGreaterThanOrEqual, start_addr, mbuf_start);
-        let mbuf_end_valid = bcx
-            .ins()
-            .icmp(IntCC::UnsignedLessThanOrEqual, end_addr, mbuf_end);
-        let mbuf_valid = bcx.ins().band(mbuf_start_valid, mbuf_end_valid);
-        let mbuf_valid = bcx.ins().band(mbuf_valid, has_mbuf);
-
-        // Join all of these checks together and trap if any of them fails
-
-        // We need it to be valid to at least one region of memory
-        let valid_region = bcx.ins().bor(stack_valid, mem_valid);
-        let valid_region = bcx.ins().bor(valid_region, mbuf_valid);
-
-        // And that it does not overflow
-        let valid = bcx.ins().band(does_not_overflow, valid_region);
-
-        // TODO: We can potentially throw a custom trap code here to indicate
-        // which check failed.
-        bcx.ins().trapz(valid, TrapCode::HeapOutOfBounds);
-    }
-
-    /// Analyze the program and build the CFG
-    ///
-    /// We do this because cranelift does not allow us to switch back to a previously
-    /// filled block and add instructions to it. So we can't split the program as we
-    /// translate it.
-    fn build_cfg(&mut self, bcx: &mut FunctionBuilder, prog: &[u8]) -> Result<(), Error> {
-        let mut insn_ptr: usize = 0;
-        while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-            let insn = ebpf::get_insn(prog, insn_ptr);
-
-            match insn.opc {
-                // This instruction consumes two opcodes
-                ebpf::LD_DW_IMM => {
-                    insn_ptr += 1;
-                }
-
-                ebpf::JA
-                | ebpf::JEQ_IMM
-                | ebpf::JEQ_REG
-                | ebpf::JGT_IMM
-                | ebpf::JGT_REG
-                | ebpf::JGE_IMM
-                | ebpf::JGE_REG
-                | ebpf::JLT_IMM
-                | ebpf::JLT_REG
-                | ebpf::JLE_IMM
-                | ebpf::JLE_REG
-                | ebpf::JNE_IMM
-                | ebpf::JNE_REG
-                | ebpf::JSGT_IMM
-                | ebpf::JSGT_REG
-                | ebpf::JSGE_IMM
-                | ebpf::JSGE_REG
-                | ebpf::JSLT_IMM
-                | ebpf::JSLT_REG
-                | ebpf::JSLE_IMM
-                | ebpf::JSLE_REG
-                | ebpf::JSET_IMM
-                | ebpf::JSET_REG
-                | ebpf::JEQ_IMM32
-                | ebpf::JEQ_REG32
-                | ebpf::JGT_IMM32
-                | ebpf::JGT_REG32
-                | ebpf::JGE_IMM32
-                | ebpf::JGE_REG32
-                | ebpf::JLT_IMM32
-                | ebpf::JLT_REG32
-                | ebpf::JLE_IMM32
-                | ebpf::JLE_REG32
-                | ebpf::JNE_IMM32
-                | ebpf::JNE_REG32
-                | ebpf::JSGT_IMM32
-                | ebpf::JSGT_REG32
-                | ebpf::JSGE_IMM32
-                | ebpf::JSGE_REG32
-                | ebpf::JSLT_IMM32
-                | ebpf::JSLT_REG32
-                | ebpf::JSLE_IMM32
-                | ebpf::JSLE_REG32
-                | ebpf::JSET_IMM32
-                | ebpf::JSET_REG32
-                | ebpf::EXIT
-                | ebpf::TAIL_CALL => {
-                    self.prepare_jump_blocks(bcx, insn_ptr, &insn);
-                }
-                _ => {}
-            }
-
-            insn_ptr += 1;
-        }
-
-        Ok(())
-    }
-
-    fn prepare_jump_blocks(&mut self, bcx: &mut FunctionBuilder, insn_ptr: usize, insn: &Insn) {
-        let insn_ptr = insn_ptr as u32;
-        let next_pc: u32 = insn_ptr + 1;
-        let target_pc: u32 = (insn_ptr as isize + insn.off as isize + 1)
-            .try_into()
-            .unwrap();
-
-        // This is the fallthrough block
-        let fallthrough_block = *self
-            .insn_blocks
-            .entry(next_pc)
-            .or_insert_with(|| bcx.create_block());
-
-        // Jump Target
-        let target_block = *self
-            .insn_blocks
-            .entry(target_pc)
-            .or_insert_with(|| bcx.create_block());
-
-        // Mark the blocks for this instruction
-        self.insn_targets
-            .insert(insn_ptr, (fallthrough_block, target_block));
-    }
-}
-
-/// Contains the backing memory for a previously compiled function.
-///
-/// Currently this will allways just contain code for a single function, but
-/// in the future we might want to support multiple functions per module.
-///
-/// Ensures that the backing memory is freed when dropped.
-pub struct CraneliftProgram {
-    module: ManuallyDrop<JITModule>,
-
-    main_id: FuncId,
-}
-
-impl CraneliftProgram {
-    pub(crate) fn new(module: JITModule, main_id: FuncId) -> Self {
-        Self {
-            module: ManuallyDrop::new(module),
-            main_id,
-        }
-    }
-
-    /// We shouldn't allow this function pointer to be exposed outside of this
-    /// module, since it's not guaranteed to be valid after the module is dropped.
-    pub(crate) fn get_main_function(&self) -> JittedFunction {
-        let function_ptr = self.module.get_finalized_function(self.main_id);
-        unsafe { mem::transmute(function_ptr) }
-    }
-
-    /// Execute this module by calling the main function
-    pub fn execute(
-        &self,
-        mem_ptr: *mut u8,
-        mem_len: usize,
-        mbuff_ptr: *mut u8,
-        mbuff_len: usize,
-    ) -> u64 {
-        let main = self.get_main_function();
-
-        main(mem_ptr, mem_len, mbuff_ptr, mbuff_len)
-    }
-}
-
-impl Drop for CraneliftProgram {
-    fn drop(&mut self) {
-        // We need to have an owned version of `JITModule` to be able to free
-        // it's memory. Use `ManuallyDrop` to get the owned `JITModule`.
-        //
-        // We can no longer use `module` after this, but since we are `Drop`
-        // it should be safe.
-        unsafe {
-            let module = ManuallyDrop::take(&mut self.module);
-            module.free_memory()
-        };
-    }
-}

+ 0 - 807
kernel/crates/rbpf/src/disassembler.rs

@@ -1,807 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
-
-//! Functions in this module are used to handle eBPF programs with a higher level representation,
-//! for example to disassemble the code into a human-readable format.
-
-use alloc::{
-    format,
-    string::{String, ToString},
-    vec,
-    vec::Vec,
-};
-
-use log::warn;
-
-use crate::ebpf;
-
-#[inline]
-fn alu_imm_str(name: &str, insn: &ebpf::Insn) -> String {
-    format!("{name} r{}, {:#x}", insn.dst, insn.imm)
-}
-
-#[inline]
-fn alu_reg_str(name: &str, insn: &ebpf::Insn) -> String {
-    format!("{name} r{}, r{}", insn.dst, insn.src)
-}
-
-#[inline]
-fn byteswap_str(name: &str, insn: &ebpf::Insn) -> String {
-    match insn.imm {
-        16 | 32 | 64 => {}
-        _ => warn!("[Disassembler] Warning: Invalid offset value for {name} insn"),
-    }
-    format!("{name}{} r{}", insn.imm, insn.dst)
-}
-
-#[inline]
-fn ld_st_imm_str(name: &str, insn: &ebpf::Insn) -> String {
-    if insn.off >= 0 {
-        format!("{name} [r{}+{:#x}], {:#x}", insn.dst, insn.off, insn.imm)
-    } else {
-        format!(
-            "{name} [r{}-{:#x}], {:#x}",
-            insn.dst,
-            -(insn.off as isize),
-            insn.imm
-        )
-    }
-}
-
-#[inline]
-fn ld_reg_str(name: &str, insn: &ebpf::Insn) -> String {
-    if insn.off >= 0 {
-        format!("{name} r{}, [r{}+{:#x}]", insn.dst, insn.src, insn.off)
-    } else {
-        format!(
-            "{name} r{}, [r{}-{:#x}]",
-            insn.dst,
-            insn.src,
-            -(insn.off as isize)
-        )
-    }
-}
-
-#[inline]
-fn st_reg_str(name: &str, insn: &ebpf::Insn) -> String {
-    if insn.off >= 0 {
-        format!("{name} [r{}+{:#x}], r{}", insn.dst, insn.off, insn.src)
-    } else {
-        format!(
-            "{name} [r{}-{:#x}], r{}",
-            insn.dst,
-            -(insn.off as isize),
-            insn.src
-        )
-    }
-}
-
-#[inline]
-fn ldabs_str(name: &str, insn: &ebpf::Insn) -> String {
-    format!("{name} {:#x}", insn.imm)
-}
-
-#[inline]
-fn ldind_str(name: &str, insn: &ebpf::Insn) -> String {
-    format!("{name} r{}, {:#x}", insn.src, insn.imm)
-}
-
-#[inline]
-fn jmp_imm_str(name: &str, insn: &ebpf::Insn) -> String {
-    if insn.off >= 0 {
-        format!("{name} r{}, {:#x}, +{:#x}", insn.dst, insn.imm, insn.off)
-    } else {
-        format!(
-            "{name} r{}, {:#x}, -{:#x}",
-            insn.dst,
-            insn.imm,
-            -(insn.off as isize)
-        )
-    }
-}
-
-#[inline]
-fn jmp_reg_str(name: &str, insn: &ebpf::Insn) -> String {
-    if insn.off >= 0 {
-        format!("{name} r{}, r{}, +{:#x}", insn.dst, insn.src, insn.off)
-    } else {
-        format!(
-            "{name} r{}, r{}, -{:#x}",
-            insn.dst,
-            insn.src,
-            -(insn.off as isize)
-        )
-    }
-}
-
-/// High-level representation of an eBPF instruction.
-///
-/// In addition to standard operation code and various operand, this struct has the following
-/// properties:
-///
-/// * It stores a name, corresponding to a mnemonic for the operation code.
-/// * It also stores a description, which is a mnemonic for the full instruction, using the actual
-///   values of the relevant operands, and that can be used for disassembling the eBPF program for
-///   example.
-/// * Immediate values are stored in an `i64` instead of a traditional i32, in order to merge the
-///   two parts of (otherwise double-length) `LD_DW_IMM` instructions.
-///
-/// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
-/// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
-/// more concise version.
-#[derive(Debug, PartialEq, Eq)]
-pub struct HLInsn {
-    /// Operation code.
-    pub opc: u8,
-    /// Name (mnemonic). This name is not canon.
-    pub name: String,
-    /// Description of the instruction. This is not canon.
-    pub desc: String,
-    /// Destination register operand.
-    pub dst: u8,
-    /// Source register operand.
-    pub src: u8,
-    /// Offset operand.
-    pub off: i16,
-    /// Immediate value operand. For `LD_DW_IMM` instructions, contains the whole value merged from
-    /// the two 8-bytes parts of the instruction.
-    pub imm: i64,
-}
-
-/// Return a vector of `struct HLInsn` built from an eBPF program.
-///
-/// This is made public to provide a way to manipulate a program as a vector of instructions, in a
-/// high-level format, for example for dumping the program instruction after instruction with a
-/// custom format.
-///
-/// Note that the two parts of `LD_DW_IMM` instructions (that have the size of two standard
-/// instructions) are considered as making a single immediate value. As a consequence, the number
-/// of instructions stored in the vector may not be equal to the size in bytes of the program
-/// divided by the length of an instructions.
-///
-/// To do so, the immediate value operand is stored as an `i64` instead as an i32, so be careful
-/// when you use it (see example `examples/to_json.rs`).
-///
-/// This is to oppose to `ebpf::to_insn_vec()` function, that treats instructions on a low-level
-/// ground and do not merge the parts of `LD_DW_IMM`. Also, the version in `ebpf` module does not
-/// use names or descriptions when storing the instructions.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::disassembler;
-///
-/// let prog = &[
-///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
-///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-/// ];
-///
-/// let v = disassembler::to_insn_vec(prog);
-/// assert_eq!(v, vec![
-///     disassembler::HLInsn {
-///         opc: 0x18,
-///         name: "lddw".to_string(),
-///         desc: "lddw r0, 0x1122334455667788".to_string(),
-///         dst: 0,
-///         src: 0,
-///         off: 0,
-///         imm: 0x1122334455667788
-///     },
-///     disassembler::HLInsn {
-///         opc: 0x95,
-///         name: "exit".to_string(),
-///         desc: "exit".to_string(),
-///         dst: 0,
-///         src: 0,
-///         off: 0,
-///         imm: 0
-///     },
-/// ]);
-/// ```
-pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
-    if prog.len() % ebpf::INSN_SIZE != 0 {
-        panic!(
-            "[Disassembler] Error: eBPF program length must be a multiple of {:?} octets",
-            ebpf::INSN_SIZE
-        );
-    }
-    if prog.is_empty() {
-        return vec![];
-    }
-
-    let mut res = vec![];
-    let mut insn_ptr: usize = 0;
-
-    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-        let insn = ebpf::get_insn(prog, insn_ptr);
-
-        let name;
-        let desc;
-        let mut imm = insn.imm as i64;
-        match insn.opc {
-            // BPF_LD class
-            ebpf::LD_ABS_B => {
-                name = "ldabsb";
-                desc = ldabs_str(name, &insn);
-            }
-            ebpf::LD_ABS_H => {
-                name = "ldabsh";
-                desc = ldabs_str(name, &insn);
-            }
-            ebpf::LD_ABS_W => {
-                name = "ldabsw";
-                desc = ldabs_str(name, &insn);
-            }
-            ebpf::LD_ABS_DW => {
-                name = "ldabsdw";
-                desc = ldabs_str(name, &insn);
-            }
-            ebpf::LD_IND_B => {
-                name = "ldindb";
-                desc = ldind_str(name, &insn);
-            }
-            ebpf::LD_IND_H => {
-                name = "ldindh";
-                desc = ldind_str(name, &insn);
-            }
-            ebpf::LD_IND_W => {
-                name = "ldindw";
-                desc = ldind_str(name, &insn);
-            }
-            ebpf::LD_IND_DW => {
-                name = "ldinddw";
-                desc = ldind_str(name, &insn);
-            }
-
-            ebpf::LD_DW_IMM => {
-                insn_ptr += 1;
-                let next_insn = ebpf::get_insn(prog, insn_ptr);
-                imm = ((insn.imm as u32) as u64 + ((next_insn.imm as u64) << 32)) as i64;
-                name = "lddw";
-                desc = format!("{name} r{:}, {imm:#x}", insn.dst);
-            }
-
-            // BPF_LDX class
-            ebpf::LD_B_REG => {
-                name = "ldxb";
-                desc = ld_reg_str(name, &insn);
-            }
-            ebpf::LD_H_REG => {
-                name = "ldxh";
-                desc = ld_reg_str(name, &insn);
-            }
-            ebpf::LD_W_REG => {
-                name = "ldxw";
-                desc = ld_reg_str(name, &insn);
-            }
-            ebpf::LD_DW_REG => {
-                name = "ldxdw";
-                desc = ld_reg_str(name, &insn);
-            }
-
-            // BPF_ST class
-            ebpf::ST_B_IMM => {
-                name = "stb";
-                desc = ld_st_imm_str(name, &insn);
-            }
-            ebpf::ST_H_IMM => {
-                name = "sth";
-                desc = ld_st_imm_str(name, &insn);
-            }
-            ebpf::ST_W_IMM => {
-                name = "stw";
-                desc = ld_st_imm_str(name, &insn);
-            }
-            ebpf::ST_DW_IMM => {
-                name = "stdw";
-                desc = ld_st_imm_str(name, &insn);
-            }
-
-            // BPF_STX class
-            ebpf::ST_B_REG => {
-                name = "stxb";
-                desc = st_reg_str(name, &insn);
-            }
-            ebpf::ST_H_REG => {
-                name = "stxh";
-                desc = st_reg_str(name, &insn);
-            }
-            ebpf::ST_W_REG => {
-                name = "stxw";
-                desc = st_reg_str(name, &insn);
-            }
-            ebpf::ST_DW_REG => {
-                name = "stxdw";
-                desc = st_reg_str(name, &insn);
-            }
-            ebpf::ST_W_XADD => {
-                name = "stxxaddw";
-                desc = st_reg_str(name, &insn);
-            }
-            ebpf::ST_DW_XADD => {
-                name = "stxxadddw";
-                desc = st_reg_str(name, &insn);
-            }
-
-            // BPF_ALU class
-            ebpf::ADD32_IMM => {
-                name = "add32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::ADD32_REG => {
-                name = "add32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::SUB32_IMM => {
-                name = "sub32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::SUB32_REG => {
-                name = "sub32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::MUL32_IMM => {
-                name = "mul32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MUL32_REG => {
-                name = "mul32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::DIV32_IMM => {
-                name = "div32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::DIV32_REG => {
-                name = "div32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::OR32_IMM => {
-                name = "or32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::OR32_REG => {
-                name = "or32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::AND32_IMM => {
-                name = "and32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::AND32_REG => {
-                name = "and32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::LSH32_IMM => {
-                name = "lsh32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::LSH32_REG => {
-                name = "lsh32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::RSH32_IMM => {
-                name = "rsh32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::RSH32_REG => {
-                name = "rsh32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::NEG32 => {
-                name = "neg32";
-                desc = format!("{name} r{:}", insn.dst);
-            }
-            ebpf::MOD32_IMM => {
-                name = "mod32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MOD32_REG => {
-                name = "mod32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::XOR32_IMM => {
-                name = "xor32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::XOR32_REG => {
-                name = "xor32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::MOV32_IMM => {
-                name = "mov32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MOV32_REG => {
-                name = "mov32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::ARSH32_IMM => {
-                name = "arsh32";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::ARSH32_REG => {
-                name = "arsh32";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::LE => {
-                name = "le";
-                desc = byteswap_str(name, &insn);
-            }
-            ebpf::BE => {
-                name = "be";
-                desc = byteswap_str(name, &insn);
-            }
-
-            // BPF_ALU64 class
-            ebpf::ADD64_IMM => {
-                name = "add64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::ADD64_REG => {
-                name = "add64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::SUB64_IMM => {
-                name = "sub64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::SUB64_REG => {
-                name = "sub64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::MUL64_IMM => {
-                name = "mul64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MUL64_REG => {
-                name = "mul64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::DIV64_IMM => {
-                name = "div64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::DIV64_REG => {
-                name = "div64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::OR64_IMM => {
-                name = "or64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::OR64_REG => {
-                name = "or64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::AND64_IMM => {
-                name = "and64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::AND64_REG => {
-                name = "and64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::LSH64_IMM => {
-                name = "lsh64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::LSH64_REG => {
-                name = "lsh64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::RSH64_IMM => {
-                name = "rsh64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::RSH64_REG => {
-                name = "rsh64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::NEG64 => {
-                name = "neg64";
-                desc = format!("{name} r{:}", insn.dst);
-            }
-            ebpf::MOD64_IMM => {
-                name = "mod64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MOD64_REG => {
-                name = "mod64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::XOR64_IMM => {
-                name = "xor64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::XOR64_REG => {
-                name = "xor64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::MOV64_IMM => {
-                name = "mov64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::MOV64_REG => {
-                name = "mov64";
-                desc = alu_reg_str(name, &insn);
-            }
-            ebpf::ARSH64_IMM => {
-                name = "arsh64";
-                desc = alu_imm_str(name, &insn);
-            }
-            ebpf::ARSH64_REG => {
-                name = "arsh64";
-                desc = alu_reg_str(name, &insn);
-            }
-
-            // BPF_JMP class
-            ebpf::JA => {
-                name = "ja";
-                desc = if insn.off >= 0 {
-                    format!("{name} +{:#x}", insn.off)
-                } else {
-                    format!("{name} -{:#x}", -insn.off)
-                }
-            }
-            ebpf::JEQ_IMM => {
-                name = "jeq";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JEQ_REG => {
-                name = "jeq";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JGT_IMM => {
-                name = "jgt";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JGT_REG => {
-                name = "jgt";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JGE_IMM => {
-                name = "jge";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JGE_REG => {
-                name = "jge";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JLT_IMM => {
-                name = "jlt";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JLT_REG => {
-                name = "jlt";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JLE_IMM => {
-                name = "jle";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JLE_REG => {
-                name = "jle";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSET_IMM => {
-                name = "jset";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSET_REG => {
-                name = "jset";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JNE_IMM => {
-                name = "jne";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JNE_REG => {
-                name = "jne";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSGT_IMM => {
-                name = "jsgt";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSGT_REG => {
-                name = "jsgt";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSGE_IMM => {
-                name = "jsge";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSGE_REG => {
-                name = "jsge";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSLT_IMM => {
-                name = "jslt";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSLT_REG => {
-                name = "jslt";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSLE_IMM => {
-                name = "jsle";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSLE_REG => {
-                name = "jsle";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::CALL => {
-                name = "call";
-                desc = format!("{name} {:#x}", insn.imm);
-            }
-            ebpf::TAIL_CALL => {
-                name = "tail_call";
-                desc = name.to_string();
-            }
-            ebpf::EXIT => {
-                name = "exit";
-                desc = name.to_string();
-            }
-
-            // BPF_JMP32 class
-            ebpf::JEQ_IMM32 => {
-                name = "jeq32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JEQ_REG32 => {
-                name = "jeq32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JGT_IMM32 => {
-                name = "jgt32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JGT_REG32 => {
-                name = "jgt32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JGE_IMM32 => {
-                name = "jge32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JGE_REG32 => {
-                name = "jge32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JLT_IMM32 => {
-                name = "jlt32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JLT_REG32 => {
-                name = "jlt32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JLE_IMM32 => {
-                name = "jle32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JLE_REG32 => {
-                name = "jle32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSET_IMM32 => {
-                name = "jset32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSET_REG32 => {
-                name = "jset32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JNE_IMM32 => {
-                name = "jne32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JNE_REG32 => {
-                name = "jne32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSGT_IMM32 => {
-                name = "jsgt32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSGT_REG32 => {
-                name = "jsgt32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSGE_IMM32 => {
-                name = "jsge32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSGE_REG32 => {
-                name = "jsge32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSLT_IMM32 => {
-                name = "jslt32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSLT_REG32 => {
-                name = "jslt32";
-                desc = jmp_reg_str(name, &insn);
-            }
-            ebpf::JSLE_IMM32 => {
-                name = "jsle32";
-                desc = jmp_imm_str(name, &insn);
-            }
-            ebpf::JSLE_REG32 => {
-                name = "jsle32";
-                desc = jmp_reg_str(name, &insn);
-            }
-
-            _ => {
-                panic!(
-                    "[Disassembler] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
-                    insn.opc, insn_ptr
-                );
-            }
-        };
-
-        let hl_insn = HLInsn {
-            opc: insn.opc,
-            name: name.to_string(),
-            desc,
-            dst: insn.dst,
-            src: insn.src,
-            off: insn.off,
-            imm,
-        };
-
-        res.push(hl_insn);
-
-        insn_ptr += 1;
-    }
-    res
-}
-
-/// Disassemble an eBPF program into human-readable instructions and prints it to standard output.
-///
-/// The program is not checked for errors or inconsistencies.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::disassembler;
-/// let prog = &[
-///     0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
-///     0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
-///     0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
-///     0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-/// ];
-/// disassembler::disassemble(prog);
-/// # // "\nadd64 r1, 0x605\nmov64 r2, 0x32\nmov64 r1, r0\nbe16 r0\nneg64 r2\nexit"
-/// ```
-///
-/// This will produce the following output:
-///
-/// ```test
-/// add64 r1, 0x605
-/// mov64 r2, 0x32
-/// mov64 r1, r0
-/// be16 r0
-/// neg64 r2
-/// exit
-/// ```
-pub fn disassemble(prog: &[u8]) {
-    #[cfg(feature = "std")]
-    {
-        for insn in to_insn_vec(prog) {
-            println!("{}", insn.desc);
-        }
-    }
-    #[cfg(not(feature = "std"))]
-    {
-        for insn in to_insn_vec(prog) {
-            log::info!("{}", insn.desc);
-        }
-    }
-}

+ 0 - 635
kernel/crates/rbpf/src/ebpf.rs

@@ -1,635 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-//! This module contains all the definitions related to eBPF, and some functions permitting to
-//! manipulate eBPF instructions.
-//!
-//! The number of bytes in an instruction, the maximum number of instructions in a program, and
-//! also all operation codes are defined here as constants.
-//!
-//! The structure for an instruction used by this crate, as well as the function to extract it from
-//! a program, is also defined in the module.
-//!
-//! To learn more about these instructions, see the Linux kernel documentation:
-//! <https://www.kernel.org/doc/Documentation/networking/filter.txt>, or for a shorter version of
-//! the list of the operation codes: <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md>
-
-use alloc::{vec, vec::Vec};
-
-use byteorder::{ByteOrder, LittleEndian};
-
-/// The maximum call depth is 8
-pub const RBPF_MAX_CALL_DEPTH: usize = 8;
-
-/// Maximum number of instructions in an eBPF program.
-pub const PROG_MAX_INSNS: usize = 1000000;
-/// Size of an eBPF instructions, in bytes.
-pub const INSN_SIZE: usize = 8;
-/// Maximum size of an eBPF program, in bytes.
-pub const PROG_MAX_SIZE: usize = PROG_MAX_INSNS * INSN_SIZE;
-/// Stack for the eBPF stack, in bytes.
-pub const STACK_SIZE: usize = 512;
-
-// eBPF op codes.
-// See also https://www.kernel.org/doc/Documentation/networking/filter.txt
-
-// Three least significant bits are operation class:
-/// BPF operation class: load from immediate.
-pub const BPF_LD: u8 = 0x00;
-/// BPF operation class: load from register.
-pub const BPF_LDX: u8 = 0x01;
-/// BPF operation class: store immediate.
-pub const BPF_ST: u8 = 0x02;
-/// BPF operation class: store value from register.
-pub const BPF_STX: u8 = 0x03;
-/// BPF operation class: 32 bits arithmetic operation.
-pub const BPF_ALU: u8 = 0x04;
-/// BPF operation class: jump (64-bit wide operands for comparisons).
-pub const BPF_JMP: u8 = 0x05;
-/// BPF operation class: jump (32-bit wide operands for comparisons).
-pub const BPF_JMP32: u8 = 0x06;
-// [ class 6 unused, reserved for future use ]
-/// BPF operation class: 64 bits arithmetic operation.
-pub const BPF_ALU64: u8 = 0x07;
-
-// For load and store instructions:
-// +------------+--------+------------+
-// |   3 bits   | 2 bits |   3 bits   |
-// |    mode    |  size  | insn class |
-// +------------+--------+------------+
-// (MSB)                          (LSB)
-
-// Size modifiers:
-/// BPF size modifier: word (4 bytes).
-pub const BPF_W: u8 = 0x00;
-/// BPF size modifier: half-word (2 bytes).
-pub const BPF_H: u8 = 0x08;
-/// BPF size modifier: byte (1 byte).
-pub const BPF_B: u8 = 0x10;
-/// BPF size modifier: double word (8 bytes).
-pub const BPF_DW: u8 = 0x18;
-
-// Mode modifiers:
-/// BPF mode modifier: immediate value.
-pub const BPF_IMM: u8 = 0x00;
-/// BPF mode modifier: absolute load.
-pub const BPF_ABS: u8 = 0x20;
-/// BPF mode modifier: indirect load.
-pub const BPF_IND: u8 = 0x40;
-/// BPF mode modifier: load from / store to memory.
-pub const BPF_MEM: u8 = 0x60;
-// [ 0x80 reserved ]
-// [ 0xa0 reserved ]
-/// BPF mode modifier: exclusive add.
-pub const BPF_XADD: u8 = 0xc0;
-
-// For arithmetic (BPF_ALU/BPF_ALU64) and jump (BPF_JMP) instructions:
-// +----------------+--------+--------+
-// |     4 bits     |1 b.|   3 bits   |
-// | operation code | src| insn class |
-// +----------------+----+------------+
-// (MSB)                          (LSB)
-
-// Source modifiers:
-/// BPF source operand modifier: 32-bit immediate value.
-pub const BPF_K: u8 = 0x00;
-/// BPF source operand modifier: `src` register.
-pub const BPF_X: u8 = 0x08;
-
-// Operation codes -- BPF_ALU or BPF_ALU64 classes:
-/// BPF ALU/ALU64 operation code: addition.
-pub const BPF_ADD: u8 = 0x00;
-/// BPF ALU/ALU64 operation code: subtraction.
-pub const BPF_SUB: u8 = 0x10;
-/// BPF ALU/ALU64 operation code: multiplication.
-pub const BPF_MUL: u8 = 0x20;
-/// BPF ALU/ALU64 operation code: division.
-pub const BPF_DIV: u8 = 0x30;
-/// BPF ALU/ALU64 operation code: or.
-pub const BPF_OR: u8 = 0x40;
-/// BPF ALU/ALU64 operation code: and.
-pub const BPF_AND: u8 = 0x50;
-/// BPF ALU/ALU64 operation code: left shift.
-pub const BPF_LSH: u8 = 0x60;
-/// BPF ALU/ALU64 operation code: right shift.
-pub const BPF_RSH: u8 = 0x70;
-/// BPF ALU/ALU64 operation code: negation.
-pub const BPF_NEG: u8 = 0x80;
-/// BPF ALU/ALU64 operation code: modulus.
-pub const BPF_MOD: u8 = 0x90;
-/// BPF ALU/ALU64 operation code: exclusive or.
-pub const BPF_XOR: u8 = 0xa0;
-/// BPF ALU/ALU64 operation code: move.
-pub const BPF_MOV: u8 = 0xb0;
-/// BPF ALU/ALU64 operation code: sign extending right shift.
-pub const BPF_ARSH: u8 = 0xc0;
-/// BPF ALU/ALU64 operation code: endianness conversion.
-pub const BPF_END: u8 = 0xd0;
-
-// Operation codes -- BPF_JMP or BPF_JMP32 classes:
-/// BPF JMP operation code: jump.
-pub const BPF_JA: u8 = 0x00;
-/// BPF JMP operation code: jump if equal.
-pub const BPF_JEQ: u8 = 0x10;
-/// BPF JMP operation code: jump if greater than.
-pub const BPF_JGT: u8 = 0x20;
-/// BPF JMP operation code: jump if greater or equal.
-pub const BPF_JGE: u8 = 0x30;
-/// BPF JMP operation code: jump if `src` & `reg`.
-pub const BPF_JSET: u8 = 0x40;
-/// BPF JMP operation code: jump if not equal.
-pub const BPF_JNE: u8 = 0x50;
-/// BPF JMP operation code: jump if greater than (signed).
-pub const BPF_JSGT: u8 = 0x60;
-/// BPF JMP operation code: jump if greater or equal (signed).
-pub const BPF_JSGE: u8 = 0x70;
-/// BPF JMP operation code: helper function call.
-pub const BPF_CALL: u8 = 0x80;
-/// BPF JMP operation code: return from program.
-pub const BPF_EXIT: u8 = 0x90;
-/// BPF JMP operation code: jump if lower than.
-pub const BPF_JLT: u8 = 0xa0;
-/// BPF JMP operation code: jump if lower or equal.
-pub const BPF_JLE: u8 = 0xb0;
-/// BPF JMP operation code: jump if lower than (signed).
-pub const BPF_JSLT: u8 = 0xc0;
-/// BPF JMP operation code: jump if lower or equal (signed).
-pub const BPF_JSLE: u8 = 0xd0;
-
-// Op codes
-// (Following operation names are not “official”, but may be proper to rbpf; Linux kernel only
-// combines above flags and does not attribute a name per operation.)
-
-/// BPF opcode: `ldabsb src, dst, imm`.
-pub const LD_ABS_B: u8 = BPF_LD | BPF_ABS | BPF_B;
-/// BPF opcode: `ldabsh src, dst, imm`.
-pub const LD_ABS_H: u8 = BPF_LD | BPF_ABS | BPF_H;
-/// BPF opcode: `ldabsw src, dst, imm`.
-pub const LD_ABS_W: u8 = BPF_LD | BPF_ABS | BPF_W;
-/// BPF opcode: `ldabsdw src, dst, imm`.
-pub const LD_ABS_DW: u8 = BPF_LD | BPF_ABS | BPF_DW;
-/// BPF opcode: `ldindb src, dst, imm`.
-pub const LD_IND_B: u8 = BPF_LD | BPF_IND | BPF_B;
-/// BPF opcode: `ldindh src, dst, imm`.
-pub const LD_IND_H: u8 = BPF_LD | BPF_IND | BPF_H;
-/// BPF opcode: `ldindw src, dst, imm`.
-pub const LD_IND_W: u8 = BPF_LD | BPF_IND | BPF_W;
-/// BPF opcode: `ldinddw src, dst, imm`.
-pub const LD_IND_DW: u8 = BPF_LD | BPF_IND | BPF_DW;
-
-#[allow(unknown_lints)]
-#[allow(clippy::eq_op)]
-/// BPF opcode: `lddw dst, imm` /// `dst = imm`.
-pub const LD_DW_IMM: u8 = BPF_LD | BPF_IMM | BPF_DW;
-/// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`.
-pub const LD_B_REG: u8 = BPF_LDX | BPF_MEM | BPF_B;
-/// BPF opcode: `ldxh dst, [src + off]` /// `dst = (src + off) as u16`.
-pub const LD_H_REG: u8 = BPF_LDX | BPF_MEM | BPF_H;
-/// BPF opcode: `ldxw dst, [src + off]` /// `dst = (src + off) as u32`.
-pub const LD_W_REG: u8 = BPF_LDX | BPF_MEM | BPF_W;
-/// BPF opcode: `ldxdw dst, [src + off]` /// `dst = (src + off) as u64`.
-pub const LD_DW_REG: u8 = BPF_LDX | BPF_MEM | BPF_DW;
-/// BPF opcode: `stb [dst + off], imm` /// `(dst + offset) as u8 = imm`.
-pub const ST_B_IMM: u8 = BPF_ST | BPF_MEM | BPF_B;
-/// BPF opcode: `sth [dst + off], imm` /// `(dst + offset) as u16 = imm`.
-pub const ST_H_IMM: u8 = BPF_ST | BPF_MEM | BPF_H;
-/// BPF opcode: `stw [dst + off], imm` /// `(dst + offset) as u32 = imm`.
-pub const ST_W_IMM: u8 = BPF_ST | BPF_MEM | BPF_W;
-/// BPF opcode: `stdw [dst + off], imm` /// `(dst + offset) as u64 = imm`.
-pub const ST_DW_IMM: u8 = BPF_ST | BPF_MEM | BPF_DW;
-/// BPF opcode: `stxb [dst + off], src` /// `(dst + offset) as u8 = src`.
-pub const ST_B_REG: u8 = BPF_STX | BPF_MEM | BPF_B;
-/// BPF opcode: `stxh [dst + off], src` /// `(dst + offset) as u16 = src`.
-pub const ST_H_REG: u8 = BPF_STX | BPF_MEM | BPF_H;
-/// BPF opcode: `stxw [dst + off], src` /// `(dst + offset) as u32 = src`.
-pub const ST_W_REG: u8 = BPF_STX | BPF_MEM | BPF_W;
-/// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`.
-pub const ST_DW_REG: u8 = BPF_STX | BPF_MEM | BPF_DW;
-
-/// BPF opcode: `stxxaddw [dst + off], src`.
-pub const ST_W_XADD: u8 = BPF_STX | BPF_XADD | BPF_W;
-/// BPF opcode: `stxxadddw [dst + off], src`.
-pub const ST_DW_XADD: u8 = BPF_STX | BPF_XADD | BPF_DW;
-
-/// BPF opcode: `add32 dst, imm` /// `dst += imm`.
-pub const ADD32_IMM: u8 = BPF_ALU | BPF_K | BPF_ADD;
-/// BPF opcode: `add32 dst, src` /// `dst += src`.
-pub const ADD32_REG: u8 = BPF_ALU | BPF_X | BPF_ADD;
-/// BPF opcode: `sub32 dst, imm` /// `dst -= imm`.
-pub const SUB32_IMM: u8 = BPF_ALU | BPF_K | BPF_SUB;
-/// BPF opcode: `sub32 dst, src` /// `dst -= src`.
-pub const SUB32_REG: u8 = BPF_ALU | BPF_X | BPF_SUB;
-/// BPF opcode: `mul32 dst, imm` /// `dst *= imm`.
-pub const MUL32_IMM: u8 = BPF_ALU | BPF_K | BPF_MUL;
-/// BPF opcode: `mul32 dst, src` /// `dst *= src`.
-pub const MUL32_REG: u8 = BPF_ALU | BPF_X | BPF_MUL;
-/// BPF opcode: `div32 dst, imm` /// `dst /= imm`.
-pub const DIV32_IMM: u8 = BPF_ALU | BPF_K | BPF_DIV;
-/// BPF opcode: `div32 dst, src` /// `dst /= src`.
-pub const DIV32_REG: u8 = BPF_ALU | BPF_X | BPF_DIV;
-/// BPF opcode: `or32 dst, imm` /// `dst |= imm`.
-pub const OR32_IMM: u8 = BPF_ALU | BPF_K | BPF_OR;
-/// BPF opcode: `or32 dst, src` /// `dst |= src`.
-pub const OR32_REG: u8 = BPF_ALU | BPF_X | BPF_OR;
-/// BPF opcode: `and32 dst, imm` /// `dst &= imm`.
-pub const AND32_IMM: u8 = BPF_ALU | BPF_K | BPF_AND;
-/// BPF opcode: `and32 dst, src` /// `dst &= src`.
-pub const AND32_REG: u8 = BPF_ALU | BPF_X | BPF_AND;
-/// BPF opcode: `lsh32 dst, imm` /// `dst <<= imm`.
-pub const LSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_LSH;
-/// BPF opcode: `lsh32 dst, src` /// `dst <<= src`.
-pub const LSH32_REG: u8 = BPF_ALU | BPF_X | BPF_LSH;
-/// BPF opcode: `rsh32 dst, imm` /// `dst >>= imm`.
-pub const RSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_RSH;
-/// BPF opcode: `rsh32 dst, src` /// `dst >>= src`.
-pub const RSH32_REG: u8 = BPF_ALU | BPF_X | BPF_RSH;
-/// BPF opcode: `neg32 dst` /// `dst = -dst`.
-pub const NEG32: u8 = BPF_ALU | BPF_NEG;
-/// BPF opcode: `mod32 dst, imm` /// `dst %= imm`.
-pub const MOD32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOD;
-/// BPF opcode: `mod32 dst, src` /// `dst %= src`.
-pub const MOD32_REG: u8 = BPF_ALU | BPF_X | BPF_MOD;
-/// BPF opcode: `xor32 dst, imm` /// `dst ^= imm`.
-pub const XOR32_IMM: u8 = BPF_ALU | BPF_K | BPF_XOR;
-/// BPF opcode: `xor32 dst, src` /// `dst ^= src`.
-pub const XOR32_REG: u8 = BPF_ALU | BPF_X | BPF_XOR;
-/// BPF opcode: `mov32 dst, imm` /// `dst = imm`.
-pub const MOV32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOV;
-/// BPF opcode: `mov32 dst, src` /// `dst = src`.
-pub const MOV32_REG: u8 = BPF_ALU | BPF_X | BPF_MOV;
-/// BPF opcode: `arsh32 dst, imm` /// `dst >>= imm (arithmetic)`.
-///
-/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
-pub const ARSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_ARSH;
-/// BPF opcode: `arsh32 dst, src` /// `dst >>= src (arithmetic)`.
-///
-/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
-pub const ARSH32_REG: u8 = BPF_ALU | BPF_X | BPF_ARSH;
-
-/// BPF opcode: `le dst` /// `dst = htole<imm>(dst), with imm in {16, 32, 64}`.
-pub const LE: u8 = BPF_ALU | BPF_K | BPF_END;
-/// BPF opcode: `be dst` /// `dst = htobe<imm>(dst), with imm in {16, 32, 64}`.
-pub const BE: u8 = BPF_ALU | BPF_X | BPF_END;
-
-/// BPF opcode: `add64 dst, imm` /// `dst += imm`.
-pub const ADD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ADD;
-/// BPF opcode: `add64 dst, src` /// `dst += src`.
-pub const ADD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ADD;
-/// BPF opcode: `sub64 dst, imm` /// `dst -= imm`.
-pub const SUB64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_SUB;
-/// BPF opcode: `sub64 dst, src` /// `dst -= src`.
-pub const SUB64_REG: u8 = BPF_ALU64 | BPF_X | BPF_SUB;
-/// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
-pub const MUL64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MUL;
-/// BPF opcode: `div64 dst, src` /// `dst /= src`.
-pub const MUL64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MUL;
-/// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
-pub const DIV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_DIV;
-/// BPF opcode: `div64 dst, src` /// `dst /= src`.
-pub const DIV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_DIV;
-/// BPF opcode: `or64 dst, imm` /// `dst |= imm`.
-pub const OR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_OR;
-/// BPF opcode: `or64 dst, src` /// `dst |= src`.
-pub const OR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_OR;
-/// BPF opcode: `and64 dst, imm` /// `dst &= imm`.
-pub const AND64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_AND;
-/// BPF opcode: `and64 dst, src` /// `dst &= src`.
-pub const AND64_REG: u8 = BPF_ALU64 | BPF_X | BPF_AND;
-/// BPF opcode: `lsh64 dst, imm` /// `dst <<= imm`.
-pub const LSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_LSH;
-/// BPF opcode: `lsh64 dst, src` /// `dst <<= src`.
-pub const LSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_LSH;
-/// BPF opcode: `rsh64 dst, imm` /// `dst >>= imm`.
-pub const RSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_RSH;
-/// BPF opcode: `rsh64 dst, src` /// `dst >>= src`.
-pub const RSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_RSH;
-/// BPF opcode: `neg64 dst, imm` /// `dst = -dst`.
-pub const NEG64: u8 = BPF_ALU64 | BPF_NEG;
-/// BPF opcode: `mod64 dst, imm` /// `dst %= imm`.
-pub const MOD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOD;
-/// BPF opcode: `mod64 dst, src` /// `dst %= src`.
-pub const MOD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOD;
-/// BPF opcode: `xor64 dst, imm` /// `dst ^= imm`.
-pub const XOR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_XOR;
-/// BPF opcode: `xor64 dst, src` /// `dst ^= src`.
-pub const XOR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_XOR;
-/// BPF opcode: `mov64 dst, imm` /// `dst = imm`.
-pub const MOV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOV;
-/// BPF opcode: `mov64 dst, src` /// `dst = src`.
-pub const MOV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOV;
-/// BPF opcode: `arsh64 dst, imm` /// `dst >>= imm (arithmetic)`.
-///
-/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
-pub const ARSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ARSH;
-/// BPF opcode: `arsh64 dst, src` /// `dst >>= src (arithmetic)`.
-///
-/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
-pub const ARSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ARSH;
-
-/// BPF opcode: `ja +off` /// `PC += off`.
-pub const JA: u8 = BPF_JMP | BPF_JA;
-/// BPF opcode: `jeq dst, imm, +off` /// `PC += off if dst == imm`.
-pub const JEQ_IMM: u8 = BPF_JMP | BPF_K | BPF_JEQ;
-/// BPF opcode: `jeq dst, src, +off` /// `PC += off if dst == src`.
-pub const JEQ_REG: u8 = BPF_JMP | BPF_X | BPF_JEQ;
-/// BPF opcode: `jgt dst, imm, +off` /// `PC += off if dst > imm`.
-pub const JGT_IMM: u8 = BPF_JMP | BPF_K | BPF_JGT;
-/// BPF opcode: `jgt dst, src, +off` /// `PC += off if dst > src`.
-pub const JGT_REG: u8 = BPF_JMP | BPF_X | BPF_JGT;
-/// BPF opcode: `jge dst, imm, +off` /// `PC += off if dst >= imm`.
-pub const JGE_IMM: u8 = BPF_JMP | BPF_K | BPF_JGE;
-/// BPF opcode: `jge dst, src, +off` /// `PC += off if dst >= src`.
-pub const JGE_REG: u8 = BPF_JMP | BPF_X | BPF_JGE;
-/// BPF opcode: `jlt dst, imm, +off` /// `PC += off if dst < imm`.
-pub const JLT_IMM: u8 = BPF_JMP | BPF_K | BPF_JLT;
-/// BPF opcode: `jlt dst, src, +off` /// `PC += off if dst < src`.
-pub const JLT_REG: u8 = BPF_JMP | BPF_X | BPF_JLT;
-/// BPF opcode: `jle dst, imm, +off` /// `PC += off if dst <= imm`.
-pub const JLE_IMM: u8 = BPF_JMP | BPF_K | BPF_JLE;
-/// BPF opcode: `jle dst, src, +off` /// `PC += off if dst <= src`.
-pub const JLE_REG: u8 = BPF_JMP | BPF_X | BPF_JLE;
-/// BPF opcode: `jset dst, imm, +off` /// `PC += off if dst & imm`.
-pub const JSET_IMM: u8 = BPF_JMP | BPF_K | BPF_JSET;
-/// BPF opcode: `jset dst, src, +off` /// `PC += off if dst & src`.
-pub const JSET_REG: u8 = BPF_JMP | BPF_X | BPF_JSET;
-/// BPF opcode: `jne dst, imm, +off` /// `PC += off if dst != imm`.
-pub const JNE_IMM: u8 = BPF_JMP | BPF_K | BPF_JNE;
-/// BPF opcode: `jne dst, src, +off` /// `PC += off if dst != src`.
-pub const JNE_REG: u8 = BPF_JMP | BPF_X | BPF_JNE;
-/// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if dst > imm (signed)`.
-pub const JSGT_IMM: u8 = BPF_JMP | BPF_K | BPF_JSGT;
-/// BPF opcode: `jsgt dst, src, +off` /// `PC += off if dst > src (signed)`.
-pub const JSGT_REG: u8 = BPF_JMP | BPF_X | BPF_JSGT;
-/// BPF opcode: `jsge dst, imm, +off` /// `PC += off if dst >= imm (signed)`.
-pub const JSGE_IMM: u8 = BPF_JMP | BPF_K | BPF_JSGE;
-/// BPF opcode: `jsge dst, src, +off` /// `PC += off if dst >= src (signed)`.
-pub const JSGE_REG: u8 = BPF_JMP | BPF_X | BPF_JSGE;
-/// BPF opcode: `jslt dst, imm, +off` /// `PC += off if dst < imm (signed)`.
-pub const JSLT_IMM: u8 = BPF_JMP | BPF_K | BPF_JSLT;
-/// BPF opcode: `jslt dst, src, +off` /// `PC += off if dst < src (signed)`.
-pub const JSLT_REG: u8 = BPF_JMP | BPF_X | BPF_JSLT;
-/// BPF opcode: `jsle dst, imm, +off` /// `PC += off if dst <= imm (signed)`.
-pub const JSLE_IMM: u8 = BPF_JMP | BPF_K | BPF_JSLE;
-/// BPF opcode: `jsle dst, src, +off` /// `PC += off if dst <= src (signed)`.
-pub const JSLE_REG: u8 = BPF_JMP | BPF_X | BPF_JSLE;
-
-/// BPF opcode: `jeq dst, imm, +off` /// `PC += off if (dst as u32) == imm`.
-pub const JEQ_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JEQ;
-/// BPF opcode: `jeq dst, src, +off` /// `PC += off if (dst as u32) == (src as u32)`.
-pub const JEQ_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JEQ;
-/// BPF opcode: `jgt dst, imm, +off` /// `PC += off if (dst as u32) > imm`.
-pub const JGT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JGT;
-/// BPF opcode: `jgt dst, src, +off` /// `PC += off if (dst as u32) > (src as u32)`.
-pub const JGT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JGT;
-/// BPF opcode: `jge dst, imm, +off` /// `PC += off if (dst as u32) >= imm`.
-pub const JGE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JGE;
-/// BPF opcode: `jge dst, src, +off` /// `PC += off if (dst as u32) >= (src as u32)`.
-pub const JGE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JGE;
-/// BPF opcode: `jlt dst, imm, +off` /// `PC += off if (dst as u32) < imm`.
-pub const JLT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JLT;
-/// BPF opcode: `jlt dst, src, +off` /// `PC += off if (dst as u32) < (src as u32)`.
-pub const JLT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JLT;
-/// BPF opcode: `jle dst, imm, +off` /// `PC += off if (dst as u32) <= imm`.
-pub const JLE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JLE;
-/// BPF opcode: `jle dst, src, +off` /// `PC += off if (dst as u32) <= (src as u32)`.
-pub const JLE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JLE;
-/// BPF opcode: `jset dst, imm, +off` /// `PC += off if (dst as u32) & imm`.
-pub const JSET_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSET;
-/// BPF opcode: `jset dst, src, +off` /// `PC += off if (dst as u32) & (src as u32)`.
-pub const JSET_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSET;
-/// BPF opcode: `jne dst, imm, +off` /// `PC += off if (dst as u32) != imm`.
-pub const JNE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JNE;
-/// BPF opcode: `jne dst, src, +off` /// `PC += off if (dst as u32) != (src as u32)`.
-pub const JNE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JNE;
-/// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if (dst as i32) > imm (signed)`.
-pub const JSGT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSGT;
-/// BPF opcode: `jsgt dst, src, +off` /// `PC += off if (dst as i32) > (src as i32) (signed)`.
-pub const JSGT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSGT;
-/// BPF opcode: `jsge dst, imm, +off` /// `PC += off if (dst as i32) >= imm (signed)`.
-pub const JSGE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSGE;
-/// BPF opcode: `jsge dst, src, +off` /// `PC += off if (dst as i32) >= (src as i32) (signed)`.
-pub const JSGE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSGE;
-/// BPF opcode: `jslt dst, imm, +off` /// `PC += off if (dst as i32) < imm (signed)`.
-pub const JSLT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSLT;
-/// BPF opcode: `jslt dst, src, +off` /// `PC += off if (dst as i32) < (src as i32) (signed)`.
-pub const JSLT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSLT;
-/// BPF opcode: `jsle dst, imm, +off` /// `PC += off if (dst as i32) <= imm (signed)`.
-pub const JSLE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSLE;
-/// BPF opcode: `jsle dst, src, +off` /// `PC += off if (dst as i32) <= (src as i32) (signed)`.
-pub const JSLE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSLE;
-
-/// BPF opcode: `call imm` /// helper function call to helper with key `imm`.
-pub const CALL: u8 = BPF_JMP | BPF_CALL;
-/// BPF opcode: tail call.
-pub const TAIL_CALL: u8 = BPF_JMP | BPF_X | BPF_CALL;
-/// BPF opcode: `exit` /// `return r0`.
-pub const EXIT: u8 = BPF_JMP | BPF_EXIT;
-
-// Used in JIT
-/// Mask to extract the operation class from an operation code.
-pub const BPF_CLS_MASK: u8 = 0x07;
-/// Mask to extract the arithmetic operation code from an instruction operation code.
-pub const BPF_ALU_OP_MASK: u8 = 0xf0;
-
-/// Prototype of an eBPF helper function.
-pub type Helper = fn(u64, u64, u64, u64, u64) -> u64;
-
-/// An eBPF instruction.
-///
-/// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
-/// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
-/// more concise version.
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Insn {
-    /// Operation code.
-    pub opc: u8,
-    /// Destination register operand.
-    pub dst: u8,
-    /// Source register operand.
-    pub src: u8,
-    /// Offset operand.
-    pub off: i16,
-    /// Immediate value operand.
-    pub imm: i32,
-}
-
-impl Insn {
-    /// Turn an `Insn` back into an array of bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::ebpf;
-    ///
-    /// let prog: &[u8] = &[
-    ///     0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
-    ///     ];
-    /// let insn = ebpf::Insn {
-    ///     opc: 0xb7,
-    ///     dst: 2,
-    ///     src: 1,
-    ///     off: 0x3456,
-    ///     imm: 0x789abcde
-    /// };
-    /// assert_eq!(insn.to_array(), prog);
-    /// ```
-    pub fn to_array(&self) -> [u8; INSN_SIZE] {
-        [
-            self.opc,
-            self.src.wrapping_shl(4) | self.dst,
-            (self.off & 0xff) as u8,
-            self.off.wrapping_shr(8) as u8,
-            (self.imm & 0xff) as u8,
-            (self.imm & 0xff_00).wrapping_shr(8) as u8,
-            (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
-            (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
-        ]
-    }
-
-    /// Turn an `Insn` into an vector of bytes.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::ebpf;
-    ///
-    /// let prog: Vec<u8> = vec![
-    ///     0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
-    ///     ];
-    /// let insn = ebpf::Insn {
-    ///     opc: 0xb7,
-    ///     dst: 2,
-    ///     src: 1,
-    ///     off: 0x3456,
-    ///     imm: 0x789abcde
-    /// };
-    /// assert_eq!(insn.to_vec(), prog);
-    /// ```
-    pub fn to_vec(&self) -> Vec<u8> {
-        vec![
-            self.opc,
-            self.src.wrapping_shl(4) | self.dst,
-            (self.off & 0xff) as u8,
-            self.off.wrapping_shr(8) as u8,
-            (self.imm & 0xff) as u8,
-            (self.imm & 0xff_00).wrapping_shr(8) as u8,
-            (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
-            (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
-        ]
-    }
-}
-
-/// Get the instruction at `idx` of an eBPF program. `idx` is the index (number) of the
-/// instruction (not a byte offset). The first instruction has index 0.
-///
-/// # Panics
-///
-/// Panics if it is not possible to get the instruction (if idx is too high, or last instruction is
-/// incomplete).
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::ebpf;
-///
-/// let prog = &[
-///     0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-///     ];
-/// let insn = ebpf::get_insn(prog, 1);
-/// assert_eq!(insn.opc, 0x95);
-/// ```
-///
-/// The example below will panic, since the last instruction is not complete and cannot be loaded.
-///
-/// ```rust,should_panic
-/// use rbpf::ebpf;
-///
-/// let prog = &[
-///     0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00              // two bytes missing
-///     ];
-/// let insn = ebpf::get_insn(prog, 1);
-/// ```
-pub fn get_insn(prog: &[u8], idx: usize) -> Insn {
-    // This guard should not be needed in most cases, since the verifier already checks the program
-    // size, and indexes should be fine in the interpreter/JIT. But this function is publicly
-    // available and user can call it with any `idx`, so we have to check anyway.
-    if (idx + 1) * INSN_SIZE > prog.len() {
-        panic!(
-            "Error: cannot reach instruction at index {:?} in program containing {:?} bytes",
-            idx,
-            prog.len()
-        );
-    }
-    Insn {
-        opc: prog[INSN_SIZE * idx],
-        dst: prog[INSN_SIZE * idx + 1] & 0x0f,
-        src: (prog[INSN_SIZE * idx + 1] & 0xf0) >> 4,
-        off: LittleEndian::read_i16(&prog[(INSN_SIZE * idx + 2)..]),
-        imm: LittleEndian::read_i32(&prog[(INSN_SIZE * idx + 4)..]),
-    }
-}
-
-/// Return a vector of `struct Insn` built from a program.
-///
-/// This is provided as a convenience for users wishing to manipulate a vector of instructions, for
-/// example for dumping the program instruction after instruction with a custom format.
-///
-/// Note that the two parts of `LD_DW_IMM` instructions (spanning on 64 bits) are considered as two
-/// distinct instructions.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::ebpf;
-///
-/// let prog = &[
-///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
-///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-/// ];
-///
-/// let v = ebpf::to_insn_vec(prog);
-/// assert_eq!(v, vec![
-///     ebpf::Insn {
-///         opc: 0x18,
-///         dst: 0,
-///         src: 0,
-///         off: 0,
-///         imm: 0x55667788
-///     },
-///     ebpf::Insn {
-///         opc: 0,
-///         dst: 0,
-///         src: 0,
-///         off: 0,
-///         imm: 0x11223344
-///     },
-///     ebpf::Insn {
-///         opc: 0x95,
-///         dst: 0,
-///         src: 0,
-///         off: 0,
-///         imm: 0
-///     },
-/// ]);
-/// ```
-pub fn to_insn_vec(prog: &[u8]) -> Vec<Insn> {
-    if prog.len() % INSN_SIZE != 0 {
-        panic!(
-            "Error: eBPF program length must be a multiple of {:?} octets",
-            INSN_SIZE
-        );
-    }
-
-    let mut res = vec![];
-    let mut insn_ptr: usize = 0;
-
-    while insn_ptr * INSN_SIZE < prog.len() {
-        let insn = get_insn(prog, insn_ptr);
-        res.push(insn);
-        insn_ptr += 1;
-    }
-    res
-}

+ 0 - 488
kernel/crates/rbpf/src/helpers.rs

@@ -1,488 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2015 Big Switch Networks, Inc
-//      (Algorithms for uBPF helpers, originally in C)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-//      (Translation to Rust, other helpers)
-
-//! This module implements some built-in helpers that can be called from within an eBPF program.
-//!
-//! These helpers may originate from several places:
-//!
-//! * Some of them mimic the helpers available in the Linux kernel.
-//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
-//! * Other helpers may be specific to rbpf.
-//!
-//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
-//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
-//! respect this convention.
-
-// Helpers associated to kernel helpers
-// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.
-
-// bpf_ktime_getns()
-
-/// Index of helper `bpf_ktime_getns()`, equivalent to `bpf_time_getns()`, in Linux kernel, see
-/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
-pub const BPF_KTIME_GETNS_IDX: u32 = 5;
-
-/// Get monotonic time (since boot time) in nanoseconds. All arguments are unused.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let t = helpers::bpf_time_getns(0, 0, 0, 0, 0);
-/// let d =  t / 10u64.pow(9)  / 60   / 60  / 24;
-/// let h = (t / 10u64.pow(9)  / 60   / 60) % 24;
-/// let m = (t / 10u64.pow(9)  / 60 ) % 60;
-/// let s = (t / 10u64.pow(9)) % 60;
-/// let ns = t % 10u64.pow(9);
-/// println!("Uptime: {:#x} == {} days {}:{}:{}, {} ns", t, d, h, m, s, ns);
-/// ```
-#[allow(dead_code)]
-#[allow(unused_variables)]
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub fn bpf_time_getns(unused1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
-    time::precise_time_ns()
-}
-
-// bpf_trace_printk()
-
-/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
-/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
-pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
-
-/// Prints its **last three** arguments to standard output. The **first two** arguments are
-/// **unused**. Returns the number of bytes written.
-///
-/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
-/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let res = helpers::bpf_trace_printf(0, 0, 1, 15, 32);
-/// assert_eq!(res as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len());
-/// ```
-///
-/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
-///
-/// The eBPF code needed to perform the call in this example would be nearly identical to the code
-/// obtained by compiling the following code from C to eBPF with clang:
-///
-/// ```c
-/// #include <linux/bpf.h>
-/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
-///
-/// int main(struct __sk_buff *skb)
-/// {
-///     // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed.
-///     // See <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/kernel/trace/bpf_trace.c>.
-///     char *fmt = "bpf_trace_printk %llx, %llx, %llx\n";
-///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
-/// }
-/// ```
-///
-/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
-/// program is run.
-#[allow(dead_code)]
-#[allow(unused_variables)]
-#[cfg(feature = "std")]
-pub fn bpf_trace_printf(unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
-    println!("bpf_trace_printf: {arg3:#x}, {arg4:#x}, {arg5:#x}");
-    let size_arg = |x| {
-        if x == 0 {
-            1
-        } else {
-            (x as f64).log(16.0).floor() as u64 + 1
-        }
-    };
-    "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64 + size_arg(arg3) + size_arg(arg4) + size_arg(arg5)
-}
-
-// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>
-
-/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
-/// each argument must be a `u64`.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
-/// assert_eq!(gathered, 0x1122334455);
-/// ```
-pub fn gather_bytes(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
-    arg1.wrapping_shl(32)
-        | arg2.wrapping_shl(24)
-        | arg3.wrapping_shl(16)
-        | arg4.wrapping_shl(8)
-        | arg5
-}
-
-/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
-/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
-/// cases. Arguments 3 to 5 are unused.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let val: u64 = 0x112233;
-/// let val_ptr = &val as *const u64;
-///
-/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
-/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
-/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
-/// assert_eq!(val, 0x112233);
-/// ```
-#[allow(unused_variables)]
-pub fn memfrob(ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
-    for i in 0..len {
-        unsafe {
-            let mut p = (ptr + i) as *mut u8;
-            *p ^= 0b101010;
-        }
-    }
-    0
-}
-
-// TODO: Try again when asm!() is available in stable Rust.
-// #![feature(asm)]
-// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-// #[allow(unused_variables)]
-// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
-//     unsafe {
-//         asm!(
-//                 "mov $0xf0, %rax"
-//             ::: "mov $0xf1, %rcx"
-//             ::: "mov $0xf2, %rdx"
-//             ::: "mov $0xf3, %rsi"
-//             ::: "mov $0xf4, %rdi"
-//             ::: "mov $0xf5, %r8"
-//             ::: "mov $0xf6, %r9"
-//             ::: "mov $0xf7, %r10"
-//             ::: "mov $0xf8, %r11"
-//         );
-//     }
-//     0
-// }
-
-/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
-/// unused.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let x = helpers::sqrti(9, 0, 0, 0, 0);
-/// assert_eq!(x, 3);
-/// ```
-#[allow(dead_code)]
-#[allow(unused_variables)]
-#[cfg(feature = "std")] // sqrt is only available when using `std`
-pub fn sqrti(arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
-    (arg1 as f64).sqrt() as u64
-}
-
-/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
-///
-/// # Examples
-///
-/// ```
-/// use rbpf::helpers;
-///
-/// let foo = "This is a string.\0".as_ptr() as u64;
-/// let bar = "This is another sting.\0".as_ptr() as u64;
-///
-/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
-/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
-/// ```
-#[allow(dead_code)]
-#[allow(unused_variables)]
-pub fn strcmp(arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
-    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
-    if arg1 == 0 || arg2 == 0 {
-        return u64::MAX;
-    }
-    let mut a = arg1;
-    let mut b = arg2;
-    unsafe {
-        let mut a_val = *(a as *const u8);
-        let mut b_val = *(b as *const u8);
-        while a_val == b_val && a_val != 0 && b_val != 0 {
-            a += 1;
-            b += 1;
-            a_val = *(a as *const u8);
-            b_val = *(b as *const u8);
-        }
-        if a_val >= b_val {
-            (a_val - b_val) as u64
-        } else {
-            (b_val - a_val) as u64
-        }
-    }
-}
-
-// Some additional helpers
-
-/// Returns a random u64 value comprised between `min` and `max` values (inclusive). Arguments 3 to
-/// 5 are unused.
-///
-/// Relies on `rand()` function from libc, so `libc::srand()` should be called once before this
-/// helper is used.
-///
-/// # Examples
-///
-/// ```
-/// extern crate libc;
-/// extern crate rbpf;
-/// extern crate time;
-///
-/// unsafe {
-///     libc::srand(time::precise_time_ns() as u32)
-/// }
-///
-/// let n = rbpf::helpers::rand(3, 6, 0, 0, 0);
-/// assert!(3 <= n && n <= 6);
-/// ```
-#[allow(dead_code)]
-#[allow(unused_variables)]
-#[cfg(feature = "std")]
-pub fn rand(min: u64, max: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
-    let mut n = unsafe { (libc::rand() as u64).wrapping_shl(32) + libc::rand() as u64 };
-    if min < max {
-        n = n % (max + 1 - min) + min;
-    };
-    n
-}
-/// Prints the helper functions name and it's index.
-#[cfg(feature = "std")]
-pub fn show_helper() {
-    for (index, name) in BPF_FUNC_MAPPER.iter().enumerate() {
-        println!("{}:{}", index, name);
-    }
-}
-
-/// See https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h
-pub const BPF_FUNC_MAPPER: &[&str] = &[
-    "unspec",
-    "map_lookup_elem",
-    "map_update_elem",
-    "map_delete_elem",
-    "probe_read",
-    "ktime_get_ns",
-    "trace_printk",
-    "get_prandom_u32",
-    "get_smp_processor_id",
-    "skb_store_bytes",
-    "l3_csum_replace",
-    "l4_csum_replace",
-    "tail_call",
-    "clone_redirect",
-    "get_current_pid_tgid",
-    "get_current_uid_gid",
-    "get_current_comm",
-    "get_cgroup_classid",
-    "skb_vlan_push",
-    "skb_vlan_pop",
-    "skb_get_tunnel_key",
-    "skb_set_tunnel_key",
-    "perf_event_read",
-    "redirect",
-    "get_route_realm",
-    "perf_event_output",
-    "skb_load_bytes",
-    "get_stackid",
-    "csum_diff",
-    "skb_get_tunnel_opt",
-    "skb_set_tunnel_opt",
-    "skb_change_proto",
-    "skb_change_type",
-    "skb_under_cgroup",
-    "get_hash_recalc",
-    "get_current_task",
-    "probe_write_user",
-    "current_task_under_cgroup",
-    "skb_change_tail",
-    "skb_pull_data",
-    "csum_update",
-    "set_hash_invalid",
-    "get_numa_node_id",
-    "skb_change_head",
-    "xdp_adjust_head",
-    "probe_read_str",
-    "get_socket_cookie",
-    "get_socket_uid",
-    "set_hash",
-    "setsockopt",
-    "skb_adjust_room",
-    "redirect_map",
-    "sk_redirect_map",
-    "sock_map_update",
-    "xdp_adjust_meta",
-    "perf_event_read_value",
-    "perf_prog_read_value",
-    "getsockopt",
-    "override_return",
-    "sock_ops_cb_flags_set",
-    "msg_redirect_map",
-    "msg_apply_bytes",
-    "msg_cork_bytes",
-    "msg_pull_data",
-    "bind",
-    "xdp_adjust_tail",
-    "skb_get_xfrm_state",
-    "get_stack",
-    "skb_load_bytes_relative",
-    "fib_lookup",
-    "sock_hash_update",
-    "msg_redirect_hash",
-    "sk_redirect_hash",
-    "lwt_push_encap",
-    "lwt_seg6_store_bytes",
-    "lwt_seg6_adjust_srh",
-    "lwt_seg6_action",
-    "rc_repeat",
-    "rc_keydown",
-    "skb_cgroup_id",
-    "get_current_cgroup_id",
-    "get_local_storage",
-    "sk_select_reuseport",
-    "skb_ancestor_cgroup_id",
-    "sk_lookup_tcp",
-    "sk_lookup_udp",
-    "sk_release",
-    "map_push_elem",
-    "map_pop_elem",
-    "map_peek_elem",
-    "msg_push_data",
-    "msg_pop_data",
-    "rc_pointer_rel",
-    "spin_lock",
-    "spin_unlock",
-    "sk_fullsock",
-    "tcp_sock",
-    "skb_ecn_set_ce",
-    "get_listener_sock",
-    "skc_lookup_tcp",
-    "tcp_check_syncookie",
-    "sysctl_get_name",
-    "sysctl_get_current_value",
-    "sysctl_get_new_value",
-    "sysctl_set_new_value",
-    "strtol",
-    "strtoul",
-    "sk_storage_get",
-    "sk_storage_delete",
-    "send_signal",
-    "tcp_gen_syncookie",
-    "skb_output",
-    "probe_read_user",
-    "probe_read_kernel",
-    "probe_read_user_str",
-    "probe_read_kernel_str",
-    "tcp_send_ack",
-    "send_signal_thread",
-    "jiffies64",
-    "read_branch_records",
-    "get_ns_current_pid_tgid",
-    "xdp_output",
-    "get_netns_cookie",
-    "get_current_ancestor_cgroup_id",
-    "sk_assign",
-    "ktime_get_boot_ns",
-    "seq_printf",
-    "seq_write",
-    "sk_cgroup_id",
-    "sk_ancestor_cgroup_id",
-    "ringbuf_output",
-    "ringbuf_reserve",
-    "ringbuf_submit",
-    "ringbuf_discard",
-    "ringbuf_query",
-    "csum_level",
-    "skc_to_tcp6_sock",
-    "skc_to_tcp_sock",
-    "skc_to_tcp_timewait_sock",
-    "skc_to_tcp_request_sock",
-    "skc_to_udp6_sock",
-    "get_task_stack",
-    "load_hdr_opt",
-    "store_hdr_opt",
-    "reserve_hdr_opt",
-    "inode_storage_get",
-    "inode_storage_delete",
-    "d_path",
-    "copy_from_user",
-    "snprintf_btf",
-    "seq_printf_btf",
-    "skb_cgroup_classid",
-    "redirect_neigh",
-    "per_cpu_ptr",
-    "this_cpu_ptr",
-    "redirect_peer",
-    "task_storage_get",
-    "task_storage_delete",
-    "get_current_task_btf",
-    "bprm_opts_set",
-    "ktime_get_coarse_ns",
-    "ima_inode_hash",
-    "sock_from_file",
-    "check_mtu",
-    "for_each_map_elem",
-    "snprintf",
-    "sys_bpf",
-    "btf_find_by_name_kind",
-    "sys_close",
-    "timer_init",
-    "timer_set_callback",
-    "timer_start",
-    "timer_cancel",
-    "get_func_ip",
-    "get_attach_cookie",
-    "task_pt_regs",
-    "get_branch_snapshot",
-    "trace_vprintk",
-    "skc_to_unix_sock",
-    "kallsyms_lookup_name",
-    "find_vma",
-    "loop",
-    "strncmp",
-    "get_func_arg",
-    "get_func_ret",
-    "get_func_arg_cnt",
-    "get_retval",
-    "set_retval",
-    "xdp_get_buff_len",
-    "xdp_load_bytes",
-    "xdp_store_bytes",
-    "copy_from_user_task",
-    "skb_set_tstamp",
-    "ima_file_hash",
-    "kptr_xchg",
-    "map_lookup_percpu_elem",
-    "skc_to_mptcp_sock",
-    "dynptr_from_mem",
-    "ringbuf_reserve_dynptr",
-    "ringbuf_submit_dynptr",
-    "ringbuf_discard_dynptr",
-    "dynptr_read",
-    "dynptr_write",
-    "dynptr_data",
-    "tcp_raw_gen_syncookie_ipv4",
-    "tcp_raw_gen_syncookie_ipv6",
-    "tcp_raw_check_syncookie_ipv4",
-    "tcp_raw_check_syncookie_ipv6",
-    "ktime_get_tai_ns",
-    "user_ringbuf_drain",
-    "cgrp_storage_get",
-    "cgrp_storage_delete",
-];

+ 0 - 2199
kernel/crates/rbpf/src/insn_builder.rs

@@ -1,2199 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 Alex Dukhno <alex.dukhno@icloud.com>
-
-//! Module provides API to create eBPF programs by Rust programming language
-
-use alloc::{vec, vec::Vec};
-
-use crate::ebpf::*;
-
-/// Represents single eBPF instruction
-pub trait Instruction: Sized {
-    /// returns instruction opt code
-    fn opt_code_byte(&self) -> u8;
-
-    /// returns destination register
-    fn get_dst(&self) -> u8 {
-        self.get_insn().dst
-    }
-
-    /// returns source register
-    fn get_src(&self) -> u8 {
-        self.get_insn().src
-    }
-
-    /// returns offset bytes
-    fn get_off(&self) -> i16 {
-        self.get_insn().off
-    }
-
-    /// returns immediate value
-    fn get_imm(&self) -> i32 {
-        self.get_insn().imm
-    }
-
-    /// sets destination register
-    fn set_dst(mut self, dst: u8) -> Self {
-        self.get_insn_mut().dst = dst;
-        self
-    }
-
-    /// sets source register
-    fn set_src(mut self, src: u8) -> Self {
-        self.get_insn_mut().src = src;
-        self
-    }
-
-    /// sets offset bytes
-    fn set_off(mut self, offset: i16) -> Self {
-        self.get_insn_mut().off = offset;
-        self
-    }
-
-    /// sets immediate value
-    fn set_imm(mut self, imm: i32) -> Self {
-        self.get_insn_mut().imm = imm;
-        self
-    }
-
-    /// get `ebpf::Insn` struct
-    fn get_insn(&self) -> &Insn;
-
-    /// get mutable `ebpf::Insn` struct
-    fn get_insn_mut(&mut self) -> &mut Insn;
-}
-
-/// General trait for `Instruction`s and `BpfCode`.
-/// Provides functionality to transform `struct` into collection of bytes
-pub trait IntoBytes {
-    /// type of targeted transformation
-    type Bytes;
-
-    /// consume `Self` with transformation into `Self::Bytes`
-    fn into_bytes(self) -> Self::Bytes;
-}
-
-/// General implementation of `IntoBytes` for `Instruction`
-impl<I: Instruction> IntoBytes for &'_ I {
-    type Bytes = Vec<u8>;
-
-    /// transform immutable reference of `Instruction` into `Vec<u8>` with size of 8
-    /// [ 1 byte ,      1 byte      , 2 bytes,  4 bytes  ]
-    /// [ OP_CODE, SRC_REG | DST_REG, OFFSET , IMMEDIATE ]
-    fn into_bytes(self) -> Self::Bytes {
-        let buffer = vec![
-            self.opt_code_byte(),
-            self.get_src() << 4 | self.get_dst(),
-            self.get_off() as u8,
-            (self.get_off() >> 8) as u8,
-            self.get_imm() as u8,
-            (self.get_imm() >> 8) as u8,
-            (self.get_imm() >> 16) as u8,
-            (self.get_imm() >> 24) as u8,
-        ];
-        buffer
-    }
-}
-
-/// BPF instruction stack in byte representation
-#[derive(Default)]
-pub struct BpfCode {
-    instructions: Vec<u8>,
-}
-
-impl BpfCode {
-    /// creates new empty BPF instruction stack
-    pub fn new() -> Self {
-        BpfCode {
-            instructions: vec![],
-        }
-    }
-
-    /// create ADD instruction
-    pub fn add(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Add)
-    }
-
-    /// create SUB instruction
-    pub fn sub(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Sub)
-    }
-
-    /// create MUL instruction
-    pub fn mul(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Mul)
-    }
-
-    /// create DIV instruction
-    pub fn div(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Div)
-    }
-
-    /// create OR instruction
-    pub fn bit_or(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::BitOr)
-    }
-
-    /// create AND instruction
-    pub fn bit_and(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::BitAnd)
-    }
-
-    /// create LSHIFT instruction
-    pub fn left_shift(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::LShift)
-    }
-
-    /// create RSHIFT instruction
-    pub fn right_shift(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::RShift)
-    }
-
-    /// create NEGATE instruction
-    pub fn negate(&mut self, arch: Arch) -> Move {
-        self.mov_internal(Source::Imm, arch, OpBits::Negate)
-    }
-
-    /// create MOD instruction
-    pub fn modulo(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Mod)
-    }
-
-    /// create XOR instruction
-    pub fn bit_xor(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::BitXor)
-    }
-
-    /// create MOV instruction
-    pub fn mov(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::Mov)
-    }
-
-    /// create SIGNED RSHIFT instruction
-    pub fn signed_right_shift(&mut self, source: Source, arch: Arch) -> Move {
-        self.mov_internal(source, arch, OpBits::SignRShift)
-    }
-
-    #[inline]
-    fn mov_internal(&mut self, source: Source, arch_bits: Arch, op_bits: OpBits) -> Move {
-        Move {
-            bpf_code: self,
-            src_bit: source,
-            op_bits,
-            arch_bits,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// create byte swap instruction
-    pub fn swap_bytes(&mut self, endian: Endian) -> SwapBytes {
-        SwapBytes {
-            bpf_code: self,
-            endian,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// create LOAD instruction, IMMEDIATE is the source
-    pub fn load(&mut self, mem_size: MemSize) -> Load {
-        self.load_internal(mem_size, Addressing::Imm, BPF_LD)
-    }
-
-    /// create ABSOLUTE LOAD instruction
-    pub fn load_abs(&mut self, mem_size: MemSize) -> Load {
-        self.load_internal(mem_size, Addressing::Abs, BPF_LD)
-    }
-
-    /// create INDIRECT LOAD instruction
-    pub fn load_ind(&mut self, mem_size: MemSize) -> Load {
-        self.load_internal(mem_size, Addressing::Ind, BPF_LD)
-    }
-
-    /// create LOAD instruction, MEMORY is the source
-    pub fn load_x(&mut self, mem_size: MemSize) -> Load {
-        self.load_internal(mem_size, Addressing::Mem, BPF_LDX)
-    }
-
-    #[inline]
-    fn load_internal(&mut self, mem_size: MemSize, addressing: Addressing, source: u8) -> Load {
-        Load {
-            bpf_code: self,
-            addressing,
-            mem_size,
-            source,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// creates STORE instruction, IMMEDIATE is the source
-    pub fn store(&mut self, mem_size: MemSize) -> Store {
-        self.store_internal(mem_size, BPF_IMM)
-    }
-
-    /// creates STORE instruction, MEMORY is the source
-    pub fn store_x(&mut self, mem_size: MemSize) -> Store {
-        self.store_internal(mem_size, BPF_MEM | BPF_STX)
-    }
-
-    #[inline]
-    fn store_internal(&mut self, mem_size: MemSize, source: u8) -> Store {
-        Store {
-            bpf_code: self,
-            mem_size,
-            source,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// create unconditional JMP instruction
-    pub fn jump_unconditional(&mut self) -> Jump {
-        self.jump_conditional(Cond::Abs, Source::Imm)
-    }
-
-    /// create conditional JMP instruction
-    pub fn jump_conditional(&mut self, cond: Cond, src_bit: Source) -> Jump {
-        Jump {
-            bpf_code: self,
-            cond,
-            src_bit,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// create CALL instruction
-    pub fn call(&mut self) -> FunctionCall {
-        FunctionCall {
-            bpf_code: self,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-
-    /// create EXIT instruction
-    pub fn exit(&mut self) -> Exit {
-        Exit {
-            bpf_code: self,
-            insn: Insn {
-                opc: 0x00,
-                dst: 0x00,
-                src: 0x00,
-                off: 0x00_00,
-                imm: 0x00_00_00_00,
-            },
-        }
-    }
-}
-
-/// Transform `BpfCode` into assemble representation
-impl<'a> IntoBytes for &'a BpfCode {
-    type Bytes = &'a [u8];
-
-    /// returns `BpfCode` instruction stack as `&[u8]`
-    fn into_bytes(self) -> Self::Bytes {
-        self.instructions.as_slice()
-    }
-}
-
-/// struct to represent `MOV ALU` instructions
-pub struct Move<'i> {
-    bpf_code: &'i mut BpfCode,
-    src_bit: Source,
-    op_bits: OpBits,
-    arch_bits: Arch,
-    insn: Insn,
-}
-
-impl<'i> Move<'i> {
-    /// push MOV instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for Move<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        let op_bits = self.op_bits as u8;
-        let src_bit = self.src_bit as u8;
-        let arch_bits = self.arch_bits as u8;
-        op_bits | src_bit | arch_bits
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-/// The source of ALU and JMP instructions
-pub enum Source {
-    /// immediate field will be used as a source
-    Imm = BPF_IMM as isize,
-    /// src register will be used as a source
-    Reg = BPF_X as isize,
-}
-
-#[derive(Copy, Clone)]
-enum OpBits {
-    Add = BPF_ADD as isize,
-    Sub = BPF_SUB as isize,
-    Mul = BPF_MUL as isize,
-    Div = BPF_DIV as isize,
-    BitOr = BPF_OR as isize,
-    BitAnd = BPF_AND as isize,
-    LShift = BPF_LSH as isize,
-    RShift = BPF_RSH as isize,
-    Negate = BPF_NEG as isize,
-    Mod = BPF_MOD as isize,
-    BitXor = BPF_XOR as isize,
-    Mov = BPF_MOV as isize,
-    SignRShift = BPF_ARSH as isize,
-}
-
-#[derive(Copy, Clone)]
-/// Architecture of instructions
-pub enum Arch {
-    /// 64-bit instructions
-    X64 = BPF_ALU64 as isize,
-    /// 32-bit instructions
-    X32 = BPF_ALU as isize,
-}
-
-/// struct representation of byte swap operation
-pub struct SwapBytes<'i> {
-    bpf_code: &'i mut BpfCode,
-    endian: Endian,
-    insn: Insn,
-}
-
-impl<'i> SwapBytes<'i> {
-    /// push bytes swap instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for SwapBytes<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        self.endian as u8
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-}
-
-#[derive(Copy, Clone)]
-/// Bytes endian
-pub enum Endian {
-    /// Little endian
-    Little = LE as isize,
-    /// Big endian
-    Big = BE as isize,
-}
-
-/// struct representation of LOAD instructions
-pub struct Load<'i> {
-    bpf_code: &'i mut BpfCode,
-    addressing: Addressing,
-    mem_size: MemSize,
-    source: u8,
-    insn: Insn,
-}
-
-impl<'i> Load<'i> {
-    /// push LOAD instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for Load<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        let size = self.mem_size as u8;
-        let addressing = self.addressing as u8;
-        addressing | size | self.source
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-}
-
-/// struct representation of STORE instructions
-pub struct Store<'i> {
-    bpf_code: &'i mut BpfCode,
-    mem_size: MemSize,
-    source: u8,
-    insn: Insn,
-}
-
-impl<'i> Store<'i> {
-    /// push STORE instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for Store<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        let size = self.mem_size as u8;
-        BPF_MEM | BPF_ST | size | self.source
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-}
-
-#[derive(Copy, Clone)]
-/// Memory size for LOAD and STORE instructions
-pub enum MemSize {
-    /// 8-bit size
-    Byte = BPF_B as isize,
-    /// 16-bit size
-    HalfWord = BPF_H as isize,
-    /// 32-bit size
-    Word = BPF_W as isize,
-    /// 64-bit size
-    DoubleWord = BPF_DW as isize,
-}
-
-#[derive(Copy, Clone)]
-enum Addressing {
-    Imm = BPF_IMM as isize,
-    Abs = BPF_ABS as isize,
-    Ind = BPF_IND as isize,
-    Mem = BPF_MEM as isize,
-}
-
-/// struct representation of JMP instructions
-pub struct Jump<'i> {
-    bpf_code: &'i mut BpfCode,
-    cond: Cond,
-    src_bit: Source,
-    insn: Insn,
-}
-
-impl<'i> Jump<'i> {
-    /// push JMP instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for Jump<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        let cmp: u8 = self.cond as u8;
-        let src_bit = self.src_bit as u8;
-        cmp | src_bit | BPF_JMP
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-/// Conditions for JMP instructions
-pub enum Cond {
-    /// Absolute or unconditional
-    Abs = BPF_JA as isize,
-    /// Jump if `==`
-    Equals = BPF_JEQ as isize,
-    /// Jump if `>`
-    Greater = BPF_JGT as isize,
-    /// Jump if `>=`
-    GreaterEquals = BPF_JGE as isize,
-    /// Jump if `<`
-    Lower = BPF_JLT as isize,
-    /// Jump if `<=`
-    LowerEquals = BPF_JLE as isize,
-    /// Jump if `src` & `dst`
-    BitAnd = BPF_JSET as isize,
-    /// Jump if `!=`
-    NotEquals = BPF_JNE as isize,
-    /// Jump if `>` (signed)
-    GreaterSigned = BPF_JSGT as isize,
-    /// Jump if `>=` (signed)
-    GreaterEqualsSigned = BPF_JSGE as isize,
-    /// Jump if `<` (signed)
-    LowerSigned = BPF_JSLT as isize,
-    /// Jump if `<=` (signed)
-    LowerEqualsSigned = BPF_JSLE as isize,
-}
-
-/// struct representation of CALL instruction
-pub struct FunctionCall<'i> {
-    bpf_code: &'i mut BpfCode,
-    insn: Insn,
-}
-
-impl<'i> FunctionCall<'i> {
-    /// push CALL instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for FunctionCall<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        BPF_CALL | BPF_JMP
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-}
-
-/// struct representation of EXIT instruction
-pub struct Exit<'i> {
-    bpf_code: &'i mut BpfCode,
-    insn: Insn,
-}
-
-impl<'i> Exit<'i> {
-    /// push EXIT instruction into BpfCode instruction stack
-    pub fn push(self) -> &'i mut BpfCode {
-        let mut asm = self.into_bytes();
-        self.bpf_code.instructions.append(&mut asm);
-        self.bpf_code
-    }
-}
-
-impl Instruction for Exit<'_> {
-    fn opt_code_byte(&self) -> u8 {
-        BPF_EXIT | BPF_JMP
-    }
-
-    fn get_insn_mut(&mut self) -> &mut Insn {
-        &mut self.insn
-    }
-
-    fn get_insn(&self) -> &Insn {
-        &self.insn
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    #[cfg(test)]
-    mod special {
-        use super::super::*;
-
-        #[test]
-        fn call_immediate() {
-            let mut program = BpfCode::new();
-            program.call().set_imm(0x11_22_33_44).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x85, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
-            );
-        }
-
-        #[test]
-        fn exit_operation() {
-            let mut program = BpfCode::new();
-            program.exit().push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-    }
-
-    #[cfg(test)]
-    mod jump_instructions {
-        #[cfg(test)]
-        mod register {
-            use super::super::super::*;
-
-            #[test]
-            fn jump_on_dst_equals_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Equals, Source::Reg)
-                    .set_dst(0x01)
-                    .set_src(0x02)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x1d, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_than_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Greater, Source::Reg)
-                    .set_dst(0x03)
-                    .set_src(0x02)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x2d, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_or_equals_to_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterEquals, Source::Reg)
-                    .set_dst(0x04)
-                    .set_src(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x3d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_than_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Lower, Source::Reg)
-                    .set_dst(0x03)
-                    .set_src(0x02)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xad, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_or_equals_to_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerEquals, Source::Reg)
-                    .set_dst(0x04)
-                    .set_src(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xbd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_bit_and_with_src_not_equal_zero() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::BitAnd, Source::Reg)
-                    .set_dst(0x05)
-                    .set_src(0x02)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x4d, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_not_equals_src() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::NotEquals, Source::Reg)
-                    .set_dst(0x03)
-                    .set_src(0x05)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x5d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_than_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterSigned, Source::Reg)
-                    .set_dst(0x04)
-                    .set_src(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x6d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_or_equals_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterEqualsSigned, Source::Reg)
-                    .set_dst(0x01)
-                    .set_src(0x03)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x7d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_than_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerSigned, Source::Reg)
-                    .set_dst(0x04)
-                    .set_src(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xcd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_or_equals_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerEqualsSigned, Source::Reg)
-                    .set_dst(0x01)
-                    .set_src(0x03)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xdd, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-        }
-
-        #[cfg(test)]
-        mod immediate {
-            use super::super::super::*;
-
-            #[test]
-            fn jump_to_label() {
-                let mut program = BpfCode::new();
-                program.jump_unconditional().set_off(0x00_11).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_equals_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Equals, Source::Imm)
-                    .set_dst(0x01)
-                    .set_imm(0x00_11_22_33)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x15, 0x01, 0x00, 0x00, 0x33, 0x22, 0x11, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_than_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Greater, Source::Imm)
-                    .set_dst(0x02)
-                    .set_imm(0x00_11_00_11)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x25, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_or_equals_to_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterEquals, Source::Imm)
-                    .set_dst(0x04)
-                    .set_imm(0x00_22_11_00)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x35, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_than_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::Lower, Source::Imm)
-                    .set_dst(0x02)
-                    .set_imm(0x00_11_00_11)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xa5, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_or_equals_to_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerEquals, Source::Imm)
-                    .set_dst(0x04)
-                    .set_imm(0x00_22_11_00)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xb5, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_bit_and_with_const_not_equal_zero() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::BitAnd, Source::Imm)
-                    .set_dst(0x05)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_not_equals_const() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::NotEquals, Source::Imm)
-                    .set_dst(0x03)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_than_const_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterSigned, Source::Imm)
-                    .set_dst(0x04)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x65, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_greater_or_equals_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::GreaterEqualsSigned, Source::Imm)
-                    .set_dst(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_than_const_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerSigned, Source::Imm)
-                    .set_dst(0x04)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xc5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn jump_on_dst_lower_or_equals_src_signed() {
-                let mut program = BpfCode::new();
-                program
-                    .jump_conditional(Cond::LowerEqualsSigned, Source::Imm)
-                    .set_dst(0x01)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-        }
-    }
-
-    #[cfg(test)]
-    mod store_instructions {
-        use super::super::*;
-
-        #[test]
-        fn store_word_from_dst_into_immediate_address() {
-            let mut program = BpfCode::new();
-            program
-                .store(MemSize::Word)
-                .set_dst(0x01)
-                .set_off(0x00_11)
-                .set_imm(0x11_22_33_44)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x62, 0x01, 0x11, 0x00, 0x44, 0x33, 0x22, 0x11]
-            );
-        }
-
-        #[test]
-        fn store_half_word_from_dst_into_immediate_address() {
-            let mut program = BpfCode::new();
-            program
-                .store(MemSize::HalfWord)
-                .set_dst(0x02)
-                .set_off(0x11_22)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x6a, 0x02, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_byte_from_dst_into_immediate_address() {
-            let mut program = BpfCode::new();
-            program.store(MemSize::Byte).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_double_word_from_dst_into_immediate_address() {
-            let mut program = BpfCode::new();
-            program.store(MemSize::DoubleWord).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_word_from_dst_into_src_address() {
-            let mut program = BpfCode::new();
-            program
-                .store_x(MemSize::Word)
-                .set_dst(0x01)
-                .set_src(0x02)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x63, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_half_word_from_dst_into_src_address() {
-            let mut program = BpfCode::new();
-            program.store_x(MemSize::HalfWord).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_byte_from_dst_into_src_address() {
-            let mut program = BpfCode::new();
-            program.store_x(MemSize::Byte).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn store_double_word_from_dst_into_src_address() {
-            let mut program = BpfCode::new();
-            program.store_x(MemSize::DoubleWord).push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-            );
-        }
-    }
-
-    #[cfg(test)]
-    mod load_instructions {
-        #[cfg(test)]
-        mod register {
-            use super::super::super::*;
-
-            #[test]
-            fn load_word_from_set_src_with_offset() {
-                let mut program = BpfCode::new();
-                program
-                    .load_x(MemSize::Word)
-                    .set_dst(0x01)
-                    .set_src(0x02)
-                    .set_off(0x00_02)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x61, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_half_word_from_set_src_with_offset() {
-                let mut program = BpfCode::new();
-                program
-                    .load_x(MemSize::HalfWord)
-                    .set_dst(0x02)
-                    .set_src(0x01)
-                    .set_off(0x11_22)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x69, 0x12, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_byte_from_set_src_with_offset() {
-                let mut program = BpfCode::new();
-                program
-                    .load_x(MemSize::Byte)
-                    .set_dst(0x01)
-                    .set_src(0x04)
-                    .set_off(0x00_11)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x71, 0x41, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_double_word_from_set_src_with_offset() {
-                let mut program = BpfCode::new();
-                program
-                    .load_x(MemSize::DoubleWord)
-                    .set_dst(0x04)
-                    .set_src(0x05)
-                    .set_off(0x44_55)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x79, 0x54, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-        }
-
-        #[cfg(test)]
-        mod immediate {
-            use super::super::super::*;
-
-            #[test]
-            fn load_double_word() {
-                let mut program = BpfCode::new();
-                program
-                    .load(MemSize::DoubleWord)
-                    .set_dst(0x01)
-                    .set_imm(0x00_01_02_03)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x18, 0x01, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_abs_word() {
-                let mut program = BpfCode::new();
-                program.load_abs(MemSize::Word).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_abs_half_word() {
-                let mut program = BpfCode::new();
-                program.load_abs(MemSize::HalfWord).set_dst(0x05).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_abs_byte() {
-                let mut program = BpfCode::new();
-                program.load_abs(MemSize::Byte).set_dst(0x01).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_abs_double_word() {
-                let mut program = BpfCode::new();
-                program
-                    .load_abs(MemSize::DoubleWord)
-                    .set_dst(0x01)
-                    .set_imm(0x01_02_03_04)
-                    .push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x38, 0x01, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
-                );
-            }
-
-            #[test]
-            fn load_indirect_word() {
-                let mut program = BpfCode::new();
-                program.load_ind(MemSize::Word).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_indirect_half_word() {
-                let mut program = BpfCode::new();
-                program.load_ind(MemSize::HalfWord).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_indirect_byte() {
-                let mut program = BpfCode::new();
-                program.load_ind(MemSize::Byte).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-
-            #[test]
-            fn load_indirect_double_word() {
-                let mut program = BpfCode::new();
-                program.load_ind(MemSize::DoubleWord).push();
-
-                assert_eq!(
-                    program.into_bytes(),
-                    &[0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                );
-            }
-        }
-    }
-
-    #[cfg(test)]
-    mod byte_swap_instructions {
-        use super::super::*;
-
-        #[test]
-        fn convert_host_to_little_endian_16bits() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Little)
-                .set_dst(0x01)
-                .set_imm(0x00_00_00_10)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xd4, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn convert_host_to_little_endian_32bits() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Little)
-                .set_dst(0x02)
-                .set_imm(0x00_00_00_20)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xd4, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn convert_host_to_little_endian_64bit() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Little)
-                .set_dst(0x03)
-                .set_imm(0x00_00_00_40)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xd4, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn convert_host_to_big_endian_16bits() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Big)
-                .set_dst(0x01)
-                .set_imm(0x00_00_00_10)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn convert_host_to_big_endian_32bits() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Big)
-                .set_dst(0x02)
-                .set_imm(0x00_00_00_20)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xdc, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]
-            );
-        }
-
-        #[test]
-        fn convert_host_to_big_endian_64bit() {
-            let mut program = BpfCode::new();
-            program
-                .swap_bytes(Endian::Big)
-                .set_dst(0x03)
-                .set_imm(0x00_00_00_40)
-                .push();
-
-            assert_eq!(
-                program.into_bytes(),
-                &[0xdc, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]
-            );
-        }
-    }
-
-    #[cfg(test)]
-    mod moves_instructions {
-        #[cfg(test)]
-        mod arch_x64 {
-            #[cfg(test)]
-            mod immediate {
-                use super::super::super::super::*;
-
-                #[test]
-                fn move_and_add_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .add(Source::Imm, Arch::X64)
-                        .set_dst(0x02)
-                        .set_imm(0x01_02_03_04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x07, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
-                    );
-                }
-
-                #[test]
-                fn move_sub_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .sub(Source::Imm, Arch::X64)
-                        .set_dst(0x04)
-                        .set_imm(0x00_01_02_03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x17, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mul_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mul(Source::Imm, Arch::X64)
-                        .set_dst(0x05)
-                        .set_imm(0x04_03_02_01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x27, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]
-                    );
-                }
-
-                #[test]
-                fn move_div_constant_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .div(Source::Imm, Arch::X64)
-                        .set_dst(0x02)
-                        .set_imm(0x00_ff_00_ff)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x37, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_or_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_or(Source::Imm, Arch::X64)
-                        .set_dst(0x02)
-                        .set_imm(0x00_11_00_22)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x47, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_and_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_and(Source::Imm, Arch::X64)
-                        .set_dst(0x02)
-                        .set_imm(0x11_22_33_44)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x57, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
-                    );
-                }
-
-                #[test]
-                fn move_left_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .left_shift(Source::Imm, Arch::X64)
-                        .set_dst(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_logical_right_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .right_shift(Source::Imm, Arch::X64)
-                        .set_dst(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_negate_register() {
-                    let mut program = BpfCode::new();
-                    program.negate(Arch::X64).set_dst(0x02).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mod_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program.modulo(Source::Imm, Arch::X64).set_dst(0x02).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x97, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_xor_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program.bit_xor(Source::Imm, Arch::X64).set_dst(0x03).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xa7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mov(Source::Imm, Arch::X64)
-                        .set_dst(0x01)
-                        .set_imm(0x00_00_00_FF)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xb7, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_signed_right_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .signed_right_shift(Source::Imm, Arch::X64)
-                        .set_dst(0x05)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xc7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-            }
-
-            #[cfg(test)]
-            mod register {
-                use super::super::super::super::*;
-
-                #[test]
-                fn move_and_add_from_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .add(Source::Reg, Arch::X64)
-                        .set_dst(0x03)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x0f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_sub_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .sub(Source::Reg, Arch::X64)
-                        .set_dst(0x03)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x1f, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mul_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mul(Source::Reg, Arch::X64)
-                        .set_dst(0x04)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x2f, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_div_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .div(Source::Reg, Arch::X64)
-                        .set_dst(0x01)
-                        .set_src(0x00)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_or_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_or(Source::Reg, Arch::X64)
-                        .set_dst(0x03)
-                        .set_src(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x4f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_and_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_and(Source::Reg, Arch::X64)
-                        .set_dst(0x03)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x5f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_left_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .left_shift(Source::Reg, Arch::X64)
-                        .set_dst(0x02)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x6f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_logical_right_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .right_shift(Source::Reg, Arch::X64)
-                        .set_dst(0x02)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x7f, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mod_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .modulo(Source::Reg, Arch::X64)
-                        .set_dst(0x01)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x9f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_xor_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_xor(Source::Reg, Arch::X64)
-                        .set_dst(0x02)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xaf, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_from_register_to_another_register() {
-                    let mut program = BpfCode::new();
-                    program.mov(Source::Reg, Arch::X64).set_src(0x01).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_signed_right_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .signed_right_shift(Source::Reg, Arch::X64)
-                        .set_dst(0x02)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xcf, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-            }
-        }
-
-        #[cfg(test)]
-        mod arch_x32 {
-            #[cfg(test)]
-            mod immediate {
-                use super::super::super::super::*;
-
-                #[test]
-                fn move_and_add_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .add(Source::Imm, Arch::X32)
-                        .set_dst(0x02)
-                        .set_imm(0x01_02_03_04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x04, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
-                    );
-                }
-
-                #[test]
-                fn move_sub_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .sub(Source::Imm, Arch::X32)
-                        .set_dst(0x04)
-                        .set_imm(0x00_01_02_03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x14, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mul_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mul(Source::Imm, Arch::X32)
-                        .set_dst(0x05)
-                        .set_imm(0x04_03_02_01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x24, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]
-                    );
-                }
-
-                #[test]
-                fn move_div_constant_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .div(Source::Imm, Arch::X32)
-                        .set_dst(0x02)
-                        .set_imm(0x00_ff_00_ff)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x34, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_or_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_or(Source::Imm, Arch::X32)
-                        .set_dst(0x02)
-                        .set_imm(0x00_11_00_22)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x44, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_and_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_and(Source::Imm, Arch::X32)
-                        .set_dst(0x02)
-                        .set_imm(0x11_22_33_44)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x54, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
-                    );
-                }
-
-                #[test]
-                fn move_left_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .left_shift(Source::Imm, Arch::X32)
-                        .set_dst(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_logical_right_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .right_shift(Source::Imm, Arch::X32)
-                        .set_dst(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_negate_register() {
-                    let mut program = BpfCode::new();
-                    program.negate(Arch::X32).set_dst(0x02).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x84, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mod_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program.modulo(Source::Imm, Arch::X32).set_dst(0x02).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_xor_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program.bit_xor(Source::Imm, Arch::X32).set_dst(0x03).push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mov(Source::Imm, Arch::X32)
-                        .set_dst(0x01)
-                        .set_imm(0x00_00_00_FF)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xb4, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_signed_right_shift_const_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .signed_right_shift(Source::Imm, Arch::X32)
-                        .set_dst(0x05)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xc4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-            }
-
-            #[cfg(test)]
-            mod register {
-                use super::super::super::super::*;
-
-                #[test]
-                fn move_and_add_from_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .add(Source::Reg, Arch::X32)
-                        .set_dst(0x03)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x0c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_sub_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .sub(Source::Reg, Arch::X32)
-                        .set_dst(0x03)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x1c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mul_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mul(Source::Reg, Arch::X32)
-                        .set_dst(0x04)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x2c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_div_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .div(Source::Reg, Arch::X32)
-                        .set_dst(0x01)
-                        .set_src(0x00)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_or_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_or(Source::Reg, Arch::X32)
-                        .set_dst(0x03)
-                        .set_src(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_and_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_and(Source::Reg, Arch::X32)
-                        .set_dst(0x03)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x5c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_left_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .left_shift(Source::Reg, Arch::X32)
-                        .set_dst(0x02)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x6c, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_logical_right_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .right_shift(Source::Reg, Arch::X32)
-                        .set_dst(0x02)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x7c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_mod_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .modulo(Source::Reg, Arch::X32)
-                        .set_dst(0x01)
-                        .set_src(0x02)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0x9c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_bit_xor_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .bit_xor(Source::Reg, Arch::X32)
-                        .set_dst(0x02)
-                        .set_src(0x04)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xac, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_from_register_to_another_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .mov(Source::Reg, Arch::X32)
-                        .set_dst(0x00)
-                        .set_src(0x01)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-
-                #[test]
-                fn move_signed_right_shift_from_register_to_register() {
-                    let mut program = BpfCode::new();
-                    program
-                        .signed_right_shift(Source::Reg, Arch::X32)
-                        .set_dst(0x02)
-                        .set_src(0x03)
-                        .push();
-
-                    assert_eq!(
-                        program.into_bytes(),
-                        &[0xcc, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-                    );
-                }
-            }
-        }
-    }
-
-    #[cfg(test)]
-    mod programs {
-        use super::super::*;
-
-        #[test]
-        fn example_from_assembler() {
-            let mut program = BpfCode::new();
-            program
-                .add(Source::Imm, Arch::X64)
-                .set_dst(1)
-                .set_imm(0x605)
-                .push()
-                .mov(Source::Imm, Arch::X64)
-                .set_dst(2)
-                .set_imm(0x32)
-                .push()
-                .mov(Source::Reg, Arch::X64)
-                .set_src(0)
-                .set_dst(1)
-                .push()
-                .swap_bytes(Endian::Big)
-                .set_dst(0)
-                .set_imm(0x10)
-                .push()
-                .negate(Arch::X64)
-                .set_dst(2)
-                .push()
-                .exit()
-                .push();
-
-            let bytecode = program.into_bytes();
-            let ref_prog = &[
-                0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00,
-                0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00,
-                0x10, 0x00, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            ];
-            // cargo says: "`[{integer}; 48]` cannot be formatted using `{:?}`
-            //              because it doesn't implement `std::fmt::Debug`"
-            // So let's check in two steps.
-            assert_eq!(bytecode[..32], ref_prog[..32]);
-            assert_eq!(bytecode[33..], ref_prog[33..]);
-        }
-    }
-}

+ 0 - 708
kernel/crates/rbpf/src/interpreter.rs

@@ -1,708 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Derived from uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-//      (uBPF: VM architecture, parts of the interpreter, originally in C)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-//      (Translation to Rust, MetaBuff/multiple classes addition, hashmaps for helpers)
-
-use crate::{
-    ebpf::{self, Insn},
-    helpers::BPF_FUNC_MAPPER,
-    stack::StackFrame,
-    *,
-};
-
-#[cfg(not(feature = "user"))]
-#[allow(unused)]
-fn check_mem(
-    addr: u64,
-    len: usize,
-    access_type: &str,
-    insn_ptr: usize,
-    mbuff: &[u8],
-    mem: &[u8],
-    stack: &[u8],
-) -> Result<(), Error> {
-    log::trace!(
-        "check_mem: addr {:#x}, len {}, access_type {}, insn_ptr {}",
-        addr,
-        len,
-        access_type,
-        insn_ptr
-    );
-    log::trace!(
-        "check_mem: mbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
-        mbuff.as_ptr() as u64,
-        mbuff.len(),
-        mem.as_ptr() as u64,
-        mem.len(),
-        stack.as_ptr() as u64,
-        stack.len()
-    );
-    Ok(())
-}
-
-#[cfg(feature = "user")]
-fn check_mem(
-    addr: u64,
-    len: usize,
-    access_type: &str,
-    insn_ptr: usize,
-    mbuff: &[u8],
-    mem: &[u8],
-    stack: &[u8],
-) -> Result<(), Error> {
-    if let Some(addr_end) = addr.checked_add(len as u64) {
-        if mbuff.as_ptr() as u64 <= addr && addr_end <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
-            return Ok(());
-        }
-        if mem.as_ptr() as u64 <= addr && addr_end <= mem.as_ptr() as u64 + mem.len() as u64 {
-            return Ok(());
-        }
-        if stack.as_ptr() as u64 <= addr && addr_end <= stack.as_ptr() as u64 + stack.len() as u64 {
-            return Ok(());
-        }
-    }
-
-    Err(Error::new(ErrorKind::Other, format!(
-        "Error: out of bounds memory {} (insn #{:?}), addr {:#x}, size {:?}\nmbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
-        access_type, insn_ptr, addr, len,
-        mbuff.as_ptr() as u64, mbuff.len(),
-        mem.as_ptr() as u64, mem.len(),
-        stack.as_ptr() as u64, stack.len()
-    )))
-}
-
-#[inline]
-fn do_jump(insn_ptr: &mut usize, insn: &Insn) {
-    *insn_ptr = (*insn_ptr as i16 + insn.off) as usize;
-}
-
-#[allow(unknown_lints)]
-#[allow(cyclomatic_complexity)]
-pub fn execute_program(
-    prog_: Option<&[u8]>,
-    mem: &[u8],
-    mbuff: &[u8],
-    helpers: &HashMap<u32, ebpf::Helper>,
-) -> Result<u64, Error> {
-    const U32MAX: u64 = u32::MAX as u64;
-    const SHIFT_MASK_64: u64 = 0x3f;
-
-    let prog = match prog_ {
-        Some(prog) => prog,
-        None => Err(Error::new(
-            ErrorKind::Other,
-            "Error: No program set, call prog_set() to load one",
-        ))?,
-    };
-    let mut stacks = Vec::new();
-    let stack = StackFrame::new();
-    // R1 points to beginning of memory area, R10 to stack
-    let mut reg: [u64; 11] = [
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        stack.as_ptr() as u64 + stack.len() as u64,
-    ];
-    stacks.push(stack);
-    if !mbuff.is_empty() {
-        reg[1] = mbuff.as_ptr() as u64;
-    } else if !mem.is_empty() {
-        reg[1] = mem.as_ptr() as u64;
-    }
-    let check_mem_load =
-        |stack: &[u8], addr: u64, len: usize, insn_ptr: usize| -> Result<(), Error> {
-            check_mem(addr, len, "load", insn_ptr, mbuff, mem, stack)
-        };
-    let check_mem_store =
-        |stack: &[u8], addr: u64, len: usize, insn_ptr: usize| -> Result<(), Error> {
-            check_mem(addr, len, "store", insn_ptr, mbuff, mem, stack)
-        };
-
-    // Loop on instructions
-    let mut insn_ptr: usize = 0;
-    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-        let insn = ebpf::get_insn(prog, insn_ptr);
-        insn_ptr += 1;
-        let _dst = insn.dst as usize;
-        let _src = insn.src as usize;
-
-        match insn.opc {
-            // BPF_LD class
-            // LD_ABS_* and LD_IND_* are supposed to load pointer to data from metadata buffer.
-            // Since this pointer is constant, and since we already know it (mem), do not
-            // bother re-fetching it, just use mem already.
-            ebpf::LD_ABS_B => {
-                reg[0] = unsafe {
-                    let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u8;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_ABS_H => {
-                reg[0] = unsafe {
-                    let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u16;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_ABS_W => {
-                reg[0] = unsafe {
-                    let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u32;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_ABS_DW => {
-                log::info!("executing LD_ABS_DW, set reg[{}] to {:#x}", _dst, insn.imm);
-                reg[0] = unsafe {
-                    let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u64;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned()
-                }
-            }
-            ebpf::LD_IND_B => {
-                reg[0] = unsafe {
-                    let x =
-                        (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u8;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_IND_H => {
-                reg[0] = unsafe {
-                    let x =
-                        (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u16;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_IND_W => {
-                reg[0] = unsafe {
-                    let x =
-                        (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u32;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_IND_DW => {
-                reg[0] = unsafe {
-                    let x =
-                        (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u64;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned()
-                }
-            }
-
-            ebpf::LD_DW_IMM => {
-                let next_insn = ebpf::get_insn(prog, insn_ptr);
-                insn_ptr += 1;
-                // log::warn!(
-                //     "executing LD_DW_IMM, set reg[{}] to {:#x}",
-                //     _dst,
-                //     ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32)
-                // );
-                reg[_dst] = ((insn.imm as u32) as u64) + ((next_insn.imm as u64) << 32);
-            }
-
-            // BPF_LDX class
-            ebpf::LD_B_REG => {
-                reg[_dst] = unsafe {
-                    #[allow(clippy::cast_ptr_alignment)]
-                    let x = (reg[_src] as *const u8).offset(insn.off as isize);
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_H_REG => {
-                reg[_dst] = unsafe {
-                    #[allow(clippy::cast_ptr_alignment)]
-                    let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u16;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_W_REG => {
-                reg[_dst] = unsafe {
-                    #[allow(clippy::cast_ptr_alignment)]
-                    let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u32;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
-                    // log::warn!(
-                    //     "executing LD_W_REG, the ptr is REG:{} -> [{:#x}] + {:#x}",
-                    //     _src,
-                    //     reg[_src],
-                    //     insn.off
-                    // );
-                    x.read_unaligned() as u64
-                }
-            }
-            ebpf::LD_DW_REG => {
-                reg[_dst] = unsafe {
-                    #[allow(clippy::cast_ptr_alignment)]
-                    let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u64;
-                    check_mem_load(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                    x.read_unaligned()
-                }
-            }
-
-            // BPF_ST class
-            ebpf::ST_B_IMM => unsafe {
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
-                x.write_unaligned(insn.imm as u8);
-            },
-            ebpf::ST_H_IMM => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
-                x.write_unaligned(insn.imm as u16);
-            },
-            ebpf::ST_W_IMM => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
-                x.write_unaligned(insn.imm as u32);
-            },
-            ebpf::ST_DW_IMM => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                x.write_unaligned(insn.imm as u64);
-            },
-
-            // BPF_STX class
-            ebpf::ST_B_REG => unsafe {
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 1, insn_ptr)?;
-                x.write_unaligned(reg[_src] as u8);
-            },
-            ebpf::ST_H_REG => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 2, insn_ptr)?;
-                x.write_unaligned(reg[_src] as u16);
-            },
-            ebpf::ST_W_REG => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 4, insn_ptr)?;
-                x.write_unaligned(reg[_src] as u32);
-            },
-            ebpf::ST_DW_REG => unsafe {
-                #[allow(clippy::cast_ptr_alignment)]
-                let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
-                check_mem_store(stacks.last().unwrap().as_slice(), x as u64, 8, insn_ptr)?;
-                x.write_unaligned(reg[_src]);
-            },
-            ebpf::ST_W_XADD => unimplemented!(),
-            ebpf::ST_DW_XADD => unimplemented!(),
-
-            // BPF_ALU class
-            // TODO Check how overflow works in kernel. Should we &= U32MAX all src register value
-            // before we do the operation?
-            // Cf ((0x11 << 32) - (0x1 << 32)) as u32 VS ((0x11 << 32) as u32 - (0x1 << 32) as u32
-            ebpf::ADD32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_add(insn.imm) as u64, //((reg[_dst] & U32MAX) + insn.imm  as u64)     & U32MAX,
-            ebpf::ADD32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_add(reg[_src] as i32) as u64, //((reg[_dst] & U32MAX) + (reg[_src] & U32MAX)) & U32MAX,
-            ebpf::SUB32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_sub(insn.imm) as u64,
-            ebpf::SUB32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_sub(reg[_src] as i32) as u64,
-            ebpf::MUL32_IMM => reg[_dst] = (reg[_dst] as i32).wrapping_mul(insn.imm) as u64,
-            ebpf::MUL32_REG => reg[_dst] = (reg[_dst] as i32).wrapping_mul(reg[_src] as i32) as u64,
-            ebpf::DIV32_IMM if insn.imm as u32 == 0 => reg[_dst] = 0,
-            ebpf::DIV32_IMM => reg[_dst] = (reg[_dst] as u32 / insn.imm as u32) as u64,
-            ebpf::DIV32_REG if reg[_src] as u32 == 0 => reg[_dst] = 0,
-            ebpf::DIV32_REG => reg[_dst] = (reg[_dst] as u32 / reg[_src] as u32) as u64,
-            ebpf::OR32_IMM => reg[_dst] = (reg[_dst] as u32 | insn.imm as u32) as u64,
-            ebpf::OR32_REG => reg[_dst] = (reg[_dst] as u32 | reg[_src] as u32) as u64,
-            ebpf::AND32_IMM => reg[_dst] = (reg[_dst] as u32 & insn.imm as u32) as u64,
-            ebpf::AND32_REG => reg[_dst] = (reg[_dst] as u32 & reg[_src] as u32) as u64,
-            // As for the 64-bit version, we should mask the number of bits to shift with
-            // 0x1f, but .wrappping_shr() already takes care of it for us.
-            ebpf::LSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shl(insn.imm as u32) as u64,
-            ebpf::LSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shl(reg[_src] as u32) as u64,
-            ebpf::RSH32_IMM => reg[_dst] = (reg[_dst] as u32).wrapping_shr(insn.imm as u32) as u64,
-            ebpf::RSH32_REG => reg[_dst] = (reg[_dst] as u32).wrapping_shr(reg[_src] as u32) as u64,
-            ebpf::NEG32 => {
-                reg[_dst] = (reg[_dst] as i32).wrapping_neg() as u64;
-                reg[_dst] &= U32MAX;
-            }
-            ebpf::MOD32_IMM if insn.imm as u32 == 0 => (),
-            ebpf::MOD32_IMM => reg[_dst] = (reg[_dst] as u32 % insn.imm as u32) as u64,
-            ebpf::MOD32_REG if reg[_src] as u32 == 0 => (),
-            ebpf::MOD32_REG => reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64,
-            ebpf::XOR32_IMM => reg[_dst] = (reg[_dst] as u32 ^ insn.imm as u32) as u64,
-            ebpf::XOR32_REG => reg[_dst] = (reg[_dst] as u32 ^ reg[_src] as u32) as u64,
-            ebpf::MOV32_IMM => reg[_dst] = insn.imm as u32 as u64,
-            ebpf::MOV32_REG => reg[_dst] = (reg[_src] as u32) as u64,
-            // As for the 64-bit version, we should mask the number of bits to shift with
-            // 0x1f, but .wrappping_shr() already takes care of it for us.
-            ebpf::ARSH32_IMM => {
-                reg[_dst] = (reg[_dst] as i32).wrapping_shr(insn.imm as u32) as u64;
-                reg[_dst] &= U32MAX;
-            }
-            ebpf::ARSH32_REG => {
-                reg[_dst] = (reg[_dst] as i32).wrapping_shr(reg[_src] as u32) as u64;
-                reg[_dst] &= U32MAX;
-            }
-            ebpf::LE => {
-                reg[_dst] = match insn.imm {
-                    16 => (reg[_dst] as u16).to_le() as u64,
-                    32 => (reg[_dst] as u32).to_le() as u64,
-                    64 => reg[_dst].to_le(),
-                    _ => unreachable!(),
-                };
-            }
-            ebpf::BE => {
-                reg[_dst] = match insn.imm {
-                    16 => (reg[_dst] as u16).to_be() as u64,
-                    32 => (reg[_dst] as u32).to_be() as u64,
-                    64 => reg[_dst].to_be(),
-                    _ => unreachable!(),
-                };
-            }
-
-            // BPF_ALU64 class
-            ebpf::ADD64_IMM => reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
-            ebpf::ADD64_REG => reg[_dst] = reg[_dst].wrapping_add(reg[_src]),
-            ebpf::SUB64_IMM => reg[_dst] = reg[_dst].wrapping_sub(insn.imm as u64),
-            ebpf::SUB64_REG => reg[_dst] = reg[_dst].wrapping_sub(reg[_src]),
-            ebpf::MUL64_IMM => reg[_dst] = reg[_dst].wrapping_mul(insn.imm as u64),
-            ebpf::MUL64_REG => reg[_dst] = reg[_dst].wrapping_mul(reg[_src]),
-            ebpf::DIV64_IMM if insn.imm == 0 => reg[_dst] = 0,
-            ebpf::DIV64_IMM => reg[_dst] /= insn.imm as u64,
-            ebpf::DIV64_REG if reg[_src] == 0 => reg[_dst] = 0,
-            ebpf::DIV64_REG => reg[_dst] /= reg[_src],
-            ebpf::OR64_IMM => reg[_dst] |= insn.imm as u64,
-            ebpf::OR64_REG => reg[_dst] |= reg[_src],
-            ebpf::AND64_IMM => reg[_dst] &= insn.imm as u64,
-            ebpf::AND64_REG => reg[_dst] &= reg[_src],
-            ebpf::LSH64_IMM => reg[_dst] <<= insn.imm as u64 & SHIFT_MASK_64,
-            ebpf::LSH64_REG => reg[_dst] <<= reg[_src] & SHIFT_MASK_64,
-            ebpf::RSH64_IMM => reg[_dst] >>= insn.imm as u64 & SHIFT_MASK_64,
-            ebpf::RSH64_REG => reg[_dst] >>= reg[_src] & SHIFT_MASK_64,
-            ebpf::NEG64 => reg[_dst] = -(reg[_dst] as i64) as u64,
-            ebpf::MOD64_IMM if insn.imm == 0 => (),
-            ebpf::MOD64_IMM => reg[_dst] %= insn.imm as u64,
-            ebpf::MOD64_REG if reg[_src] == 0 => (),
-            ebpf::MOD64_REG => reg[_dst] %= reg[_src],
-            ebpf::XOR64_IMM => reg[_dst] ^= insn.imm as u64,
-            ebpf::XOR64_REG => reg[_dst] ^= reg[_src],
-            ebpf::MOV64_IMM => reg[_dst] = insn.imm as u64,
-            ebpf::MOV64_REG => reg[_dst] = reg[_src],
-            ebpf::ARSH64_IMM => {
-                reg[_dst] = (reg[_dst] as i64 >> (insn.imm as u64 & SHIFT_MASK_64)) as u64
-            }
-            ebpf::ARSH64_REG => {
-                reg[_dst] = (reg[_dst] as i64 >> (reg[_src] as u64 & SHIFT_MASK_64)) as u64
-            }
-
-            // BPF_JMP class
-            // TODO: check this actually works as expected for signed / unsigned ops
-            ebpf::JA => do_jump(&mut insn_ptr, &insn),
-            ebpf::JEQ_IMM => {
-                if reg[_dst] == insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JEQ_REG => {
-                if reg[_dst] == reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGT_IMM => {
-                if reg[_dst] > insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGT_REG => {
-                if reg[_dst] > reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGE_IMM => {
-                if reg[_dst] >= insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGE_REG => {
-                if reg[_dst] >= reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLT_IMM => {
-                if reg[_dst] < insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLT_REG => {
-                if reg[_dst] < reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLE_IMM => {
-                if reg[_dst] <= insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLE_REG => {
-                if reg[_dst] <= reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSET_IMM => {
-                if reg[_dst] & insn.imm as u64 != 0 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSET_REG => {
-                if reg[_dst] & reg[_src] != 0 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JNE_IMM => {
-                if reg[_dst] != insn.imm as u64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JNE_REG => {
-                if reg[_dst] != reg[_src] {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGT_IMM => {
-                if reg[_dst] as i64 > insn.imm as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGT_REG => {
-                if reg[_dst] as i64 > reg[_src] as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGE_IMM => {
-                if reg[_dst] as i64 >= insn.imm as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGE_REG => {
-                if reg[_dst] as i64 >= reg[_src] as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLT_IMM => {
-                if (reg[_dst] as i64) < insn.imm as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLT_REG => {
-                if (reg[_dst] as i64) < reg[_src] as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLE_IMM => {
-                if reg[_dst] as i64 <= insn.imm as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLE_REG => {
-                if reg[_dst] as i64 <= reg[_src] as i64 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-
-            // BPF_JMP32 class
-            ebpf::JEQ_IMM32 => {
-                if reg[_dst] as u32 == insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JEQ_REG32 => {
-                if reg[_dst] as u32 == reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGT_IMM32 => {
-                if reg[_dst] as u32 > insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGT_REG32 => {
-                if reg[_dst] as u32 > reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGE_IMM32 => {
-                if reg[_dst] as u32 >= insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JGE_REG32 => {
-                if reg[_dst] as u32 >= reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLT_IMM32 => {
-                if (reg[_dst] as u32) < insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLT_REG32 => {
-                if (reg[_dst] as u32) < reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLE_IMM32 => {
-                if reg[_dst] as u32 <= insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JLE_REG32 => {
-                if reg[_dst] as u32 <= reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSET_IMM32 => {
-                if reg[_dst] as u32 & insn.imm as u32 != 0 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSET_REG32 => {
-                if reg[_dst] as u32 & reg[_src] as u32 != 0 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JNE_IMM32 => {
-                if reg[_dst] as u32 != insn.imm as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JNE_REG32 => {
-                if reg[_dst] as u32 != reg[_src] as u32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGT_IMM32 => {
-                if reg[_dst] as i32 > insn.imm {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGT_REG32 => {
-                if reg[_dst] as i32 > reg[_src] as i32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGE_IMM32 => {
-                if reg[_dst] as i32 >= insn.imm {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSGE_REG32 => {
-                if reg[_dst] as i32 >= reg[_src] as i32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLT_IMM32 => {
-                if (reg[_dst] as i32) < insn.imm {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLT_REG32 => {
-                if (reg[_dst] as i32) < reg[_src] as i32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLE_IMM32 => {
-                if reg[_dst] as i32 <= insn.imm {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-            ebpf::JSLE_REG32 => {
-                if reg[_dst] as i32 <= reg[_src] as i32 {
-                    do_jump(&mut insn_ptr, &insn);
-                }
-            }
-
-            // Do not delegate the check to the verifier, since registered functions can be
-            // changed after the program has been verified.
-            ebpf::CALL => {
-                // See https://www.kernel.org/doc/html/latest/bpf/standardization/instruction-set.html#id16
-                let src_reg = _src;
-                let call_func_res = match src_reg {
-                    0 => {
-                        // Handle call by address to external function.
-                        if let Some(function) = helpers.get(&(insn.imm as u32)) {
-                            reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]);
-                            Ok(())
-                        }else {
-                            Err(format!(
-                                "Error: unknown helper function (id: {:#x}) [{}], (instruction #{})",
-                                insn.imm as u32,BPF_FUNC_MAPPER[insn.imm as usize],insn_ptr
-                            ))
-                        }
-                    }
-                    1 => {
-                        // bpf to bpf call
-                        // The function is in the same program, so we can just jump to the address
-                        if stacks.len() >= ebpf::RBPF_MAX_CALL_DEPTH{
-                            Err(format!(
-                                "Error: bpf to bpf call stack limit reached (instruction #{}) max depth: {}",
-                                insn_ptr, ebpf::RBPF_MAX_CALL_DEPTH
-                            ))
-                        }else {
-                            let mut pre_stack = stacks.last_mut().unwrap();
-                            // Save the callee saved registers
-                            pre_stack.save_registers(&reg[6..=9]);
-                            // Save the return address
-                            pre_stack.save_return_address(insn_ptr as u64);
-                            // save the stack pointer
-                            pre_stack.save_sp(reg[10]);
-                            let mut stack = StackFrame::new();
-                            log::trace!("BPF TO BPF CALL: new pc: {} + {} = {}",insn_ptr ,insn.imm,insn_ptr + insn.imm as usize);
-                            reg[10] = stack.as_ptr() as u64 + stack.len() as u64;
-                            stacks.push(stack);
-                            insn_ptr += insn.imm as usize;
-                            Ok(())
-                        }
-                    }
-                    _ =>{
-                        Err(format!(
-                            "Error: the function call type (id: {:#x}) [{}], (instruction #{}) not supported",
-                            insn.imm as u32,BPF_FUNC_MAPPER[insn.imm as usize],insn_ptr
-                        ))
-                    }
-                };
-                if let Err(e) = call_func_res {
-                    Err(Error::new(ErrorKind::Other, e))?;
-                }
-            }
-            ebpf::TAIL_CALL => unimplemented!(),
-            ebpf::EXIT => {
-                if stacks.len() == 1 {
-                    return Ok(reg[0]);
-                } else {
-                    // Pop the stack
-                    stacks.pop();
-                    let stack = stacks.last().unwrap();
-                    // Restore the callee saved registers
-                    reg[6..=9].copy_from_slice(&stack.get_registers());
-                    // Restore the return address
-                    insn_ptr = stack.get_return_address() as usize;
-                    // Restore the stack pointer
-                    reg[10] = stack.get_sp();
-                    log::trace!("EXIT: new pc: {}", insn_ptr);
-                }
-            }
-
-            _ => unreachable!(),
-        }
-    }
-
-    unreachable!()
-}

+ 0 - 1054
kernel/crates/rbpf/src/jit.rs

@@ -1,1054 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Derived from uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-//      (uBPF: JIT algorithm, originally in C)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-//      (Translation to Rust, MetaBuff addition)
-
-use std::{
-    fmt::{Error as FormatterError, Formatter},
-    io::{Error, ErrorKind},
-    mem,
-    ops::{Index, IndexMut},
-};
-
-use crate::{ebpf, HashMap};
-
-extern crate libc;
-
-type MachineCode = unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64;
-
-const PAGE_SIZE: usize = 4096;
-// TODO: check how long the page must be to be sure to support an eBPF program of maximum possible
-// length
-const NUM_PAGES: usize = 1;
-
-// Special values for target_pc in struct Jump
-const TARGET_OFFSET: isize = ebpf::PROG_MAX_INSNS as isize;
-const TARGET_PC_EXIT: isize = TARGET_OFFSET + 1;
-
-#[derive(Copy, Clone)]
-enum OperandSize {
-    S8 = 8,
-    S16 = 16,
-    S32 = 32,
-    S64 = 64,
-}
-
-// Registers
-const RAX: u8 = 0;
-const RCX: u8 = 1;
-const RDX: u8 = 2;
-const RBX: u8 = 3;
-const RSP: u8 = 4;
-const RBP: u8 = 5;
-const RSI: u8 = 6;
-const RDI: u8 = 7;
-const R8: u8 = 8;
-const R9: u8 = 9;
-const R10: u8 = 10;
-const R11: u8 = 11;
-//const R12: u8 = 12;
-const R13: u8 = 13;
-const R14: u8 = 14;
-const R15: u8 = 15;
-
-const REGISTER_MAP_SIZE: usize = 11;
-const REGISTER_MAP: [u8; REGISTER_MAP_SIZE] = [
-    RAX, // 0  return value
-    RDI, // 1  arg 1
-    RSI, // 2  arg 2
-    RDX, // 3  arg 3
-    R9,  // 4  arg 4
-    R8,  // 5  arg 5
-    RBX, // 6  callee-saved
-    R13, // 7  callee-saved
-    R14, // 8  callee-saved
-    R15, // 9  callee-saved
-    RBP, // 10 stack pointer
-         // R10 and R11 are used to compute store a constant pointer to mem and to compute offset for
-         // LD_ABS_* and LD_IND_* operations, so they are not mapped to any eBPF register.
-];
-
-// Return the x86 register for the given eBPF register
-fn map_register(r: u8) -> u8 {
-    assert!(r < REGISTER_MAP_SIZE as u8);
-    REGISTER_MAP[(r % REGISTER_MAP_SIZE as u8) as usize]
-}
-
-macro_rules! emit_bytes {
-    ( $mem:ident, $data:tt, $t:ty ) => {{
-        let size = mem::size_of::<$t>() as usize;
-        assert!($mem.offset + size <= $mem.contents.len());
-        unsafe {
-            let mut ptr = $mem.contents.as_ptr().add($mem.offset) as *mut $t;
-            ptr.write_unaligned($data);
-        }
-        $mem.offset += size;
-    }};
-}
-
-#[derive(Debug)]
-struct Jump {
-    offset_loc: usize,
-    target_pc: isize,
-}
-
-#[derive(Debug)]
-struct JitCompiler {
-    pc_locs: Vec<usize>,
-    special_targets: HashMap<isize, usize>,
-    jumps: Vec<Jump>,
-}
-
-impl JitCompiler {
-    fn new() -> JitCompiler {
-        JitCompiler {
-            pc_locs: vec![],
-            jumps: vec![],
-            special_targets: HashMap::new(),
-        }
-    }
-
-    fn emit1(&self, mem: &mut JitMemory, data: u8) {
-        emit_bytes!(mem, data, u8);
-    }
-
-    fn emit2(&self, mem: &mut JitMemory, data: u16) {
-        emit_bytes!(mem, data, u16);
-    }
-
-    fn emit4(&self, mem: &mut JitMemory, data: u32) {
-        emit_bytes!(mem, data, u32);
-    }
-
-    fn emit8(&self, mem: &mut JitMemory, data: u64) {
-        emit_bytes!(mem, data, u64);
-    }
-
-    fn emit_modrm(&self, mem: &mut JitMemory, modrm: u8, r: u8, m: u8) {
-        assert_eq!((modrm | 0xc0), 0xc0);
-        self.emit1(mem, (modrm & 0xc0) | ((r & 0b111) << 3) | (m & 0b111));
-    }
-
-    fn emit_modrm_reg2reg(&self, mem: &mut JitMemory, r: u8, m: u8) {
-        self.emit_modrm(mem, 0xc0, r, m);
-    }
-
-    fn emit_modrm_and_displacement(&self, mem: &mut JitMemory, r: u8, m: u8, d: i32) {
-        if d == 0 && (m & 0b111) != RBP {
-            self.emit_modrm(mem, 0x00, r, m);
-        } else if (-128..=127).contains(&d) {
-            self.emit_modrm(mem, 0x40, r, m);
-            self.emit1(mem, d as u8);
-        } else {
-            self.emit_modrm(mem, 0x80, r, m);
-            self.emit4(mem, d as u32);
-        }
-    }
-
-    fn basix_rex_would_set_bits(&self, w: u8, src: u8, dst: u8) -> bool {
-        w != 0 || (src & 0b1000) != 0 || (dst & 0b1000) != 0
-    }
-
-    fn emit_rex(&self, mem: &mut JitMemory, w: u8, r: u8, x: u8, b: u8) {
-        assert_eq!((w | 1), 1);
-        assert_eq!((r | 1), 1);
-        assert_eq!((x | 1), 1);
-        assert_eq!((b | 1), 1);
-        self.emit1(mem, 0x40 | (w << 3) | (r << 2) | (x << 1) | b);
-    }
-
-    // Emits a REX prefix with the top bit of src and dst.
-    // Skipped if no bits would be set.
-    fn emit_basic_rex(&self, mem: &mut JitMemory, w: u8, src: u8, dst: u8) {
-        if self.basix_rex_would_set_bits(w, src, dst) {
-            let is_masked = |val, mask| match val & mask {
-                0 => 0,
-                _ => 1,
-            };
-            self.emit_rex(mem, w, is_masked(src, 8), 0, is_masked(dst, 8));
-        }
-    }
-
-    fn emit_push(&self, mem: &mut JitMemory, r: u8) {
-        self.emit_basic_rex(mem, 0, 0, r);
-        self.emit1(mem, 0x50 | (r & 0b111));
-    }
-
-    fn emit_pop(&self, mem: &mut JitMemory, r: u8) {
-        self.emit_basic_rex(mem, 0, 0, r);
-        self.emit1(mem, 0x58 | (r & 0b111));
-    }
-
-    // REX prefix and ModRM byte
-    // We use the MR encoding when there is a choice
-    // 'src' is often used as an opcode extension
-    fn emit_alu32(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8) {
-        self.emit_basic_rex(mem, 0, src, dst);
-        self.emit1(mem, op);
-        self.emit_modrm_reg2reg(mem, src, dst);
-    }
-
-    // REX prefix, ModRM byte, and 32-bit immediate
-    fn emit_alu32_imm32(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8, imm: i32) {
-        self.emit_alu32(mem, op, src, dst);
-        self.emit4(mem, imm as u32);
-    }
-
-    // REX prefix, ModRM byte, and 8-bit immediate
-    fn emit_alu32_imm8(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8, imm: i8) {
-        self.emit_alu32(mem, op, src, dst);
-        self.emit1(mem, imm as u8);
-    }
-
-    // REX.W prefix and ModRM byte
-    // We use the MR encoding when there is a choice
-    // 'src' is often used as an opcode extension
-    fn emit_alu64(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8) {
-        self.emit_basic_rex(mem, 1, src, dst);
-        self.emit1(mem, op);
-        self.emit_modrm_reg2reg(mem, src, dst);
-    }
-
-    // REX.W prefix, ModRM byte, and 32-bit immediate
-    fn emit_alu64_imm32(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8, imm: i32) {
-        self.emit_alu64(mem, op, src, dst);
-        self.emit4(mem, imm as u32);
-    }
-
-    // REX.W prefix, ModRM byte, and 8-bit immediate
-    fn emit_alu64_imm8(&self, mem: &mut JitMemory, op: u8, src: u8, dst: u8, imm: i8) {
-        self.emit_alu64(mem, op, src, dst);
-        self.emit1(mem, imm as u8);
-    }
-
-    // Register to register mov
-    fn emit_mov(&self, mem: &mut JitMemory, src: u8, dst: u8) {
-        self.emit_alu64(mem, 0x89, src, dst);
-    }
-
-    fn emit_cmp_imm32(&self, mem: &mut JitMemory, dst: u8, imm: i32) {
-        self.emit_alu64_imm32(mem, 0x81, 7, dst, imm);
-    }
-
-    fn emit_cmp(&self, mem: &mut JitMemory, src: u8, dst: u8) {
-        self.emit_alu64(mem, 0x39, src, dst);
-    }
-
-    fn emit_cmp32_imm32(&self, mem: &mut JitMemory, dst: u8, imm: i32) {
-        self.emit_alu32_imm32(mem, 0x81, 7, dst, imm);
-    }
-
-    fn emit_cmp32(&self, mem: &mut JitMemory, src: u8, dst: u8) {
-        self.emit_alu32(mem, 0x39, src, dst);
-    }
-
-    // Load [src + offset] into dst
-    fn emit_load(&self, mem: &mut JitMemory, size: OperandSize, src: u8, dst: u8, offset: i32) {
-        let data = match size {
-            OperandSize::S64 => 1,
-            _ => 0,
-        };
-        self.emit_basic_rex(mem, data, dst, src);
-
-        match size {
-            OperandSize::S8 => {
-                // movzx
-                self.emit1(mem, 0x0f);
-                self.emit1(mem, 0xb6);
-            }
-            OperandSize::S16 => {
-                // movzx
-                self.emit1(mem, 0x0f);
-                self.emit1(mem, 0xb7);
-            }
-            OperandSize::S32 | OperandSize::S64 => {
-                // mov
-                self.emit1(mem, 0x8b);
-            }
-        }
-
-        self.emit_modrm_and_displacement(mem, dst, src, offset);
-    }
-
-    // Load sign-extended immediate into register
-    fn emit_load_imm(&self, mem: &mut JitMemory, dst: u8, imm: i64) {
-        if imm >= i32::MIN as i64 && imm <= i32::MAX as i64 {
-            self.emit_alu64_imm32(mem, 0xc7, 0, dst, imm as i32);
-        } else {
-            // movabs $imm,dst
-            self.emit_basic_rex(mem, 1, 0, dst);
-            self.emit1(mem, 0xb8 | (dst & 0b111));
-            self.emit8(mem, imm as u64);
-        }
-    }
-
-    // Store register src to [dst + offset]
-    fn emit_store(&self, mem: &mut JitMemory, size: OperandSize, src: u8, dst: u8, offset: i32) {
-        match size {
-            OperandSize::S16 => self.emit1(mem, 0x66), // 16-bit override
-            _ => {}
-        };
-        let (is_s8, is_u64, rexw) = match size {
-            OperandSize::S8 => (true, false, 0),
-            OperandSize::S64 => (false, true, 1),
-            _ => (false, false, 0),
-        };
-        if is_u64 || (src & 0b1000) != 0 || (dst & 0b1000) != 0 || is_s8 {
-            let is_masked = |val, mask| match val & mask {
-                0 => 0,
-                _ => 1,
-            };
-            self.emit_rex(mem, rexw, is_masked(src, 8), 0, is_masked(dst, 8));
-        }
-        match size {
-            OperandSize::S8 => self.emit1(mem, 0x88),
-            _ => self.emit1(mem, 0x89),
-        };
-        self.emit_modrm_and_displacement(mem, src, dst, offset);
-    }
-
-    // Store immediate to [dst + offset]
-    fn emit_store_imm32(
-        &self,
-        mem: &mut JitMemory,
-        size: OperandSize,
-        dst: u8,
-        offset: i32,
-        imm: i32,
-    ) {
-        match size {
-            OperandSize::S16 => self.emit1(mem, 0x66), // 16-bit override
-            _ => {}
-        };
-        match size {
-            OperandSize::S64 => self.emit_basic_rex(mem, 1, 0, dst),
-            _ => self.emit_basic_rex(mem, 0, 0, dst),
-        };
-        match size {
-            OperandSize::S8 => self.emit1(mem, 0xc6),
-            _ => self.emit1(mem, 0xc7),
-        };
-        self.emit_modrm_and_displacement(mem, 0, dst, offset);
-        match size {
-            OperandSize::S8 => self.emit1(mem, imm as u8),
-            OperandSize::S16 => self.emit2(mem, imm as u16),
-            _ => self.emit4(mem, imm as u32),
-        };
-    }
-
-    fn emit_direct_jcc(&self, mem: &mut JitMemory, code: u8, offset: u32) {
-        self.emit1(mem, 0x0f);
-        self.emit1(mem, code);
-        emit_bytes!(mem, offset, u32);
-    }
-
-    fn emit_call(&self, mem: &mut JitMemory, target: usize) {
-        // TODO use direct call when possible
-        self.emit_load_imm(mem, RAX, target as i64);
-        // callq *%rax
-        self.emit1(mem, 0xff);
-        self.emit1(mem, 0xd0);
-    }
-
-    fn emit_jump_offset(&mut self, mem: &mut JitMemory, target_pc: isize) {
-        let jump = Jump {
-            offset_loc: mem.offset,
-            target_pc,
-        };
-        self.jumps.push(jump);
-        self.emit4(mem, 0);
-    }
-
-    fn emit_jcc(&mut self, mem: &mut JitMemory, code: u8, target_pc: isize) {
-        self.emit1(mem, 0x0f);
-        self.emit1(mem, code);
-        self.emit_jump_offset(mem, target_pc);
-    }
-
-    fn emit_jmp(&mut self, mem: &mut JitMemory, target_pc: isize) {
-        self.emit1(mem, 0xe9);
-        self.emit_jump_offset(mem, target_pc);
-    }
-
-    fn set_anchor(&mut self, mem: &mut JitMemory, target: isize) {
-        self.special_targets.insert(target, mem.offset);
-    }
-
-    fn emit_muldivmod(
-        &mut self,
-        mem: &mut JitMemory,
-        pc: u16,
-        opc: u8,
-        src: u8,
-        dst: u8,
-        imm: i32,
-    ) {
-        let mul = (opc & ebpf::BPF_ALU_OP_MASK) == (ebpf::MUL32_IMM & ebpf::BPF_ALU_OP_MASK);
-        let div = (opc & ebpf::BPF_ALU_OP_MASK) == (ebpf::DIV32_IMM & ebpf::BPF_ALU_OP_MASK);
-        let modrm = (opc & ebpf::BPF_ALU_OP_MASK) == (ebpf::MOD32_IMM & ebpf::BPF_ALU_OP_MASK);
-        let is64 = (opc & ebpf::BPF_CLS_MASK) == ebpf::BPF_ALU64;
-        let is_reg = (opc & ebpf::BPF_X) == ebpf::BPF_X;
-
-        if (div || mul) && !is_reg && imm == 0 {
-            // Division by zero returns 0
-            // Set register to 0: xor with itself
-            self.emit_alu32(mem, 0x31, dst, dst);
-            return;
-        }
-        if modrm && !is_reg && imm == 0 {
-            // Modulo remainder of division by zero keeps destination register unchanged
-            return;
-        }
-        if (div || modrm) && is_reg {
-            self.emit_load_imm(mem, RCX, pc as i64);
-
-            // test src,src
-            if is64 {
-                self.emit_alu64(mem, 0x85, src, src);
-            } else {
-                self.emit_alu32(mem, 0x85, src, src);
-            }
-
-            if div {
-                // No division by 0: skip next instructions
-                // Jump offset: emit_alu32 adds 2 to 3 bytes, emit_jmp adds 5
-                let offset = match self.basix_rex_would_set_bits(0, dst, dst) {
-                    true => 3 + 5,
-                    false => 2 + 5,
-                };
-                self.emit_direct_jcc(mem, 0x85, offset);
-                // Division by 0: set dst to 0 then go to next instruction
-                // Set register to 0: xor with itself
-                self.emit_alu32(mem, 0x31, dst, dst);
-                self.emit_jmp(mem, (pc + 1) as isize);
-            }
-            if modrm {
-                // Modulo by zero: keep destination register unchanged
-                self.emit_jcc(mem, 0x84, (pc + 1) as isize);
-            }
-        }
-
-        if dst != RAX {
-            self.emit_push(mem, RAX);
-        }
-        if dst != RDX {
-            self.emit_push(mem, RDX);
-        }
-        if imm != 0 {
-            self.emit_load_imm(mem, RCX, imm as i64);
-        } else {
-            self.emit_mov(mem, src, RCX);
-        }
-
-        self.emit_mov(mem, dst, RAX);
-
-        if div || modrm {
-            // Set register to 0: xor %edx,%edx
-            self.emit_alu32(mem, 0x31, RDX, RDX);
-        }
-
-        if is64 {
-            self.emit_rex(mem, 1, 0, 0, 0);
-        }
-
-        // mul %ecx or div %ecx
-        self.emit_alu32(mem, 0xf7, if mul { 4 } else { 6 }, RCX);
-
-        if dst != RDX {
-            if modrm {
-                self.emit_mov(mem, RDX, dst);
-            }
-            self.emit_pop(mem, RDX);
-        }
-        if dst != RAX {
-            if div || mul {
-                self.emit_mov(mem, RAX, dst);
-            }
-            self.emit_pop(mem, RAX);
-        }
-    }
-
-    fn jit_compile(
-        &mut self,
-        mem: &mut JitMemory,
-        prog: &[u8],
-        use_mbuff: bool,
-        update_data_ptr: bool,
-        helpers: &HashMap<u32, ebpf::Helper>,
-    ) -> Result<(), Error> {
-        self.emit_push(mem, RBP);
-        self.emit_push(mem, RBX);
-        self.emit_push(mem, R13);
-        self.emit_push(mem, R14);
-        self.emit_push(mem, R15);
-
-        // RDI: mbuff
-        // RSI: mbuff_len
-        // RDX: mem
-        // RCX: mem_len
-        // R8:  mem_offset
-        // R9:  mem_end_offset
-
-        // Save mem pointer for use with LD_ABS_* and LD_IND_* instructions
-        self.emit_mov(mem, RDX, R10);
-
-        match (use_mbuff, update_data_ptr) {
-            (false, _) => {
-                // We do not use any mbuff. Move mem pointer into register 1.
-                if map_register(1) != RDX {
-                    self.emit_mov(mem, RDX, map_register(1));
-                }
-            }
-            (true, false) => {
-                // We use a mbuff already pointing to mem and mem_end: move it to register 1.
-                if map_register(1) != RDI {
-                    self.emit_mov(mem, RDI, map_register(1));
-                }
-            }
-            (true, true) => {
-                // We have a fixed (simulated) mbuff: update mem and mem_end offset values in it.
-                // Store mem at mbuff + mem_offset. Trash R8.
-                self.emit_alu64(mem, 0x01, RDI, R8); // add mbuff to mem_offset in R8
-                self.emit_store(mem, OperandSize::S64, RDX, R8, 0); // set mem at mbuff + mem_offset
-                                                                    // Store mem_end at mbuff + mem_end_offset. Trash R9.
-                self.emit_load(mem, OperandSize::S64, RDX, R8, 0); // load mem into R8
-                self.emit_alu64(mem, 0x01, RCX, R8); // add mem_len to mem (= mem_end)
-                self.emit_alu64(mem, 0x01, RDI, R9); // add mbuff to mem_end_offset
-                self.emit_store(mem, OperandSize::S64, R8, R9, 0); // store mem_end
-
-                // Move rdi into register 1
-                if map_register(1) != RDI {
-                    self.emit_mov(mem, RDI, map_register(1));
-                }
-            }
-        }
-
-        // Copy stack pointer to R10
-        self.emit_mov(mem, RSP, map_register(10));
-
-        // Allocate stack space
-        self.emit_alu64_imm32(mem, 0x81, 5, RSP, ebpf::STACK_SIZE as i32);
-
-        self.pc_locs = vec![0; prog.len() / ebpf::INSN_SIZE + 1];
-
-        let mut insn_ptr: usize = 0;
-        while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-            let insn = ebpf::get_insn(prog, insn_ptr);
-
-            self.pc_locs[insn_ptr] = mem.offset;
-
-            let dst = map_register(insn.dst);
-            let src = map_register(insn.src);
-            let target_pc = insn_ptr as isize + insn.off as isize + 1;
-
-            match insn.opc {
-                // BPF_LD class
-                // R10 is a constant pointer to mem.
-                ebpf::LD_ABS_B => self.emit_load(mem, OperandSize::S8, R10, RAX, insn.imm),
-                ebpf::LD_ABS_H => self.emit_load(mem, OperandSize::S16, R10, RAX, insn.imm),
-                ebpf::LD_ABS_W => self.emit_load(mem, OperandSize::S32, R10, RAX, insn.imm),
-                ebpf::LD_ABS_DW => self.emit_load(mem, OperandSize::S64, R10, RAX, insn.imm),
-                ebpf::LD_IND_B => {
-                    self.emit_mov(mem, R10, R11); // load mem into R11
-                    self.emit_alu64(mem, 0x01, src, R11); // add src to R11
-                    self.emit_load(mem, OperandSize::S8, R11, RAX, insn.imm); // ld R0, mem[src+imm]
-                }
-                ebpf::LD_IND_H => {
-                    self.emit_mov(mem, R10, R11); // load mem into R11
-                    self.emit_alu64(mem, 0x01, src, R11); // add src to R11
-                    self.emit_load(mem, OperandSize::S16, R11, RAX, insn.imm); // ld R0, mem[src+imm]
-                }
-                ebpf::LD_IND_W => {
-                    self.emit_mov(mem, R10, R11); // load mem into R11
-                    self.emit_alu64(mem, 0x01, src, R11); // add src to R11
-                    self.emit_load(mem, OperandSize::S32, R11, RAX, insn.imm); // ld R0, mem[src+imm]
-                }
-                ebpf::LD_IND_DW => {
-                    self.emit_mov(mem, R10, R11); // load mem into R11
-                    self.emit_alu64(mem, 0x01, src, R11); // add src to R11
-                    self.emit_load(mem, OperandSize::S64, R11, RAX, insn.imm); // ld R0, mem[src+imm]
-                }
-
-                ebpf::LD_DW_IMM => {
-                    insn_ptr += 1;
-                    let second_part = ebpf::get_insn(prog, insn_ptr).imm as u64;
-                    let imm = (insn.imm as u32) as u64 | second_part.wrapping_shl(32);
-                    self.emit_load_imm(mem, dst, imm as i64);
-                }
-
-                // BPF_LDX class
-                ebpf::LD_B_REG => self.emit_load(mem, OperandSize::S8, src, dst, insn.off as i32),
-                ebpf::LD_H_REG => self.emit_load(mem, OperandSize::S16, src, dst, insn.off as i32),
-                ebpf::LD_W_REG => self.emit_load(mem, OperandSize::S32, src, dst, insn.off as i32),
-                ebpf::LD_DW_REG => self.emit_load(mem, OperandSize::S64, src, dst, insn.off as i32),
-
-                // BPF_ST class
-                ebpf::ST_B_IMM => {
-                    self.emit_store_imm32(mem, OperandSize::S8, dst, insn.off as i32, insn.imm)
-                }
-                ebpf::ST_H_IMM => {
-                    self.emit_store_imm32(mem, OperandSize::S16, dst, insn.off as i32, insn.imm)
-                }
-                ebpf::ST_W_IMM => {
-                    self.emit_store_imm32(mem, OperandSize::S32, dst, insn.off as i32, insn.imm)
-                }
-                ebpf::ST_DW_IMM => {
-                    self.emit_store_imm32(mem, OperandSize::S64, dst, insn.off as i32, insn.imm)
-                }
-
-                // BPF_STX class
-                ebpf::ST_B_REG => self.emit_store(mem, OperandSize::S8, src, dst, insn.off as i32),
-                ebpf::ST_H_REG => self.emit_store(mem, OperandSize::S16, src, dst, insn.off as i32),
-                ebpf::ST_W_REG => self.emit_store(mem, OperandSize::S32, src, dst, insn.off as i32),
-                ebpf::ST_DW_REG => {
-                    self.emit_store(mem, OperandSize::S64, src, dst, insn.off as i32)
-                }
-                ebpf::ST_W_XADD => unimplemented!(),
-                ebpf::ST_DW_XADD => unimplemented!(),
-
-                // BPF_ALU class
-                ebpf::ADD32_IMM => self.emit_alu32_imm32(mem, 0x81, 0, dst, insn.imm),
-                ebpf::ADD32_REG => self.emit_alu32(mem, 0x01, src, dst),
-                ebpf::SUB32_IMM => self.emit_alu32_imm32(mem, 0x81, 5, dst, insn.imm),
-                ebpf::SUB32_REG => self.emit_alu32(mem, 0x29, src, dst),
-                ebpf::MUL32_IMM
-                | ebpf::MUL32_REG
-                | ebpf::DIV32_IMM
-                | ebpf::DIV32_REG
-                | ebpf::MOD32_IMM
-                | ebpf::MOD32_REG => {
-                    self.emit_muldivmod(mem, insn_ptr as u16, insn.opc, src, dst, insn.imm)
-                }
-                ebpf::OR32_IMM => self.emit_alu32_imm32(mem, 0x81, 1, dst, insn.imm),
-                ebpf::OR32_REG => self.emit_alu32(mem, 0x09, src, dst),
-                ebpf::AND32_IMM => self.emit_alu32_imm32(mem, 0x81, 4, dst, insn.imm),
-                ebpf::AND32_REG => self.emit_alu32(mem, 0x21, src, dst),
-                ebpf::LSH32_IMM => self.emit_alu32_imm8(mem, 0xc1, 4, dst, insn.imm as i8),
-                ebpf::LSH32_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu32(mem, 0xd3, 4, dst);
-                }
-                ebpf::RSH32_IMM => self.emit_alu32_imm8(mem, 0xc1, 5, dst, insn.imm as i8),
-                ebpf::RSH32_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu32(mem, 0xd3, 5, dst);
-                }
-                ebpf::NEG32 => self.emit_alu32(mem, 0xf7, 3, dst),
-                ebpf::XOR32_IMM => self.emit_alu32_imm32(mem, 0x81, 6, dst, insn.imm),
-                ebpf::XOR32_REG => self.emit_alu32(mem, 0x31, src, dst),
-                ebpf::MOV32_IMM => self.emit_alu32_imm32(mem, 0xc7, 0, dst, insn.imm),
-                ebpf::MOV32_REG => self.emit_mov(mem, src, dst),
-                ebpf::ARSH32_IMM => self.emit_alu32_imm8(mem, 0xc1, 7, dst, insn.imm as i8),
-                ebpf::ARSH32_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu32(mem, 0xd3, 7, dst);
-                }
-                ebpf::LE => {} // No-op
-                ebpf::BE => {
-                    match insn.imm {
-                        16 => {
-                            // rol
-                            self.emit1(mem, 0x66); // 16-bit override
-                            self.emit_alu32_imm8(mem, 0xc1, 0, dst, 8);
-                            // and
-                            self.emit_alu32_imm32(mem, 0x81, 4, dst, 0xffff);
-                        }
-                        32 | 64 => {
-                            // bswap
-                            let bit = match insn.imm {
-                                64 => 1,
-                                _ => 0,
-                            };
-                            self.emit_basic_rex(mem, bit, 0, dst);
-                            self.emit1(mem, 0x0f);
-                            self.emit1(mem, 0xc8 | (dst & 0b111));
-                        }
-                        _ => unreachable!(), // Should have been caught by verifier
-                    }
-                }
-
-                // BPF_ALU64 class
-                ebpf::ADD64_IMM => self.emit_alu64_imm32(mem, 0x81, 0, dst, insn.imm),
-                ebpf::ADD64_REG => self.emit_alu64(mem, 0x01, src, dst),
-                ebpf::SUB64_IMM => self.emit_alu64_imm32(mem, 0x81, 5, dst, insn.imm),
-                ebpf::SUB64_REG => self.emit_alu64(mem, 0x29, src, dst),
-                ebpf::MUL64_IMM
-                | ebpf::MUL64_REG
-                | ebpf::DIV64_IMM
-                | ebpf::DIV64_REG
-                | ebpf::MOD64_IMM
-                | ebpf::MOD64_REG => {
-                    self.emit_muldivmod(mem, insn_ptr as u16, insn.opc, src, dst, insn.imm)
-                }
-                ebpf::OR64_IMM => self.emit_alu64_imm32(mem, 0x81, 1, dst, insn.imm),
-                ebpf::OR64_REG => self.emit_alu64(mem, 0x09, src, dst),
-                ebpf::AND64_IMM => self.emit_alu64_imm32(mem, 0x81, 4, dst, insn.imm),
-                ebpf::AND64_REG => self.emit_alu64(mem, 0x21, src, dst),
-                ebpf::LSH64_IMM => self.emit_alu64_imm8(mem, 0xc1, 4, dst, insn.imm as i8),
-                ebpf::LSH64_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu64(mem, 0xd3, 4, dst);
-                }
-                ebpf::RSH64_IMM => self.emit_alu64_imm8(mem, 0xc1, 5, dst, insn.imm as i8),
-                ebpf::RSH64_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu64(mem, 0xd3, 5, dst);
-                }
-                ebpf::NEG64 => self.emit_alu64(mem, 0xf7, 3, dst),
-                ebpf::XOR64_IMM => self.emit_alu64_imm32(mem, 0x81, 6, dst, insn.imm),
-                ebpf::XOR64_REG => self.emit_alu64(mem, 0x31, src, dst),
-                ebpf::MOV64_IMM => self.emit_load_imm(mem, dst, insn.imm as i64),
-                ebpf::MOV64_REG => self.emit_mov(mem, src, dst),
-                ebpf::ARSH64_IMM => self.emit_alu64_imm8(mem, 0xc1, 7, dst, insn.imm as i8),
-                ebpf::ARSH64_REG => {
-                    self.emit_mov(mem, src, RCX);
-                    self.emit_alu64(mem, 0xd3, 7, dst);
-                }
-
-                // BPF_JMP class
-                ebpf::JA => self.emit_jmp(mem, target_pc),
-                ebpf::JEQ_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x84, target_pc);
-                }
-                ebpf::JEQ_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x84, target_pc);
-                }
-                ebpf::JGT_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x87, target_pc);
-                }
-                ebpf::JGT_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x87, target_pc);
-                }
-                ebpf::JGE_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x83, target_pc);
-                }
-                ebpf::JGE_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x83, target_pc);
-                }
-                ebpf::JLT_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x82, target_pc);
-                }
-                ebpf::JLT_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x82, target_pc);
-                }
-                ebpf::JLE_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x86, target_pc);
-                }
-                ebpf::JLE_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x86, target_pc);
-                }
-                ebpf::JSET_IMM => {
-                    self.emit_alu64_imm32(mem, 0xf7, 0, dst, insn.imm);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JSET_REG => {
-                    self.emit_alu64(mem, 0x85, src, dst);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JNE_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JNE_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JSGT_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8f, target_pc);
-                }
-                ebpf::JSGT_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x8f, target_pc);
-                }
-                ebpf::JSGE_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8d, target_pc);
-                }
-                ebpf::JSGE_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x8d, target_pc);
-                }
-                ebpf::JSLT_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8c, target_pc);
-                }
-                ebpf::JSLT_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x8c, target_pc);
-                }
-                ebpf::JSLE_IMM => {
-                    self.emit_cmp_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8e, target_pc);
-                }
-                ebpf::JSLE_REG => {
-                    self.emit_cmp(mem, src, dst);
-                    self.emit_jcc(mem, 0x8e, target_pc);
-                }
-
-                // BPF_JMP32 class
-                ebpf::JEQ_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x84, target_pc);
-                }
-                ebpf::JEQ_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x84, target_pc);
-                }
-                ebpf::JGT_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x87, target_pc);
-                }
-                ebpf::JGT_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x87, target_pc);
-                }
-                ebpf::JGE_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x83, target_pc);
-                }
-                ebpf::JGE_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x83, target_pc);
-                }
-                ebpf::JLT_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x82, target_pc);
-                }
-                ebpf::JLT_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x82, target_pc);
-                }
-                ebpf::JLE_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x86, target_pc);
-                }
-                ebpf::JLE_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x86, target_pc);
-                }
-                ebpf::JSET_IMM32 => {
-                    self.emit_alu32_imm32(mem, 0xf7, 0, dst, insn.imm);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JSET_REG32 => {
-                    self.emit_alu32(mem, 0x85, src, dst);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JNE_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JNE_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x85, target_pc);
-                }
-                ebpf::JSGT_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8f, target_pc);
-                }
-                ebpf::JSGT_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x8f, target_pc);
-                }
-                ebpf::JSGE_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8d, target_pc);
-                }
-                ebpf::JSGE_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x8d, target_pc);
-                }
-                ebpf::JSLT_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8c, target_pc);
-                }
-                ebpf::JSLT_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x8c, target_pc);
-                }
-                ebpf::JSLE_IMM32 => {
-                    self.emit_cmp32_imm32(mem, dst, insn.imm);
-                    self.emit_jcc(mem, 0x8e, target_pc);
-                }
-                ebpf::JSLE_REG32 => {
-                    self.emit_cmp32(mem, src, dst);
-                    self.emit_jcc(mem, 0x8e, target_pc);
-                }
-
-                ebpf::CALL => {
-                    // For JIT, helpers in use MUST be registered at compile time. They can be
-                    // updated later, but not created after compiling (we need the address of the
-                    // helper function in the JIT-compiled program).
-                    if let Some(helper) = helpers.get(&(insn.imm as u32)) {
-                        // We reserve RCX for shifts
-                        self.emit_mov(mem, R9, RCX);
-                        self.emit_call(mem, *helper as usize);
-                    } else {
-                        Err(Error::new(
-                            ErrorKind::Other,
-                            format!(
-                                "[JIT] Error: unknown helper function (id: {:#x})",
-                                insn.imm as u32
-                            ),
-                        ))?;
-                    };
-                }
-                ebpf::TAIL_CALL => {
-                    unimplemented!()
-                }
-                ebpf::EXIT => {
-                    if insn_ptr != prog.len() / ebpf::INSN_SIZE - 1 {
-                        self.emit_jmp(mem, TARGET_PC_EXIT);
-                    };
-                }
-
-                _ => {
-                    Err(Error::new(
-                        ErrorKind::Other,
-                        format!(
-                            "[JIT] Error: unknown eBPF opcode {:#2x} (insn #{insn_ptr:?})",
-                            insn.opc
-                        ),
-                    ))?;
-                }
-            }
-
-            insn_ptr += 1;
-        }
-
-        // Epilogue
-        self.set_anchor(mem, TARGET_PC_EXIT);
-
-        // Move register 0 into rax
-        if map_register(0) != RAX {
-            self.emit_mov(mem, map_register(0), RAX);
-        }
-
-        // Deallocate stack space
-        self.emit_alu64_imm32(mem, 0x81, 0, RSP, ebpf::STACK_SIZE as i32);
-
-        self.emit_pop(mem, R15);
-        self.emit_pop(mem, R14);
-        self.emit_pop(mem, R13);
-        self.emit_pop(mem, RBX);
-        self.emit_pop(mem, RBP);
-
-        self.emit1(mem, 0xc3); // ret
-
-        Ok(())
-    }
-
-    fn resolve_jumps(&mut self, mem: &mut JitMemory) -> Result<(), Error> {
-        for jump in &self.jumps {
-            let target_loc = match self.special_targets.get(&jump.target_pc) {
-                Some(target) => *target,
-                None => self.pc_locs[jump.target_pc as usize],
-            };
-
-            // Assumes jump offset is at end of instruction
-            unsafe {
-                let offset_loc = jump.offset_loc as i32 + std::mem::size_of::<i32>() as i32;
-                let rel = &(target_loc as i32 - offset_loc) as *const i32;
-
-                let offset_ptr = mem.contents.as_ptr().add(jump.offset_loc);
-
-                libc::memcpy(
-                    offset_ptr as *mut libc::c_void,
-                    rel as *const libc::c_void,
-                    std::mem::size_of::<i32>(),
-                );
-            }
-        }
-        Ok(())
-    }
-} // impl JitCompiler
-
-pub struct JitMemory<'a> {
-    contents: &'a mut [u8],
-    offset: usize,
-}
-
-impl<'a> JitMemory<'a> {
-    pub fn new(
-        prog: &[u8],
-        helpers: &HashMap<u32, ebpf::Helper>,
-        use_mbuff: bool,
-        update_data_ptr: bool,
-    ) -> Result<JitMemory<'a>, Error> {
-        let contents: &mut [u8];
-        let mut raw: mem::MaybeUninit<*mut libc::c_void> = mem::MaybeUninit::uninit();
-        unsafe {
-            let size = NUM_PAGES * PAGE_SIZE;
-            libc::posix_memalign(raw.as_mut_ptr(), PAGE_SIZE, size);
-            libc::mprotect(
-                *raw.as_mut_ptr(),
-                size,
-                libc::PROT_EXEC | libc::PROT_READ | libc::PROT_WRITE,
-            );
-            std::ptr::write_bytes(*raw.as_mut_ptr(), 0xc3, size); // for now, prepopulate with 'RET' calls
-            contents =
-                std::slice::from_raw_parts_mut(*raw.as_mut_ptr() as *mut u8, NUM_PAGES * PAGE_SIZE);
-            raw.assume_init();
-        }
-
-        let mut mem = JitMemory {
-            contents,
-            offset: 0,
-        };
-
-        let mut jit = JitCompiler::new();
-        jit.jit_compile(&mut mem, prog, use_mbuff, update_data_ptr, helpers)?;
-        jit.resolve_jumps(&mut mem)?;
-
-        Ok(mem)
-    }
-
-    pub fn get_prog(&self) -> MachineCode {
-        unsafe { mem::transmute(self.contents.as_ptr()) }
-    }
-}
-
-impl<'a> Index<usize> for JitMemory<'a> {
-    type Output = u8;
-
-    fn index(&self, _index: usize) -> &u8 {
-        &self.contents[_index]
-    }
-}
-
-impl<'a> IndexMut<usize> for JitMemory<'a> {
-    fn index_mut(&mut self, _index: usize) -> &mut u8 {
-        &mut self.contents[_index]
-    }
-}
-
-impl<'a> Drop for JitMemory<'a> {
-    fn drop(&mut self) {
-        unsafe {
-            libc::free(self.contents.as_mut_ptr() as *mut libc::c_void);
-        }
-    }
-}
-
-impl<'a> std::fmt::Debug for JitMemory<'a> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatterError> {
-        fmt.write_str("JIT contents: [")?;
-        fmt.write_str(" ] | ")?;
-        fmt.debug_struct("JIT memory")
-            .field("offset", &self.offset)
-            .finish()
-    }
-}

+ 0 - 1782
kernel/crates/rbpf/src/lib.rs

@@ -1,1782 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Derived from uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-// Copyright 2023 Isovalent, Inc. <quentin@isovalent.com>
-
-//! Virtual machine and JIT compiler for eBPF programs.
-#![doc(
-    html_logo_url = "https://raw.githubusercontent.com/qmonnet/rbpf/main/misc/rbpf.png",
-    html_favicon_url = "https://raw.githubusercontent.com/qmonnet/rbpf/main/misc/rbpf.ico"
-)]
-#![warn(missing_docs)]
-// There are unused mut warnings due to unsafe code.
-#![allow(unused_mut)]
-// Allows old-style clippy
-#![allow(renamed_and_removed_lints)]
-#![cfg_attr(
-    clippy,
-    allow(
-        redundant_field_names,
-        single_match,
-        cast_lossless,
-        doc_markdown,
-        match_same_arms,
-        unreadable_literal
-    )
-)]
-// Configures the crate to be `no_std` when `std` feature is disabled.
-#![cfg_attr(not(feature = "std"), no_std)]
-extern crate alloc;
-use alloc::{collections::BTreeMap, format, vec, vec::Vec};
-
-use byteorder::{ByteOrder, LittleEndian};
-
-type HashMap<K, V> = BTreeMap<K, V>;
-#[cfg(feature = "cranelift")]
-type HashSet<T> = alloc::collections::BTreeSet<T>;
-mod asm_parser;
-pub mod assembler;
-#[cfg(feature = "cranelift")]
-mod cranelift;
-pub mod disassembler;
-pub mod ebpf;
-pub mod helpers;
-pub mod insn_builder;
-mod interpreter;
-#[cfg(all(not(windows), feature = "std"))]
-mod jit;
-#[cfg(not(feature = "std"))]
-mod no_std_error;
-mod stack;
-mod verifier;
-
-#[cfg(feature = "std")]
-pub use std::io::{Error, ErrorKind};
-
-/// In no_std we use a custom implementation of the error which acts as a
-/// replacement for the io Error.
-#[cfg(not(feature = "std"))]
-pub use crate::no_std_error::{Error, ErrorKind};
-
-/// eBPF verification function that returns an error if the program does not meet its requirements.
-///
-/// Some examples of things the verifier may reject the program for:
-///
-///   - Program does not terminate.
-///   - Unknown instructions.
-///   - Bad formed instruction.
-///   - Unknown eBPF helper index.
-pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;
-
-/// eBPF helper function.
-pub type Helper = fn(u64, u64, u64, u64, u64) -> u64;
-
-// A metadata buffer with two offset indications. It can be used in one kind of eBPF VM to simulate
-// the use of a metadata buffer each time the program is executed, without the user having to
-// actually handle it. The offsets are used to tell the VM where in the buffer the pointers to
-// packet data start and end should be stored each time the program is run on a new packet.
-struct MetaBuff {
-    data_offset: usize,
-    data_end_offset: usize,
-    buffer: Vec<u8>,
-}
-
-/// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
-/// on a metadata buffer containing pointers to packet data.
-///
-/// # Examples
-///
-/// ```
-/// let prog = &[
-///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff at offset 8 into R1.
-///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-/// ];
-/// let mem = &mut [
-///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-/// ];
-///
-/// // Just for the example we create our metadata buffer from scratch, and we store the pointers
-/// // to packet data start and end in it.
-/// let mut mbuff = [0u8; 32];
-/// unsafe {
-///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
-///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-///     *data     = mem.as_ptr() as u64;
-///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-/// }
-///
-/// // Instantiate a VM.
-/// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-///
-/// // Provide both a reference to the packet data, and to the metadata buffer.
-/// let res = vm.execute_program(mem, &mut mbuff).unwrap();
-/// assert_eq!(res, 0x2211);
-/// ```
-pub struct EbpfVmMbuff<'a> {
-    prog: Option<&'a [u8]>,
-    verifier: Verifier,
-    #[cfg(all(not(windows), feature = "std"))]
-    jit: Option<jit::JitMemory<'a>>,
-    #[cfg(feature = "cranelift")]
-    cranelift_prog: Option<cranelift::CraneliftProgram>,
-    helpers: HashMap<u32, ebpf::Helper>,
-}
-
-impl<'a> EbpfVmMbuff<'a> {
-    /// Create a new virtual machine instance, and load an eBPF program into that instance.
-    /// When attempting to load the program, it passes through a simple verifier.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    /// ```
-    pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmMbuff<'a>, Error> {
-        if let Some(prog) = prog {
-            verifier::check(prog)?;
-        }
-
-        Ok(EbpfVmMbuff {
-            prog,
-            verifier: verifier::check,
-            #[cfg(all(not(windows), feature = "std"))]
-            jit: None,
-            #[cfg(feature = "cranelift")]
-            cranelift_prog: None,
-            helpers: HashMap::new(),
-        })
-    }
-
-    /// Load a new eBPF program into the virtual machine instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let prog2 = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
-    /// vm.set_program(prog2).unwrap();
-    /// ```
-    pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
-        (self.verifier)(prog)?;
-        self.prog = Some(prog);
-        Ok(())
-    }
-
-    /// Set a new verifier function. The function should return an `Error` if the program should be
-    /// rejected by the virtual machine. If a program has been loaded to the VM already, the
-    /// verifier is immediately run.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::{Error, ErrorKind};
-    /// use rbpf::ebpf;
-    ///
-    /// // Define a simple verifier function.
-    /// fn verifier(prog: &[u8]) -> Result<(), Error> {
-    ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
-    ///     if last_insn.opc != ebpf::EXIT {
-    ///         return Err(Error::new(ErrorKind::Other,
-    ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
-    ///     }
-    ///     Ok(())
-    /// }
-    ///
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
-    /// // Change the verifier.
-    /// vm.set_verifier(verifier).unwrap();
-    /// ```
-    pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
-        if let Some(prog) = self.prog {
-            verifier(prog)?;
-        }
-        self.verifier = verifier;
-        Ok(())
-    }
-
-    /// Register a built-in or user-defined helper function in order to use it later from within
-    /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
-    ///
-    /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
-    /// program. You should be able to change registered helpers after compiling, but not to add
-    /// new ones (i.e. with new keys).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::helpers;
-    ///
-    /// // This program was compiled with clang, from a C program containing the following single
-    /// // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
-    /// let prog = &[
-    ///     0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load 0 as u64 into r1 (That would be
-    ///     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // replaced by tc by the address of
-    ///                                                     // the format string, in the .map
-    ///                                                     // section of the ELF file).
-    ///     0xb7, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, // mov r2, 10
-    ///     0xb7, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r3, 1
-    ///     0xb7, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r4, 2
-    ///     0xb7, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r5, 3
-    ///     0x85, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // call helper with key 6
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// // Register a helper.
-    /// // On running the program this helper will print the content of registers r3, r4 and r5 to
-    /// // standard output.
-    /// # #[cfg(feature = "std")]
-    /// vm.register_helper(6, helpers::bpf_trace_printf).unwrap();
-    /// ```
-    pub fn register_helper(&mut self, key: u32, function: Helper) -> Result<(), Error> {
-        self.helpers.insert(key, function);
-        Ok(())
-    }
-
-    /// Execute the program loaded, with the given packet data and metadata buffer.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from the
-    /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
-    /// pointers are correctly stored in the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Just for the example we create our metadata buffer from scratch, and we store the
-    /// // pointers to packet data start and end in it.
-    /// let mut mbuff = [0u8; 32];
-    /// unsafe {
-    ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
-    ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-    ///     *data     = mem.as_ptr() as u64;
-    ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    /// }
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// // Provide both a reference to the packet data, and to the metadata buffer.
-    /// let res = vm.execute_program(mem, &mut mbuff).unwrap();
-    /// assert_eq!(res, 0x2211);
-    /// ```
-    pub fn execute_program(&self, mem: &[u8], mbuff: &[u8]) -> Result<u64, Error> {
-        interpreter::execute_program(self.prog, mem, mbuff, &self.helpers)
-    }
-
-    /// JIT-compile the loaded program. No argument required for this.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// vm.jit_compile();
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub fn jit_compile(&mut self) -> Result<(), Error> {
-        let prog = match self.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-        self.jit = Some(jit::JitMemory::new(prog, &self.helpers, true, false)?);
-        Ok(())
-    }
-
-    /// Execute the previously JIT-compiled program, with the given packet data and metadata
-    /// buffer, in a manner very similar to `execute_program()`.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from the
-    /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
-    /// pointers are correctly stored in the buffer.
-    ///
-    /// # Safety
-    ///
-    /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
-    /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
-    /// very bad (program may segfault). It may be wise to check that the program works with the
-    /// interpreter before running the JIT-compiled version of it.
-    ///
-    /// For this reason the function should be called from within an `unsafe` bloc.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Just for the example we create our metadata buffer from scratch, and we store the
-    /// // pointers to packet data start and end in it.
-    /// let mut mbuff = [0u8; 32];
-    /// unsafe {
-    ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
-    ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-    ///     *data     = mem.as_ptr() as u64;
-    ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    /// }
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// vm.jit_compile();
-    ///
-    /// // Provide both a reference to the packet data, and to the metadata buffer.
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// unsafe {
-    ///     let res = vm.execute_program_jit(mem, &mut mbuff).unwrap();
-    ///     assert_eq!(res, 0x2211);
-    /// }
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub unsafe fn execute_program_jit(
-        &self,
-        mem: &mut [u8],
-        mbuff: &'a mut [u8],
-    ) -> Result<u64, Error> {
-        // If packet data is empty, do not send the address of an empty slice; send a null pointer
-        //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
-        //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
-        //  See `mul_loop` test.
-        let mem_ptr = match mem.len() {
-            0 => std::ptr::null_mut(),
-            _ => mem.as_ptr() as *mut u8,
-        };
-        // The last two arguments are not used in this function. They would be used if there was a
-        // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
-        // should be stored; this is what happens with struct EbpfVmFixedMbuff.
-        match &self.jit {
-            Some(jit) => Ok(jit.get_prog()(
-                mbuff.as_ptr() as *mut u8,
-                mbuff.len(),
-                mem_ptr,
-                mem.len(),
-                0,
-                0,
-            )),
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: program has not been JIT-compiled",
-            )),
-        }
-    }
-
-    /// Compile the loaded program using the Cranelift JIT.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
-        use crate::cranelift::CraneliftCompiler;
-
-        let prog = match self.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-
-        let mut compiler = CraneliftCompiler::new(self.helpers.clone());
-        let program = compiler.compile_function(prog)?;
-
-        self.cranelift_prog = Some(program);
-        Ok(())
-    }
-
-    /// Execute the previously compiled program, with the given packet data and metadata
-    /// buffer, in a manner very similar to `execute_program()`.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from the
-    /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
-    /// pointers are correctly stored in the buffer.
-    ///
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
-    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Just for the example we create our metadata buffer from scratch, and we store the
-    /// // pointers to packet data start and end in it.
-    /// let mut mbuff = [0u8; 32];
-    /// unsafe {
-    ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
-    ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-    ///     *data     = mem.as_ptr() as u64;
-    ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    /// }
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    ///
-    /// // Provide both a reference to the packet data, and to the metadata buffer.
-    /// let res = vm.execute_program_cranelift(mem, &mut mbuff).unwrap();
-    /// assert_eq!(res, 0x2211);
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn execute_program_cranelift(
-        &self,
-        mem: &mut [u8],
-        mbuff: &'a mut [u8],
-    ) -> Result<u64, Error> {
-        // If packet data is empty, do not send the address of an empty slice; send a null pointer
-        //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
-        //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
-        //  See `mul_loop` test.
-        let mem_ptr = match mem.len() {
-            0 => core::ptr::null_mut(),
-            _ => mem.as_ptr() as *mut u8,
-        };
-
-        // The last two arguments are not used in this function. They would be used if there was a
-        // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
-        // should be stored; this is what happens with struct EbpfVmFixedMbuff.
-        match &self.cranelift_prog {
-            Some(prog) => {
-                Ok(prog.execute(mem_ptr, mem.len(), mbuff.as_ptr() as *mut u8, mbuff.len()))
-            }
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: program has not been compiled with cranelift",
-            )),
-        }
-    }
-}
-
-/// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
-/// on a metadata buffer containing pointers to packet data, but it internally handles the buffer
-/// so as to save the effort to manually handle the metadata buffer for the user.
-///
-/// This struct implements a static internal buffer that is passed to the program. The user has to
-/// indicate the offset values at which the eBPF program expects to find the start and the end of
-/// packet data in the buffer. On calling the `execute_program()` or `execute_program_jit()` functions, the
-/// struct automatically updates the addresses in this static buffer, at the appointed offsets, for
-/// the start and the end of the packet data the program is called upon.
-///
-/// # Examples
-///
-/// This was compiled with clang from the following program, in C:
-///
-/// ```c
-/// #include <linux/bpf.h>
-/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
-///
-/// SEC(".classifier")
-/// int classifier(struct __sk_buff *skb)
-/// {
-///   void *data = (void *)(long)skb->data;
-///   void *data_end = (void *)(long)skb->data_end;
-///
-///   // Check program is long enough.
-///   if (data + 5 > data_end)
-///     return 0;
-///
-///   return *((char *)data + 5);
-/// }
-/// ```
-///
-/// Some small modifications have been brought to have it work, see comments.
-///
-/// ```
-/// let prog = &[
-///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-///     // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
-///     // Also, offset 0x4c had to be replace with e.g. 0x40 so as to prevent the two pointers
-///     // from overlapping in the buffer.
-///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load pointer to mem from r1[0x40] to r2
-///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-///     // Here opcode 0x61 had to be replace by 0x79 so as to load a 8-bytes long address.
-///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load ptr to mem_end from r1[0x50] to r1
-///     0x2d, 0x12, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-///     0x67, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 >>= 56
-///     0xc7, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, // r0 <<= 56 (arsh) extend byte sign to u64
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-/// ];
-/// let mem1 = &mut [
-///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-/// ];
-/// let mem2 = &mut [
-///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
-/// ];
-///
-/// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-/// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-///
-/// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-/// let res = vm.execute_program(mem1).unwrap();
-/// assert_eq!(res, 0xffffffffffffffdd);
-///
-/// let res = vm.execute_program(mem2).unwrap();
-/// assert_eq!(res, 0x27);
-/// ```
-pub struct EbpfVmFixedMbuff<'a> {
-    parent: EbpfVmMbuff<'a>,
-    mbuff: MetaBuff,
-}
-
-impl<'a> EbpfVmFixedMbuff<'a> {
-    /// Create a new virtual machine instance, and load an eBPF program into that instance.
-    /// When attempting to load the program, it passes through a simple verifier.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    /// ```
-    pub fn new(
-        prog: Option<&'a [u8]>,
-        data_offset: usize,
-        data_end_offset: usize,
-    ) -> Result<EbpfVmFixedMbuff<'a>, Error> {
-        let parent = EbpfVmMbuff::new(prog)?;
-        let get_buff_len = |x: usize, y: usize| if x >= y { x + 8 } else { y + 8 };
-        let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
-        let mbuff = MetaBuff {
-            data_offset,
-            data_end_offset,
-            buffer,
-        };
-        Ok(EbpfVmFixedMbuff { parent, mbuff })
-    }
-
-    /// Load a new eBPF program into the virtual machine instance.
-    ///
-    /// At the same time, load new offsets for storing pointers to start and end of packet data in
-    /// the internal metadata buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let prog2 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog1), 0, 0).unwrap();
-    /// vm.set_program(prog2, 0x40, 0x50);
-    ///
-    /// let res = vm.execute_program(mem).unwrap();
-    /// assert_eq!(res, 0x27);
-    /// ```
-    pub fn set_program(
-        &mut self,
-        prog: &'a [u8],
-        data_offset: usize,
-        data_end_offset: usize,
-    ) -> Result<(), Error> {
-        let get_buff_len = |x: usize, y: usize| if x >= y { x + 8 } else { y + 8 };
-        let buffer = vec![0u8; get_buff_len(data_offset, data_end_offset)];
-        self.mbuff.buffer = buffer;
-        self.mbuff.data_offset = data_offset;
-        self.mbuff.data_end_offset = data_end_offset;
-        self.parent.set_program(prog)?;
-        Ok(())
-    }
-
-    /// Set a new verifier function. The function should return an `Error` if the program should be
-    /// rejected by the virtual machine. If a program has been loaded to the VM already, the
-    /// verifier is immediately run.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::{Error, ErrorKind};
-    /// use rbpf::ebpf;
-    ///
-    /// // Define a simple verifier function.
-    /// fn verifier(prog: &[u8]) -> Result<(), Error> {
-    ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
-    ///     if last_insn.opc != ebpf::EXIT {
-    ///         return Err(Error::new(ErrorKind::Other,
-    ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
-    ///     }
-    ///     Ok(())
-    /// }
-    ///
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
-    /// // Change the verifier.
-    /// vm.set_verifier(verifier).unwrap();
-    /// ```
-    pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
-        self.parent.set_verifier(verifier)
-    }
-
-    /// Register a built-in or user-defined helper function in order to use it later from within
-    /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
-    ///
-    /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
-    /// program. You should be able to change registered helpers after compiling, but not to add
-    /// new ones (i.e. with new keys).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #[cfg(feature = "std")] {
-    ///     use rbpf::helpers;
-    ///
-    ///     // This program was compiled with clang, from a C program containing the following single
-    ///     // instruction: `return bpf_trace_printk("foo %c %c %c\n", 10, 1, 2, 3);`
-    ///     let prog = &[
-    ///         0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///         0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///         0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///         0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///         0x2d, 0x12, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 6 instructions
-    ///         0x71, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r1
-    ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
-    ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
-    ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
-    ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
-    ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
-    ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    ///     ];
-    ///
-    ///     let mem = &mut [
-    ///         0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x09,
-    ///     ];
-    ///
-    ///     // Instantiate a VM.
-    ///     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
-    ///     vm.register_helper(1, helpers::sqrti);
-    ///
-    ///     let res = vm.execute_program(mem).unwrap();
-    ///     assert_eq!(res, 3);
-    /// }
-    /// ```
-    pub fn register_helper(
-        &mut self,
-        key: u32,
-        function: fn(u64, u64, u64, u64, u64) -> u64,
-    ) -> Result<(), Error> {
-        self.parent.register_helper(key, function)
-    }
-
-    /// Execute the program loaded, with the given packet data.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from some
-    /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
-    /// the addresses should be placed should have be set at the creation of the VM.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-    /// let res = vm.execute_program(mem).unwrap();
-    /// assert_eq!(res, 0xdd);
-    /// ```
-    pub fn execute_program(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        let l = self.mbuff.buffer.len();
-        // Can this ever happen? Probably not, should be ensured at mbuff creation.
-        if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
-            Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
-            l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
-        }
-        LittleEndian::write_u64(
-            &mut self.mbuff.buffer[(self.mbuff.data_offset)..],
-            mem.as_ptr() as u64,
-        );
-        LittleEndian::write_u64(
-            &mut self.mbuff.buffer[(self.mbuff.data_end_offset)..],
-            mem.as_ptr() as u64 + mem.len() as u64,
-        );
-        self.parent.execute_program(mem, &self.mbuff.buffer)
-    }
-
-    /// JIT-compile the loaded program. No argument required for this.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    /// vm.jit_compile();
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub fn jit_compile(&mut self) -> Result<(), Error> {
-        let prog = match self.parent.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-        self.parent.jit = Some(jit::JitMemory::new(prog, &self.parent.helpers, true, true)?);
-        Ok(())
-    }
-
-    /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
-    /// similar to `execute_program()`.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from some
-    /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
-    /// the addresses should be placed should have be set at the creation of the VM.
-    ///
-    /// # Safety
-    ///
-    /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
-    /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
-    /// very bad (program may segfault). It may be wise to check that the program works with the
-    /// interpreter before running the JIT-compiled version of it.
-    ///
-    /// For this reason the function should be called from within an `unsafe` bloc.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// vm.jit_compile();
-    ///
-    /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// unsafe {
-    ///     let res = vm.execute_program_jit(mem).unwrap();
-    ///     assert_eq!(res, 0xdd);
-    /// }
-    /// ```
-    // This struct redefines the `execute_program_jit()` function, in order to pass the offsets
-    // associated with the fixed mbuff.
-    #[cfg(all(not(windows), feature = "std"))]
-    pub unsafe fn execute_program_jit(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        // If packet data is empty, do not send the address of an empty slice; send a null pointer
-        //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
-        //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
-        //  See `mul_loop` test.
-        let mem_ptr = match mem.len() {
-            0 => core::ptr::null_mut(),
-            _ => mem.as_ptr() as *mut u8,
-        };
-
-        match &self.parent.jit {
-            Some(jit) => Ok(jit.get_prog()(
-                self.mbuff.buffer.as_ptr() as *mut u8,
-                self.mbuff.buffer.len(),
-                mem_ptr,
-                mem.len(),
-                self.mbuff.data_offset,
-                self.mbuff.data_end_offset,
-            )),
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: program has not been JIT-compiled",
-            )),
-        }
-    }
-
-    /// Compile the loaded program using the Cranelift JIT.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
-        use crate::cranelift::CraneliftCompiler;
-
-        let prog = match self.parent.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-
-        let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
-        let program = compiler.compile_function(prog)?;
-
-        self.parent.cranelift_prog = Some(program);
-        Ok(())
-    }
-
-    /// Execute the previously compiled program, with the given packet data and metadata
-    /// buffer, in a manner very similar to `execute_program()`.
-    ///
-    /// If the program is made to be compatible with Linux kernel, it is expected to load the
-    /// address of the beginning and of the end of the memory area used for packet data from some
-    /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
-    /// the addresses should be placed should have be set at the creation of the VM.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
-    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
-    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
-    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
-    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-    /// ];
-    ///
-    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
-    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    ///
-    /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-    /// let res = vm.execute_program_cranelift(mem).unwrap();
-    /// assert_eq!(res, 0xdd);
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn execute_program_cranelift(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        // If packet data is empty, do not send the address of an empty slice; send a null pointer
-        //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
-        //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
-        //  See `mul_loop` test.
-        let mem_ptr = match mem.len() {
-            0 => core::ptr::null_mut(),
-            _ => mem.as_ptr() as *mut u8,
-        };
-
-        let l = self.mbuff.buffer.len();
-        // Can this ever happen? Probably not, should be ensured at mbuff creation.
-        if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
-            Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
-            l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
-        }
-        LittleEndian::write_u64(
-            &mut self.mbuff.buffer[(self.mbuff.data_offset)..],
-            mem.as_ptr() as u64,
-        );
-        LittleEndian::write_u64(
-            &mut self.mbuff.buffer[(self.mbuff.data_end_offset)..],
-            mem.as_ptr() as u64 + mem.len() as u64,
-        );
-
-        match &self.parent.cranelift_prog {
-            Some(prog) => Ok(prog.execute(
-                mem_ptr,
-                mem.len(),
-                self.mbuff.buffer.as_ptr() as *mut u8,
-                self.mbuff.buffer.len(),
-            )),
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: program has not been compiled with cranelift",
-            )),
-        }
-    }
-}
-
-/// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
-/// directly on the memory area representing packet data.
-///
-/// # Examples
-///
-/// ```
-/// let prog = &[
-///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-/// ];
-/// let mem = &mut [
-///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
-/// ];
-///
-/// // Instantiate a VM.
-/// let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-///
-/// // Provide only a reference to the packet data.
-/// let res = vm.execute_program(mem).unwrap();
-/// assert_eq!(res, 0x22cc);
-/// ```
-pub struct EbpfVmRaw<'a> {
-    parent: EbpfVmMbuff<'a>,
-}
-
-impl<'a> EbpfVmRaw<'a> {
-    /// Create a new virtual machine instance, and load an eBPF program into that instance.
-    /// When attempting to load the program, it passes through a simple verifier.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    /// ```
-    pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmRaw<'a>, Error> {
-        let parent = EbpfVmMbuff::new(prog)?;
-        Ok(EbpfVmRaw { parent })
-    }
-
-    /// Load a new eBPF program into the virtual machine instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let prog2 = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27,
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog1)).unwrap();
-    /// vm.set_program(prog2);
-    ///
-    /// let res = vm.execute_program(mem).unwrap();
-    /// assert_eq!(res, 0x22cc);
-    /// ```
-    pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
-        self.parent.set_program(prog)?;
-        Ok(())
-    }
-
-    /// Set a new verifier function. The function should return an `Error` if the program should be
-    /// rejected by the virtual machine. If a program has been loaded to the VM already, the
-    /// verifier is immediately run.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::{Error, ErrorKind};
-    /// use rbpf::ebpf;
-    ///
-    /// // Define a simple verifier function.
-    /// fn verifier(prog: &[u8]) -> Result<(), Error> {
-    ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
-    ///     if last_insn.opc != ebpf::EXIT {
-    ///         return Err(Error::new(ErrorKind::Other,
-    ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
-    ///     }
-    ///     Ok(())
-    /// }
-    ///
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
-    /// // Change the verifier.
-    /// vm.set_verifier(verifier).unwrap();
-    /// ```
-    pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
-        self.parent.set_verifier(verifier)
-    }
-
-    /// Register a built-in or user-defined helper function in order to use it later from within
-    /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
-    ///
-    /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
-    /// program. You should be able to change registered helpers after compiling, but not to add
-    /// new ones (i.e. with new keys).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #[cfg(feature = "std")] {
-    ///     use rbpf::helpers;
-    ///
-    ///     let prog = &[
-    ///         0x79, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxdw r1, r1[0x00]
-    ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
-    ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
-    ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
-    ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
-    ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
-    ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    ///     ];
-    ///
-    ///     let mem = &mut [
-    ///         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
-    ///     ];
-    ///
-    ///     // Instantiate a VM.
-    ///     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
-    ///     vm.register_helper(1, helpers::sqrti);
-    ///
-    ///     let res = vm.execute_program(mem).unwrap();
-    ///     assert_eq!(res, 0x10000000);
-    /// }
-    /// ```
-    pub fn register_helper(
-        &mut self,
-        key: u32,
-        function: fn(u64, u64, u64, u64, u64) -> u64,
-    ) -> Result<(), Error> {
-        self.parent.register_helper(key, function)
-    }
-
-    /// Register a set of built-in or user-defined helper functions in order to use them later from
-    /// within the eBPF program. The helpers are registered into a hashmap, so the `key` can be any
-    /// `u32`.
-    #[allow(clippy::type_complexity)]
-    pub fn register_helper_set(
-        &mut self,
-        helpers: &HashMap<u32, fn(u64, u64, u64, u64, u64) -> u64>,
-    ) -> Result<(), Error> {
-        for (key, function) in helpers {
-            self.parent.register_helper(*key, *function)?;
-        }
-        Ok(())
-    }
-
-    /// Execute the program loaded, with the given packet data.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    /// let res = vm.execute_program(mem).unwrap();
-    /// assert_eq!(res, 0x22cc);
-    /// ```
-    pub fn execute_program(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        self.parent.execute_program(mem, &[])
-    }
-
-    /// JIT-compile the loaded program. No argument required for this.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    /// vm.jit_compile();
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub fn jit_compile(&mut self) -> Result<(), Error> {
-        let prog = match self.parent.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-        self.parent.jit = Some(jit::JitMemory::new(
-            prog,
-            &self.parent.helpers,
-            false,
-            false,
-        )?);
-        Ok(())
-    }
-
-    /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
-    /// similar to `execute_program()`.
-    ///
-    /// # Safety
-    ///
-    /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
-    /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
-    /// very bad (program may segfault). It may be wise to check that the program works with the
-    /// interpreter before running the JIT-compiled version of it.
-    ///
-    /// For this reason the function should be called from within an `unsafe` bloc.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// vm.jit_compile();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// unsafe {
-    ///     let res = vm.execute_program_jit(mem).unwrap();
-    ///     assert_eq!(res, 0x22cc);
-    /// }
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub unsafe fn execute_program_jit(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        let mut mbuff = vec![];
-        self.parent.execute_program_jit(mem, &mut mbuff)
-    }
-
-    /// Compile the loaded program using the Cranelift JIT.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
-        use crate::cranelift::CraneliftCompiler;
-
-        let prog = match self.parent.prog {
-            Some(prog) => prog,
-            None => Err(Error::new(
-                ErrorKind::Other,
-                "Error: No program set, call prog_set() to load one",
-            ))?,
-        };
-
-        let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
-        let program = compiler.compile_function(prog)?;
-
-        self.parent.cranelift_prog = Some(program);
-        Ok(())
-    }
-
-    /// Execute the previously compiled program, with the given packet data, in a manner very
-    /// similar to `execute_program()`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
-    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
-    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mem = &mut [
-    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    ///
-    /// let res = vm.execute_program_cranelift(mem).unwrap();
-    /// assert_eq!(res, 0x22cc);
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn execute_program_cranelift(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
-        let mut mbuff = vec![];
-        self.parent.execute_program_cranelift(mem, &mut mbuff)
-    }
-}
-
-/// A virtual machine to run eBPF program. This kind of VM is used for programs that do not work
-/// with any memory area—no metadata buffer, no packet data either.
-///
-/// # Examples
-///
-/// ```
-/// let prog = &[
-///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-///     0xb7, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r1, 1
-///     0xb7, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r2, 2
-///     0xb7, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r3, 3
-///     0xb7, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // mov r4, 4
-///     0xb7, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // mov r5, 5
-///     0xb7, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // mov r6, 6
-///     0xb7, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, // mov r7, 7
-///     0xb7, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // mov r8, 8
-///     0x4f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // or r0, r5
-///     0x47, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, // or r0, 0xa0
-///     0x57, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, // and r0, 0xa3
-///     0xb7, 0x09, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, // mov r9, 0x91
-///     0x5f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // and r0, r9
-///     0x67, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // lsh r0, 32
-///     0x67, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, // lsh r0, 22
-///     0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // lsh r0, r8
-///     0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // rsh r0, 32
-///     0x77, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, // rsh r0, 19
-///     0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // rsh r0, r7
-///     0xa7, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // xor r0, 0x03
-///     0xaf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xor r0, r2
-///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-/// ];
-///
-/// // Instantiate a VM.
-/// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-///
-/// // Provide only a reference to the packet data.
-/// let res = vm.execute_program().unwrap();
-/// assert_eq!(res, 0x11);
-/// ```
-pub struct EbpfVmNoData<'a> {
-    parent: EbpfVmRaw<'a>,
-}
-
-impl<'a> EbpfVmNoData<'a> {
-    /// Create a new virtual machine instance, and load an eBPF program into that instance.
-    /// When attempting to load the program, it passes through a simple verifier.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let vm = rbpf::EbpfVmNoData::new(Some(prog));
-    /// ```
-    pub fn new(prog: Option<&'a [u8]>) -> Result<EbpfVmNoData<'a>, Error> {
-        let parent = EbpfVmRaw::new(prog)?;
-        Ok(EbpfVmNoData { parent })
-    }
-
-    /// Load a new eBPF program into the virtual machine instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    /// let prog2 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();
-    ///
-    /// let res = vm.execute_program().unwrap();
-    /// assert_eq!(res, 0x2211);
-    ///
-    /// vm.set_program(prog2);
-    ///
-    /// let res = vm.execute_program().unwrap();
-    /// assert_eq!(res, 0x1122);
-    /// ```
-    pub fn set_program(&mut self, prog: &'a [u8]) -> Result<(), Error> {
-        self.parent.set_program(prog)?;
-        Ok(())
-    }
-
-    /// Set a new verifier function. The function should return an `Error` if the program should be
-    /// rejected by the virtual machine. If a program has been loaded to the VM already, the
-    /// verifier is immediately run.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use rbpf::{Error, ErrorKind};
-    /// use rbpf::ebpf;
-    ///
-    /// // Define a simple verifier function.
-    /// fn verifier(prog: &[u8]) -> Result<(), Error> {
-    ///     let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
-    ///     if last_insn.opc != ebpf::EXIT {
-    ///         return Err(Error::new(ErrorKind::Other,
-    ///                    "[Verifier] Error: program does not end with “EXIT” instruction"));
-    ///     }
-    ///     Ok(())
-    /// }
-    ///
-    /// let prog1 = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// // Instantiate a VM.
-    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
-    /// // Change the verifier.
-    /// vm.set_verifier(verifier).unwrap();
-    /// ```
-    pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
-        self.parent.set_verifier(verifier)
-    }
-
-    /// Register a built-in or user-defined helper function in order to use it later from within
-    /// the eBPF program. The helper is registered into a hashmap, so the `key` can be any `u32`.
-    ///
-    /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the
-    /// program. You should be able to change registered helpers after compiling, but not to add
-    /// new ones (i.e. with new keys).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #[cfg(feature = "std")] {
-    ///     use rbpf::helpers;
-    ///
-    ///     let prog = &[
-    ///         0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // mov r1, 0x010000000
-    ///         0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
-    ///         0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
-    ///         0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
-    ///         0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
-    ///         0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
-    ///         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    ///     ];
-    ///
-    ///     let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    ///     // Register a helper. This helper will store the result of the square root of r1 into r0.
-    ///     vm.register_helper(1, helpers::sqrti).unwrap();
-    ///
-    ///     let res = vm.execute_program().unwrap();
-    ///     assert_eq!(res, 0x1000);
-    /// }
-    /// ```
-    pub fn register_helper(
-        &mut self,
-        key: u32,
-        function: fn(u64, u64, u64, u64, u64) -> u64,
-    ) -> Result<(), Error> {
-        self.parent.register_helper(key, function)
-    }
-
-    /// JIT-compile the loaded program. No argument required for this.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    ///
-    /// vm.jit_compile();
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub fn jit_compile(&mut self) -> Result<(), Error> {
-        self.parent.jit_compile()
-    }
-
-    /// Execute the program loaded, without providing pointers to any memory area whatsoever.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    /// // For this kind of VM, the `execute_program()` function needs no argument.
-    /// let res = vm.execute_program().unwrap();
-    /// assert_eq!(res, 0x1122);
-    /// ```
-    pub fn execute_program(&self) -> Result<u64, Error> {
-        self.parent.execute_program(&mut [])
-    }
-
-    /// Execute the previously JIT-compiled program, without providing pointers to any memory area
-    /// whatsoever, in a manner very similar to `execute_program()`.
-    ///
-    /// # Safety
-    ///
-    /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
-    /// check for memory access; so if the eBPF program attempts erroneous accesses, this may end
-    /// very bad (program may segfault). It may be wise to check that the program works with the
-    /// interpreter before running the JIT-compiled version of it.
-    ///
-    /// For this reason the function should be called from within an `unsafe` bloc.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// vm.jit_compile();
-    ///
-    /// # #[cfg(all(not(windows), feature = "std"))]
-    /// unsafe {
-    ///     let res = vm.execute_program_jit().unwrap();
-    ///     assert_eq!(res, 0x1122);
-    /// }
-    /// ```
-    #[cfg(all(not(windows), feature = "std"))]
-    pub unsafe fn execute_program_jit(&self) -> Result<u64, Error> {
-        self.parent.execute_program_jit(&mut [])
-    }
-
-    /// Compile the loaded program using the Cranelift JIT.
-    ///
-    /// If using helper functions, be sure to register them into the VM before calling this
-    /// function.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    ///
-    /// vm.cranelift_compile();
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
-        self.parent.cranelift_compile()
-    }
-
-    /// Execute the previously JIT-compiled program, without providing pointers to any memory area
-    /// whatsoever, in a manner very similar to `execute_program()`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let prog = &[
-    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
-    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
-    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
-    /// ];
-    ///
-    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    ///
-    /// vm.cranelift_compile();
-    ///
-    /// let res = vm.execute_program_cranelift().unwrap();
-    /// assert_eq!(res, 0x1122);
-    /// ```
-    #[cfg(feature = "cranelift")]
-    pub fn execute_program_cranelift(&self) -> Result<u64, Error> {
-        self.parent.execute_program_cranelift(&mut [])
-    }
-}
-
-/// EbpfVm with Owned data
-pub struct EbpfVmRawOwned {
-    parent: EbpfVmRaw<'static>,
-    data_len: usize,
-    data_cap: usize,
-}
-
-impl EbpfVmRawOwned {
-    /// Create a new virtual machine instance, and load an eBPF program into that instance.
-    /// When attempting to load the program, it passes through a simple verifier.
-    pub fn new(prog: Option<Vec<u8>>) -> Result<EbpfVmRawOwned, Error> {
-        let (prog, data_len, data_cap) = match prog {
-            Some(prog) => {
-                let data_len = prog.len();
-                let data_cap = prog.capacity();
-                let slice = prog.leak();
-                let slice = unsafe { core::slice::from_raw_parts(slice.as_ptr(), data_len) };
-                (Some(slice), data_len, data_cap)
-            }
-            None => (None, 0, 0),
-        };
-        let parent = EbpfVmRaw::new(prog)?;
-        Ok(Self {
-            parent,
-            data_len,
-            data_cap,
-        })
-    }
-    /// Load a new eBPF program into the virtual machine instance
-    pub fn set_program(&mut self, prog: Vec<u8>) -> Result<(), Error> {
-        self.data_len = prog.len();
-        self.data_cap = prog.capacity();
-        let slice = prog.leak();
-        self.parent.set_program(slice)?;
-        Ok(())
-    }
-
-    /// Set a new verifier function. The function should return an Error if the program should be rejected by the virtual machine.
-    /// If a program has been loaded to the VM already, the verifier is immediately run.
-    pub fn set_verifier(&mut self, verifier: Verifier) -> Result<(), Error> {
-        self.parent.set_verifier(verifier)
-    }
-
-    /// Register a built-in or user-defined helper function in order to use it later from within the eBPF program.
-    /// The helper is registered into a hashmap, so the key can be any u32.
-    /// If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the program.
-    /// You should be able to change registered helpers after compiling, but not to add new ones (i. e. with new keys).
-    pub fn register_helper(
-        &mut self,
-        key: u32,
-        function: fn(u64, u64, u64, u64, u64) -> u64,
-    ) -> Result<(), Error> {
-        self.parent.register_helper(key, function)
-    }
-
-    /// Register a set of built-in or user-defined helper functions in order to use them later from
-    /// within the eBPF program. The helpers are registered into a hashmap, so the `key` can be any
-    /// `u32`.
-    #[allow(clippy::type_complexity)]
-    pub fn register_helper_set(
-        &mut self,
-        helpers: &HashMap<u32, fn(u64, u64, u64, u64, u64) -> u64>,
-    ) -> Result<(), Error> {
-        for (key, function) in helpers {
-            self.parent.register_helper(*key, *function)?;
-        }
-        Ok(())
-    }
-
-    /// Execute the previously JIT-compiled program, with the given packet data, in a manner very similar to execute_program().
-    ///
-    /// Safety
-    ///
-    /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime check for memory access;
-    /// so if the eBPF program attempts erroneous accesses, this may end very bad (program may segfault).
-    /// It may be wise to check that the program works with the interpreter before running the JIT-compiled version of it.
-    ///
-    /// For this reason the function should be called from within an unsafe bloc.
-    pub fn execute_program(&self, mem: &mut [u8]) -> Result<u64, Error> {
-        self.parent.execute_program(mem)
-    }
-}
-
-impl Drop for EbpfVmRawOwned {
-    fn drop(&mut self) {
-        match self.parent.parent.prog {
-            Some(prog) => unsafe {
-                let ptr = prog.as_ptr();
-                let _prog = Vec::from_raw_parts(ptr as *mut u8, self.data_len, self.data_cap);
-            },
-            None => {}
-        };
-    }
-}

+ 0 - 41
kernel/crates/rbpf/src/no_std_error.rs

@@ -1,41 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-//! This module provides a simple implementation of the Error struct that is
-//! used as a drop-in replacement for `std::io::Error` when using `rbpf` in `no_std`.
-
-use alloc::string::String;
-
-/// Implementation of Error for no_std applications.
-/// Ensures that the existing code can use it with the same interface
-/// as the Error from std::io::Error.
-#[derive(Debug)]
-pub struct Error {
-    #[allow(dead_code)]
-    kind: ErrorKind,
-    #[allow(dead_code)]
-    error: String,
-}
-
-impl Error {
-    /// New function exposing the same signature as `std::io::Error::new`.
-    #[allow(dead_code)]
-    pub fn new<S: Into<String>>(kind: ErrorKind, error: S) -> Error {
-        Error {
-            kind,
-            error: error.into(),
-        }
-    }
-}
-
-/// The current version of `rbpf` only uses the [`Other`](ErrorKind::Other) variant
-/// from the [std::io::ErrorKind] enum. If a dependency on other variants were
-/// introduced in the future, this enum needs to be updated accordingly to maintain
-/// compatibility with the real `ErrorKind`. The reason all available variants
-/// aren't included in the first place is that [std::io::ErrorKind] exposes
-/// 40 variants, and not all of them are meaningful under `no_std`.
-#[derive(Debug)]
-pub enum ErrorKind {
-    /// The no_std code only uses this variant.
-    #[allow(dead_code)]
-    Other,
-}

+ 0 - 75
kernel/crates/rbpf/src/stack.rs

@@ -1,75 +0,0 @@
-use crate::{ebpf::STACK_SIZE, vec, Vec};
-
-pub struct StackFrame {
-    return_address: u64,
-    saved_registers: [u64; 4],
-    sp: u64,
-    frame: Vec<u8>,
-}
-
-impl StackFrame {
-    /// Create a new stack frame
-    ///
-    /// The stack frame is created with a capacity of `STACK_SIZE` == 512 bytes
-    pub fn new() -> Self {
-        Self {
-            sp: 0,
-            return_address: 0,
-            saved_registers: [0; 4],
-            frame: vec![0; STACK_SIZE],
-        }
-    }
-
-    /// Create a new stack frame with a given capacity
-    #[allow(unused)]
-    pub fn with_capacity(capacity: usize) -> Self {
-        Self {
-            sp: 0,
-            return_address: 0,
-            saved_registers: [0; 4],
-            frame: vec![0; capacity],
-        }
-    }
-
-    /// The capacity of the stack frame
-    pub fn len(&self) -> usize {
-        self.frame.len()
-    }
-
-    pub fn as_ptr(&self) -> *const u8 {
-        self.frame.as_ptr()
-    }
-
-    pub fn as_slice(&self) -> &[u8] {
-        self.frame.as_slice()
-    }
-    /// Save the callee-saved registers
-    pub fn save_registers(&mut self, regs: &[u64]) {
-        self.saved_registers.copy_from_slice(regs);
-    }
-
-    /// Get the callee-saved registers
-    pub fn get_registers(&self) -> [u64; 4] {
-        self.saved_registers
-    }
-
-    /// Save the return address
-    pub fn save_return_address(&mut self, address: u64) {
-        self.return_address = address;
-    }
-
-    /// Get the return address
-    pub fn get_return_address(&self) -> u64 {
-        self.return_address
-    }
-
-    /// Save the stack pointer
-    pub fn save_sp(&mut self, sp: u64) {
-        self.sp = sp;
-    }
-
-    /// Get the stack pointer
-    pub fn get_sp(&self) -> u64 {
-        self.sp
-    }
-}

+ 0 - 386
kernel/crates/rbpf/src/verifier.rs

@@ -1,386 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Derived from uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-//      (uBPF: safety checks, originally in C)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-//      (Translation to Rust)
-
-// This “verifier” performs simple checks when the eBPF program is loaded into the VM (before it is
-// interpreted or JIT-compiled). It has nothing to do with the much more elaborated verifier inside
-// Linux kernel. There is no verification regarding the program flow control (should be a Direct
-// Acyclic Graph) or the consistency for registers usage (the verifier of the kernel assigns types
-// to the registers and is much stricter).
-//
-// On the other hand, rbpf is not expected to run in kernel space.
-//
-// Improving the verifier would be nice, but this is not trivial (and Linux kernel is under GPL
-// license, so we cannot copy it).
-//
-// Contrary to the verifier of the Linux kernel, this one does not modify the bytecode at all.
-
-use alloc::format;
-
-use crate::{ebpf, Error, ErrorKind};
-
-fn reject<S: AsRef<str>>(msg: S) -> Result<(), Error> {
-    let full_msg = format!("[Verifier] Error: {}", msg.as_ref());
-    Err(Error::new(ErrorKind::Other, full_msg))
-}
-
-fn check_prog_len(prog: &[u8]) -> Result<(), Error> {
-    if prog.len() % ebpf::INSN_SIZE != 0 {
-        reject(format!(
-            "eBPF program length must be a multiple of {:?} octets",
-            ebpf::INSN_SIZE
-        ))?;
-    }
-    if prog.len() > ebpf::PROG_MAX_SIZE {
-        reject(format!(
-            "eBPF program length limited to {:?}, here {:?}",
-            ebpf::PROG_MAX_INSNS,
-            prog.len() / ebpf::INSN_SIZE
-        ))?;
-    }
-
-    if prog.is_empty() {
-        reject("no program set, call set_program() to load one")?;
-    }
-    let last_opc = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1).opc;
-    if last_opc & ebpf::BPF_CLS_MASK != ebpf::BPF_JMP {
-        reject("program does not end with “EXIT” instruction")?;
-    }
-
-    Ok(())
-}
-
-fn check_imm_endian(insn: &ebpf::Insn, insn_ptr: usize) -> Result<(), Error> {
-    match insn.imm {
-        16 | 32 | 64 => Ok(()),
-        _ => reject(format!(
-            "unsupported argument for LE/BE (insn #{insn_ptr:?})"
-        )),
-    }
-}
-
-fn check_load_dw(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
-    // We know we can reach next insn since we enforce an EXIT insn at the end of program, while
-    // this function should be called only for LD_DW insn, that cannot be last in program.
-    let next_insn = ebpf::get_insn(prog, insn_ptr + 1);
-    if next_insn.opc != 0 {
-        reject(format!("incomplete LD_DW instruction (insn #{insn_ptr:?})"))?;
-    }
-
-    Ok(())
-}
-
-fn check_jmp_offset(prog: &[u8], insn_ptr: usize) -> Result<(), Error> {
-    let insn = ebpf::get_insn(prog, insn_ptr);
-    if insn.off == -1 {
-        reject(format!("infinite loop (insn #{insn_ptr:?})"))?;
-    }
-
-    let dst_insn_ptr = insn_ptr as isize + 1 + insn.off as isize;
-    if dst_insn_ptr < 0 || dst_insn_ptr as usize >= (prog.len() / ebpf::INSN_SIZE) {
-        reject(format!(
-            "jump out of code to #{dst_insn_ptr:?} (insn #{insn_ptr:?})"
-        ))?;
-    }
-
-    let dst_insn = ebpf::get_insn(prog, dst_insn_ptr as usize);
-    if dst_insn.opc == 0 {
-        reject(format!(
-            "jump to middle of LD_DW at #{dst_insn_ptr:?} (insn #{insn_ptr:?})"
-        ))?;
-    }
-
-    Ok(())
-}
-
-fn check_registers(insn: &ebpf::Insn, store: bool, insn_ptr: usize) -> Result<(), Error> {
-    if insn.src > 10 {
-        reject(format!("invalid source register (insn #{insn_ptr:?})"))?;
-    }
-
-    match (insn.dst, store) {
-        (0..=9, _) | (10, true) => Ok(()),
-        (10, false) => reject(format!(
-            "cannot write into register r10 (insn #{insn_ptr:?})"
-        )),
-        (_, _) => reject(format!("invalid destination register (insn #{insn_ptr:?})")),
-    }
-}
-
-pub fn check(prog: &[u8]) -> Result<(), Error> {
-    check_prog_len(prog)?;
-
-    let mut insn_ptr: usize = 0;
-    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
-        let insn = ebpf::get_insn(prog, insn_ptr);
-        let mut store = false;
-
-        match insn.opc {
-            // BPF_LD class
-            ebpf::LD_ABS_B => {}
-            ebpf::LD_ABS_H => {}
-            ebpf::LD_ABS_W => {}
-            ebpf::LD_ABS_DW => {}
-            ebpf::LD_IND_B => {}
-            ebpf::LD_IND_H => {}
-            ebpf::LD_IND_W => {}
-            ebpf::LD_IND_DW => {}
-
-            ebpf::LD_DW_IMM => {
-                store = true;
-                check_load_dw(prog, insn_ptr)?;
-                insn_ptr += 1;
-            }
-
-            // BPF_LDX class
-            ebpf::LD_B_REG => {}
-            ebpf::LD_H_REG => {}
-            ebpf::LD_W_REG => {}
-            ebpf::LD_DW_REG => {}
-
-            // BPF_ST class
-            ebpf::ST_B_IMM => store = true,
-            ebpf::ST_H_IMM => store = true,
-            ebpf::ST_W_IMM => store = true,
-            ebpf::ST_DW_IMM => store = true,
-
-            // BPF_STX class
-            ebpf::ST_B_REG => store = true,
-            ebpf::ST_H_REG => store = true,
-            ebpf::ST_W_REG => store = true,
-            ebpf::ST_DW_REG => store = true,
-            ebpf::ST_W_XADD => {
-                unimplemented!();
-            }
-            ebpf::ST_DW_XADD => {
-                unimplemented!();
-            }
-
-            // BPF_ALU class
-            ebpf::ADD32_IMM => {}
-            ebpf::ADD32_REG => {}
-            ebpf::SUB32_IMM => {}
-            ebpf::SUB32_REG => {}
-            ebpf::MUL32_IMM => {}
-            ebpf::MUL32_REG => {}
-            ebpf::DIV32_IMM => {}
-            ebpf::DIV32_REG => {}
-            ebpf::OR32_IMM => {}
-            ebpf::OR32_REG => {}
-            ebpf::AND32_IMM => {}
-            ebpf::AND32_REG => {}
-            ebpf::LSH32_IMM => {}
-            ebpf::LSH32_REG => {}
-            ebpf::RSH32_IMM => {}
-            ebpf::RSH32_REG => {}
-            ebpf::NEG32 => {}
-            ebpf::MOD32_IMM => {}
-            ebpf::MOD32_REG => {}
-            ebpf::XOR32_IMM => {}
-            ebpf::XOR32_REG => {}
-            ebpf::MOV32_IMM => {}
-            ebpf::MOV32_REG => {}
-            ebpf::ARSH32_IMM => {}
-            ebpf::ARSH32_REG => {}
-            ebpf::LE => {
-                check_imm_endian(&insn, insn_ptr)?;
-            }
-            ebpf::BE => {
-                check_imm_endian(&insn, insn_ptr)?;
-            }
-
-            // BPF_ALU64 class
-            ebpf::ADD64_IMM => {}
-            ebpf::ADD64_REG => {}
-            ebpf::SUB64_IMM => {}
-            ebpf::SUB64_REG => {}
-            ebpf::MUL64_IMM => {}
-            ebpf::MUL64_REG => {}
-            ebpf::DIV64_IMM => {}
-            ebpf::DIV64_REG => {}
-            ebpf::OR64_IMM => {}
-            ebpf::OR64_REG => {}
-            ebpf::AND64_IMM => {}
-            ebpf::AND64_REG => {}
-            ebpf::LSH64_IMM => {}
-            ebpf::LSH64_REG => {}
-            ebpf::RSH64_IMM => {}
-            ebpf::RSH64_REG => {}
-            ebpf::NEG64 => {}
-            ebpf::MOD64_IMM => {}
-            ebpf::MOD64_REG => {}
-            ebpf::XOR64_IMM => {}
-            ebpf::XOR64_REG => {}
-            ebpf::MOV64_IMM => {}
-            ebpf::MOV64_REG => {}
-            ebpf::ARSH64_IMM => {}
-            ebpf::ARSH64_REG => {}
-
-            // BPF_JMP class
-            ebpf::JA => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JEQ_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JEQ_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGT_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGT_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGE_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGE_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLT_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLT_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLE_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLE_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSET_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSET_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JNE_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JNE_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGT_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGT_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGE_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGE_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLT_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLT_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLE_IMM => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLE_REG => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-
-            // BPF_JMP32 class
-            ebpf::JEQ_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JEQ_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGT_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGT_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGE_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JGE_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLT_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLT_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLE_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JLE_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSET_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSET_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JNE_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JNE_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGT_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGT_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGE_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSGE_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLT_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLT_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLE_IMM32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-            ebpf::JSLE_REG32 => {
-                check_jmp_offset(prog, insn_ptr)?;
-            }
-
-            ebpf::CALL => {}
-            ebpf::TAIL_CALL => {
-                unimplemented!()
-            }
-            ebpf::EXIT => {}
-
-            _ => {
-                reject(format!(
-                    "unknown eBPF opcode {:#2x} (insn #{insn_ptr:?})",
-                    insn.opc
-                ))?;
-            }
-        }
-
-        check_registers(&insn, store, insn_ptr)?;
-
-        insn_ptr += 1;
-    }
-
-    // insn_ptr should now be equal to number of instructions.
-    if insn_ptr != prog.len() / ebpf::INSN_SIZE {
-        reject(format!("jumped out of code to #{insn_ptr:?}"))?;
-    }
-
-    Ok(())
-}

+ 0 - 655
kernel/crates/rbpf/tests/assembler.rs

@@ -1,655 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 Rich Lane <lanerl@gmail.com>
-
-#![allow(clippy::unreadable_literal)]
-
-extern crate rbpf;
-mod common;
-
-use common::{TCP_SACK_ASM, TCP_SACK_BIN};
-use rbpf::{assembler::assemble, ebpf};
-
-fn asm(src: &str) -> Result<Vec<ebpf::Insn>, String> {
-    Ok(ebpf::to_insn_vec(&(assemble(src))?))
-}
-
-fn insn(opc: u8, dst: u8, src: u8, off: i16, imm: i32) -> ebpf::Insn {
-    ebpf::Insn {
-        opc,
-        dst,
-        src,
-        off,
-        imm,
-    }
-}
-
-#[test]
-fn test_empty() {
-    assert_eq!(asm(""), Ok(vec![]));
-}
-
-// Example for InstructionType::NoOperand.
-#[test]
-fn test_exit() {
-    assert_eq!(asm("exit"), Ok(vec![insn(ebpf::EXIT, 0, 0, 0, 0)]));
-}
-
-// Example for InstructionType::AluBinary.
-#[test]
-fn test_add64() {
-    assert_eq!(
-        asm("add64 r1, r3"),
-        Ok(vec![insn(ebpf::ADD64_REG, 1, 3, 0, 0)])
-    );
-    assert_eq!(
-        asm("add64 r1, 5"),
-        Ok(vec![insn(ebpf::ADD64_IMM, 1, 0, 0, 5)])
-    );
-}
-
-// Example for InstructionType::AluUnary.
-#[test]
-fn test_neg64() {
-    assert_eq!(asm("neg64 r1"), Ok(vec![insn(ebpf::NEG64, 1, 0, 0, 0)]));
-}
-
-// Example for InstructionType::LoadReg.
-#[test]
-fn test_ldxw() {
-    assert_eq!(
-        asm("ldxw r1, [r2+5]"),
-        Ok(vec![insn(ebpf::LD_W_REG, 1, 2, 5, 0)])
-    );
-}
-
-// Example for InstructionType::StoreImm.
-#[test]
-fn test_stw() {
-    assert_eq!(
-        asm("stw [r2+5], 7"),
-        Ok(vec![insn(ebpf::ST_W_IMM, 2, 0, 5, 7)])
-    );
-}
-
-// Example for InstructionType::StoreReg.
-#[test]
-fn test_stxw() {
-    assert_eq!(
-        asm("stxw [r2+5], r8"),
-        Ok(vec![insn(ebpf::ST_W_REG, 2, 8, 5, 0)])
-    );
-}
-
-// Example for InstructionType::JumpUnconditional.
-#[test]
-fn test_ja() {
-    assert_eq!(asm("ja +8"), Ok(vec![insn(ebpf::JA, 0, 0, 8, 0)]));
-    assert_eq!(asm("ja -3"), Ok(vec![insn(ebpf::JA, 0, 0, -3, 0)]));
-}
-
-// Example for InstructionType::JumpConditional.
-#[test]
-fn test_jeq() {
-    assert_eq!(
-        asm("jeq r1, 4, +8"),
-        Ok(vec![insn(ebpf::JEQ_IMM, 1, 0, 8, 4)])
-    );
-    assert_eq!(
-        asm("jeq r1, r3, +8"),
-        Ok(vec![insn(ebpf::JEQ_REG, 1, 3, 8, 0)])
-    );
-}
-
-// Example for InstructionType::Call.
-#[test]
-fn test_call() {
-    assert_eq!(asm("call 300"), Ok(vec![insn(ebpf::CALL, 0, 0, 0, 300)]));
-}
-
-// Example for InstructionType::Endian.
-#[test]
-fn test_be32() {
-    assert_eq!(asm("be32 r1"), Ok(vec![insn(ebpf::BE, 1, 0, 0, 32)]));
-}
-
-// Example for InstructionType::LoadImm.
-#[test]
-fn test_lddw() {
-    assert_eq!(
-        asm("lddw r1, 0x1234abcd5678eeff"),
-        Ok(vec![
-            insn(ebpf::LD_DW_IMM, 1, 0, 0, 0x5678eeff),
-            insn(0, 0, 0, 0, 0x1234abcd)
-        ])
-    );
-    assert_eq!(
-        asm("lddw r1, 0xff11ee22dd33cc44"),
-        Ok(vec![
-            insn(ebpf::LD_DW_IMM, 1, 0, 0, 0xdd33cc44u32 as i32),
-            insn(0, 0, 0, 0, 0xff11ee22u32 as i32)
-        ])
-    );
-}
-
-// Example for InstructionType::LoadAbs.
-#[test]
-fn test_ldabsw() {
-    assert_eq!(asm("ldabsw 1"), Ok(vec![insn(ebpf::LD_ABS_W, 0, 0, 0, 1)]));
-}
-
-// Example for InstructionType::LoadInd.
-#[test]
-fn test_ldindw() {
-    assert_eq!(
-        asm("ldindw r1, 2"),
-        Ok(vec![insn(ebpf::LD_IND_W, 0, 1, 0, 2)])
-    );
-}
-
-// Example for InstructionType::LoadReg.
-#[test]
-fn test_ldxdw() {
-    assert_eq!(
-        asm("ldxdw r1, [r2+3]"),
-        Ok(vec![insn(ebpf::LD_DW_REG, 1, 2, 3, 0)])
-    );
-}
-
-// Example for InstructionType::StoreImm.
-#[test]
-fn test_sth() {
-    assert_eq!(
-        asm("sth [r1+2], 3"),
-        Ok(vec![insn(ebpf::ST_H_IMM, 1, 0, 2, 3)])
-    );
-}
-
-// Example for InstructionType::StoreReg.
-#[test]
-fn test_stxh() {
-    assert_eq!(
-        asm("stxh [r1+2], r3"),
-        Ok(vec![insn(ebpf::ST_H_REG, 1, 3, 2, 0)])
-    );
-}
-
-// Test all supported AluBinary mnemonics.
-#[test]
-fn test_alu_binary() {
-    assert_eq!(
-        asm("add r1, r2
-                    sub r1, r2
-                    mul r1, r2
-                    div r1, r2
-                    or r1, r2
-                    and r1, r2
-                    lsh r1, r2
-                    rsh r1, r2
-                    mod r1, r2
-                    xor r1, r2
-                    mov r1, r2
-                    arsh r1, r2"),
-        Ok(vec![
-            insn(ebpf::ADD64_REG, 1, 2, 0, 0),
-            insn(ebpf::SUB64_REG, 1, 2, 0, 0),
-            insn(ebpf::MUL64_REG, 1, 2, 0, 0),
-            insn(ebpf::DIV64_REG, 1, 2, 0, 0),
-            insn(ebpf::OR64_REG, 1, 2, 0, 0),
-            insn(ebpf::AND64_REG, 1, 2, 0, 0),
-            insn(ebpf::LSH64_REG, 1, 2, 0, 0),
-            insn(ebpf::RSH64_REG, 1, 2, 0, 0),
-            insn(ebpf::MOD64_REG, 1, 2, 0, 0),
-            insn(ebpf::XOR64_REG, 1, 2, 0, 0),
-            insn(ebpf::MOV64_REG, 1, 2, 0, 0),
-            insn(ebpf::ARSH64_REG, 1, 2, 0, 0)
-        ])
-    );
-
-    assert_eq!(
-        asm("add r1, 2
-                    sub r1, 2
-                    mul r1, 2
-                    div r1, 2
-                    or r1, 2
-                    and r1, 2
-                    lsh r1, 2
-                    rsh r1, 2
-                    mod r1, 2
-                    xor r1, 2
-                    mov r1, 2
-                    arsh r1, 2"),
-        Ok(vec![
-            insn(ebpf::ADD64_IMM, 1, 0, 0, 2),
-            insn(ebpf::SUB64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MUL64_IMM, 1, 0, 0, 2),
-            insn(ebpf::DIV64_IMM, 1, 0, 0, 2),
-            insn(ebpf::OR64_IMM, 1, 0, 0, 2),
-            insn(ebpf::AND64_IMM, 1, 0, 0, 2),
-            insn(ebpf::LSH64_IMM, 1, 0, 0, 2),
-            insn(ebpf::RSH64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOD64_IMM, 1, 0, 0, 2),
-            insn(ebpf::XOR64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOV64_IMM, 1, 0, 0, 2),
-            insn(ebpf::ARSH64_IMM, 1, 0, 0, 2)
-        ])
-    );
-
-    assert_eq!(
-        asm("add64 r1, r2
-                    sub64 r1, r2
-                    mul64 r1, r2
-                    div64 r1, r2
-                    or64 r1, r2
-                    and64 r1, r2
-                    lsh64 r1, r2
-                    rsh64 r1, r2
-                    mod64 r1, r2
-                    xor64 r1, r2
-                    mov64 r1, r2
-                    arsh64 r1, r2"),
-        Ok(vec![
-            insn(ebpf::ADD64_REG, 1, 2, 0, 0),
-            insn(ebpf::SUB64_REG, 1, 2, 0, 0),
-            insn(ebpf::MUL64_REG, 1, 2, 0, 0),
-            insn(ebpf::DIV64_REG, 1, 2, 0, 0),
-            insn(ebpf::OR64_REG, 1, 2, 0, 0),
-            insn(ebpf::AND64_REG, 1, 2, 0, 0),
-            insn(ebpf::LSH64_REG, 1, 2, 0, 0),
-            insn(ebpf::RSH64_REG, 1, 2, 0, 0),
-            insn(ebpf::MOD64_REG, 1, 2, 0, 0),
-            insn(ebpf::XOR64_REG, 1, 2, 0, 0),
-            insn(ebpf::MOV64_REG, 1, 2, 0, 0),
-            insn(ebpf::ARSH64_REG, 1, 2, 0, 0)
-        ])
-    );
-
-    assert_eq!(
-        asm("add64 r1, 2
-                    sub64 r1, 2
-                    mul64 r1, 2
-                    div64 r1, 2
-                    or64 r1, 2
-                    and64 r1, 2
-                    lsh64 r1, 2
-                    rsh64 r1, 2
-                    mod64 r1, 2
-                    xor64 r1, 2
-                    mov64 r1, 2
-                    arsh64 r1, 2"),
-        Ok(vec![
-            insn(ebpf::ADD64_IMM, 1, 0, 0, 2),
-            insn(ebpf::SUB64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MUL64_IMM, 1, 0, 0, 2),
-            insn(ebpf::DIV64_IMM, 1, 0, 0, 2),
-            insn(ebpf::OR64_IMM, 1, 0, 0, 2),
-            insn(ebpf::AND64_IMM, 1, 0, 0, 2),
-            insn(ebpf::LSH64_IMM, 1, 0, 0, 2),
-            insn(ebpf::RSH64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOD64_IMM, 1, 0, 0, 2),
-            insn(ebpf::XOR64_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOV64_IMM, 1, 0, 0, 2),
-            insn(ebpf::ARSH64_IMM, 1, 0, 0, 2)
-        ])
-    );
-
-    assert_eq!(
-        asm("add32 r1, r2
-                    sub32 r1, r2
-                    mul32 r1, r2
-                    div32 r1, r2
-                    or32 r1, r2
-                    and32 r1, r2
-                    lsh32 r1, r2
-                    rsh32 r1, r2
-                    mod32 r1, r2
-                    xor32 r1, r2
-                    mov32 r1, r2
-                    arsh32 r1, r2"),
-        Ok(vec![
-            insn(ebpf::ADD32_REG, 1, 2, 0, 0),
-            insn(ebpf::SUB32_REG, 1, 2, 0, 0),
-            insn(ebpf::MUL32_REG, 1, 2, 0, 0),
-            insn(ebpf::DIV32_REG, 1, 2, 0, 0),
-            insn(ebpf::OR32_REG, 1, 2, 0, 0),
-            insn(ebpf::AND32_REG, 1, 2, 0, 0),
-            insn(ebpf::LSH32_REG, 1, 2, 0, 0),
-            insn(ebpf::RSH32_REG, 1, 2, 0, 0),
-            insn(ebpf::MOD32_REG, 1, 2, 0, 0),
-            insn(ebpf::XOR32_REG, 1, 2, 0, 0),
-            insn(ebpf::MOV32_REG, 1, 2, 0, 0),
-            insn(ebpf::ARSH32_REG, 1, 2, 0, 0)
-        ])
-    );
-
-    assert_eq!(
-        asm("add32 r1, 2
-                    sub32 r1, 2
-                    mul32 r1, 2
-                    div32 r1, 2
-                    or32 r1, 2
-                    and32 r1, 2
-                    lsh32 r1, 2
-                    rsh32 r1, 2
-                    mod32 r1, 2
-                    xor32 r1, 2
-                    mov32 r1, 2
-                    arsh32 r1, 2"),
-        Ok(vec![
-            insn(ebpf::ADD32_IMM, 1, 0, 0, 2),
-            insn(ebpf::SUB32_IMM, 1, 0, 0, 2),
-            insn(ebpf::MUL32_IMM, 1, 0, 0, 2),
-            insn(ebpf::DIV32_IMM, 1, 0, 0, 2),
-            insn(ebpf::OR32_IMM, 1, 0, 0, 2),
-            insn(ebpf::AND32_IMM, 1, 0, 0, 2),
-            insn(ebpf::LSH32_IMM, 1, 0, 0, 2),
-            insn(ebpf::RSH32_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOD32_IMM, 1, 0, 0, 2),
-            insn(ebpf::XOR32_IMM, 1, 0, 0, 2),
-            insn(ebpf::MOV32_IMM, 1, 0, 0, 2),
-            insn(ebpf::ARSH32_IMM, 1, 0, 0, 2)
-        ])
-    );
-}
-
-// Test all supported AluUnary mnemonics.
-#[test]
-fn test_alu_unary() {
-    assert_eq!(
-        asm("neg r1
-                    neg64 r1
-                    neg32 r1"),
-        Ok(vec![
-            insn(ebpf::NEG64, 1, 0, 0, 0),
-            insn(ebpf::NEG64, 1, 0, 0, 0),
-            insn(ebpf::NEG32, 1, 0, 0, 0)
-        ])
-    );
-}
-
-// Test all supported LoadAbs mnemonics.
-#[test]
-fn test_load_abs() {
-    assert_eq!(
-        asm("ldabsw 1
-                    ldabsh 1
-                    ldabsb 1
-                    ldabsdw 1"),
-        Ok(vec![
-            insn(ebpf::LD_ABS_W, 0, 0, 0, 1),
-            insn(ebpf::LD_ABS_H, 0, 0, 0, 1),
-            insn(ebpf::LD_ABS_B, 0, 0, 0, 1),
-            insn(ebpf::LD_ABS_DW, 0, 0, 0, 1)
-        ])
-    );
-}
-
-// Test all supported LoadInd mnemonics.
-#[test]
-fn test_load_ind() {
-    assert_eq!(
-        asm("ldindw r1, 2
-                    ldindh r1, 2
-                    ldindb r1, 2
-                    ldinddw r1, 2"),
-        Ok(vec![
-            insn(ebpf::LD_IND_W, 0, 1, 0, 2),
-            insn(ebpf::LD_IND_H, 0, 1, 0, 2),
-            insn(ebpf::LD_IND_B, 0, 1, 0, 2),
-            insn(ebpf::LD_IND_DW, 0, 1, 0, 2)
-        ])
-    );
-}
-
-// Test all supported LoadReg mnemonics.
-#[test]
-fn test_load_reg() {
-    assert_eq!(
-        asm("ldxw r1, [r2+3]
-                    ldxh r1, [r2+3]
-                    ldxb r1, [r2+3]
-                    ldxdw r1, [r2+3]"),
-        Ok(vec![
-            insn(ebpf::LD_W_REG, 1, 2, 3, 0),
-            insn(ebpf::LD_H_REG, 1, 2, 3, 0),
-            insn(ebpf::LD_B_REG, 1, 2, 3, 0),
-            insn(ebpf::LD_DW_REG, 1, 2, 3, 0)
-        ])
-    );
-}
-
-// Test all supported StoreImm mnemonics.
-#[test]
-fn test_store_imm() {
-    assert_eq!(
-        asm("stw [r1+2], 3
-                    sth [r1+2], 3
-                    stb [r1+2], 3
-                    stdw [r1+2], 3"),
-        Ok(vec![
-            insn(ebpf::ST_W_IMM, 1, 0, 2, 3),
-            insn(ebpf::ST_H_IMM, 1, 0, 2, 3),
-            insn(ebpf::ST_B_IMM, 1, 0, 2, 3),
-            insn(ebpf::ST_DW_IMM, 1, 0, 2, 3)
-        ])
-    );
-}
-
-// Test all supported StoreReg mnemonics.
-#[test]
-fn test_store_reg() {
-    assert_eq!(
-        asm("stxw [r1+2], r3
-                    stxh [r1+2], r3
-                    stxb [r1+2], r3
-                    stxdw [r1+2], r3"),
-        Ok(vec![
-            insn(ebpf::ST_W_REG, 1, 3, 2, 0),
-            insn(ebpf::ST_H_REG, 1, 3, 2, 0),
-            insn(ebpf::ST_B_REG, 1, 3, 2, 0),
-            insn(ebpf::ST_DW_REG, 1, 3, 2, 0)
-        ])
-    );
-}
-
-// Test all supported JumpConditional mnemonics.
-#[test]
-fn test_jump_conditional() {
-    assert_eq!(
-        asm("jeq r1, r2, +3
-                    jgt r1, r2, +3
-                    jge r1, r2, +3
-                    jlt r1, r2, +3
-                    jle r1, r2, +3
-                    jset r1, r2, +3
-                    jne r1, r2, +3
-                    jsgt r1, r2, +3
-                    jsge r1, r2, +3
-                    jslt r1, r2, +3
-                    jsle r1, r2, +3"),
-        Ok(vec![
-            insn(ebpf::JEQ_REG, 1, 2, 3, 0),
-            insn(ebpf::JGT_REG, 1, 2, 3, 0),
-            insn(ebpf::JGE_REG, 1, 2, 3, 0),
-            insn(ebpf::JLT_REG, 1, 2, 3, 0),
-            insn(ebpf::JLE_REG, 1, 2, 3, 0),
-            insn(ebpf::JSET_REG, 1, 2, 3, 0),
-            insn(ebpf::JNE_REG, 1, 2, 3, 0),
-            insn(ebpf::JSGT_REG, 1, 2, 3, 0),
-            insn(ebpf::JSGE_REG, 1, 2, 3, 0),
-            insn(ebpf::JSLT_REG, 1, 2, 3, 0),
-            insn(ebpf::JSLE_REG, 1, 2, 3, 0)
-        ])
-    );
-
-    assert_eq!(
-        asm("jeq r1, 2, +3
-                    jgt r1, 2, +3
-                    jge r1, 2, +3
-                    jlt r1, 2, +3
-                    jle r1, 2, +3
-                    jset r1, 2, +3
-                    jne r1, 2, +3
-                    jsgt r1, 2, +3
-                    jsge r1, 2, +3
-                    jslt r1, 2, +3
-                    jsle r1, 2, +3"),
-        Ok(vec![
-            insn(ebpf::JEQ_IMM, 1, 0, 3, 2),
-            insn(ebpf::JGT_IMM, 1, 0, 3, 2),
-            insn(ebpf::JGE_IMM, 1, 0, 3, 2),
-            insn(ebpf::JLT_IMM, 1, 0, 3, 2),
-            insn(ebpf::JLE_IMM, 1, 0, 3, 2),
-            insn(ebpf::JSET_IMM, 1, 0, 3, 2),
-            insn(ebpf::JNE_IMM, 1, 0, 3, 2),
-            insn(ebpf::JSGT_IMM, 1, 0, 3, 2),
-            insn(ebpf::JSGE_IMM, 1, 0, 3, 2),
-            insn(ebpf::JSLT_IMM, 1, 0, 3, 2),
-            insn(ebpf::JSLE_IMM, 1, 0, 3, 2)
-        ])
-    );
-
-    assert_eq!(
-        asm("jeq32 r1, r2, +3
-                    jgt32 r1, r2, +3
-                    jge32 r1, r2, +3
-                    jlt32 r1, r2, +3
-                    jle32 r1, r2, +3
-                    jset32 r1, r2, +3
-                    jne32 r1, r2, +3
-                    jsgt32 r1, r2, +3
-                    jsge32 r1, r2, +3
-                    jslt32 r1, r2, +3
-                    jsle32 r1, r2, +3"),
-        Ok(vec![
-            insn(ebpf::JEQ_REG32, 1, 2, 3, 0),
-            insn(ebpf::JGT_REG32, 1, 2, 3, 0),
-            insn(ebpf::JGE_REG32, 1, 2, 3, 0),
-            insn(ebpf::JLT_REG32, 1, 2, 3, 0),
-            insn(ebpf::JLE_REG32, 1, 2, 3, 0),
-            insn(ebpf::JSET_REG32, 1, 2, 3, 0),
-            insn(ebpf::JNE_REG32, 1, 2, 3, 0),
-            insn(ebpf::JSGT_REG32, 1, 2, 3, 0),
-            insn(ebpf::JSGE_REG32, 1, 2, 3, 0),
-            insn(ebpf::JSLT_REG32, 1, 2, 3, 0),
-            insn(ebpf::JSLE_REG32, 1, 2, 3, 0)
-        ])
-    );
-
-    assert_eq!(
-        asm("jeq32 r1, 2, +3
-                    jgt32 r1, 2, +3
-                    jge32 r1, 2, +3
-                    jlt32 r1, 2, +3
-                    jle32 r1, 2, +3
-                    jset32 r1, 2, +3
-                    jne32 r1, 2, +3
-                    jsgt32 r1, 2, +3
-                    jsge32 r1, 2, +3
-                    jslt32 r1, 2, +3
-                    jsle32 r1, 2, +3"),
-        Ok(vec![
-            insn(ebpf::JEQ_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JGT_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JGE_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JLT_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JLE_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JSET_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JNE_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JSGT_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JSGE_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JSLT_IMM32, 1, 0, 3, 2),
-            insn(ebpf::JSLE_IMM32, 1, 0, 3, 2)
-        ])
-    );
-}
-
-// Test all supported Endian mnemonics.
-#[test]
-fn test_endian() {
-    assert_eq!(
-        asm("be16 r1
-                    be32 r1
-                    be64 r1
-                    le16 r1
-                    le32 r1
-                    le64 r1"),
-        Ok(vec![
-            insn(ebpf::BE, 1, 0, 0, 16),
-            insn(ebpf::BE, 1, 0, 0, 32),
-            insn(ebpf::BE, 1, 0, 0, 64),
-            insn(ebpf::LE, 1, 0, 0, 16),
-            insn(ebpf::LE, 1, 0, 0, 32),
-            insn(ebpf::LE, 1, 0, 0, 64)
-        ])
-    );
-}
-
-#[test]
-fn test_large_immediate() {
-    assert_eq!(
-        asm("add64 r1, 2147483647"),
-        Ok(vec![insn(ebpf::ADD64_IMM, 1, 0, 0, 2147483647)])
-    );
-    assert_eq!(
-        asm("add64 r1, -2147483648"),
-        Ok(vec![insn(ebpf::ADD64_IMM, 1, 0, 0, -2147483648)])
-    );
-}
-
-#[test]
-fn test_tcp_sack() {
-    assert_eq!(assemble(TCP_SACK_ASM), Ok(TCP_SACK_BIN.to_vec()));
-}
-
-#[test]
-fn test_error_invalid_instruction() {
-    assert_eq!(asm("abcd"), Err("Invalid instruction \"abcd\"".to_string()));
-}
-
-#[test]
-fn test_error_unexpected_operands() {
-    assert_eq!(
-        asm("add 1, 2"),
-        Err("Failed to encode add: Unexpected operands: [Integer(1), Integer(2)]".to_string())
-    );
-}
-
-#[test]
-fn test_error_too_many_operands() {
-    assert_eq!(
-        asm("add 1, 2, 3, 4"),
-        Err("Failed to encode add: Too many operands".to_string())
-    );
-}
-
-#[test]
-fn test_error_operands_out_of_range() {
-    assert_eq!(
-        asm("add r16, r2"),
-        Err("Failed to encode add: Invalid destination register 16".to_string())
-    );
-    assert_eq!(
-        asm("add r1, r16"),
-        Err("Failed to encode add: Invalid source register 16".to_string())
-    );
-    assert_eq!(
-        asm("ja -32769"),
-        Err("Failed to encode ja: Invalid offset -32769".to_string())
-    );
-    assert_eq!(
-        asm("ja 32768"),
-        Err("Failed to encode ja: Invalid offset 32768".to_string())
-    );
-    assert_eq!(
-        asm("add r1, 4294967296"),
-        Err("Failed to encode add: Invalid immediate 4294967296".to_string())
-    );
-    assert_eq!(
-        asm("add r1, 2147483648"),
-        Err("Failed to encode add: Invalid immediate 2147483648".to_string())
-    );
-    assert_eq!(
-        asm("add r1, -2147483649"),
-        Err("Failed to encode add: Invalid immediate -2147483649".to_string())
-    );
-}

+ 0 - 97
kernel/crates/rbpf/tests/common.rs

@@ -1,97 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Converted from the tests for uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// Assembly code and data for tcp_sack testcases.
-
-#[allow(dead_code)]
-pub const TCP_SACK_ASM: &str = "
-    ldxb r2, [r1+12]
-    ldxb r3, [r1+13]
-    lsh r3, 0x8
-    or r3, r2
-    mov r0, 0x0
-    jne r3, 0x8, +37
-    ldxb r2, [r1+23]
-    jne r2, 0x6, +35
-    ldxb r2, [r1+14]
-    add r1, 0xe
-    and r2, 0xf
-    lsh r2, 0x2
-    add r1, r2
-    mov r0, 0x0
-    ldxh r4, [r1+12]
-    add r1, 0x14
-    rsh r4, 0x2
-    and r4, 0x3c
-    mov r2, r4
-    add r2, -20
-    mov r5, 0x15
-    mov r3, 0x0
-    jgt r5, r4, +20
-    mov r5, r3
-    lsh r5, 0x20
-    arsh r5, 0x20
-    mov r4, r1
-    add r4, r5
-    ldxb r5, [r4]
-    jeq r5, 0x1, +4
-    jeq r5, 0x0, +12
-    mov r6, r3
-    jeq r5, 0x5, +9
-    ja +2
-    add r3, 0x1
-    mov r6, r3
-    ldxb r3, [r4+1]
-    add r3, r6
-    lsh r3, 0x20
-    arsh r3, 0x20
-    jsgt r2, r3, -18
-    ja +1
-    mov r0, 0x1
-    exit";
-
-#[allow(dead_code)]
-pub const TCP_SACK_BIN: [u8; 352] = [
-    0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x25, 0x00, 0x08, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x23, 0x00, 0x06, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-    0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-    0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x69, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
-    0x77, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x57, 0x04, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
-    0xbf, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x00, 0xec, 0xff, 0xff, 0xff,
-    0xb7, 0x05, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x2d, 0x45, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xc7, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-    0xbf, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x71, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x05, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x15, 0x05, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x15, 0x05, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x07, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x71, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xc7, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-    0x6d, 0x32, 0xee, 0xff, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xb7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-];
-
-#[allow(dead_code)]
-pub const TCP_SACK_MATCH: [u8; 78] = [
-    0x00, 0x26, 0x62, 0x2f, 0x47, 0x87, 0x00, 0x1d, 0x60, 0xb3, 0x01, 0x84, 0x08, 0x00, 0x45, 0x00,
-    0x00, 0x40, 0xa8, 0xde, 0x40, 0x00, 0x40, 0x06, 0x9d, 0x58, 0xc0, 0xa8, 0x01, 0x03, 0x3f, 0x74,
-    0xf3, 0x61, 0xe5, 0xc0, 0x00, 0x50, 0xe5, 0x94, 0x3f, 0x77, 0xa3, 0xc4, 0xc4, 0x80, 0xb0, 0x10,
-    0x01, 0x3e, 0x34, 0xb6, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x17, 0x95, 0x6f, 0x8d, 0x9d,
-    0x9e, 0x27, 0x01, 0x01, 0x05, 0x0a, 0xa3, 0xc4, 0xca, 0x28, 0xa3, 0xc4, 0xcf, 0xd0,
-];
-
-#[allow(dead_code)]
-pub const TCP_SACK_NOMATCH: [u8; 66] = [
-    0x00, 0x26, 0x62, 0x2f, 0x47, 0x87, 0x00, 0x1d, 0x60, 0xb3, 0x01, 0x84, 0x08, 0x00, 0x45, 0x00,
-    0x00, 0x40, 0xa8, 0xde, 0x40, 0x00, 0x40, 0x06, 0x9d, 0x58, 0xc0, 0xa8, 0x01, 0x03, 0x3f, 0x74,
-    0xf3, 0x61, 0xe5, 0xc0, 0x00, 0x50, 0xe5, 0x94, 0x3f, 0x77, 0xa3, 0xc4, 0xc4, 0x80, 0x80, 0x10,
-    0x01, 0x3e, 0x34, 0xb6, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0x00, 0x17, 0x95, 0x6f, 0x8d, 0x9d,
-    0x9e, 0x27,
-];

+ 0 - 2257
kernel/crates/rbpf/tests/cranelift.rs

@@ -1,2257 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-
-#![allow(clippy::unreadable_literal)]
-#![cfg(feature = "cranelift")]
-
-extern crate rbpf;
-mod common;
-
-use rbpf::{assembler::assemble, helpers};
-
-use crate::common::{TCP_SACK_ASM, TCP_SACK_MATCH, TCP_SACK_NOMATCH};
-
-macro_rules! test_cranelift {
-    ($name:ident, $prog:expr, $expected:expr) => {
-        #[test]
-        fn $name() {
-            let prog = assemble($prog).unwrap();
-            let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-            vm.cranelift_compile().unwrap();
-            assert_eq!(vm.execute_program_cranelift().unwrap(), $expected);
-        }
-    };
-    ($name:ident, $prog:expr, $mem:expr, $expected:expr) => {
-        #[test]
-        fn $name() {
-            let prog = assemble($prog).unwrap();
-            let mem = &mut $mem;
-            let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-            vm.cranelift_compile().unwrap();
-            assert_eq!(vm.execute_program_cranelift(mem).unwrap(), $expected);
-        }
-    };
-}
-
-test_cranelift!(
-    test_cranelift_add,
-    "
-    mov32 r0, 0
-    mov32 r1, 2
-    add32 r0, 1
-    add32 r0, r1
-    exit
-    ",
-    0x3
-);
-
-test_cranelift!(
-    test_cranelift_alu64_arith,
-    "
-    mov r0, 0
-    mov r1, 1
-    mov r2, 2
-    mov r3, 3
-    mov r4, 4
-    mov r5, 5
-    mov r6, 6
-    mov r7, 7
-    mov r8, 8
-    mov r9, 9
-    add r0, 23
-    add r0, r7
-    sub r0, 13
-    sub r0, r1
-    mul r0, 7
-    mul r0, r3
-    div r0, 2
-    div r0, r4
-    exit
-    ",
-    0x2a
-);
-
-test_cranelift!(
-    test_cranelift_alu64_bit,
-    "
-    mov r0, 0
-    mov r1, 1
-    mov r2, 2
-    mov r3, 3
-    mov r4, 4
-    mov r5, 5
-    mov r6, 6
-    mov r7, 7
-    mov r8, 8
-    or r0, r5
-    or r0, 0xa0
-    and r0, 0xa3
-    mov r9, 0x91
-    and r0, r9
-    lsh r0, 32
-    lsh r0, 22
-    lsh r0, r8
-    rsh r0, 32
-    rsh r0, 19
-    rsh r0, r7
-    xor r0, 0x03
-    xor r0, r2
-    exit
-    ",
-    0x11
-);
-
-test_cranelift!(
-    test_cranelift_alu_arith,
-    "
-    mov32 r0, 0
-    mov32 r1, 1
-    mov32 r2, 2
-    mov32 r3, 3
-    mov32 r4, 4
-    mov32 r5, 5
-    mov32 r6, 6
-    mov32 r7, 7
-    mov32 r8, 8
-    mov32 r9, 9
-    add32 r0, 23
-    add32 r0, r7
-    sub32 r0, 13
-    sub32 r0, r1
-    mul32 r0, 7
-    mul32 r0, r3
-    div32 r0, 2
-    div32 r0, r4
-    exit
-    ",
-    0x2a
-);
-
-test_cranelift!(
-    test_cranelift_alu_bit,
-    "
-    mov32 r0, 0
-    mov32 r1, 1
-    mov32 r2, 2
-    mov32 r3, 3
-    mov32 r4, 4
-    mov32 r5, 5
-    mov32 r6, 6
-    mov32 r7, 7
-    mov32 r8, 8
-    or32 r0, r5
-    or32 r0, 0xa0
-    and32 r0, 0xa3
-    mov32 r9, 0x91
-    and32 r0, r9
-    lsh32 r0, 22
-    lsh32 r0, r8
-    rsh32 r0, 19
-    rsh32 r0, r7
-    xor32 r0, 0x03
-    xor32 r0, r2
-    exit
-    ",
-    0x11
-);
-
-test_cranelift!(
-    test_cranelift_arsh32_high_shift,
-    "
-    mov r0, 8
-    lddw r1, 0x100000001
-    arsh32 r0, r1
-    exit
-    ",
-    0x4
-);
-
-test_cranelift!(
-    test_cranelift_arsh,
-    "
-    mov32 r0, 0xf8
-    lsh32 r0, 28
-    arsh32 r0, 16
-    exit
-    ",
-    0xffff8000
-);
-
-test_cranelift!(
-    test_cranelift_arsh64,
-    "
-    mov32 r0, 1
-    lsh r0, 63
-    arsh r0, 55
-    mov32 r1, 5
-    arsh r0, r1
-    exit
-    ",
-    0xfffffffffffffff8
-);
-
-test_cranelift!(
-    test_cranelift_arsh_reg,
-    "
-    mov32 r0, 0xf8
-    mov32 r1, 16
-    lsh32 r0, 28
-    arsh32 r0, r1
-    exit
-    ",
-    0xffff8000
-);
-
-test_cranelift!(
-    test_cranelift_be16,
-    "
-    ldxh r0, [r1]
-    be16 r0
-    exit
-    ",
-    [0x11, 0x22],
-    0x1122
-);
-
-test_cranelift!(
-    test_cranelift_be16_high,
-    "
-    ldxdw r0, [r1]
-    be16 r0
-    exit
-    ",
-    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
-    0x1122
-);
-
-test_cranelift!(
-    test_cranelift_be32,
-    "
-    ldxw r0, [r1]
-    be32 r0
-    exit
-    ",
-    [0x11, 0x22, 0x33, 0x44],
-    0x11223344
-);
-
-test_cranelift!(
-    test_cranelift_be32_high,
-    "
-    ldxdw r0, [r1]
-    be32 r0
-    exit
-    ",
-    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
-    0x11223344
-);
-
-test_cranelift!(
-    test_cranelift_be64,
-    "
-    ldxdw r0, [r1]
-    be64 r0
-    exit
-    ",
-    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
-    0x1122334455667788
-);
-
-#[test]
-fn test_cranelift_call() {
-    let prog = assemble(
-        "
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        call 0
-        exit",
-    )
-    .unwrap();
-
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x0102030405);
-}
-
-#[test]
-#[should_panic(expected = "[CRANELIFT] Error: unknown helper function (id: 0x3f)")]
-fn test_cranelift_err_call_unreg() {
-    let prog = assemble(
-        "
-         mov r1, 1
-         mov r2, 2
-         mov r3, 3
-         mov r4, 4
-         mov r5, 5
-         call 63
-         exit
-    ",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-}
-
-#[test]
-fn test_cranelift_call_memfrob() {
-    let prog = assemble(
-        "
-        mov r6, r1
-        add r1, 2
-        mov r2, 4
-        call 1
-        ldxdw r0, [r6]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    let mem = &mut [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
-    vm.cranelift_compile().unwrap();
-    assert_eq!(
-        vm.execute_program_cranelift(mem).unwrap(),
-        0x102292e2f2c0708
-    );
-}
-
-test_cranelift!(
-    test_cranelift_div32_high_divisor,
-    "
-    mov r0, 12
-    lddw r1, 0x100000004
-    div32 r0, r1
-    exit
-    ",
-    0x3
-);
-
-test_cranelift!(
-    test_cranelift_div32_imm,
-    "
-    lddw r0, 0x10000000c
-    div32 r0, 4
-    exit
-    ",
-    0x3
-);
-
-test_cranelift!(
-    test_cranelift_div32_reg,
-    "
-    lddw r0, 0x10000000c
-    mov r1, 4
-    div32 r0, r1
-    exit
-    ",
-    0x3
-);
-
-test_cranelift!(
-    test_cranelift_div64_imm,
-    "
-    mov r0, 0xc
-    lsh r0, 32
-    div r0, 4
-    exit
-    ",
-    0x300000000
-);
-
-test_cranelift!(
-    test_cranelift_div64_reg,
-    "
-    mov r0, 0xc
-    lsh r0, 32
-    mov r1, 4
-    div r0, r1
-    exit
-    ",
-    0x300000000
-);
-
-test_cranelift!(
-    test_cranelift_early_exit,
-    "
-    mov r0, 3
-    exit
-    mov r0, 4
-    exit
-    ",
-    0x3
-);
-
-test_cranelift!(
-    test_cranelift_div64_by_zero_imm,
-    "
-    mov32 r0, 1
-    div r0, 0
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_div_by_zero_imm,
-    "
-    mov32 r0, 1
-    div32 r0, 0
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_mod64_by_zero_imm,
-    "
-    mov32 r0, 1
-    mod r0, 0
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_mod_by_zero_imm,
-    "
-    mov32 r0, 1
-    mod32 r0, 0
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_div64_by_zero_reg,
-    "
-    mov32 r0, 1
-    mov32 r1, 0
-    div r0, r1
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_div_by_zero_reg,
-    "
-    mov32 r0, 1
-    mov32 r1, 0
-    div32 r0, r1
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_mod64_by_zero_reg,
-    "
-    mov32 r0, 1
-    mov32 r1, 0
-    mod r0, r1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_mod_by_zero_reg,
-    "
-    mov32 r0, 1
-    mov32 r1, 0
-    mod32 r0, r1
-    exit
-    ",
-    0x1
-);
-
-#[test]
-// #[should_panic(expected = "Error: out of bounds memory store (insn #1)")]
-#[ignore = "We have stack OOB checks, but we don't yet catch the trap code and convert it into a panic"]
-fn test_cranelift_err_stack_out_of_bound() {
-    let prog = [
-        0x72, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    vm.execute_program_cranelift().unwrap();
-}
-
-test_cranelift!(
-    test_cranelift_exit,
-    "
-    mov r0, 0
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_ja,
-    "
-    mov r0, 1
-    ja +1
-    mov r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jeq_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 0xa
-    jeq r1, 0xb, +4
-    mov32 r0, 1
-    mov32 r1, 0xb
-    jeq r1, 0xb, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jeq_reg,
-    "
-    mov32 r0, 0
-    mov32 r1, 0xa
-    mov32 r2, 0xb
-    jeq r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0xb
-    jeq r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jge_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 0xa
-    jge r1, 0xb, +4
-    mov32 r0, 1
-    mov32 r1, 0xc
-    jge r1, 0xb, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jle_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 5
-    jle r1, 4, +1
-    jle r1, 6, +1
-    exit
-    jle r1, 5, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jle_reg,
-    "
-    mov r0, 0
-    mov r1, 5
-    mov r2, 4
-    mov r3, 6
-    jle r1, r2, +2
-    jle r1, r1, +1
-    exit
-    jle r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jgt_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 5
-    jgt r1, 6, +2
-    jgt r1, 5, +1
-    jgt r1, 4, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jgt_reg,
-    "
-    mov r0, 0
-    mov r1, 5
-    mov r2, 6
-    mov r3, 4
-    jgt r1, r2, +2
-    jgt r1, r1, +1
-    jgt r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jlt_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 5
-    jlt r1, 4, +2
-    jlt r1, 5, +1
-    jlt r1, 6, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jlt_reg,
-    "
-    mov r0, 0
-    mov r1, 5
-    mov r2, 4
-    mov r3, 6
-    jlt r1, r2, +2
-    jlt r1, r1, +1
-    jlt r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jit_bounce,
-    "
-    mov r0, 1
-    mov r6, r0
-    mov r7, r6
-    mov r8, r7
-    mov r9, r8
-    mov r0, r9
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jne_reg,
-    "
-    mov32 r0, 0
-    mov32 r1, 0xb
-    mov32 r2, 0xb
-    jne r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0xa
-    jne r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jset_imm,
-    "
-    mov32 r0, 0
-    mov32 r1, 0x7
-    jset r1, 0x8, +4
-    mov32 r0, 1
-    mov32 r1, 0x9
-    jset r1, 0x8, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jset_reg,
-    "
-    mov32 r0, 0
-    mov32 r1, 0x7
-    mov32 r2, 0x8
-    jset r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0x9
-    jset r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsge_imm,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    jsge r1, -1, +5
-    jsge r1, 0, +4
-    mov32 r0, 1
-    mov r1, -1
-    jsge r1, -1, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsge_reg,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    mov r2, -1
-    mov32 r3, 0
-    jsge r1, r2, +5
-    jsge r1, r3, +4
-    mov32 r0, 1
-    mov r1, r2
-    jsge r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsle_imm,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    jsle r1, -3, +1
-    jsle r1, -1, +1
-    exit
-    mov32 r0, 1
-    jsle r1, -2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsle_reg,
-    "
-    mov32 r0, 0
-    mov r1, -1
-    mov r2, -2
-    mov32 r3, 0
-    jsle r1, r2, +1
-    jsle r1, r3, +1
-    exit
-    mov32 r0, 1
-    mov r1, r2
-    jsle r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsgt_imm,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    jsgt r1, -1, +4
-    mov32 r0, 1
-    mov32 r1, 0
-    jsgt r1, -1, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsgt_reg,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    mov r2, -1
-    jsgt r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0
-    jsgt r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jslt_imm,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    jslt r1, -3, +2
-    jslt r1, -2, +1
-    jslt r1, -1, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jslt_reg,
-    "
-    mov32 r0, 0
-    mov r1, -2
-    mov r2, -3
-    mov r3, -1
-    jslt r1, r1, +2
-    jslt r1, r2, +1
-    jslt r1, r3, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jeq32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0x0
-    mov32 r1, 0xa
-    jeq32 r1, 0xb, +5
-    mov32 r0, 1
-    mov r1, 0xb
-    or r1, r9
-    jeq32 r1, 0xb, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jeq32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0xa
-    mov32 r2, 0xb
-    jeq32 r1, r2, +5
-    mov32 r0, 1
-    mov32 r1, 0xb
-    or r1, r9
-    jeq32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jge32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0xa
-    jge32 r1, 0xb, +5
-    mov32 r0, 1
-    or r1, r9
-    mov32 r1, 0xc
-    jge32 r1, 0xb, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jge32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0xa
-    mov32 r2, 0xb
-    jge32 r1, r2, +5
-    mov32 r0, 1
-    or r1, r9
-    mov32 r1, 0xc
-    jge32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jgt32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 5
-    or r1, r9
-    jgt32 r1, 6, +4
-    jgt32 r1, 5, +3
-    jgt32 r1, 4, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jgt32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov r0, 0
-    mov r1, 5
-    mov32 r1, 5
-    or r1, r9
-    mov r2, 6
-    mov r3, 4
-    jgt32 r1, r2, +4
-    jgt32 r1, r1, +3
-    jgt32 r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jle32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 5
-    or r1, r9
-    jle32 r1, 4, +5
-    jle32 r1, 6, +1
-    exit
-    jle32 r1, 5, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jle32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov r0, 0
-    mov r1, 5
-    mov r2, 4
-    mov r3, 6
-    or r1, r9
-    jle32 r1, r2, +5
-    jle32 r1, r1, +1
-    exit
-    jle32 r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jlt32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 5
-    or r1, r9
-    jlt32 r1, 4, +4
-    jlt32 r1, 5, +3
-    jlt32 r1, 6, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jlt32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov r0, 0
-    mov r1, 5
-    mov r2, 4
-    mov r3, 6
-    or r1, r9
-    jlt32 r1, r2, +4
-    jlt32 r1, r1, +3
-    jlt32 r1, r3, +1
-    exit
-    mov r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jne32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0xb
-    or r1, r9
-    jne32 r1, 0xb, +4
-    mov32 r0, 1
-    mov32 r1, 0xa
-    or r1, r9
-    jne32 r1, 0xb, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jne32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0xb
-    or r1, r9
-    mov32 r2, 0xb
-    jne32 r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0xa
-    or r1, r9
-    jne32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jset32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0x7
-    or r1, r9
-    jset32 r1, 0x8, +4
-    mov32 r0, 1
-    mov32 r1, 0x9
-    jset32 r1, 0x8, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jset32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, 0x7
-    or r1, r9
-    mov32 r2, 0x8
-    jset32 r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0x9
-    jset32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsge32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    jsge32 r1, -1, +5
-    jsge32 r1, 0, +4
-    mov32 r0, 1
-    mov r1, -1
-    jsge32 r1, -1, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsge32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    mov r2, -1
-    mov32 r3, 0
-    jsge32 r1, r2, +5
-    jsge32 r1, r3, +4
-    mov32 r0, 1
-    mov r1, r2
-    jsge32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsgt32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    jsgt32 r1, -1, +4
-    mov32 r0, 1
-    mov32 r1, 0
-    jsgt32 r1, -1, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsgt32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    mov r2, -1
-    jsgt32 r1, r2, +4
-    mov32 r0, 1
-    mov32 r1, 0
-    jsgt32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsle32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    jsle32 r1, -3, +5
-    jsle32 r1, -1, +1
-    exit
-    mov32 r0, 1
-    jsle32 r1, -2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jsle32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    mov r2, -3
-    mov32 r3, 0
-    jsle32 r1, r2, +6
-    jsle32 r1, r3, +1
-    exit
-    mov32 r0, 1
-    mov r1, r2
-    jsle32 r1, r2, +1
-    mov32 r0, 2
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jslt32_imm,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    jslt32 r1, -3, +4
-    jslt32 r1, -2, +3
-    jslt32 r1, -1, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_jslt32_reg,
-    "
-    mov r9, 1
-    lsh r9, 32
-    mov32 r0, 0
-    mov32 r1, -2
-    or r1, r9
-    mov r2, -3
-    mov r3, -1
-    jslt32 r1, r1, +4
-    jslt32 r1, r2, +3
-    jslt32 r1, r3, +1
-    exit
-    mov32 r0, 1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_lddw,
-    "
-    lddw r0, 0x1122334455667788
-    exit
-    ",
-    0x1122334455667788
-);
-
-test_cranelift!(
-    test_cranelift_lddw2,
-    "
-    lddw r0, 0x0000000080000000
-    exit
-    ",
-    0x80000000
-);
-
-test_cranelift!(
-    test_cranelift_ldxb_all,
-    "
-    mov r0, r1
-    ldxb r9, [r0+0]
-    lsh r9, 0
-    ldxb r8, [r0+1]
-    lsh r8, 4
-    ldxb r7, [r0+2]
-    lsh r7, 8
-    ldxb r6, [r0+3]
-    lsh r6, 12
-    ldxb r5, [r0+4]
-    lsh r5, 16
-    ldxb r4, [r0+5]
-    lsh r4, 20
-    ldxb r3, [r0+6]
-    lsh r3, 24
-    ldxb r2, [r0+7]
-    lsh r2, 28
-    ldxb r1, [r0+8]
-    lsh r1, 32
-    ldxb r0, [r0+9]
-    lsh r0, 36
-    or r0, r1
-    or r0, r2
-    or r0, r3
-    or r0, r4
-    or r0, r5
-    or r0, r6
-    or r0, r7
-    or r0, r8
-    or r0, r9
-    exit
-    ",
-    [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09],
-    0x9876543210
-);
-
-test_cranelift!(
-    test_cranelift_ldxb,
-    "
-    ldxb r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0x11, 0xcc, 0xdd],
-    0x11
-);
-
-test_cranelift!(
-    test_cranelift_ldxdw,
-    "
-    ldxdw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xcc, 0xdd],
-    0x8877665544332211
-);
-
-test_cranelift!(
-    test_cranelift_ldxh_all,
-    "
-    mov r0, r1
-    ldxh r9, [r0+0]
-    be16 r9
-    lsh r9, 0
-    ldxh r8, [r0+2]
-    be16 r8
-    lsh r8, 4
-    ldxh r7, [r0+4]
-    be16 r7
-    lsh r7, 8
-    ldxh r6, [r0+6]
-    be16 r6
-    lsh r6, 12
-    ldxh r5, [r0+8]
-    be16 r5
-    lsh r5, 16
-    ldxh r4, [r0+10]
-    be16 r4
-    lsh r4, 20
-    ldxh r3, [r0+12]
-    be16 r3
-    lsh r3, 24
-    ldxh r2, [r0+14]
-    be16 r2
-    lsh r2, 28
-    ldxh r1, [r0+16]
-    be16 r1
-    lsh r1, 32
-    ldxh r0, [r0+18]
-    be16 r0
-    lsh r0, 36
-    or r0, r1
-    or r0, r2
-    or r0, r3
-    or r0, r4
-    or r0, r5
-    or r0, r6
-    or r0, r7
-    or r0, r8
-    or r0, r9
-    exit
-    ",
-    [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00,
-        0x07, 0x00, 0x08, 0x00, 0x09
-    ],
-    0x9876543210
-);
-
-test_cranelift!(
-    test_cranelift_ldxh_all2,
-    "
-    mov r0, r1
-    ldxh r9, [r0+0]
-    be16 r9
-    ldxh r8, [r0+2]
-    be16 r8
-    ldxh r7, [r0+4]
-    be16 r7
-    ldxh r6, [r0+6]
-    be16 r6
-    ldxh r5, [r0+8]
-    be16 r5
-    ldxh r4, [r0+10]
-    be16 r4
-    ldxh r3, [r0+12]
-    be16 r3
-    ldxh r2, [r0+14]
-    be16 r2
-    ldxh r1, [r0+16]
-    be16 r1
-    ldxh r0, [r0+18]
-    be16 r0
-    or r0, r1
-    or r0, r2
-    or r0, r3
-    or r0, r4
-    or r0, r5
-    or r0, r6
-    or r0, r7
-    or r0, r8
-    or r0, r9
-    exit
-    ",
-    [
-        0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00,
-        0x80, 0x01, 0x00, 0x02, 0x00
-    ],
-    0x3ff
-);
-
-test_cranelift!(
-    test_cranelift_ldxh,
-    "
-    ldxh r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd],
-    0x2211
-);
-
-test_cranelift!(
-    test_cranelift_ldxh_same_reg,
-    "
-    mov r0, r1
-    sth [r0], 0x1234
-    ldxh r0, [r0]
-    exit
-    ",
-    [0xff, 0xff],
-    0x1234
-);
-
-test_cranelift!(
-    test_cranelift_ldxw_all,
-    "
-    mov r0, r1
-    ldxw r9, [r0+0]
-    be32 r9
-    ldxw r8, [r0+4]
-    be32 r8
-    ldxw r7, [r0+8]
-    be32 r7
-    ldxw r6, [r0+12]
-    be32 r6
-    ldxw r5, [r0+16]
-    be32 r5
-    ldxw r4, [r0+20]
-    be32 r4
-    ldxw r3, [r0+24]
-    be32 r3
-    ldxw r2, [r0+28]
-    be32 r2
-    ldxw r1, [r0+32]
-    be32 r1
-    ldxw r0, [r0+36]
-    be32 r0
-    or r0, r1
-    or r0, r2
-    or r0, r3
-    or r0, r4
-    or r0, r5
-    or r0, r6
-    or r0, r7
-    or r0, r8
-    or r0, r9
-    exit
-    ",
-    [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00
-    ],
-    0x030f0f
-);
-
-test_cranelift!(
-    test_cranelift_ldxw,
-    "
-    ldxw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd],
-    0x44332211
-);
-
-test_cranelift!(
-    test_cranelift_le16,
-    "
-    ldxh r0, [r1]
-    le16 r0
-    exit
-    ",
-    [0x22, 0x11],
-    0x1122
-);
-
-test_cranelift!(
-    test_cranelift_le32,
-    "
-    ldxw r0, [r1]
-    le32 r0
-    exit
-    ",
-    [0x44, 0x33, 0x22, 0x11],
-    0x11223344
-);
-
-test_cranelift!(
-    test_cranelift_le64,
-    "
-    ldxdw r0, [r1]
-    le64 r0
-    exit
-    ",
-    [0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11],
-    0x1122334455667788
-);
-
-test_cranelift!(
-    test_cranelift_lsh_reg,
-    "
-    mov r0, 0x1
-    mov r7, 4
-    lsh r0, r7
-    exit
-    ",
-    0x10
-);
-
-test_cranelift!(
-    test_cranelift_mod,
-    "
-    mov32 r0, 5748
-    mod32 r0, 92
-    mov32 r1, 13
-    mod32 r0, r1
-    exit
-    ",
-    0x5
-);
-
-test_cranelift!(
-    test_cranelift_mod32,
-    "
-    lddw r0, 0x100000003
-    mod32 r0, 3
-    exit
-    ",
-    0x0
-);
-
-test_cranelift!(
-    test_cranelift_mod64,
-    "
-    mov32 r0, -1316649930
-    lsh r0, 32
-    or r0, 0x100dc5c8
-    mov32 r1, 0xdde263e
-    lsh r1, 32
-    or r1, 0x3cbef7f3
-    mod r0, r1
-    mod r0, 0x658f1778
-    exit
-    ",
-    0x30ba5a04
-);
-
-test_cranelift!(
-    test_cranelift_mov,
-    "
-    mov32 r1, 1
-    mov32 r0, r1
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_mul32_imm,
-    "
-    mov r0, 3
-    mul32 r0, 4
-    exit
-    ",
-    0xc
-);
-
-test_cranelift!(
-    test_cranelift_mul32_reg,
-    "
-    mov r0, 3
-    mov r1, 4
-    mul32 r0, r1
-    exit
-    ",
-    0xc
-);
-
-test_cranelift!(
-    test_cranelift_mul32_reg_overflow,
-    "
-    mov r0, 0x40000001
-    mov r1, 4
-    mul32 r0, r1
-    exit
-    ",
-    0x4
-);
-
-test_cranelift!(
-    test_cranelift_mul64_imm,
-    "
-    mov r0, 0x40000001
-    mul r0, 4
-    exit
-    ",
-    0x100000004
-);
-
-test_cranelift!(
-    test_cranelift_mul64_reg,
-    "
-    mov r0, 0x40000001
-    mov r1, 4
-    mul r0, r1
-    exit
-    ",
-    0x100000004
-);
-
-test_cranelift!(
-    test_cranelift_mul_loop,
-    "
-    mov r0, 0x7
-    add r1, 0xa
-    lsh r1, 0x20
-    rsh r1, 0x20
-    jeq r1, 0x0, +4
-    mov r0, 0x7
-    mul r0, 0x7
-    add r1, -1
-    jne r1, 0x0, -3
-    exit
-    ",
-    0x75db9c97
-);
-
-test_cranelift!(
-    test_cranelift_neg64,
-    "
-    mov32 r0, 2
-    neg r0
-    exit
-    ",
-    0xfffffffffffffffe
-);
-
-test_cranelift!(
-    test_cranelift_neg,
-    "
-    mov32 r0, 2
-    neg32 r0
-    exit
-    ",
-    0xfffffffe
-);
-
-test_cranelift!(
-    test_cranelift_prime,
-    "
-    mov r1, 67
-    mov r0, 0x1
-    mov r2, 0x2
-    jgt r1, 0x2, +4
-    ja +10
-    add r2, 0x1
-    mov r0, 0x1
-    jge r2, r1, +7
-    mov r3, r1
-    div r3, r2
-    mul r3, r2
-    mov r4, r1
-    sub r4, r3
-    mov r0, 0x0
-    jne r4, 0x0, -10
-    exit
-    ",
-    1
-);
-
-test_cranelift!(
-    test_cranelift_rhs32,
-    "
-    xor r0, r0
-    sub r0, 1
-    rsh32 r0, 8
-    exit
-    ",
-    0x00ffffff
-);
-
-test_cranelift!(
-    test_cranelift_rsh_reg,
-    "
-    mov r0, 0x10
-    mov r7, 4
-    rsh r0, r7
-    exit
-    ",
-    0x1
-);
-
-test_cranelift!(
-    test_cranelift_stack,
-    "
-    mov r1, 51
-    stdw [r10-16], 0xab
-    stdw [r10-8], 0xcd
-    and r1, 1
-    lsh r1, 3
-    mov r2, r10
-    add r2, r1
-    ldxdw r0, [r2-16]
-    exit
-    ",
-    0xcd
-);
-
-#[test]
-fn test_cranelift_stack2() {
-    let prog = assemble(
-        "
-        stb [r10-4], 0x01
-        stb [r10-3], 0x02
-        stb [r10-2], 0x03
-        stb [r10-1], 0x04
-        mov r1, r10
-        mov r2, 0x4
-        sub r1, r2
-        call 1
-        mov r1, 0
-        ldxb r2, [r10-4]
-        ldxb r3, [r10-3]
-        ldxb r4, [r10-2]
-        ldxb r5, [r10-1]
-        call 0
-        xor r0, 0x2a2a2a2a
-        exit",
-    )
-    .unwrap();
-
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x01020304);
-}
-
-test_cranelift!(
-    test_cranelift_stb,
-    "
-    stb [r1+2], 0x11
-    ldxb r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xcc, 0xdd],
-    0x11
-);
-
-test_cranelift!(
-    test_cranelift_stdw,
-    "
-    stdw [r1+2], 0x44332211
-    ldxdw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd],
-    0x44332211
-);
-
-test_cranelift!(
-    test_cranelift_sth,
-    "
-    sth [r1+2], 0x2211
-    ldxh r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd],
-    0x2211
-);
-
-#[test]
-#[ignore]
-fn test_cranelift_string_stack() {
-    let prog = assemble(
-        "
-        mov r1, 0x78636261
-        stxw [r10-8], r1
-        mov r6, 0x0
-        stxb [r10-4], r6
-        stxb [r10-12], r6
-        mov r1, 0x79636261
-        stxw [r10-16], r1
-        mov r1, r10
-        add r1, -8
-        mov r2, r1
-        call 0x4
-        mov r1, r0
-        mov r0, 0x1
-        lsh r1, 0x20
-        rsh r1, 0x20
-        jne r1, 0x0, +11
-        mov r1, r10
-        add r1, -8
-        mov r2, r10
-        add r2, -16
-        call 0x4
-        mov r1, r0
-        lsh r1, 0x20
-        rsh r1, 0x20
-        mov r0, 0x1
-        jeq r1, r6, +1
-        mov r0, 0x0
-        exit",
-    )
-    .unwrap();
-
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(4, helpers::strcmp).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x0);
-}
-
-test_cranelift!(
-    test_cranelift_stw,
-    "
-    stw [r1+2], 0x44332211
-    ldxw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd],
-    0x44332211
-);
-
-test_cranelift!(
-    test_cranelift_stxb,
-    "
-    mov32 r2, 0x11
-    stxb [r1+2], r2
-    ldxb r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xcc, 0xdd],
-    0x11
-);
-
-test_cranelift!(
-    test_cranelift_stxb_all,
-    "
-    mov r0, 0xf0
-    mov r2, 0xf2
-    mov r3, 0xf3
-    mov r4, 0xf4
-    mov r5, 0xf5
-    mov r6, 0xf6
-    mov r7, 0xf7
-    mov r8, 0xf8
-    stxb [r1], r0
-    stxb [r1+1], r2
-    stxb [r1+2], r3
-    stxb [r1+3], r4
-    stxb [r1+4], r5
-    stxb [r1+5], r6
-    stxb [r1+6], r7
-    stxb [r1+7], r8
-    ldxdw r0, [r1]
-    be64 r0
-    exit
-    ",
-    [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
-    0xf0f2f3f4f5f6f7f8
-);
-
-test_cranelift!(
-    test_cranelift_stxb_all2,
-    "
-    mov r0, r1
-    mov r1, 0xf1
-    mov r9, 0xf9
-    stxb [r0], r1
-    stxb [r0+1], r9
-    ldxh r0, [r0]
-    be16 r0
-    exit
-    ",
-    [0xff, 0xff],
-    0xf1f9
-);
-
-test_cranelift!(
-    test_cranelift_stxb_chain,
-    "
-    mov r0, r1
-    ldxb r9, [r0+0]
-    stxb [r0+1], r9
-    ldxb r8, [r0+1]
-    stxb [r0+2], r8
-    ldxb r7, [r0+2]
-    stxb [r0+3], r7
-    ldxb r6, [r0+3]
-    stxb [r0+4], r6
-    ldxb r5, [r0+4]
-    stxb [r0+5], r5
-    ldxb r4, [r0+5]
-    stxb [r0+6], r4
-    ldxb r3, [r0+6]
-    stxb [r0+7], r3
-    ldxb r2, [r0+7]
-    stxb [r0+8], r2
-    ldxb r1, [r0+8]
-    stxb [r0+9], r1
-    ldxb r0, [r0+9]
-    exit
-    ",
-    [0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
-    0x2a
-);
-
-test_cranelift!(
-    test_cranelift_stxdw,
-    "
-    mov r2, -2005440939
-    lsh r2, 32
-    or r2, 0x44332211
-    stxdw [r1+2], r2
-    ldxdw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd],
-    0x8877665544332211
-);
-
-test_cranelift!(
-    test_cranelift_stxh,
-    "
-    mov32 r2, 0x2211
-    stxh [r1+2], r2
-    ldxh r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd],
-    0x2211
-);
-
-test_cranelift!(
-    test_cranelift_stxw,
-    "
-    mov32 r2, 0x44332211
-    stxw [r1+2], r2
-    ldxw r0, [r1+2]
-    exit
-    ",
-    [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd],
-    0x44332211
-);
-
-test_cranelift!(
-    test_cranelift_subnet,
-    "
-    mov r2, 0xe
-    ldxh r3, [r1+12]
-    jne r3, 0x81, +2
-    mov r2, 0x12
-    ldxh r3, [r1+16]
-    and r3, 0xffff
-    jne r3, 0x8, +5
-    add r1, r2
-    mov r0, 0x1
-    ldxw r1, [r1+16]
-    and r1, 0xffffff
-    jeq r1, 0x1a8c0, +1
-    mov r0, 0x0
-    exit
-    ",
-    [
-        0x00, 0x00, 0xc0, 0x9f, 0xa0, 0x97, 0x00, 0xa0, 0xcc, 0x3b, 0xbf, 0xfa, 0x08, 0x00, 0x45,
-        0x10, 0x00, 0x3c, 0x46, 0x3c, 0x40, 0x00, 0x40, 0x06, 0x73, 0x1c, 0xc0, 0xa8, 0x01, 0x02,
-        0xc0, 0xa8, 0x01, 0x01, 0x06, 0x0e, 0x00, 0x17, 0x99, 0xc5, 0xa0, 0xec, 0x00, 0x00, 0x00,
-        0x00, 0xa0, 0x02, 0x7d, 0x78, 0xe0, 0xa3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02,
-        0x08, 0x0a, 0x00, 0x9c, 0x27, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x00,
-    ],
-    0x1
-);
-
-const PROG_TCP_PORT_80: [u8; 152] = [
-    0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x0a, 0x00, 0x06, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-    0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-    0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x15, 0x02, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x69, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x55, 0x01, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-];
-
-#[test]
-fn test_cranelift_tcp_port80_match() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x1);
-}
-
-#[test]
-fn test_cranelift_tcp_port80_nomatch() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x00, 0x16, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x51, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_cranelift_tcp_port80_nomatch_ethertype() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x01, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_cranelift_tcp_port80_nomatch_proto() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_cranelift_tcp_sack_match() {
-    let mut mem = TCP_SACK_MATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(
-        vm.execute_program_cranelift(mem.as_mut_slice()).unwrap(),
-        0x1
-    );
-}
-
-#[test]
-fn test_cranelift_tcp_sack_nomatch() {
-    let mut mem = TCP_SACK_NOMATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.cranelift_compile().unwrap();
-    assert_eq!(
-        vm.execute_program_cranelift(mem.as_mut_slice()).unwrap(),
-        0x0
-    );
-}
-
-#[test]
-fn test_cranelift_ldabsb() {
-    let prog = &[
-        0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x33);
-}
-
-#[test]
-fn test_cranelift_ldabsh() {
-    let prog = &[
-        0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x4433);
-}
-
-#[test]
-fn test_cranelift_ldabsw() {
-    let prog = &[
-        0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x66554433);
-}
-
-#[test]
-fn test_cranelift_ldabsdw() {
-    let prog = &[
-        0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(
-        vm.execute_program_cranelift(mem).unwrap(),
-        0xaa99887766554433
-    );
-}
-
-#[test]
-fn test_cranelift_ldindb() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x88);
-}
-
-#[test]
-fn test_cranelift_ldindh() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x9988);
-}
-
-#[test]
-fn test_cranelift_ldindw() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x88776655);
-}
-
-#[test]
-fn test_cranelift_ldinddw() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x00, 0x08).unwrap();
-
-    vm.cranelift_compile().unwrap();
-    assert_eq!(
-        vm.execute_program_cranelift(mem).unwrap(),
-        0xccbbaa9988776655
-    );
-}

+ 0 - 377
kernel/crates/rbpf/tests/disassembler.rs

@@ -1,377 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us>
-//
-// Adopted from tests in `tests/assembler.rs`
-
-extern crate rbpf;
-mod common;
-
-use rbpf::{assembler::assemble, disassembler::to_insn_vec};
-
-// Using a macro to keep actual line numbers in failure output
-macro_rules! disasm {
-    ($src:expr) => {{
-        let src = $src;
-        let asm = assemble(src).expect("Can't assemble from string");
-        let insn = to_insn_vec(&asm);
-        let reasm = insn
-            .into_iter()
-            .map(|ins| ins.desc)
-            .collect::<Vec<_>>()
-            .join("\n");
-
-        assert_eq!(src, reasm);
-    }};
-}
-
-#[test]
-fn test_empty() {
-    disasm!("");
-}
-
-// Example for InstructionType::NoOperand.
-#[test]
-fn test_exit() {
-    disasm!("exit");
-}
-
-// Example for InstructionType::AluBinary.
-#[test]
-fn test_add64() {
-    disasm!("add64 r1, r3");
-    disasm!("add64 r1, 0x5");
-}
-
-// Example for InstructionType::AluUnary.
-#[test]
-fn test_neg64() {
-    disasm!("neg64 r1");
-}
-
-// Example for InstructionType::LoadReg.
-#[test]
-fn test_ldxw() {
-    disasm!("ldxw r1, [r2+0x5]");
-}
-
-// Example for InstructionType::StoreImm.
-#[test]
-fn test_stw() {
-    disasm!("stw [r2+0x5], 0x7");
-}
-
-// Example for InstructionType::StoreReg.
-#[test]
-fn test_stxw() {
-    disasm!("stxw [r2+0x5], r8");
-}
-
-// Example for InstructionType::JumpUnconditional.
-#[test]
-fn test_ja() {
-    disasm!("ja +0x8");
-}
-
-// Example for InstructionType::JumpConditional.
-#[test]
-fn test_jeq() {
-    disasm!("jeq r1, 0x4, +0x8");
-    disasm!("jeq r1, r3, +0x8");
-}
-
-// Example for InstructionType::Call.
-#[test]
-fn test_call() {
-    disasm!("call 0x3");
-}
-
-// Example for InstructionType::Endian.
-#[test]
-fn test_be32() {
-    disasm!("be32 r1");
-}
-
-// Example for InstructionType::LoadImm.
-#[test]
-fn test_lddw() {
-    disasm!("lddw r1, 0x1234abcd5678eeff");
-    disasm!("lddw r1, 0xff11ee22dd33cc44");
-}
-
-// Example for InstructionType::LoadAbs.
-#[test]
-fn test_ldabsw() {
-    disasm!("ldabsw 0x1");
-}
-
-// Example for InstructionType::LoadInd.
-#[test]
-fn test_ldindw() {
-    disasm!("ldindw r1, 0x2");
-}
-
-// Example for InstructionType::LoadReg.
-#[test]
-fn test_ldxdw() {
-    disasm!("ldxdw r1, [r2+0x3]");
-}
-
-// Example for InstructionType::StoreImm.
-#[test]
-fn test_sth() {
-    disasm!("sth [r1+0x2], 0x3");
-}
-
-// Example for InstructionType::StoreReg.
-#[test]
-fn test_stxh() {
-    disasm!("stxh [r1+0x2], r3");
-}
-
-// Test all supported AluBinary mnemonics.
-#[test]
-fn test_alu_binary() {
-    disasm!(
-        "add64 r1, r2
-sub64 r1, r2
-mul64 r1, r2
-div64 r1, r2
-or64 r1, r2
-and64 r1, r2
-lsh64 r1, r2
-rsh64 r1, r2
-mod64 r1, r2
-xor64 r1, r2
-mov64 r1, r2
-arsh64 r1, r2"
-    );
-
-    disasm!(
-        "add64 r1, 0x2
-sub64 r1, 0x2
-mul64 r1, 0x2
-div64 r1, 0x2
-or64 r1, 0x2
-and64 r1, 0x2
-lsh64 r1, 0x2
-rsh64 r1, 0x2
-mod64 r1, 0x2
-xor64 r1, 0x2
-mov64 r1, 0x2
-arsh64 r1, 0x2"
-    );
-
-    disasm!(
-        "add32 r1, r2
-sub32 r1, r2
-mul32 r1, r2
-div32 r1, r2
-or32 r1, r2
-and32 r1, r2
-lsh32 r1, r2
-rsh32 r1, r2
-mod32 r1, r2
-xor32 r1, r2
-mov32 r1, r2
-arsh32 r1, r2"
-    );
-
-    disasm!(
-        "add32 r1, 0x2
-sub32 r1, 0x2
-mul32 r1, 0x2
-div32 r1, 0x2
-or32 r1, 0x2
-and32 r1, 0x2
-lsh32 r1, 0x2
-rsh32 r1, 0x2
-mod32 r1, 0x2
-xor32 r1, 0x2
-mov32 r1, 0x2
-arsh32 r1, 0x2"
-    );
-}
-
-// Test all supported AluUnary mnemonics.
-#[test]
-fn test_alu_unary() {
-    disasm!(
-        "neg64 r1
-neg32 r1"
-    );
-}
-
-// Test all supported LoadAbs mnemonics.
-#[test]
-fn test_load_abs() {
-    disasm!(
-        "ldabsw 0x1
-ldabsh 0x1
-ldabsb 0x1
-ldabsdw 0x1"
-    );
-}
-
-// Test all supported LoadInd mnemonics.
-#[test]
-fn test_load_ind() {
-    disasm!(
-        "ldindw r1, 0x2
-ldindh r1, 0x2
-ldindb r1, 0x2
-ldinddw r1, 0x2"
-    );
-}
-
-// Test all supported LoadReg mnemonics.
-#[test]
-fn test_load_reg() {
-    disasm!(
-        r"ldxw r1, [r2+0x3]
-ldxh r1, [r2+0x3]
-ldxb r1, [r2+0x3]
-ldxdw r1, [r2+0x3]"
-    );
-}
-
-// Test all supported StoreImm mnemonics.
-#[test]
-fn test_store_imm() {
-    disasm!(
-        "stw [r1+0x2], 0x3
-sth [r1+0x2], 0x3
-stb [r1+0x2], 0x3
-stdw [r1+0x2], 0x3"
-    );
-}
-
-// Test all supported StoreReg mnemonics.
-#[test]
-fn test_store_reg() {
-    disasm!(
-        "stxw [r1+0x2], r3
-stxh [r1+0x2], r3
-stxb [r1+0x2], r3
-stxdw [r1+0x2], r3"
-    );
-}
-
-// Test all supported JumpConditional mnemonics.
-#[test]
-fn test_jump_conditional() {
-    disasm!(
-        "jeq r1, r2, +0x3
-jgt r1, r2, +0x3
-jge r1, r2, +0x3
-jlt r1, r2, +0x3
-jle r1, r2, +0x3
-jset r1, r2, +0x3
-jne r1, r2, +0x3
-jsgt r1, r2, +0x3
-jsge r1, r2, -0x3
-jslt r1, r2, +0x3
-jsle r1, r2, -0x3"
-    );
-
-    disasm!(
-        "jeq r1, 0x2, +0x3
-jgt r1, 0x2, +0x3
-jge r1, 0x2, +0x3
-jlt r1, 0x2, +0x3
-jle r1, 0x2, +0x3
-jset r1, 0x2, +0x3
-jne r1, 0x2, +0x3
-jsgt r1, 0x2, +0x3
-jsge r1, 0x2, -0x3
-jslt r1, 0x2, +0x3
-jsle r1, 0x2, -0x3"
-    );
-
-    disasm!(
-        "jeq32 r1, r2, +0x3
-jgt32 r1, r2, +0x3
-jge32 r1, r2, +0x3
-jlt32 r1, r2, +0x3
-jle32 r1, r2, +0x3
-jset32 r1, r2, +0x3
-jne32 r1, r2, +0x3
-jsgt32 r1, r2, +0x3
-jsge32 r1, r2, -0x3
-jslt32 r1, r2, +0x3
-jsle32 r1, r2, -0x3"
-    );
-
-    disasm!(
-        "jeq32 r1, 0x2, +0x3
-jgt32 r1, 0x2, +0x3
-jge32 r1, 0x2, +0x3
-jlt32 r1, 0x2, +0x3
-jle32 r1, 0x2, +0x3
-jset32 r1, 0x2, +0x3
-jne32 r1, 0x2, +0x3
-jsgt32 r1, 0x2, +0x3
-jsge32 r1, 0x2, -0x3
-jslt32 r1, 0x2, +0x3
-jsle32 r1, 0x2, -0x3"
-    );
-}
-
-// Test all supported Endian mnemonics.
-#[test]
-fn test_endian() {
-    disasm!(
-        "be16 r1
-be32 r1
-be64 r1
-le16 r1
-le32 r1
-le64 r1"
-    );
-}
-
-#[test]
-fn test_large_immediate() {
-    disasm!("add64 r1, 0x7fffffff");
-    disasm!("add64 r1, 0x7fffffff");
-}
-
-// Non-regression tests for overflow when trying to negate offset 0x8000i16.
-#[test]
-fn test_offset_overflow() {
-    let insns = [
-        0x62, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stw
-        0x6a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // sth
-        0x72, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stb
-        0x7a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stdw
-        0x61, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxw
-        0x69, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxh
-        0x71, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxb
-        0x79, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxdw
-        0x15, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq (imm)
-        0x1d, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq (reg)
-        0x16, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq32 (imm)
-        0x1e, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq32 (reg)
-    ];
-
-    let expected_output = "stw [r1-0x8000], 0x1
-sth [r1-0x8000], 0x1
-stb [r1-0x8000], 0x1
-stdw [r1-0x8000], 0x1
-ldxw r1, [r0-0x8000]
-ldxh r1, [r0-0x8000]
-ldxb r1, [r0-0x8000]
-ldxdw r1, [r0-0x8000]
-jeq r1, 0x2, -0x8000
-jeq r1, r2, -0x8000
-jeq32 r1, 0x2, -0x8000
-jeq32 r1, r2, -0x8000";
-
-    let prog = to_insn_vec(&insns);
-    let asm = prog
-        .into_iter()
-        .map(|ins| ins.desc)
-        .collect::<Vec<_>>()
-        .join("\n");
-
-    assert_eq!(asm, expected_output);
-}

+ 0 - 571
kernel/crates/rbpf/tests/misc.rs

@@ -1,571 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// There are unused mut warnings due to unsafe code.
-#![allow(unused_mut)]
-#![allow(clippy::unreadable_literal)]
-
-// This crate would be needed to load bytecode from a BPF-compiled object file. Since the crate
-// is not used anywhere else in the library, it is deactivated: we do not want to load and compile
-// it just for the tests. If you want to use it, do not forget to add the following
-// dependency to your Cargo.toml file:
-//
-// ---
-// elf = "0.0.10"
-// ---
-//
-// extern crate elf;
-// use std::path::PathBuf;
-
-extern crate rbpf;
-
-#[cfg(feature = "std")]
-use rbpf::helpers;
-use rbpf::{assembler::assemble, Error, ErrorKind};
-
-// The following two examples have been compiled from C with the following command:
-//
-// ```bash
-//  clang -O2 -emit-llvm -c <file.c> -o - | llc -march=bpf -filetype=obj -o <file.o>
-// ```
-//
-// The C source code was the following:
-//
-// ```c
-// #include <linux/ip.h>
-// #include <linux/in.h>
-// #include <linux/tcp.h>
-// #include <linux/bpf.h>
-//
-// #define ETH_ALEN 6
-// #define ETH_P_IP 0x0008 /* htons(0x0800) */
-// #define TCP_HDR_LEN 20
-//
-// #define BLOCKED_TCP_PORT 0x9999
-//
-// struct eth_hdr {
-//     unsigned char   h_dest[ETH_ALEN];
-//     unsigned char   h_source[ETH_ALEN];
-//     unsigned short  h_proto;
-// };
-//
-// #define SEC(NAME) __attribute__((section(NAME), used))
-// SEC(".classifier")
-// int handle_ingress(struct __sk_buff *skb)
-// {
-//     void *data = (void *)(long)skb->data;
-//     void *data_end = (void *)(long)skb->data_end;
-//     struct eth_hdr *eth = data;
-//     struct iphdr *iph = data + sizeof(*eth);
-//     struct tcphdr *tcp = data + sizeof(*eth) + sizeof(*iph);
-//
-//     /* single length check */
-//     if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcp) > data_end)
-//         return 0;
-//     if (eth->h_proto != ETH_P_IP)
-//         return 0;
-//     if (iph->protocol != IPPROTO_TCP)
-//         return 0;
-//     if (tcp->source == BLOCKED_TCP_PORT || tcp->dest == BLOCKED_TCP_PORT)
-//         return -1;
-//     return 0;
-// }
-// char _license[] SEC(".license") = "GPL";
-// ```
-//
-// This program, once compiled, can be injected into Linux kernel, with tc for instance. Sadly, we
-// need to bring some modifications to the generated bytecode in order to run it: the three
-// instructions with opcode 0x61 load data from a packet area as 4-byte words, where we need to
-// load it as 8-bytes double words (0x79). The kernel does the same kind of translation before
-// running the program, but rbpf does not implement this.
-//
-// In addition, the offset at which the pointer to the packet data is stored must be changed: since
-// we use 8 bytes instead of 4 for the start and end addresses of the data packet, we cannot use
-// the offsets produced by clang (0x4c and 0x50), the addresses would overlap. Instead we can use,
-// for example, 0x40 and 0x50. See comments on the bytecode below to see the modifications.
-//
-// Once the bytecode has been (manually, in our case) edited, we can load the bytecode directly
-// from the ELF object file. This is easy to do, but requires the addition of two crates in the
-// Cargo.toml file (see comments above), so here we use just the hardcoded bytecode instructions
-// instead.
-
-#[test]
-#[cfg(feature = "std")]
-fn test_vm_block_port() {
-    // To load the bytecode from an object file instead of using the hardcoded instructions,
-    // use the additional crates commented at the beginning of this file (and also add them to your
-    // Cargo.toml). See comments above.
-    //
-    // ---
-    // let filename = "my_ebpf_object_file.o";
-    //
-    // let path = PathBuf::from(filename);
-    // let file = match elf::File::open_path(&path) {
-    //     Ok(f) => f,
-    //     Err(e) => panic!("Error: {:?}", e),
-    // };
-    //
-    // let text_scn = match file.get_section(".classifier") {
-    //     Some(s) => s,
-    //     None => panic!("Failed to look up .classifier section"),
-    // };
-    //
-    // let prog = &text_scn.data;
-    // ---
-
-    let prog = &[
-        0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00,
-        0x00, // 0x79 instead of 0x61
-        0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00,
-        0x00, // 0x79 instead of 0x61, 0x40 i.o. 0x4c
-        0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00,
-        0x00, 0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x0c, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x71, 0x12, 0x17, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-        0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x22,
-        0x00, 0x00, 0x00, 0x00, 0x00, // 0x79 instead of 0x61
-        0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00,
-        0x00, 0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00,
-        0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x21, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x18, 0x02, 0x00, 0x00,
-        0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x21, 0x01,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-
-    let packet = &mut [
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
-        0x00, // ethertype
-        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
-        0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
-        0x01,
-        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
-        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
-        0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
-        0x00, 0x01, 0x01, 0x08, 0x0a, // start data
-        0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
-    ];
-
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
-        .unwrap();
-
-    let res = vm.execute_program(packet).unwrap();
-    println!("Program returned: {res:?} ({res:#x})");
-    assert_eq!(res, 0xffffffff);
-}
-
-#[test]
-#[cfg(all(not(windows), feature = "std"))]
-fn test_jit_block_port() {
-    // To load the bytecode from an object file instead of using the hardcoded instructions,
-    // use the additional crates commented at the beginning of this file (and also add them to your
-    // Cargo.toml). See comments above.
-    //
-    // ---
-    // let filename = "my_ebpf_object_file.o";
-    //
-    // let path = PathBuf::from(filename);
-    // let file = match elf::File::open_path(&path) {
-    //     Ok(f) => f,
-    //     Err(e) => panic!("Error: {:?}", e),
-    // };
-    //
-    // let text_scn = match file.get_section(".classifier") {
-    //     Some(s) => s,
-    //     None => panic!("Failed to look up .classifier section"),
-    // };
-    //
-    // let prog = &text_scn.data;
-    // ---
-
-    let prog = &[
-        0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x12, 0x50, 0x00, 0x00, 0x00, 0x00,
-        0x00, // 0x79 instead of 0x61
-        0x79, 0x11, 0x40, 0x00, 0x00, 0x00, 0x00,
-        0x00, // 0x79 instead of 0x61, 0x40 i.o. 0x4c
-        0xbf, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00,
-        0x00, 0x2d, 0x23, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x0c, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x55, 0x02, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, 0x71, 0x12, 0x17, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x55, 0x02, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-        0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x11, 0x22,
-        0x00, 0x00, 0x00, 0x00, 0x00, // 0x79 instead of 0x61
-        0xbf, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00,
-        0x00, 0x15, 0x02, 0x08, 0x00, 0x99, 0x99, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x00, 0x00,
-        0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x21, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x18, 0x02, 0x00, 0x00,
-        0x00, 0x00, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x21, 0x01,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-
-    let packet = &mut [
-        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x08,
-        0x00, // ethertype
-        0x45, 0x00, 0x00, 0x3b, // start ip_hdr
-        0xa6, 0xab, 0x40, 0x00, 0x40, 0x06, 0x96, 0x0f, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00,
-        0x01,
-        // Program matches the next two bytes: 0x9999 returns 0xffffffff, else return 0.
-        0x99, 0x99, 0xc6, 0xcc, // start tcp_hdr
-        0xd1, 0xe5, 0xc4, 0x9d, 0xd4, 0x30, 0xb5, 0xd2, 0x80, 0x18, 0x01, 0x56, 0xfe, 0x2f, 0x00,
-        0x00, 0x01, 0x01, 0x08, 0x0a, // start data
-        0x00, 0x23, 0x75, 0x89, 0x00, 0x23, 0x63, 0x2d, 0x71, 0x64, 0x66, 0x73, 0x64, 0x66, 0x0au8,
-    ];
-
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
-        .unwrap();
-    vm.jit_compile().unwrap();
-
-    unsafe {
-        let res = vm.execute_program_jit(packet).unwrap();
-        println!("Program returned: {res:?} ({res:#x})");
-        assert_eq!(res, 0xffffffff);
-    }
-}
-
-// Program and memory come from uBPF test ldxh.
-#[test]
-fn test_vm_mbuff() {
-    let prog = &[
-        // Load mem from mbuff into R1
-        0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-        0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &[0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
-
-    let mbuff = [0u8; 32];
-    unsafe {
-        let mut data = mbuff.as_ptr().offset(8) as *mut u64;
-        let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-        data.write_unaligned(mem.as_ptr() as u64);
-        data_end.write_unaligned(mem.as_ptr() as u64 + mem.len() as u64);
-    }
-
-    let vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem, &mbuff).unwrap(), 0x2211);
-}
-
-// Program and memory come from uBPF test ldxh.
-#[test]
-fn test_vm_mbuff_with_rust_api() {
-    use rbpf::insn_builder::*;
-
-    let mut program = BpfCode::new();
-    program
-        .load_x(MemSize::DoubleWord)
-        .set_dst(0x01)
-        .set_src(0x01)
-        .set_off(0x00_08)
-        .push()
-        .load_x(MemSize::HalfWord)
-        .set_dst(0x00)
-        .set_src(0x01)
-        .set_off(0x00_02)
-        .push()
-        .exit()
-        .push();
-
-    let mem = &[0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
-
-    let mbuff = [0u8; 32];
-    unsafe {
-        let mut data = mbuff.as_ptr().offset(8) as *mut u64;
-        let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-        *data = mem.as_ptr() as u64;
-        *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    }
-
-    let vm = rbpf::EbpfVmMbuff::new(Some(program.into_bytes())).unwrap();
-    assert_eq!(vm.execute_program(mem, &mbuff).unwrap(), 0x2211);
-}
-
-// Program and memory come from uBPF test ldxh.
-#[test]
-#[cfg(all(not(windows), feature = "std"))]
-fn test_jit_mbuff() {
-    let prog = &[
-        // Load mem from mbuff into R1
-        0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
-        0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
-
-    let mut mbuff = [0u8; 32];
-    unsafe {
-        let mut data = mbuff.as_ptr().offset(8) as *mut u64;
-        let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
-        *data = mem.as_ptr() as u64;
-        *data_end = mem.as_ptr() as u64 + mem.len() as u64;
-    }
-
-    unsafe {
-        let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-        vm.jit_compile().unwrap();
-        assert_eq!(vm.execute_program_jit(mem, &mut mbuff).unwrap(), 0x2211);
-    }
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldabsb() {
-    let prog = &[
-        0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x33);
-
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x33);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldabsh() {
-    let prog = &[
-        0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x4433);
-
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x4433);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldabsw() {
-    let prog = &[
-        0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x66554433);
-    vm.jit_compile().unwrap();
-
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x66554433);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldabsdw() {
-    let prog = &[
-        0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0xaa99887766554433);
-    vm.jit_compile().unwrap();
-
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xaa99887766554433);
-    };
-}
-
-#[test]
-#[should_panic(expected = "Error: out of bounds memory load (insn #1),")]
-fn test_vm_err_ldabsb_oob() {
-    let prog = &[
-        0x38, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.execute_program(mem).unwrap();
-
-    // Memory check not implemented for JIT yet.
-}
-
-#[test]
-#[should_panic(expected = "Error: out of bounds memory load (insn #1),")]
-fn test_vm_err_ldabsb_nomem() {
-    let prog = &[
-        0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.execute_program().unwrap();
-
-    // Memory check not implemented for JIT yet.
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldindb() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x88);
-
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x88);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldindh() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x9988);
-
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x9988);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldindw() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x88776655);
-    vm.jit_compile().unwrap();
-
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x88776655);
-    };
-}
-
-#[cfg(all(not(windows), feature = "std"))]
-#[test]
-fn test_vm_jit_ldinddw() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0xccbbaa9988776655);
-    vm.jit_compile().unwrap();
-
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xccbbaa9988776655);
-    };
-}
-
-#[test]
-#[should_panic(expected = "Error: out of bounds memory load (insn #2),")]
-fn test_vm_err_ldindb_oob() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, 0x33, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let mem = &mut [
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.execute_program(mem).unwrap();
-
-    // Memory check not implemented for JIT yet.
-}
-
-#[test]
-#[should_panic(expected = "Error: out of bounds memory load (insn #2),")]
-fn test_vm_err_ldindb_nomem() {
-    let prog = &[
-        0xb7, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.execute_program().unwrap();
-
-    // Memory check not implemented for JIT yet.
-}
-
-#[test]
-#[should_panic(expected = "Error: No program set, call prog_set() to load one")]
-fn test_vm_exec_no_program() {
-    let vm = rbpf::EbpfVmNoData::new(None).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xBEE);
-}
-
-fn verifier_success(_prog: &[u8]) -> Result<(), Error> {
-    Ok(())
-}
-
-fn verifier_fail(_prog: &[u8]) -> Result<(), Error> {
-    Err(Error::new(ErrorKind::Other, "Gaggablaghblagh!"))
-}
-
-#[test]
-fn test_verifier_success() {
-    let prog = assemble(
-        "mov32 r0, 0xBEE
-         exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
-    vm.set_verifier(verifier_success).unwrap();
-    vm.set_program(&prog).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xBEE);
-}
-
-#[test]
-#[should_panic(expected = "Gaggablaghblagh!")]
-fn test_verifier_fail() {
-    let prog = assemble(
-        "mov32 r0, 0xBEE
-         exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
-    vm.set_verifier(verifier_fail).unwrap();
-    vm.set_program(&prog).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xBEE);
-}

+ 0 - 2891
kernel/crates/rbpf/tests/ubpf_jit_x86_64.rs

@@ -1,2891 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Converted from the tests for uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// The tests contained in this file are extracted from the unit tests of uBPF software. Each test
-// in this file has a name in the form `test_jit_<name>`, and corresponds to the (human-readable)
-// code in `ubpf/tree/master/tests/<name>`, available at
-// <https://github.com/iovisor/ubpf/tree/master/tests> (hyphen had to be replaced with underscores
-// as Rust will not accept them in function names). It is strongly advised to refer to the uBPF
-// version to understand what these program do.
-//
-// Each program was assembled from the uBPF version with the assembler provided by uBPF itself, and
-// available at <https://github.com/iovisor/ubpf/tree/master/ubpf>.
-// The very few modifications that have been realized should be indicated.
-
-// These are unit tests for the eBPF JIT compiler.
-
-#![allow(clippy::unreadable_literal)]
-#![cfg(all(not(windows), feature = "std"))]
-
-extern crate rbpf;
-mod common;
-
-use common::{TCP_SACK_ASM, TCP_SACK_MATCH, TCP_SACK_NOMATCH};
-use rbpf::{assembler::assemble, helpers};
-
-#[test]
-fn test_jit_add() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 2
-        add32 r0, 1
-        add32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x3);
-    }
-}
-
-#[test]
-fn test_jit_alu64_arith() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        mov r6, 6
-        mov r7, 7
-        mov r8, 8
-        mov r9, 9
-        add r0, 23
-        add r0, r7
-        sub r0, 13
-        sub r0, r1
-        mul r0, 7
-        mul r0, r3
-        div r0, 2
-        div r0, r4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x2a);
-    }
-}
-
-#[test]
-fn test_jit_alu64_bit() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        mov r6, 6
-        mov r7, 7
-        mov r8, 8
-        or r0, r5
-        or r0, 0xa0
-        and r0, 0xa3
-        mov r9, 0x91
-        and r0, r9
-        lsh r0, 32
-        lsh r0, 22
-        lsh r0, r8
-        rsh r0, 32
-        rsh r0, 19
-        rsh r0, r7
-        xor r0, 0x03
-        xor r0, r2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x11);
-    }
-}
-
-#[test]
-fn test_jit_alu_arith() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 1
-        mov32 r2, 2
-        mov32 r3, 3
-        mov32 r4, 4
-        mov32 r5, 5
-        mov32 r6, 6
-        mov32 r7, 7
-        mov32 r8, 8
-        mov32 r9, 9
-        add32 r0, 23
-        add32 r0, r7
-        sub32 r0, 13
-        sub32 r0, r1
-        mul32 r0, 7
-        mul32 r0, r3
-        div32 r0, 2
-        div32 r0, r4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x2a);
-    }
-}
-
-#[test]
-fn test_jit_alu_bit() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 1
-        mov32 r2, 2
-        mov32 r3, 3
-        mov32 r4, 4
-        mov32 r5, 5
-        mov32 r6, 6
-        mov32 r7, 7
-        mov32 r8, 8
-        or32 r0, r5
-        or32 r0, 0xa0
-        and32 r0, 0xa3
-        mov32 r9, 0x91
-        and32 r0, r9
-        lsh32 r0, 22
-        lsh32 r0, r8
-        rsh32 r0, 19
-        rsh32 r0, r7
-        xor32 r0, 0x03
-        xor32 r0, r2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x11);
-    }
-}
-
-#[test]
-fn test_jit_arsh32_high_shift() {
-    let prog = assemble(
-        "
-        mov r0, 8
-        lddw r1, 0x100000001
-        arsh32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x4);
-    }
-}
-
-#[test]
-fn test_jit_arsh() {
-    let prog = assemble(
-        "
-        mov32 r0, 0xf8
-        lsh32 r0, 28
-        arsh32 r0, 16
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xffff8000);
-    }
-}
-
-#[test]
-fn test_jit_arsh64() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh r0, 63
-        arsh r0, 55
-        mov32 r1, 5
-        arsh r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xfffffffffffffff8);
-    }
-}
-
-#[test]
-fn test_jit_arsh_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0xf8
-        mov32 r1, 16
-        lsh32 r0, 28
-        arsh32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xffff8000);
-    }
-}
-
-#[test]
-fn test_jit_be16() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1122);
-    }
-}
-
-#[test]
-fn test_jit_be16_high() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1122);
-    }
-}
-
-#[test]
-fn test_jit_be32() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1]
-        be32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11223344);
-    }
-}
-
-#[test]
-fn test_jit_be32_high() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11223344);
-    }
-}
-
-#[test]
-fn test_jit_be64() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1122334455667788);
-    }
-}
-
-#[test]
-fn test_jit_call() {
-    let prog = assemble(
-        "
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        call 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0102030405);
-    }
-}
-
-#[test]
-fn test_jit_call_memfrob() {
-    let prog = assemble(
-        "
-        mov r6, r1
-        add r1, 2
-        mov r2, 4
-        call 1
-        ldxdw r0, [r6]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x102292e2f2c0708);
-    }
-}
-
-// TODO: helpers::trash_registers needs asm!().
-// Try this again once asm!() is available in stable.
-//#[test]
-//fn test_jit_call_save() {
-//let prog = &[
-//0xb7, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-//0xb7, 0x07, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-//0xb7, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
-//0xb7, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-//0x85, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-//0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-//];
-//let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-//vm.register_helper(2, helpers::trash_registers);
-//vm.jit_compile().unwrap();
-//unsafe { assert_eq!(vm.execute_program_jit().unwrap(), 0x4321); }
-//}
-
-#[test]
-fn test_jit_div32_high_divisor() {
-    let prog = assemble(
-        "
-        mov r0, 12
-        lddw r1, 0x100000004
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x3);
-    }
-}
-
-#[test]
-fn test_jit_div32_imm() {
-    let prog = assemble(
-        "
-        lddw r0, 0x10000000c
-        div32 r0, 4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x3);
-    }
-}
-
-#[test]
-fn test_jit_div32_reg() {
-    let prog = assemble(
-        "
-        lddw r0, 0x10000000c
-        mov r1, 4
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x3);
-    }
-}
-
-#[test]
-fn test_jit_div64_imm() {
-    let prog = assemble(
-        "
-        mov r0, 0xc
-        lsh r0, 32
-        div r0, 4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x300000000);
-    }
-}
-
-#[test]
-fn test_jit_div64_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0xc
-        lsh r0, 32
-        mov r1, 4
-        div r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x300000000);
-    }
-}
-
-// For some register numbers, we don't emit the same instructions for handling divisions by zero,
-// which means we don't use the same offset to skip these instructions when the divisor is not
-// zero. We've had a regression because of this before, make sure we test it.
-#[test]
-fn test_jit_div32_highreg() {
-    let prog = assemble(
-        "
-        mov r0, 2
-        mov r7, 4
-        div32 r7, r0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x2);
-    }
-}
-
-#[test]
-fn test_jit_div64_highreg() {
-    let prog = assemble(
-        "
-        mov r0, 2
-        mov r7, 4
-        div r7, r0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x2);
-    }
-}
-
-#[test]
-fn test_jit_early_exit() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        exit
-        mov r0, 4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x3);
-    }
-}
-
-// uBPF limits the number of user functions at 64. We don't.
-//#[test]
-//fn test_jit_err_call_bad_imm() {
-//}
-
-#[test]
-#[should_panic(expected = "[JIT] Error: unknown helper function (id: 0x3f)")]
-fn test_jit_err_call_unreg() {
-    let prog = assemble(
-        "
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        call 63
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        vm.execute_program_jit().unwrap();
-    }
-}
-
-#[test]
-fn test_jit_div64_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        div r0, 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_div_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        div32 r0, 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_mod64_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mod r0, 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_mod_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mod32 r0, 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_div64_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        div r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_div_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_mod64_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        mod r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_mod_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        mod32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-// TODO SKIP: JIT disabled for this testcase (stack oob check not implemented)
-// #[test]
-// #[should_panic(expected = "Error: out of bounds memory store (insn #1)")]
-// fn test_jit_err_stack_out_of_bound() {
-//     let prog = &[
-//         0x72, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-//     ];
-//     let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-//     vm.jit_compile().unwrap();
-//     unsafe { vm.execute_program_jit().unwrap(); }
-// }
-
-#[test]
-fn test_jit_exit() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_ja() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        ja +1
-        mov r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jeq_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jeq r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xb
-        jeq r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jeq_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jeq r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xb
-        jeq r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jge_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jge r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xc
-        jge r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jle_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jle r1, 4, +1
-        jle r1, 6, +1
-        exit
-        jle r1, 5, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jle_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        jle r1, r2, +2
-        jle r1, r1, +1
-        exit
-        jle r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jgt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jgt r1, 6, +2
-        jgt r1, 5, +1
-        jgt r1, 4, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jgt_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 6
-        mov r3, 4
-        jgt r1, r2, +2
-        jgt r1, r1, +1
-        jgt r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jlt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jlt r1, 4, +2
-        jlt r1, 5, +1
-        jlt r1, 6, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jlt_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        jlt r1, r2, +2
-        jlt r1, r1, +1
-        jlt r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jit_bounce() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        mov r6, r0
-        mov r7, r6
-        mov r8, r7
-        mov r9, r8
-        mov r0, r9
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jne_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xb
-        mov32 r2, 0xb
-        jne r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        jne r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jset_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0x7
-        jset r1, 0x8, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset r1, 0x8, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jset_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0x7
-        mov32 r2, 0x8
-        jset r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsge_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsge r1, -1, +5
-        jsge r1, 0, +4
-        mov32 r0, 1
-        mov r1, -1
-        jsge r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsge_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -1
-        mov32 r3, 0
-        jsge r1, r2, +5
-        jsge r1, r3, +4
-        mov32 r0, 1
-        mov r1, r2
-        jsge r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsle_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsle r1, -3, +1
-        jsle r1, -1, +1
-        exit
-        mov32 r0, 1
-        jsle r1, -2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsle_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -1
-        mov r2, -2
-        mov32 r3, 0
-        jsle r1, r2, +1
-        jsle r1, r3, +1
-        exit
-        mov32 r0, 1
-        mov r1, r2
-        jsle r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsgt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsgt r1, -1, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsgt_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -1
-        jsgt r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jslt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jslt r1, -3, +2
-        jslt r1, -2, +1
-        jslt r1, -1, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jslt_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -3
-        mov r3, -1
-        jslt r1, r1, +2
-        jslt r1, r2, +1
-        jslt r1, r3, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jeq32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0x0
-        mov32 r1, 0xa
-        jeq32 r1, 0xb, +5
-        mov32 r0, 1
-        mov r1, 0xb
-        or r1, r9
-        jeq32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jeq32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jeq32 r1, r2, +5
-        mov32 r0, 1
-        mov32 r1, 0xb
-        or r1, r9
-        jeq32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jge32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jge32 r1, 0xb, +5
-        mov32 r0, 1
-        or r1, r9
-        mov32 r1, 0xc
-        jge32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jge32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jge32 r1, r2, +5
-        mov32 r0, 1
-        or r1, r9
-        mov32 r1, 0xc
-        jge32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jgt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jgt32 r1, 6, +4
-        jgt32 r1, 5, +3
-        jgt32 r1, 4, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jgt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov32 r1, 5
-        or r1, r9
-        mov r2, 6
-        mov r3, 4
-        jgt32 r1, r2, +4
-        jgt32 r1, r1, +3
-        jgt32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jle32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jle32 r1, 4, +5
-        jle32 r1, 6, +1
-        exit
-        jle32 r1, 5, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jle32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        or r1, r9
-        jle32 r1, r2, +5
-        jle32 r1, r1, +1
-        exit
-        jle32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jlt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jlt32 r1, 4, +4
-        jlt32 r1, 5, +3
-        jlt32 r1, 6, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jlt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        or r1, r9
-        jlt32 r1, r2, +4
-        jlt32 r1, r1, +3
-        jlt32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jne32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xb
-        or r1, r9
-        jne32 r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        or r1, r9
-        jne32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jne32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xb
-        or r1, r9
-        mov32 r2, 0xb
-        jne32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        or r1, r9
-        jne32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jset32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0x7
-        or r1, r9
-        jset32 r1, 0x8, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset32 r1, 0x8, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jset32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0x7
-        or r1, r9
-        mov32 r2, 0x8
-        jset32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsge32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsge32 r1, -1, +5
-        jsge32 r1, 0, +4
-        mov32 r0, 1
-        mov r1, -1
-        jsge32 r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsge32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -1
-        mov32 r3, 0
-        jsge32 r1, r2, +5
-        jsge32 r1, r3, +4
-        mov32 r0, 1
-        mov r1, r2
-        jsge32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsgt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsgt32 r1, -1, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt32 r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsgt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -1
-        jsgt32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsle32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsle32 r1, -3, +5
-        jsle32 r1, -1, +1
-        exit
-        mov32 r0, 1
-        jsle32 r1, -2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jsle32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -3
-        mov32 r3, 0
-        jsle32 r1, r2, +6
-        jsle32 r1, r3, +1
-        exit
-        mov32 r0, 1
-        mov r1, r2
-        jsle32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jslt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jslt32 r1, -3, +4
-        jslt32 r1, -2, +3
-        jslt32 r1, -1, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_jslt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -3
-        mov r3, -1
-        jslt32 r1, r1, +4
-        jslt32 r1, r2, +3
-        jslt32 r1, r3, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_lddw() {
-    let prog = assemble(
-        "
-        lddw r0, 0x1122334455667788
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1122334455667788);
-    }
-}
-
-#[test]
-fn test_jit_lddw2() {
-    let prog = assemble(
-        "
-        lddw r0, 0x0000000080000000
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x80000000);
-    }
-}
-
-#[test]
-fn test_jit_ldxb_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxb r9, [r0+0]
-        lsh r9, 0
-        ldxb r8, [r0+1]
-        lsh r8, 4
-        ldxb r7, [r0+2]
-        lsh r7, 8
-        ldxb r6, [r0+3]
-        lsh r6, 12
-        ldxb r5, [r0+4]
-        lsh r5, 16
-        ldxb r4, [r0+5]
-        lsh r4, 20
-        ldxb r3, [r0+6]
-        lsh r3, 24
-        ldxb r2, [r0+7]
-        lsh r2, 28
-        ldxb r1, [r0+8]
-        lsh r1, 32
-        ldxb r0, [r0+9]
-        lsh r0, 36
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x9876543210);
-    }
-}
-
-#[test]
-fn test_jit_ldxb() {
-    let prog = assemble(
-        "
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11);
-    }
-}
-
-#[test]
-fn test_jit_ldxdw() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xcc, 0xdd,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x8877665544332211);
-    }
-}
-
-#[test]
-fn test_jit_ldxh_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxh r9, [r0+0]
-        be16 r9
-        lsh r9, 0
-        ldxh r8, [r0+2]
-        be16 r8
-        lsh r8, 4
-        ldxh r7, [r0+4]
-        be16 r7
-        lsh r7, 8
-        ldxh r6, [r0+6]
-        be16 r6
-        lsh r6, 12
-        ldxh r5, [r0+8]
-        be16 r5
-        lsh r5, 16
-        ldxh r4, [r0+10]
-        be16 r4
-        lsh r4, 20
-        ldxh r3, [r0+12]
-        be16 r3
-        lsh r3, 24
-        ldxh r2, [r0+14]
-        be16 r2
-        lsh r2, 28
-        ldxh r1, [r0+16]
-        be16 r1
-        lsh r1, 32
-        ldxh r0, [r0+18]
-        be16 r0
-        lsh r0, 36
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00,
-        0x07, 0x00, 0x08, 0x00, 0x09,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x9876543210);
-    }
-}
-
-#[test]
-fn test_jit_ldxh_all2() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxh r9, [r0+0]
-        be16 r9
-        ldxh r8, [r0+2]
-        be16 r8
-        ldxh r7, [r0+4]
-        be16 r7
-        ldxh r6, [r0+6]
-        be16 r6
-        ldxh r5, [r0+8]
-        be16 r5
-        ldxh r4, [r0+10]
-        be16 r4
-        ldxh r3, [r0+12]
-        be16 r3
-        ldxh r2, [r0+14]
-        be16 r2
-        ldxh r1, [r0+16]
-        be16 r1
-        ldxh r0, [r0+18]
-        be16 r0
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00,
-        0x80, 0x01, 0x00, 0x02, 0x00,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x3ff);
-    }
-}
-
-#[test]
-fn test_jit_ldxh() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x2211);
-    }
-}
-
-#[test]
-fn test_jit_ldxh_same_reg() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        sth [r0], 0x1234
-        ldxh r0, [r0]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1234);
-    }
-}
-
-#[test]
-fn test_jit_ldxw_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxw r9, [r0+0]
-        be32 r9
-        ldxw r8, [r0+4]
-        be32 r8
-        ldxw r7, [r0+8]
-        be32 r7
-        ldxw r6, [r0+12]
-        be32 r6
-        ldxw r5, [r0+16]
-        be32 r5
-        ldxw r4, [r0+20]
-        be32 r4
-        ldxw r3, [r0+24]
-        be32 r3
-        ldxw r2, [r0+28]
-        be32 r2
-        ldxw r1, [r0+32]
-        be32 r1
-        ldxw r0, [r0+36]
-        be32 r0
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x030f0f);
-    }
-}
-
-#[test]
-fn test_jit_ldxw() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x44332211);
-    }
-}
-
-#[test]
-fn test_jit_le16() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1]
-        le16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x22, 0x11];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1122);
-    }
-}
-
-#[test]
-fn test_jit_le32() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1]
-        le32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x44, 0x33, 0x22, 0x11];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11223344);
-    }
-}
-
-#[test]
-fn test_jit_le64() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        le64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1122334455667788);
-    }
-}
-
-#[test]
-fn test_jit_lsh_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0x1
-        mov r7, 4
-        lsh r0, r7
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x10);
-    }
-}
-
-#[test]
-fn test_jit_mod() {
-    let prog = assemble(
-        "
-        mov32 r0, 5748
-        mod32 r0, 92
-        mov32 r1, 13
-        mod32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x5);
-    }
-}
-
-#[test]
-fn test_jit_mod32() {
-    let prog = assemble(
-        "
-        lddw r0, 0x100000003
-        mod32 r0, 3
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_mod64() {
-    let prog = assemble(
-        "
-        mov32 r0, -1316649930
-        lsh r0, 32
-        or r0, 0x100dc5c8
-        mov32 r1, 0xdde263e
-        lsh r1, 32
-        or r1, 0x3cbef7f3
-        mod r0, r1
-        mod r0, 0x658f1778
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x30ba5a04);
-    }
-}
-
-#[test]
-fn test_jit_mov() {
-    let prog = assemble(
-        "
-        mov32 r1, 1
-        mov32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_mul32_imm() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        mul32 r0, 4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xc);
-    }
-}
-
-#[test]
-fn test_jit_mul32_reg() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        mov r1, 4
-        mul32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xc);
-    }
-}
-
-#[test]
-fn test_jit_mul32_reg_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mov r1, 4
-        mul32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x4);
-    }
-}
-
-#[test]
-fn test_jit_mul64_imm() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mul r0, 4
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x100000004);
-    }
-}
-
-#[test]
-fn test_jit_mul64_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mov r1, 4
-        mul r0, r1
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x100000004);
-    }
-}
-
-#[test]
-fn test_jit_mul_loop() {
-    let prog = assemble(
-        "
-        mov r0, 0x7
-        add r1, 0xa
-        lsh r1, 0x20
-        rsh r1, 0x20
-        jeq r1, 0x0, +4
-        mov r0, 0x7
-        mul r0, 0x7
-        add r1, -1
-        jne r1, 0x0, -3
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x75db9c97);
-    }
-}
-
-#[test]
-fn test_jit_neg64() {
-    let prog = assemble(
-        "
-        mov32 r0, 2
-        neg r0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xfffffffffffffffe);
-    }
-}
-
-#[test]
-fn test_jit_neg() {
-    let prog = assemble(
-        "
-        mov32 r0, 2
-        neg32 r0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xfffffffe);
-    }
-}
-
-#[test]
-fn test_jit_prime() {
-    let prog = assemble(
-        "
-        mov r1, 67
-        mov r0, 0x1
-        mov r2, 0x2
-        jgt r1, 0x2, +4
-        ja +10
-        add r2, 0x1
-        mov r0, 0x1
-        jge r2, r1, +7
-        mov r3, r1
-        div r3, r2
-        mul r3, r2
-        mov r4, r1
-        sub r4, r3
-        mov r0, 0x0
-        jne r4, 0x0, -10
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_rhs32() {
-    let prog = assemble(
-        "
-        xor r0, r0
-        sub r0, 1
-        rsh32 r0, 8
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x00ffffff);
-    }
-}
-
-#[test]
-fn test_jit_rsh_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0x10
-        mov r7, 4
-        rsh r0, r7
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_stack() {
-    let prog = assemble(
-        "
-        mov r1, 51
-        stdw [r10-16], 0xab
-        stdw [r10-8], 0xcd
-        and r1, 1
-        lsh r1, 3
-        mov r2, r10
-        add r2, r1
-        ldxdw r0, [r2-16]
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0xcd);
-    }
-}
-
-#[test]
-fn test_jit_stack2() {
-    let prog = assemble(
-        "
-        stb [r10-4], 0x01
-        stb [r10-3], 0x02
-        stb [r10-2], 0x03
-        stb [r10-1], 0x04
-        mov r1, r10
-        mov r2, 0x4
-        sub r1, r2
-        call 1
-        mov r1, 0
-        ldxb r2, [r10-4]
-        ldxb r3, [r10-3]
-        ldxb r4, [r10-2]
-        ldxb r5, [r10-1]
-        call 0
-        xor r0, 0x2a2a2a2a
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x01020304);
-    }
-}
-
-#[test]
-fn test_jit_stb() {
-    let prog = assemble(
-        "
-        stb [r1+2], 0x11
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11);
-    }
-}
-
-#[test]
-fn test_jit_stdw() {
-    let prog = assemble(
-        "
-        stdw [r1+2], 0x44332211
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x44332211);
-    }
-}
-
-#[test]
-fn test_jit_sth() {
-    let prog = assemble(
-        "
-        sth [r1+2], 0x2211
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x2211);
-    }
-}
-
-#[test]
-fn test_jit_string_stack() {
-    let prog = assemble(
-        "
-        mov r1, 0x78636261
-        stxw [r10-8], r1
-        mov r6, 0x0
-        stxb [r10-4], r6
-        stxb [r10-12], r6
-        mov r1, 0x79636261
-        stxw [r10-16], r1
-        mov r1, r10
-        add r1, -8
-        mov r2, r1
-        call 0x4
-        mov r1, r0
-        mov r0, 0x1
-        lsh r1, 0x20
-        rsh r1, 0x20
-        jne r1, 0x0, +11
-        mov r1, r10
-        add r1, -8
-        mov r2, r10
-        add r2, -16
-        call 0x4
-        mov r1, r0
-        lsh r1, 0x20
-        rsh r1, 0x20
-        mov r0, 0x1
-        jeq r1, r6, +1
-        mov r0, 0x0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(4, helpers::strcmp).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit().unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_stw() {
-    let prog = assemble(
-        "
-        stw [r1+2], 0x44332211
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x44332211);
-    }
-}
-
-#[test]
-fn test_jit_stxb() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x11
-        stxb [r1+2], r2
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x11);
-    }
-}
-
-#[test]
-fn test_jit_stxb_all() {
-    let prog = assemble(
-        "
-        mov r0, 0xf0
-        mov r2, 0xf2
-        mov r3, 0xf3
-        mov r4, 0xf4
-        mov r5, 0xf5
-        mov r6, 0xf6
-        mov r7, 0xf7
-        mov r8, 0xf8
-        stxb [r1], r0
-        stxb [r1+1], r2
-        stxb [r1+2], r3
-        stxb [r1+3], r4
-        stxb [r1+4], r5
-        stxb [r1+5], r6
-        stxb [r1+6], r7
-        stxb [r1+7], r8
-        ldxdw r0, [r1]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xf0f2f3f4f5f6f7f8);
-    }
-}
-
-#[test]
-fn test_jit_stxb_all2() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        mov r1, 0xf1
-        mov r9, 0xf9
-        stxb [r0], r1
-        stxb [r0+1], r9
-        ldxh r0, [r0]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0xf1f9);
-    }
-}
-
-#[test]
-fn test_jit_stxb_chain() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxb r9, [r0+0]
-        stxb [r0+1], r9
-        ldxb r8, [r0+1]
-        stxb [r0+2], r8
-        ldxb r7, [r0+2]
-        stxb [r0+3], r7
-        ldxb r6, [r0+3]
-        stxb [r0+4], r6
-        ldxb r5, [r0+4]
-        stxb [r0+5], r5
-        ldxb r4, [r0+5]
-        stxb [r0+6], r4
-        ldxb r3, [r0+6]
-        stxb [r0+7], r3
-        ldxb r2, [r0+7]
-        stxb [r0+8], r2
-        ldxb r1, [r0+8]
-        stxb [r0+9], r1
-        ldxb r0, [r0+9]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x2a);
-    }
-}
-
-#[test]
-fn test_jit_stxdw() {
-    let prog = assemble(
-        "
-        mov r2, -2005440939
-        lsh r2, 32
-        or r2, 0x44332211
-        stxdw [r1+2], r2
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x8877665544332211);
-    }
-}
-
-#[test]
-fn test_jit_stxh() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x2211
-        stxh [r1+2], r2
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x2211);
-    }
-}
-
-#[test]
-fn test_jit_stxw() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x44332211
-        stxw [r1+2], r2
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x44332211);
-    }
-}
-
-#[test]
-fn test_jit_subnet() {
-    let prog = assemble(
-        "
-        mov r2, 0xe
-        ldxh r3, [r1+12]
-        jne r3, 0x81, +2
-        mov r2, 0x12
-        ldxh r3, [r1+16]
-        and r3, 0xffff
-        jne r3, 0x8, +5
-        add r1, r2
-        mov r0, 0x1
-        ldxw r1, [r1+16]
-        and r1, 0xffffff
-        jeq r1, 0x1a8c0, +1
-        mov r0, 0x0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0xc0, 0x9f, 0xa0, 0x97, 0x00, 0xa0, 0xcc, 0x3b, 0xbf, 0xfa, 0x08, 0x00, 0x45,
-        0x10, 0x00, 0x3c, 0x46, 0x3c, 0x40, 0x00, 0x40, 0x06, 0x73, 0x1c, 0xc0, 0xa8, 0x01, 0x02,
-        0xc0, 0xa8, 0x01, 0x01, 0x06, 0x0e, 0x00, 0x17, 0x99, 0xc5, 0xa0, 0xec, 0x00, 0x00, 0x00,
-        0x00, 0xa0, 0x02, 0x7d, 0x78, 0xe0, 0xa3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02,
-        0x08, 0x0a, 0x00, 0x9c, 0x27, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x00,
-    ];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1);
-    }
-}
-
-const PROG_TCP_PORT_80: [u8; 152] = [
-    0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x0a, 0x00, 0x06, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-    0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-    0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x15, 0x02, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x69, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x55, 0x01, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-];
-
-#[test]
-fn test_jit_tcp_port80_match() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_tcp_port80_nomatch() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x00, 0x16, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x51, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_tcp_port80_nomatch_ethertype() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x01, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_tcp_port80_nomatch_proto() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem).unwrap(), 0x0);
-    }
-}
-
-#[test]
-fn test_jit_tcp_sack_match() {
-    let mut mem = TCP_SACK_MATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem.as_mut_slice()).unwrap(), 0x1);
-    }
-}
-
-#[test]
-fn test_jit_tcp_sack_nomatch() {
-    let mut mem = TCP_SACK_NOMATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.jit_compile().unwrap();
-    unsafe {
-        assert_eq!(vm.execute_program_jit(mem.as_mut_slice()).unwrap(), 0x0);
-    }
-}

+ 0 - 177
kernel/crates/rbpf/tests/ubpf_verifier.rs

@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Converted from the tests for uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// The tests contained in this file are extracted from the unit tests of uBPF software. Each test
-// in this file has a name in the form `test_verifier_<name>`, and corresponds to the
-// (human-readable) code in `ubpf/tree/master/tests/<name>`, available at
-// <https://github.com/iovisor/ubpf/tree/master/tests> (hyphen had to be replaced with underscores
-// as Rust will not accept them in function names). It is strongly advised to refer to the uBPF
-// version to understand what these program do.
-//
-// Each program was assembled from the uBPF version with the assembler provided by uBPF itself, and
-// available at <https://github.com/iovisor/ubpf/tree/master/ubpf>.
-// The very few modifications that have been realized should be indicated.
-
-// These are unit tests for the eBPF “verifier”.
-
-extern crate rbpf;
-
-use rbpf::{assembler::assemble, ebpf};
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: unsupported argument for LE/BE (insn #0)")]
-fn test_verifier_err_endian_size() {
-    let prog = &[
-        0xdc, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    ];
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: incomplete LD_DW instruction (insn #0)")]
-fn test_verifier_err_incomplete_lddw() {
-    // Note: ubpf has test-err-incomplete-lddw2, which is the same
-    let prog = &[
-        0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: infinite loop")]
-fn test_verifier_err_infinite_loop() {
-    let prog = assemble(
-        "
-        ja -1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: invalid destination register (insn #0)")]
-fn test_verifier_err_invalid_reg_dst() {
-    let prog = assemble(
-        "
-        mov r11, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: invalid source register (insn #0)")]
-fn test_verifier_err_invalid_reg_src() {
-    let prog = assemble(
-        "
-        mov r0, r11
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: jump to middle of LD_DW at #2 (insn #0)")]
-fn test_verifier_err_jmp_lddw() {
-    let prog = assemble(
-        "
-        ja +1
-        lddw r0, 0x1122334455667788
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: jump out of code to #3 (insn #0)")]
-fn test_verifier_err_jmp_out() {
-    let prog = assemble(
-        "
-        ja +2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: program does not end with “EXIT” instruction")]
-fn test_verifier_err_no_exit() {
-    let prog = assemble(
-        "
-        mov32 r0, 0",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-fn test_verifier_err_no_exit_backward_jump() {
-    let prog = assemble(
-        "
-        ja +1
-        exit
-        ja -2",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: eBPF program length limited to 1000000, here 1000001")]
-fn test_verifier_err_too_many_instructions() {
-    // uBPF uses 65637 instructions, because it sets its limit at 65636.
-    // We use the classic 4096 limit from kernel, so no need to produce as many instructions.
-    let mut prog = (0..(1_000_000 * ebpf::INSN_SIZE))
-        .map(|x| match x % 8 {
-            0 => 0xb7,
-            1 => 0x01,
-            _ => 0,
-        })
-        .collect::<Vec<u8>>();
-    prog.append(&mut vec![0x95, 0, 0, 0, 0, 0, 0, 0]);
-
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: unknown eBPF opcode 0x6 (insn #0)")]
-fn test_verifier_err_unknown_opcode() {
-    let prog = &[
-        0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00,
-    ];
-    let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-#[should_panic(expected = "[Verifier] Error: cannot write into register r10 (insn #0)")]
-fn test_verifier_err_write_r10() {
-    let prog = assemble(
-        "
-        mov r10, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}

+ 0 - 2674
kernel/crates/rbpf/tests/ubpf_vm.rs

@@ -1,2674 +0,0 @@
-// SPDX-License-Identifier: (Apache-2.0 OR MIT)
-// Converted from the tests for uBPF <https://github.com/iovisor/ubpf>
-// Copyright 2015 Big Switch Networks, Inc
-// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
-
-// The tests contained in this file are extracted from the unit tests of uBPF software. Each test
-// in this file has a name in the form `test_vm_<name>`, and corresponds to the (human-readable)
-// code in `ubpf/tree/master/tests/<name>`, available at
-// <https://github.com/iovisor/ubpf/tree/master/tests> (hyphen had to be replaced with underscores
-// as Rust will not accept them in function names). It is strongly advised to refer to the uBPF
-// version to understand what these program do.
-//
-// Each program was assembled from the uBPF version with the assembler provided by uBPF itself, and
-// available at <https://github.com/iovisor/ubpf/tree/master/ubpf>.
-// The very few modifications that have been realized should be indicated.
-
-// These are unit tests for the eBPF interpreter.
-
-#![allow(clippy::unreadable_literal)]
-
-extern crate rbpf;
-mod common;
-
-use common::{TCP_SACK_ASM, TCP_SACK_MATCH, TCP_SACK_NOMATCH};
-use rbpf::{assembler::assemble, helpers};
-
-#[test]
-fn test_vm_add() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 2
-        add32 r0, 1
-        add32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-
-#[test]
-fn test_vm_alu64_arith() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        mov r6, 6
-        mov r7, 7
-        mov r8, 8
-        mov r9, 9
-        add r0, 23
-        add r0, r7
-        sub r0, 13
-        sub r0, r1
-        mul r0, 7
-        mul r0, r3
-        div r0, 2
-        div r0, r4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x2a);
-}
-
-#[test]
-fn test_vm_alu64_bit() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        mov r6, 6
-        mov r7, 7
-        mov r8, 8
-        or r0, r5
-        or r0, 0xa0
-        and r0, 0xa3
-        mov r9, 0x91
-        and r0, r9
-        lsh r0, 32
-        lsh r0, 22
-        lsh r0, r8
-        rsh r0, 32
-        rsh r0, 19
-        rsh r0, r7
-        xor r0, 0x03
-        xor r0, r2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x11);
-}
-
-#[test]
-fn test_vm_alu_arith() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 1
-        mov32 r2, 2
-        mov32 r3, 3
-        mov32 r4, 4
-        mov32 r5, 5
-        mov32 r6, 6
-        mov32 r7, 7
-        mov32 r8, 8
-        mov32 r9, 9
-        add32 r0, 23
-        add32 r0, r7
-        sub32 r0, 13
-        sub32 r0, r1
-        mul32 r0, 7
-        mul32 r0, r3
-        div32 r0, 2
-        div32 r0, r4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x2a);
-}
-
-#[test]
-fn test_vm_alu_bit() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 1
-        mov32 r2, 2
-        mov32 r3, 3
-        mov32 r4, 4
-        mov32 r5, 5
-        mov32 r6, 6
-        mov32 r7, 7
-        mov32 r8, 8
-        or32 r0, r5
-        or32 r0, 0xa0
-        and32 r0, 0xa3
-        mov32 r9, 0x91
-        and32 r0, r9
-        lsh32 r0, 22
-        lsh32 r0, r8
-        rsh32 r0, 19
-        rsh32 r0, r7
-        xor32 r0, 0x03
-        xor32 r0, r2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x11);
-}
-
-#[test]
-fn test_vm_arsh32_high_shift() {
-    let prog = assemble(
-        "
-        mov r0, 8
-        lddw r1, 0x100000001
-        arsh32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x4);
-}
-
-#[test]
-fn test_vm_arsh() {
-    let prog = assemble(
-        "
-        mov32 r0, 0xf8
-        lsh32 r0, 28
-        arsh32 r0, 16
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xffff8000);
-}
-
-#[test]
-fn test_vm_arsh64() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh r0, 63
-        arsh r0, 55
-        mov32 r1, 5
-        arsh r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xfffffffffffffff8);
-}
-
-#[test]
-fn test_vm_arsh_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0xf8
-        mov32 r1, 16
-        lsh32 r0, 28
-        arsh32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xffff8000);
-}
-
-#[test]
-fn test_vm_arsh_imm_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        lsh r0, 63
-        arsh r0, 0xff20
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xffffffff80000000);
-}
-
-#[test]
-fn test_vm_arsh_reg_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        lsh r0, 63
-        mov r1, 0xff04
-        arsh r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xf800000000000000);
-}
-
-#[test]
-fn test_vm_arsh32_imm_overflow() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh32 r0, 31
-        arsh32 r0, 0xff10
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xffff8000);
-}
-
-#[test]
-fn test_vm_arsh32_reg_overflow() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh32 r0, 31
-        mov32 r1, 32
-        arsh32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x80000000);
-}
-
-#[test]
-fn test_vm_be16() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1122);
-}
-
-#[test]
-fn test_vm_be16_high() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1122);
-}
-
-#[test]
-fn test_vm_be32() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1]
-        be32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11223344);
-}
-
-#[test]
-fn test_vm_be32_high() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11223344);
-}
-
-#[test]
-fn test_vm_be64() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1122334455667788);
-}
-
-#[test]
-fn test_vm_call() {
-    let prog = assemble(
-        "
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        call 0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0102030405);
-}
-
-#[test]
-fn test_vm_call_memfrob() {
-    let prog = assemble(
-        "
-        mov r6, r1
-        add r1, 2
-        mov r2, 4
-        call 1
-        ldxdw r0, [r6]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
-    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x102292e2f2c0708);
-}
-
-// TODO: helpers::trash_registers needs asm!().
-// Try this again once asm!() is available in stable.
-//#[test]
-//fn test_vm_call_save() {
-//let prog = &[
-//0xb7, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-//0xb7, 0x07, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
-//0xb7, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
-//0xb7, 0x09, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-//0x85, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-//0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x4f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-//0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-//];
-//let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-//vm.register_helper(2, helpers::trash_registers);
-//assert_eq!(vm.execute_program().unwrap(), 0x4321);
-//}
-
-#[test]
-fn test_vm_div32_high_divisor() {
-    let prog = assemble(
-        "
-        mov r0, 12
-        lddw r1, 0x100000004
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-
-#[test]
-fn test_vm_div32_imm() {
-    let prog = assemble(
-        "
-        lddw r0, 0x10000000c
-        div32 r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-
-#[test]
-fn test_vm_div32_reg() {
-    let prog = assemble(
-        "
-        lddw r0, 0x10000000c
-        mov r1, 4
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-
-#[test]
-fn test_vm_div64_imm() {
-    let prog = assemble(
-        "
-        mov r0, 0xc
-        lsh r0, 32
-        div r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x300000000);
-}
-
-#[test]
-fn test_vm_div64_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0xc
-        lsh r0, 32
-        mov r1, 4
-        div r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x300000000);
-}
-
-#[test]
-fn test_vm_early_exit() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        exit
-        mov r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x3);
-}
-
-// uBPF limits the number of user functions at 64. We don't.
-//#[test]
-//fn test_vm_err_call_bad_imm() {
-//}
-
-#[test]
-#[should_panic(expected = "Error: unknown helper function (id: 0x3f)")]
-fn test_vm_err_call_unreg() {
-    let prog = assemble(
-        "
-        mov r1, 1
-        mov r2, 2
-        mov r3, 3
-        mov r4, 4
-        mov r5, 5
-        call 63
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-fn test_vm_div64_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        div r0, 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_div_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        div32 r0, 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_mod64_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mod r0, 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_mod_by_zero_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mod32 r0, 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-// Make sure we only consider the last 32 bits of the divisor.
-#[test]
-fn test_vm_mod_by_zero_reg_long() {
-    let prog = assemble(
-        "
-        lddw r1, 0x100000000
-        mod32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_div64_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        div r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_div_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-// Make sure we only consider the last 32 bits of the divisor.
-#[test]
-fn test_vm_div_by_zero_reg_long() {
-    let prog = assemble(
-        "
-        lddw r1, 0x100000000
-        div32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_mod64_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        mod r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_mod_by_zero_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r1, 0
-        mod32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-#[should_panic(expected = "Error: out of bounds memory store (insn #1)")]
-fn test_vm_err_stack_out_of_bound() {
-    let prog = assemble(
-        "
-        stb [r10], 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_program().unwrap();
-}
-
-#[test]
-fn test_vm_exit() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_ja() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        ja +1
-        mov r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jeq_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jeq r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xb
-        jeq r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jeq_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jeq r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xb
-        jeq r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jge_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jge r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xc
-        jge r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jle_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jle r1, 4, +1
-        jle r1, 6, +1
-        exit
-        jle r1, 5, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jle_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        jle r1, r2, +2
-        jle r1, r1, +1
-        exit
-        jle r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jgt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jgt r1, 6, +2
-        jgt r1, 5, +1
-        jgt r1, 4, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jgt_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 6
-        mov r3, 4
-        jgt r1, r2, +2
-        jgt r1, r1, +1
-        jgt r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jlt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 5
-        jlt r1, 4, +2
-        jlt r1, 5, +1
-        jlt r1, 6, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jlt_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        jlt r1, r2, +2
-        jlt r1, r1, +1
-        jlt r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jit_bounce() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        mov r6, r0
-        mov r7, r6
-        mov r8, r7
-        mov r9, r8
-        mov r0, r9
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jne_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0xb
-        mov32 r2, 0xb
-        jne r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        jne r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jset_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0x7
-        jset r1, 0x8, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset r1, 0x8, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jset_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov32 r1, 0x7
-        mov32 r2, 0x8
-        jset r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsge_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsge r1, -1, +5
-        jsge r1, 0, +4
-        mov32 r0, 1
-        mov r1, -1
-        jsge r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsge_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -1
-        mov32 r3, 0
-        jsge r1, r2, +5
-        jsge r1, r3, +4
-        mov32 r0, 1
-        mov r1, r2
-        jsge r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsle_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsle r1, -3, +1
-        jsle r1, -1, +1
-        exit
-        mov32 r0, 1
-        jsle r1, -2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsle_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -1
-        mov r2, -2
-        mov32 r3, 0
-        jsle r1, r2, +1
-        jsle r1, r3, +1
-        exit
-        mov32 r0, 1
-        mov r1, r2
-        jsle r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsgt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jsgt r1, -1, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsgt_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -1
-        jsgt r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jslt_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        jslt r1, -3, +2
-        jslt r1, -2, +1
-        jslt r1, -1, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jslt_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 0
-        mov r1, -2
-        mov r2, -3
-        mov r3, -1
-        jslt r1, r1, +2
-        jslt r1, r2, +1
-        jslt r1, r3, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jeq32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0x0
-        mov32 r1, 0xa
-        jeq32 r1, 0xb, +5
-        mov32 r0, 1
-        mov r1, 0xb
-        or r1, r9
-        jeq32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jeq32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jeq32 r1, r2, +5
-        mov32 r0, 1
-        mov32 r1, 0xb
-        or r1, r9
-        jeq32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jge32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        jge32 r1, 0xb, +5
-        mov32 r0, 1
-        or r1, r9
-        mov32 r1, 0xc
-        jge32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jge32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xa
-        mov32 r2, 0xb
-        jge32 r1, r2, +5
-        mov32 r0, 1
-        or r1, r9
-        mov32 r1, 0xc
-        jge32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jgt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jgt32 r1, 6, +4
-        jgt32 r1, 5, +3
-        jgt32 r1, 4, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jgt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov32 r1, 5
-        or r1, r9
-        mov r2, 6
-        mov r3, 4
-        jgt32 r1, r2, +4
-        jgt32 r1, r1, +3
-        jgt32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jle32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jle32 r1, 4, +5
-        jle32 r1, 6, +1
-        exit
-        jle32 r1, 5, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jle32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        or r1, r9
-        jle32 r1, r2, +5
-        jle32 r1, r1, +1
-        exit
-        jle32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jlt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 5
-        or r1, r9
-        jlt32 r1, 4, +4
-        jlt32 r1, 5, +3
-        jlt32 r1, 6, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jlt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov r0, 0
-        mov r1, 5
-        mov r2, 4
-        mov r3, 6
-        or r1, r9
-        jlt32 r1, r2, +4
-        jlt32 r1, r1, +3
-        jlt32 r1, r3, +1
-        exit
-        mov r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jne32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xb
-        or r1, r9
-        jne32 r1, 0xb, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        or r1, r9
-        jne32 r1, 0xb, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jne32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0xb
-        or r1, r9
-        mov32 r2, 0xb
-        jne32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0xa
-        or r1, r9
-        jne32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jset32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0x7
-        or r1, r9
-        jset32 r1, 0x8, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset32 r1, 0x8, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jset32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, 0x7
-        or r1, r9
-        mov32 r2, 0x8
-        jset32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0x9
-        jset32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsge32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsge32 r1, -1, +5
-        jsge32 r1, 0, +4
-        mov32 r0, 1
-        mov r1, -1
-        jsge32 r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsge32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -1
-        mov32 r3, 0
-        jsge32 r1, r2, +5
-        jsge32 r1, r3, +4
-        mov32 r0, 1
-        mov r1, r2
-        jsge32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsgt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsgt32 r1, -1, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt32 r1, -1, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsgt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -1
-        jsgt32 r1, r2, +4
-        mov32 r0, 1
-        mov32 r1, 0
-        jsgt32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsle32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jsle32 r1, -3, +5
-        jsle32 r1, -1, +1
-        exit
-        mov32 r0, 1
-        jsle32 r1, -2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jsle32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -3
-        mov32 r3, 0
-        jsle32 r1, r2, +6
-        jsle32 r1, r3, +1
-        exit
-        mov32 r0, 1
-        mov r1, r2
-        jsle32 r1, r2, +1
-        mov32 r0, 2
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jslt32_imm() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        jslt32 r1, -3, +4
-        jslt32 r1, -2, +3
-        jslt32 r1, -1, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_jslt32_reg() {
-    let prog = assemble(
-        "
-        mov r9, 1
-        lsh r9, 32
-        mov32 r0, 0
-        mov32 r1, -2
-        or r1, r9
-        mov r2, -3
-        mov r3, -1
-        jslt32 r1, r1, +4
-        jslt32 r1, r2, +3
-        jslt32 r1, r3, +1
-        exit
-        mov32 r0, 1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_lddw() {
-    let prog = assemble(
-        "lddw r0, 0x1122334455667788
-                         exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1122334455667788);
-}
-
-#[test]
-fn test_vm_lddw2() {
-    let prog = assemble(
-        "
-        lddw r0, 0x0000000080000000
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x80000000);
-}
-
-#[test]
-fn test_vm_ldxb_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxb r9, [r0+0]
-        lsh r9, 0
-        ldxb r8, [r0+1]
-        lsh r8, 4
-        ldxb r7, [r0+2]
-        lsh r7, 8
-        ldxb r6, [r0+3]
-        lsh r6, 12
-        ldxb r5, [r0+4]
-        lsh r5, 16
-        ldxb r4, [r0+5]
-        lsh r4, 20
-        ldxb r3, [r0+6]
-        lsh r3, 24
-        ldxb r2, [r0+7]
-        lsh r2, 28
-        ldxb r1, [r0+8]
-        lsh r1, 32
-        ldxb r0, [r0+9]
-        lsh r0, 36
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x9876543210);
-}
-
-#[test]
-fn test_vm_ldxb() {
-    let prog = assemble(
-        "
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11);
-}
-
-#[test]
-fn test_vm_ldxdw() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xcc, 0xdd,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x8877665544332211);
-}
-
-#[test]
-fn test_vm_ldxh_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxh r9, [r0+0]
-        be16 r9
-        lsh r9, 0
-        ldxh r8, [r0+2]
-        be16 r8
-        lsh r8, 4
-        ldxh r7, [r0+4]
-        be16 r7
-        lsh r7, 8
-        ldxh r6, [r0+6]
-        be16 r6
-        lsh r6, 12
-        ldxh r5, [r0+8]
-        be16 r5
-        lsh r5, 16
-        ldxh r4, [r0+10]
-        be16 r4
-        lsh r4, 20
-        ldxh r3, [r0+12]
-        be16 r3
-        lsh r3, 24
-        ldxh r2, [r0+14]
-        be16 r2
-        lsh r2, 28
-        ldxh r1, [r0+16]
-        be16 r1
-        lsh r1, 32
-        ldxh r0, [r0+18]
-        be16 r0
-        lsh r0, 36
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00,
-        0x07, 0x00, 0x08, 0x00, 0x09,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x9876543210);
-}
-
-#[test]
-fn test_vm_ldxh_all2() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxh r9, [r0+0]
-        be16 r9
-        ldxh r8, [r0+2]
-        be16 r8
-        ldxh r7, [r0+4]
-        be16 r7
-        ldxh r6, [r0+6]
-        be16 r6
-        ldxh r5, [r0+8]
-        be16 r5
-        ldxh r4, [r0+10]
-        be16 r4
-        ldxh r3, [r0+12]
-        be16 r3
-        ldxh r2, [r0+14]
-        be16 r2
-        ldxh r1, [r0+16]
-        be16 r1
-        ldxh r0, [r0+18]
-        be16 r0
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00,
-        0x80, 0x01, 0x00, 0x02, 0x00,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x3ff);
-}
-
-#[test]
-fn test_vm_ldxh() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x2211);
-}
-
-#[test]
-fn test_vm_ldxh_same_reg() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        sth [r0], 0x1234
-        ldxh r0, [r0]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1234);
-}
-
-#[test]
-fn test_vm_ldxw_all() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxw r9, [r0+0]
-        be32 r9
-        ldxw r8, [r0+4]
-        be32 r8
-        ldxw r7, [r0+8]
-        be32 r7
-        ldxw r6, [r0+12]
-        be32 r6
-        ldxw r5, [r0+16]
-        be32 r5
-        ldxw r4, [r0+20]
-        be32 r4
-        ldxw r3, [r0+24]
-        be32 r3
-        ldxw r2, [r0+28]
-        be32 r2
-        ldxw r1, [r0+32]
-        be32 r1
-        ldxw r0, [r0+36]
-        be32 r0
-        or r0, r1
-        or r0, r2
-        or r0, r3
-        or r0, r4
-        or r0, r5
-        or r0, r6
-        or r0, r7
-        or r0, r8
-        or r0, r9
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-        0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x030f0f);
-}
-
-#[test]
-fn test_vm_ldxw() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x44332211);
-}
-
-#[test]
-fn test_vm_le16() {
-    let prog = assemble(
-        "
-        ldxh r0, [r1]
-        le16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x22, 0x11];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1122);
-}
-
-#[test]
-fn test_vm_le32() {
-    let prog = assemble(
-        "
-        ldxw r0, [r1]
-        le32 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x44, 0x33, 0x22, 0x11];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11223344);
-}
-
-#[test]
-fn test_vm_le64() {
-    let prog = assemble(
-        "
-        ldxdw r0, [r1]
-        le64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1122334455667788);
-}
-
-#[test]
-fn test_vm_lsh_imm() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        lsh r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x10);
-}
-
-#[test]
-fn test_vm_lsh_reg() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        mov r7, 4
-        lsh r0, r7
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x10);
-}
-
-#[test]
-fn test_vm_lsh32_imm() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh32 r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x10);
-}
-
-#[test]
-fn test_vm_lsh32_reg() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r7, 4
-        lsh32 r0, r7
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x10);
-}
-
-#[test]
-fn test_vm_lsh_imm_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        lsh r0, 64
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_lsh_reg_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 1
-        mov r7, 64
-        lsh r0, r7
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_lsh32_imm_overflow() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        lsh32 r0, 32
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_lsh32_reg_overflow() {
-    let prog = assemble(
-        "
-        mov32 r0, 1
-        mov32 r7, 32
-        lsh32 r0, r7
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_mod() {
-    let prog = assemble(
-        "
-        mov32 r0, 5748
-        mod32 r0, 92
-        mov32 r1, 13
-        mod32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x5);
-}
-
-#[test]
-fn test_vm_mod32() {
-    let prog = assemble(
-        "
-        lddw r0, 0x100000003
-        mod32 r0, 3
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_mod64() {
-    let prog = assemble(
-        "
-        mov32 r0, -1316649930
-        lsh r0, 32
-        or r0, 0x100dc5c8
-        mov32 r1, 0xdde263e
-        lsh r1, 32
-        or r1, 0x3cbef7f3
-        mod r0, r1
-        mod r0, 0x658f1778
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x30ba5a04);
-}
-
-#[test]
-fn test_vm_mov() {
-    let prog = assemble(
-        "
-        mov32 r1, 1
-        mov32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_mul32_imm() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        mul32 r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xc);
-}
-
-#[test]
-fn test_vm_mul32_reg() {
-    let prog = assemble(
-        "
-        mov r0, 3
-        mov r1, 4
-        mul32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xc);
-}
-
-#[test]
-fn test_vm_mul32_reg_overflow() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mov r1, 4
-        mul32 r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x4);
-}
-
-#[test]
-fn test_vm_mul64_imm() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mul r0, 4
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x100000004);
-}
-
-#[test]
-fn test_vm_mul64_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0x40000001
-        mov r1, 4
-        mul r0, r1
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x100000004);
-}
-
-#[test]
-fn test_vm_mul_loop() {
-    let prog = assemble(
-        "
-        mov r0, 0x7
-        add r1, 0xa
-        lsh r1, 0x20
-        rsh r1, 0x20
-        jeq r1, 0x0, +4
-        mov r0, 0x7
-        mul r0, 0x7
-        add r1, -1
-        jne r1, 0x0, -3
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x75db9c97);
-}
-
-#[test]
-fn test_vm_neg64() {
-    let prog = assemble(
-        "
-        mov32 r0, 2
-        neg r0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xfffffffffffffffe);
-}
-
-#[test]
-fn test_vm_neg() {
-    let prog = assemble(
-        "
-        mov32 r0, 2
-        neg32 r0
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xfffffffe);
-}
-
-#[test]
-fn test_vm_prime() {
-    let prog = assemble(
-        "
-        mov r1, 67
-        mov r0, 0x1
-        mov r2, 0x2
-        jgt r1, 0x2, +4
-        ja +10
-        add r2, 0x1
-        mov r0, 0x1
-        jge r2, r1, +7
-        mov r3, r1
-        div r3, r2
-        mul r3, r2
-        mov r4, r1
-        sub r4, r3
-        mov r0, 0x0
-        jne r4, 0x0, -10
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_rhs32() {
-    let prog = assemble(
-        "
-        xor r0, r0
-        sub r0, 1
-        rsh32 r0, 8
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x00ffffff);
-}
-
-#[test]
-fn test_vm_rsh_reg() {
-    let prog = assemble(
-        "
-        mov r0, 0x10
-        mov r7, 4
-        rsh r0, r7
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_stack() {
-    let prog = assemble(
-        "
-        mov r1, 51
-        stdw [r10-16], 0xab
-        stdw [r10-8], 0xcd
-        and r1, 1
-        lsh r1, 3
-        mov r2, r10
-        add r2, r1
-        ldxdw r0, [r2-16]
-        exit",
-    )
-    .unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0xcd);
-}
-
-#[test]
-fn test_vm_stack2() {
-    let prog = assemble(
-        "
-        stb [r10-4], 0x01
-        stb [r10-3], 0x02
-        stb [r10-2], 0x03
-        stb [r10-1], 0x04
-        mov r1, r10
-        mov r2, 0x4
-        sub r1, r2
-        call 1
-        mov r1, 0
-        ldxb r2, [r10-4]
-        ldxb r3, [r10-3]
-        ldxb r4, [r10-2]
-        ldxb r5, [r10-1]
-        call 0
-        xor r0, 0x2a2a2a2a
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes).unwrap();
-    vm.register_helper(1, helpers::memfrob).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x01020304);
-}
-
-#[test]
-fn test_vm_stb() {
-    let prog = assemble(
-        "
-        stb [r1+2], 0x11
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11);
-}
-
-#[test]
-fn test_vm_stdw() {
-    let prog = assemble(
-        "
-        stdw [r1+2], 0x44332211
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x44332211);
-}
-
-// If this case is not handled properly in check_mem(), then we may overflow when adding the
-// context address and the offset, and make the thread panic with "attempt to add with overflow".
-// Check that we panic with the expected out-of-bounds error.
-//
-// The new toolchain introduced `assert_unsafe_precondition` which panics with a different message and can't be
-// caught by `#[should_panic]`. This is why we use `#[ignore]` here.
-#[test]
-#[should_panic(expected = "Error: out of bounds memory store (insn #1)")]
-#[ignore]
-fn test_vm_stdw_add_overflow() {
-    let prog = assemble(
-        "
-        stdw [r2-0x1], 0x44332211
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd,
-    ];
-    let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(&prog), 0x00, 0x10).unwrap();
-    _ = vm.execute_program(mem).unwrap();
-}
-
-#[test]
-fn test_vm_sth() {
-    let prog = assemble(
-        "
-        sth [r1+2], 0x2211
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x2211);
-}
-
-#[test]
-fn test_vm_string_stack() {
-    let prog = assemble(
-        "
-        mov r1, 0x78636261
-        stxw [r10-8], r1
-        mov r6, 0x0
-        stxb [r10-4], r6
-        stxb [r10-12], r6
-        mov r1, 0x79636261
-        stxw [r10-16], r1
-        mov r1, r10
-        add r1, -8
-        mov r2, r1
-        call 0x4
-        mov r1, r0
-        mov r0, 0x1
-        lsh r1, 0x20
-        rsh r1, 0x20
-        jne r1, 0x0, +11
-        mov r1, r10
-        add r1, -8
-        mov r2, r10
-        add r2, -16
-        call 0x4
-        mov r1, r0
-        lsh r1, 0x20
-        rsh r1, 0x20
-        mov r0, 0x1
-        jeq r1, r6, +1
-        mov r0, 0x0
-        exit",
-    )
-    .unwrap();
-    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(4, helpers::strcmp).unwrap();
-    assert_eq!(vm.execute_program().unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_stw() {
-    let prog = assemble(
-        "
-        stw [r1+2], 0x44332211
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x44332211);
-}
-
-#[test]
-fn test_vm_stxb() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x11
-        stxb [r1+2], r2
-        ldxb r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x11);
-}
-
-#[test]
-fn test_vm_stxb_all() {
-    let prog = assemble(
-        "
-        mov r0, 0xf0
-        mov r2, 0xf2
-        mov r3, 0xf3
-        mov r4, 0xf4
-        mov r5, 0xf5
-        mov r6, 0xf6
-        mov r7, 0xf7
-        mov r8, 0xf8
-        stxb [r1], r0
-        stxb [r1+1], r2
-        stxb [r1+2], r3
-        stxb [r1+3], r4
-        stxb [r1+4], r5
-        stxb [r1+5], r6
-        stxb [r1+6], r7
-        stxb [r1+7], r8
-        ldxdw r0, [r1]
-        be64 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0xf0f2f3f4f5f6f7f8);
-}
-
-#[test]
-fn test_vm_stxb_all2() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        mov r1, 0xf1
-        mov r9, 0xf9
-        stxb [r0], r1
-        stxb [r0+1], r9
-        ldxh r0, [r0]
-        be16 r0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xff, 0xff];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0xf1f9);
-}
-
-#[test]
-fn test_vm_stxb_chain() {
-    let prog = assemble(
-        "
-        mov r0, r1
-        ldxb r9, [r0+0]
-        stxb [r0+1], r9
-        ldxb r8, [r0+1]
-        stxb [r0+2], r8
-        ldxb r7, [r0+2]
-        stxb [r0+3], r7
-        ldxb r6, [r0+3]
-        stxb [r0+4], r6
-        ldxb r5, [r0+4]
-        stxb [r0+5], r5
-        ldxb r4, [r0+5]
-        stxb [r0+6], r4
-        ldxb r3, [r0+6]
-        stxb [r0+7], r3
-        ldxb r2, [r0+7]
-        stxb [r0+8], r2
-        ldxb r1, [r0+8]
-        stxb [r0+9], r1
-        ldxb r0, [r0+9]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x2a);
-}
-
-#[test]
-fn test_vm_stxdw() {
-    let prog = assemble(
-        "
-        mov r2, -2005440939
-        lsh r2, 32
-        or r2, 0x44332211
-        stxdw [r1+2], r2
-        ldxdw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x8877665544332211);
-}
-
-#[test]
-fn test_vm_stxh() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x2211
-        stxh [r1+2], r2
-        ldxh r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x2211);
-}
-
-#[test]
-fn test_vm_stxw() {
-    let prog = assemble(
-        "
-        mov32 r2, 0x44332211
-        stxw [r1+2], r2
-        ldxw r0, [r1+2]
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x44332211);
-}
-
-#[test]
-fn test_vm_subnet() {
-    let prog = assemble(
-        "
-        mov r2, 0xe
-        ldxh r3, [r1+12]
-        jne r3, 0x81, +2
-        mov r2, 0x12
-        ldxh r3, [r1+16]
-        and r3, 0xffff
-        jne r3, 0x8, +5
-        add r1, r2
-        mov r0, 0x1
-        ldxw r1, [r1+16]
-        and r1, 0xffffff
-        jeq r1, 0x1a8c0, +1
-        mov r0, 0x0
-        exit",
-    )
-    .unwrap();
-    let mem = &mut [
-        0x00, 0x00, 0xc0, 0x9f, 0xa0, 0x97, 0x00, 0xa0, 0xcc, 0x3b, 0xbf, 0xfa, 0x08, 0x00, 0x45,
-        0x10, 0x00, 0x3c, 0x46, 0x3c, 0x40, 0x00, 0x40, 0x06, 0x73, 0x1c, 0xc0, 0xa8, 0x01, 0x02,
-        0xc0, 0xa8, 0x01, 0x01, 0x06, 0x0e, 0x00, 0x17, 0x99, 0xc5, 0xa0, 0xec, 0x00, 0x00, 0x00,
-        0x00, 0xa0, 0x02, 0x7d, 0x78, 0xe0, 0xa3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02,
-        0x08, 0x0a, 0x00, 0x9c, 0x27, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x00,
-    ];
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1);
-}
-
-const PROG_TCP_PORT_80: [u8; 152] = [
-    0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x02, 0x0a, 0x00, 0x06, 0x00, 0x00, 0x00,
-    0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
-    0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-    0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x15, 0x02, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x69, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x55, 0x01, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-];
-
-#[test]
-fn test_vm_tcp_port80_match() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_tcp_port80_nomatch() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x00, 0x16, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x51, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_tcp_port80_nomatch_ethertype() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x01, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_tcp_port80_nomatch_proto() {
-    let mem = &mut [
-        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
-        0x00, 0x00, 0x56, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0xf9, 0x4d, 0xc0, 0xa8, 0x00, 0x01,
-        0xc0, 0xa8, 0x00, 0x02, 0x27, 0x10, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x50, 0x02, 0x20, 0x00, 0xc5, 0x18, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-        0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
-    ];
-    let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_program(mem).unwrap(), 0x0);
-}
-
-#[test]
-fn test_vm_tcp_sack_match() {
-    let mut mem = TCP_SACK_MATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem.as_mut_slice()).unwrap(), 0x1);
-}
-
-#[test]
-fn test_vm_tcp_sack_nomatch() {
-    let mut mem = TCP_SACK_NOMATCH.to_vec();
-    let prog = assemble(TCP_SACK_ASM).unwrap();
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_program(mem.as_mut_slice()).unwrap(), 0x0);
-}

+ 2 - 1
kernel/crates/system_error/Cargo.toml

@@ -6,5 +6,6 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
+num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev = "1597c1c", default-features = false }
 num-derive = "0.3"
+kdepends = { path = "../kdepends" }

+ 7 - 0
kernel/crates/system_error/src/another_ext4.rs

@@ -0,0 +1,7 @@
+use kdepends::another_ext4::Ext4Error;
+
+impl From<Ext4Error> for super::SystemError {
+    fn from(err: Ext4Error) -> Self {
+        <Self as num_traits::FromPrimitive>::from_i32(err.code() as i32).unwrap()
+    }
+}

+ 2 - 0
kernel/crates/system_error/src/lib.rs

@@ -4,6 +4,8 @@
 #![allow(non_local_definitions)]
 use num_derive::{FromPrimitive, ToPrimitive};
 
+mod another_ext4;
+
 #[repr(i32)]
 #[derive(Debug, FromPrimitive, ToPrimitive, PartialEq, Eq, Clone)]
 #[allow(dead_code, non_camel_case_types)]

+ 4 - 0
kernel/src/arch/loongarch64/mm/mod.rs

@@ -137,6 +137,10 @@ impl MemoryManagementArch for LoongArch64MMArch {
     fn make_entry(paddr: crate::mm::PhysAddr, page_flags: usize) -> usize {
         todo!()
     }
+
+    fn enable_kernel_wp() {}
+
+    fn disable_kernel_wp() {}
 }
 
 /// 获取内核地址默认的页面标志

+ 2 - 2
kernel/src/arch/loongarch64/process/kthread.rs

@@ -5,7 +5,7 @@ use alloc::sync::Arc;
 use crate::process::{
     fork::CloneFlags,
     kthread::{KernelThreadCreateInfo, KernelThreadMechanism},
-    Pid,
+    RawPid,
 };
 
 impl KernelThreadMechanism {
@@ -17,7 +17,7 @@ impl KernelThreadMechanism {
     pub fn __inner_create(
         info: &Arc<KernelThreadCreateInfo>,
         clone_flags: CloneFlags,
-    ) -> Result<Pid, SystemError> {
+    ) -> Result<RawPid, SystemError> {
         // WARNING: If create failed, we must drop the info manually or it will cause memory leak. (refcount will not decrease when create failed)
         let create_info: *const KernelThreadCreateInfo =
             KernelThreadCreateInfo::generate_unsafe_arc_ptr(info.clone());

+ 21 - 302
kernel/src/arch/riscv64/ipc/signal.rs

@@ -1,173 +1,10 @@
-use log::error;
+pub use crate::ipc::generic_signal::AtomicGenericSignal as AtomicSignal;
+pub use crate::ipc::generic_signal::GenericSigChildCode as SigChildCode;
+pub use crate::ipc::generic_signal::GenericSigSet as SigSet;
+pub use crate::ipc::generic_signal::GenericSignal as Signal;
+use crate::{arch::interrupt::TrapFrame, ipc::signal_types::SignalArch};
 
-use crate::{
-    arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch},
-    exception::InterruptArch,
-    ipc::signal_types::SignalArch,
-    process::ProcessManager,
-};
-
-/// 信号最大值
-pub const MAX_SIG_NUM: usize = 64;
-#[allow(dead_code)]
-#[derive(Eq)]
-#[repr(usize)]
-#[allow(non_camel_case_types)]
-#[atomic_enum]
-pub enum Signal {
-    INVALID = 0,
-    SIGHUP = 1,
-    SIGINT,
-    SIGQUIT,
-    SIGILL,
-    SIGTRAP,
-    /// SIGABRT和SIGIOT共用这个号码
-    SIGABRT_OR_IOT,
-    SIGBUS,
-    SIGFPE,
-    SIGKILL,
-    SIGUSR1,
-
-    SIGSEGV = 11,
-    SIGUSR2,
-    SIGPIPE,
-    SIGALRM,
-    SIGTERM,
-    SIGSTKFLT,
-    SIGCHLD,
-    SIGCONT,
-    SIGSTOP,
-    SIGTSTP,
-
-    SIGTTIN = 21,
-    SIGTTOU,
-    SIGURG,
-    SIGXCPU,
-    SIGXFSZ,
-    SIGVTALRM,
-    SIGPROF,
-    SIGWINCH,
-    /// SIGIO和SIGPOLL共用这个号码
-    SIGIO_OR_POLL,
-    SIGPWR,
-
-    SIGSYS = 31,
-
-    SIGRTMIN = 32,
-    SIGRTMAX = 64,
-}
-
-/// 为Signal实现判断相等的trait
-impl PartialEq for Signal {
-    fn eq(&self, other: &Signal) -> bool {
-        *self as usize == *other as usize
-    }
-}
-
-impl From<usize> for Signal {
-    fn from(value: usize) -> Self {
-        if value <= MAX_SIG_NUM {
-            let ret: Signal = unsafe { core::mem::transmute(value) };
-            return ret;
-        } else {
-            error!("Try to convert an invalid number to Signal");
-            return Signal::INVALID;
-        }
-    }
-}
-
-impl Into<usize> for Signal {
-    fn into(self) -> usize {
-        self as usize
-    }
-}
-
-impl From<i32> for Signal {
-    fn from(value: i32) -> Self {
-        if value < 0 {
-            error!("Try to convert an invalid number to Signal");
-            return Signal::INVALID;
-        } else {
-            return Self::from(value as usize);
-        }
-    }
-}
-
-impl From<Signal> for SigSet {
-    fn from(val: Signal) -> Self {
-        SigSet {
-            bits: (1 << (val as usize - 1) as u64),
-        }
-    }
-}
-
-impl Signal {
-    /// 判断一个数字是否为可用的信号
-    #[inline]
-    pub fn is_valid(&self) -> bool {
-        return (*self) as usize <= MAX_SIG_NUM;
-    }
-
-    /// const convertor between `Signal` and `SigSet`
-    pub const fn into_sigset(self) -> SigSet {
-        SigSet {
-            bits: (1 << (self as usize - 1) as u64),
-        }
-    }
-
-    /// 判断一个信号是不是实时信号
-    ///
-    /// ## 返回值
-    ///
-    /// - `true` 这个信号是实时信号
-    /// - `false` 这个信号不是实时信号
-    #[inline]
-    pub fn is_rt_signal(&self) -> bool {
-        return (*self) as usize >= Signal::SIGRTMIN.into();
-    }
-
-    /// 调用信号的默认处理函数
-    pub fn handle_default(&self) {
-        match self {
-            Signal::INVALID => {
-                error!("attempting to handler an Invalid");
-            }
-            Signal::SIGHUP => sig_terminate(self.clone()),
-            Signal::SIGINT => sig_terminate(self.clone()),
-            Signal::SIGQUIT => sig_terminate_dump(self.clone()),
-            Signal::SIGILL => sig_terminate_dump(self.clone()),
-            Signal::SIGTRAP => sig_terminate_dump(self.clone()),
-            Signal::SIGABRT_OR_IOT => sig_terminate_dump(self.clone()),
-            Signal::SIGBUS => sig_terminate_dump(self.clone()),
-            Signal::SIGFPE => sig_terminate_dump(self.clone()),
-            Signal::SIGKILL => sig_terminate(self.clone()),
-            Signal::SIGUSR1 => sig_terminate(self.clone()),
-            Signal::SIGSEGV => sig_terminate_dump(self.clone()),
-            Signal::SIGUSR2 => sig_terminate(self.clone()),
-            Signal::SIGPIPE => sig_terminate(self.clone()),
-            Signal::SIGALRM => sig_terminate(self.clone()),
-            Signal::SIGTERM => sig_terminate(self.clone()),
-            Signal::SIGSTKFLT => sig_terminate(self.clone()),
-            Signal::SIGCHLD => sig_ignore(self.clone()),
-            Signal::SIGCONT => sig_continue(self.clone()),
-            Signal::SIGSTOP => sig_stop(self.clone()),
-            Signal::SIGTSTP => sig_stop(self.clone()),
-            Signal::SIGTTIN => sig_stop(self.clone()),
-            Signal::SIGTTOU => sig_stop(self.clone()),
-            Signal::SIGURG => sig_ignore(self.clone()),
-            Signal::SIGXCPU => sig_terminate_dump(self.clone()),
-            Signal::SIGXFSZ => sig_terminate_dump(self.clone()),
-            Signal::SIGVTALRM => sig_terminate(self.clone()),
-            Signal::SIGPROF => sig_terminate(self.clone()),
-            Signal::SIGWINCH => sig_ignore(self.clone()),
-            Signal::SIGIO_OR_POLL => sig_terminate(self.clone()),
-            Signal::SIGPWR => sig_terminate(self.clone()),
-            Signal::SIGSYS => sig_terminate(self.clone()),
-            Signal::SIGRTMIN => sig_terminate(self.clone()),
-            Signal::SIGRTMAX => sig_terminate(self.clone()),
-        }
-    }
-}
+pub use crate::ipc::generic_signal::GENERIC_MAX_SIG_NUM as MAX_SIG_NUM;
 
 /// siginfo中的si_code的可选值
 /// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态
@@ -207,6 +44,21 @@ impl SigCode {
     }
 }
 
+pub struct RiscV64SignalArch;
+
+impl SignalArch for RiscV64SignalArch {
+    // TODO: 为RISCV64实现信号处理
+    // 注意,rv64现在在中断/系统调用返回用户态时,没有进入 irqentry_exit() 函数,
+    // 到时候实现信号处理时,需要修改中断/系统调用返回用户态的代码,进入 irqentry_exit() 函数
+    unsafe fn do_signal_or_restart(_frame: &mut TrapFrame) {
+        todo!()
+    }
+
+    fn sys_rt_sigreturn(_trap_frame: &mut TrapFrame) -> u64 {
+        todo!()
+    }
+}
+
 bitflags! {
     #[repr(C,align(8))]
     #[derive(Default)]
@@ -222,137 +74,4 @@ bitflags! {
         const SA_ALL = Self::SA_NOCLDSTOP.bits()|Self::SA_NOCLDWAIT.bits()|Self::SA_NODEFER.bits()|Self::SA_ONSTACK.bits()|Self::SA_RESETHAND.bits()|Self::SA_RESTART.bits()|Self::SA_SIGINFO.bits()|Self::SA_RESTORER.bits();
     }
 
-    /// 请注意,sigset 这个bitmap, 第0位表示sig=1的信号。也就是说,Signal-1才是sigset_t中对应的位
-    #[derive(Default)]
-    pub struct SigSet:u64{
-        const SIGHUP   =  1<<0;
-        const SIGINT   =  1<<1;
-        const SIGQUIT  =  1<<2;
-        const SIGILL   =  1<<3;
-        const SIGTRAP  =  1<<4;
-        /// SIGABRT和SIGIOT共用这个号码
-        const SIGABRT_OR_IOT    =    1<<5;
-        const SIGBUS   =  1<<6;
-        const SIGFPE   =  1<<7;
-        const SIGKILL  =  1<<8;
-        const SIGUSR   =  1<<9;
-        const SIGSEGV  =  1<<10;
-        const SIGUSR2  =  1<<11;
-        const SIGPIPE  =  1<<12;
-        const SIGALRM  =  1<<13;
-        const SIGTERM  =  1<<14;
-        const SIGSTKFLT=  1<<15;
-        const SIGCHLD  =  1<<16;
-        const SIGCONT  =  1<<17;
-        const SIGSTOP  =  1<<18;
-        const SIGTSTP  =  1<<19;
-        const SIGTTIN  =  1<<20;
-        const SIGTTOU  =  1<<21;
-        const SIGURG   =  1<<22;
-        const SIGXCPU  =  1<<23;
-        const SIGXFSZ  =  1<<24;
-        const SIGVTALRM=  1<<25;
-        const SIGPROF  =  1<<26;
-        const SIGWINCH =  1<<27;
-        /// SIGIO和SIGPOLL共用这个号码
-        const SIGIO_OR_POLL    =   1<<28;
-        const SIGPWR   =  1<<29;
-        const SIGSYS   =  1<<30;
-        const SIGRTMIN =  1<<31;
-        // TODO 写上实时信号
-        const SIGRTMAX =  1<<MAX_SIG_NUM-1;
-    }
-}
-
-/// SIGCHLD si_codes
-#[derive(Debug, Clone, Copy, PartialEq, Eq, ToPrimitive)]
-#[allow(dead_code)]
-pub enum SigChildCode {
-    /// child has exited
-    ///
-    /// CLD_EXITED
-    Exited = 1,
-    /// child was killed
-    ///
-    /// CLD_KILLED
-    Killed = 2,
-    /// child terminated abnormally
-    ///
-    /// CLD_DUMPED
-    Dumped = 3,
-    /// traced child has trapped
-    ///
-    /// CLD_TRAPPED
-    Trapped = 4,
-    /// child has stopped
-    ///
-    /// CLD_STOPPED
-    Stopped = 5,
-    /// stopped child has continued
-    ///
-    /// CLD_CONTINUED
-    Continued = 6,
-}
-
-impl Into<i32> for SigChildCode {
-    fn into(self) -> i32 {
-        self as i32
-    }
-}
-
-/// 信号默认处理函数——终止进程
-fn sig_terminate(sig: Signal) {
-    ProcessManager::exit(sig as usize);
-}
-
-/// 信号默认处理函数——终止进程并生成 core dump
-fn sig_terminate_dump(sig: Signal) {
-    ProcessManager::exit(sig as usize);
-    // TODO 生成 coredump 文件
-}
-
-/// 信号默认处理函数——暂停进程
-fn sig_stop(sig: Signal) {
-    let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
-    ProcessManager::mark_stop().unwrap_or_else(|e| {
-        error!(
-            "sleep error :{:?},failed to sleep process :{:?}, with signal :{:?}",
-            e,
-            ProcessManager::current_pcb(),
-            sig
-        );
-    });
-    drop(guard);
-    sched();
-    // TODO 暂停进程
-}
-
-/// 信号默认处理函数——继续进程
-fn sig_continue(sig: Signal) {
-    ProcessManager::wakeup_stop(&ProcessManager::current_pcb()).unwrap_or_else(|_| {
-        error!(
-            "Failed to wake up process pid = {:?} with signal :{:?}",
-            ProcessManager::current_pcb().pid(),
-            sig
-        );
-    });
-}
-/// 信号默认处理函数——忽略
-fn sig_ignore(_sig: Signal) {
-    return;
-}
-
-pub struct RiscV64SignalArch;
-
-impl SignalArch for RiscV64SignalArch {
-    // TODO: 为RISCV64实现信号处理
-    // 注意,rv64现在在中断/系统调用返回用户态时,没有进入 irqentry_exit() 函数,
-    // 到时候实现信号处理时,需要修改中断/系统调用返回用户态的代码,进入 irqentry_exit() 函数
-    unsafe fn do_signal_or_restart(_frame: &mut TrapFrame) {
-        todo!()
-    }
-
-    fn sys_rt_sigreturn(_trap_frame: &mut TrapFrame) -> u64 {
-        todo!()
-    }
 }

+ 4 - 0
kernel/src/arch/riscv64/mm/mod.rs

@@ -284,6 +284,10 @@ impl MemoryManagementArch for RiscV64MMArch {
     const PAGE_READONLY_EXEC: usize = 0;
 
     const PROTECTION_MAP: [EntryFlags<MMArch>; 16] = protection_map();
+
+    fn enable_kernel_wp() {}
+
+    fn disable_kernel_wp() {}
 }
 
 const fn protection_map() -> [EntryFlags<MMArch>; 16] {

+ 2 - 4
kernel/src/arch/riscv64/process/kthread.rs

@@ -1,11 +1,9 @@
-use core::arch::asm;
-
 use crate::{
     arch::{asm::csr::CSR_SSTATUS, interrupt::TrapFrame},
     process::{
         fork::CloneFlags,
         kthread::{kernel_thread_bootstrap_stage2, KernelThreadCreateInfo, KernelThreadMechanism},
-        Pid, ProcessManager,
+        ProcessManager, RawPid,
     },
 };
 use alloc::sync::Arc;
@@ -24,7 +22,7 @@ impl KernelThreadMechanism {
     pub fn __inner_create(
         info: &Arc<KernelThreadCreateInfo>,
         clone_flags: CloneFlags,
-    ) -> Result<Pid, SystemError> {
+    ) -> Result<RawPid, SystemError> {
         // WARNING: If create failed, we must drop the info manually or it will cause memory leak. (refcount will not decrease when create failed)
         let create_info: *const KernelThreadCreateInfo =
             KernelThreadCreateInfo::generate_unsafe_arc_ptr(info.clone());

+ 39 - 290
kernel/src/arch/x86_64/ipc/signal.rs

@@ -4,6 +4,11 @@ use defer::defer;
 use log::error;
 use system_error::SystemError;
 
+pub use crate::ipc::generic_signal::AtomicGenericSignal as AtomicSignal;
+pub use crate::ipc::generic_signal::GenericSigChildCode as SigChildCode;
+pub use crate::ipc::generic_signal::GenericSigSet as SigSet;
+pub use crate::ipc::generic_signal::GenericSignal as Signal;
+
 use crate::{
     arch::{
         fpu::FpState,
@@ -15,11 +20,10 @@ use crate::{
     exception::InterruptArch,
     ipc::{
         signal::{restore_saved_sigmask, set_current_blocked},
-        signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch},
+        signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch, SignalFlags},
     },
     mm::MemoryManagementArch,
     process::ProcessManager,
-    sched::{schedule, SchedMode},
     syscall::user_access::UserBufferWriter,
 };
 
@@ -27,164 +31,6 @@ use crate::{
 pub const STACK_ALIGN: u64 = 16;
 /// 信号最大值
 pub const MAX_SIG_NUM: usize = 64;
-#[allow(dead_code)]
-#[derive(Eq)]
-#[repr(usize)]
-#[allow(non_camel_case_types)]
-#[atomic_enum]
-pub enum Signal {
-    INVALID = 0,
-    SIGHUP = 1,
-    SIGINT,
-    SIGQUIT,
-    SIGILL,
-    SIGTRAP,
-    /// SIGABRT和SIGIOT共用这个号码
-    SIGABRT_OR_IOT,
-    SIGBUS,
-    SIGFPE,
-    SIGKILL,
-    SIGUSR1,
-
-    SIGSEGV = 11,
-    SIGUSR2,
-    SIGPIPE,
-    SIGALRM,
-    SIGTERM,
-    SIGSTKFLT,
-    SIGCHLD,
-    SIGCONT,
-    SIGSTOP,
-    SIGTSTP,
-
-    SIGTTIN = 21,
-    SIGTTOU,
-    SIGURG,
-    SIGXCPU,
-    SIGXFSZ,
-    SIGVTALRM,
-    SIGPROF,
-    SIGWINCH,
-    /// SIGIO和SIGPOLL共用这个号码
-    SIGIO_OR_POLL,
-    SIGPWR,
-
-    SIGSYS = 31,
-
-    SIGRTMIN = 32,
-    SIGRTMAX = 64,
-}
-
-/// 为Signal实现判断相等的trait
-impl PartialEq for Signal {
-    fn eq(&self, other: &Signal) -> bool {
-        *self as usize == *other as usize
-    }
-}
-
-impl From<usize> for Signal {
-    fn from(value: usize) -> Self {
-        if value <= MAX_SIG_NUM {
-            let ret: Signal = unsafe { core::mem::transmute(value) };
-            return ret;
-        } else {
-            error!("Try to convert an invalid number to Signal");
-            return Signal::INVALID;
-        }
-    }
-}
-
-impl From<Signal> for usize {
-    fn from(val: Signal) -> Self {
-        val as usize
-    }
-}
-
-impl From<i32> for Signal {
-    fn from(value: i32) -> Self {
-        if value < 0 {
-            error!("Try to convert an invalid number to Signal");
-            return Signal::INVALID;
-        } else {
-            return Self::from(value as usize);
-        }
-    }
-}
-
-impl From<Signal> for SigSet {
-    fn from(val: Signal) -> Self {
-        SigSet {
-            bits: (1 << (val as usize - 1) as u64),
-        }
-    }
-}
-impl Signal {
-    /// 判断一个数字是否为可用的信号
-    #[inline]
-    pub fn is_valid(&self) -> bool {
-        return (*self) as usize <= MAX_SIG_NUM;
-    }
-
-    /// const convertor between `Signal` and `SigSet`
-    pub const fn into_sigset(self) -> SigSet {
-        SigSet {
-            bits: (1 << (self as usize - 1) as u64),
-        }
-    }
-
-    /// 判断一个信号是不是实时信号
-    ///
-    /// ## 返回值
-    ///
-    /// - `true` 这个信号是实时信号
-    /// - `false` 这个信号不是实时信号
-    #[inline]
-    pub fn is_rt_signal(&self) -> bool {
-        return (*self) as usize >= Signal::SIGRTMIN.into();
-    }
-
-    /// 调用信号的默认处理函数
-    pub fn handle_default(&self) {
-        match self {
-            Signal::INVALID => {
-                error!("attempting to handler an Invalid");
-            }
-            Signal::SIGHUP => sig_terminate(*self),
-            Signal::SIGINT => sig_terminate(*self),
-            Signal::SIGQUIT => sig_terminate_dump(*self),
-            Signal::SIGILL => sig_terminate_dump(*self),
-            Signal::SIGTRAP => sig_terminate_dump(*self),
-            Signal::SIGABRT_OR_IOT => sig_terminate_dump(*self),
-            Signal::SIGBUS => sig_terminate_dump(*self),
-            Signal::SIGFPE => sig_terminate_dump(*self),
-            Signal::SIGKILL => sig_terminate(*self),
-            Signal::SIGUSR1 => sig_terminate(*self),
-            Signal::SIGSEGV => sig_terminate_dump(*self),
-            Signal::SIGUSR2 => sig_terminate(*self),
-            Signal::SIGPIPE => sig_terminate(*self),
-            Signal::SIGALRM => sig_terminate(*self),
-            Signal::SIGTERM => sig_terminate(*self),
-            Signal::SIGSTKFLT => sig_terminate(*self),
-            Signal::SIGCHLD => sig_ignore(*self),
-            Signal::SIGCONT => sig_continue(*self),
-            Signal::SIGSTOP => sig_stop(*self),
-            Signal::SIGTSTP => sig_stop(*self),
-            Signal::SIGTTIN => sig_stop(*self),
-            Signal::SIGTTOU => sig_stop(*self),
-            Signal::SIGURG => sig_ignore(*self),
-            Signal::SIGXCPU => sig_terminate_dump(*self),
-            Signal::SIGXFSZ => sig_terminate_dump(*self),
-            Signal::SIGVTALRM => sig_terminate(*self),
-            Signal::SIGPROF => sig_terminate(*self),
-            Signal::SIGWINCH => sig_ignore(*self),
-            Signal::SIGIO_OR_POLL => sig_terminate(*self),
-            Signal::SIGPWR => sig_terminate(*self),
-            Signal::SIGSYS => sig_terminate(*self),
-            Signal::SIGRTMIN => sig_terminate(*self),
-            Signal::SIGRTMAX => sig_terminate(*self),
-        }
-    }
-}
 
 /// siginfo中的si_code的可选值
 /// 请注意,当这个值小于0时,表示siginfo来自用户态,否则来自内核态
@@ -238,83 +84,6 @@ bitflags! {
         const SA_RESTORER   =0x04000000;
         const SA_ALL = Self::SA_NOCLDSTOP.bits()|Self::SA_NOCLDWAIT.bits()|Self::SA_NODEFER.bits()|Self::SA_ONSTACK.bits()|Self::SA_RESETHAND.bits()|Self::SA_RESTART.bits()|Self::SA_SIGINFO.bits()|Self::SA_RESTORER.bits();
     }
-
-    /// 请注意,sigset 这个bitmap, 第0位表示sig=1的信号。也就是说,Signal-1才是sigset_t中对应的位
-    #[derive(Default)]
-    pub struct SigSet:u64{
-        const SIGHUP   =  1<<0;
-        const SIGINT   =  1<<1;
-        const SIGQUIT  =  1<<2;
-        const SIGILL   =  1<<3;
-        const SIGTRAP  =  1<<4;
-        /// SIGABRT和SIGIOT共用这个号码
-        const SIGABRT_OR_IOT    =    1<<5;
-        const SIGBUS   =  1<<6;
-        const SIGFPE   =  1<<7;
-        const SIGKILL  =  1<<8;
-        const SIGUSR   =  1<<9;
-        const SIGSEGV  =  1<<10;
-        const SIGUSR2  =  1<<11;
-        const SIGPIPE  =  1<<12;
-        const SIGALRM  =  1<<13;
-        const SIGTERM  =  1<<14;
-        const SIGSTKFLT=  1<<15;
-        const SIGCHLD  =  1<<16;
-        const SIGCONT  =  1<<17;
-        const SIGSTOP  =  1<<18;
-        const SIGTSTP  =  1<<19;
-        const SIGTTIN  =  1<<20;
-        const SIGTTOU  =  1<<21;
-        const SIGURG   =  1<<22;
-        const SIGXCPU  =  1<<23;
-        const SIGXFSZ  =  1<<24;
-        const SIGVTALRM=  1<<25;
-        const SIGPROF  =  1<<26;
-        const SIGWINCH =  1<<27;
-        /// SIGIO和SIGPOLL共用这个号码
-        const SIGIO_OR_POLL    =   1<<28;
-        const SIGPWR   =  1<<29;
-        const SIGSYS   =  1<<30;
-        const SIGRTMIN =  1<<31;
-        // TODO 写上实时信号
-        const SIGRTMAX =  1 << (MAX_SIG_NUM-1);
-    }
-}
-
-/// SIGCHLD si_codes
-#[derive(Debug, Clone, Copy, PartialEq, Eq, ToPrimitive)]
-#[allow(dead_code)]
-pub enum SigChildCode {
-    /// child has exited
-    ///
-    /// CLD_EXITED
-    Exited = 1,
-    /// child was killed
-    ///
-    /// CLD_KILLED
-    Killed = 2,
-    /// child terminated abnormally
-    ///
-    /// CLD_DUMPED
-    Dumped = 3,
-    /// traced child has trapped
-    ///
-    /// CLD_TRAPPED
-    Trapped = 4,
-    /// child has stopped
-    ///
-    /// CLD_STOPPED
-    Stopped = 5,
-    /// stopped child has continued
-    ///
-    /// CLD_CONTINUED
-    Continued = 6,
-}
-
-impl From<SigChildCode> for i32 {
-    fn from(value: SigChildCode) -> Self {
-        value as i32
-    }
 }
 
 #[repr(C, align(16))]
@@ -439,7 +208,10 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) {
         return;
     }
 
-    let sig_guard = sig_guard.unwrap();
+    let sig_guard: crate::libs::spinlock::SpinLockGuard<
+        '_,
+        crate::ipc::signal_types::SignalStruct,
+    > = sig_guard.unwrap();
     let mut siginfo_mut_guard = siginfo_mut.unwrap();
     loop {
         (sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb);
@@ -453,7 +225,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) {
         match sa.action() {
             SigactionType::SaHandler(action_type) => match action_type {
                 SaHandlerType::Error => {
-                    error!("Trying to handle a Sigerror on Process:{:?}", pcb.pid());
+                    error!("Trying to handle a Sigerror on Process:{:?}", pcb.raw_pid());
                     return;
                 }
                 SaHandlerType::Default => {
@@ -467,6 +239,22 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) {
             SigactionType::SaSigaction(_) => todo!(),
         }
 
+        /*
+         * Global init gets no signals it doesn't want.
+         * Container-init gets no signals it doesn't want from same
+         * container.
+         *
+         * Note that if global/container-init sees a sig_kernel_only()
+         * signal here, the signal must have been generated internally
+         * or must have come from an ancestor namespace. In either
+         * case, the signal cannot be dropped.
+         */
+        // todo: https://code.dragonos.org.cn/xref/linux-6.6.21/include/linux/signal.h?fi=sig_kernel_only#444
+        if siginfo_mut_guard.flags().contains(SignalFlags::UNKILLABLE) && !sig_number.kernel_only()
+        {
+            continue;
+        }
+
         if sigaction.is_some() {
             break;
         }
@@ -495,7 +283,7 @@ unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) {
         error!(
             "Error occurred when handling signal: {}, pid={:?}, errcode={:?}",
             sig_number as i32,
-            ProcessManager::current_pcb().pid(),
+            ProcessManager::current_pcb().raw_pid(),
             res.as_ref().unwrap_err()
         );
     }
@@ -557,7 +345,7 @@ impl SignalArch for X86_64SignalArch {
         if UserBufferWriter::new(frame, size_of::<SigFrame>(), true).is_err() {
             error!("rsp doesn't from user level");
             let _r = crate::ipc::kill::kill_process(
-                ProcessManager::current_pcb().pid(),
+                ProcessManager::current_pcb().raw_pid(),
                 Signal::SIGSEGV,
             )
             .map_err(|e| e.to_posix_errno());
@@ -569,7 +357,7 @@ impl SignalArch for X86_64SignalArch {
         if !unsafe { &mut (*frame).context }.restore_sigcontext(trap_frame) {
             error!("unable to restore sigcontext");
             let _r = crate::ipc::kill::kill_process(
-                ProcessManager::current_pcb().pid(),
+                ProcessManager::current_pcb().raw_pid(),
                 Signal::SIGSEGV,
             )
             .map_err(|e| e.to_posix_errno());
@@ -661,11 +449,11 @@ fn setup_frame(
                     } else {
                         error!(
                             "pid-{:?} forgot to set SA_FLAG_RESTORER for signal {:?}",
-                            ProcessManager::current_pcb().pid(),
+                            ProcessManager::current_pcb().raw_pid(),
                             sig as i32
                         );
                         let r = crate::ipc::kill::kill_process(
-                            ProcessManager::current_pcb().pid(),
+                            ProcessManager::current_pcb().raw_pid(),
                             Signal::SIGSEGV,
                         );
                         if r.is_err() {
@@ -676,7 +464,7 @@ fn setup_frame(
                     if sigaction.restorer().is_none() {
                         error!(
                             "restorer in process:{:?} is not defined",
-                            ProcessManager::current_pcb().pid()
+                            ProcessManager::current_pcb().raw_pid()
                         );
                         return Err(SystemError::EINVAL);
                     }
@@ -704,8 +492,10 @@ fn setup_frame(
     if r.is_err() {
         // 如果地址区域位于内核空间,则直接报错
         // todo: 生成一个sigsegv
-        let r =
-            crate::ipc::kill::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV);
+        let r = crate::ipc::kill::kill_process(
+            ProcessManager::current_pcb().raw_pid(),
+            Signal::SIGSEGV,
+        );
         if r.is_err() {
             error!("In setup frame: generate SIGSEGV signal failed");
         }
@@ -717,7 +507,7 @@ fn setup_frame(
     info.copy_siginfo_to_user(unsafe { &mut ((*frame).info) as *mut SigInfo })
         .map_err(|e| -> SystemError {
             let r = crate::ipc::kill::kill_process(
-                ProcessManager::current_pcb().pid(),
+                ProcessManager::current_pcb().raw_pid(),
                 Signal::SIGSEGV,
             );
             if r.is_err() {
@@ -734,7 +524,7 @@ fn setup_frame(
             .setup_sigcontext(oldset, trap_frame)
             .map_err(|e: SystemError| -> SystemError {
                 let r = crate::ipc::kill::kill_process(
-                    ProcessManager::current_pcb().pid(),
+                    ProcessManager::current_pcb().raw_pid(),
                     Signal::SIGSEGV,
                 );
                 if r.is_err() {
@@ -779,44 +569,3 @@ fn get_stack(frame: &TrapFrame, size: usize) -> *mut SigFrame {
     // rsp &= (!(STACK_ALIGN - 1)) as usize;
     return rsp as *mut SigFrame;
 }
-
-/// 信号默认处理函数——终止进程
-fn sig_terminate(sig: Signal) {
-    ProcessManager::exit(sig as usize);
-}
-
-/// 信号默认处理函数——终止进程并生成 core dump
-fn sig_terminate_dump(sig: Signal) {
-    ProcessManager::exit(sig as usize);
-    // TODO 生成 coredump 文件
-}
-
-/// 信号默认处理函数——暂停进程
-fn sig_stop(sig: Signal) {
-    let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
-    ProcessManager::mark_stop().unwrap_or_else(|e| {
-        error!(
-            "sleep error :{:?},failed to sleep process :{:?}, with signal :{:?}",
-            e,
-            ProcessManager::current_pcb(),
-            sig
-        );
-    });
-    drop(guard);
-    schedule(SchedMode::SM_NONE);
-    // TODO 暂停进程
-}
-/// 信号默认处理函数——继续进程
-fn sig_continue(sig: Signal) {
-    ProcessManager::wakeup_stop(&ProcessManager::current_pcb()).unwrap_or_else(|_| {
-        error!(
-            "Failed to wake up process pid = {:?} with signal :{:?}",
-            ProcessManager::current_pcb().pid(),
-            sig
-        );
-    });
-}
-/// 信号默认处理函数——忽略
-fn sig_ignore(_sig: Signal) {
-    return;
-}

+ 27 - 5
kernel/src/arch/x86_64/mm/fault.rs

@@ -149,18 +149,37 @@ impl X86_64MMArch {
     /// - `error_code`: 错误标志
     /// - `address`: 发生缺页异常的虚拟地址
     pub fn do_kern_addr_fault(
-        _regs: &'static TrapFrame,
+        regs: &'static TrapFrame,
         error_code: X86PfErrorCode,
         address: VirtAddr,
     ) {
+        unsafe { crate::debug::traceback::lookup_kallsyms(regs.rip, 0xff) };
+        let pcb = crate::process::ProcessManager::current_pcb();
+        let kstack_guard_addr = pcb.kernel_stack().guard_page_address();
+        if let Some(guard_page) = kstack_guard_addr {
+            let guard_page_size = pcb.kernel_stack().guard_page_size().unwrap();
+            if address.data() >= guard_page.data()
+                && address.data() < guard_page.data() + guard_page_size
+            {
+                // 发生在内核栈保护页上
+                error!(
+                    "kernel stack guard page fault at {:#x}, guard page range: {:#x} - {:#x}",
+                    address.data(),
+                    guard_page.data(),
+                    guard_page.data() + guard_page_size
+                );
+            }
+        }
         panic!(
             "do_kern_addr_fault has not yet been implemented, 
-        fault address: {:#x}, 
+        fault address: {:#x},
+        rip: {:#x},
         error_code: {:#b}, 
         pid: {}\n",
             address.data(),
+            regs.rip,
             error_code,
-            crate::process::ProcessManager::current_pid().data()
+            pcb.raw_pid().data()
         );
         //TODO https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/fault.c#do_kern_addr_fault
     }
@@ -263,7 +282,8 @@ impl X86_64MMArch {
                     if !space_guard.can_extend_stack(region.start() - address) {
                         // exceeds stack limit
                         log::error!(
-                            "stack limit exceeded, error_code: {:?}, address: {:#x}",
+                            "pid {} stack limit exceeded, error_code: {:?}, address: {:#x}",
+                            ProcessManager::current_pid().data(),
                             error_code,
                             address.data(),
                         );
@@ -281,8 +301,10 @@ impl X86_64MMArch {
                         });
                 } else {
                     log::error!(
-                        "No mapped vma, error_code: {:?}, address: {:#x}, flags: {:?}",
+                        "pid: {} No mapped vma, error_code: {:?},rip:{:#x}, address: {:#x}, flags: {:?}",
+                        ProcessManager::current_pid().data(),
                         error_code,
+                        regs.rip,
                         address.data(),
                         flags
                     );

+ 32 - 4
kernel/src/arch/x86_64/mm/mod.rs

@@ -42,12 +42,14 @@ static mut INITIAL_CR3_VALUE: PhysAddr = PhysAddr::new(0);
 
 static INNER_ALLOCATOR: SpinLock<Option<BuddyAllocator<MMArch>>> = SpinLock::new(None);
 
+#[allow(dead_code)]
 #[derive(Clone, Copy, Debug)]
 pub struct X86_64MMBootstrapInfo {
     kernel_load_base_paddr: usize,
     kernel_code_start: usize,
     kernel_code_end: usize,
     kernel_data_end: usize,
+    kernel_rodata_start: usize,
     kernel_rodata_end: usize,
     start_brk: usize,
 }
@@ -134,6 +136,7 @@ impl MemoryManagementArch for X86_64MMArch {
             fn _text();
             fn _etext();
             fn _edata();
+            fn _rodata();
             fn _erodata();
             fn _end();
             fn _default_kernel_load_base();
@@ -146,6 +149,7 @@ impl MemoryManagementArch for X86_64MMArch {
             kernel_code_start: _text as usize,
             kernel_code_end: _etext as usize,
             kernel_data_end: _edata as usize,
+            kernel_rodata_start: _rodata as usize,
             kernel_rodata_end: _erodata as usize,
             start_brk: _end as usize,
         };
@@ -158,15 +162,14 @@ impl MemoryManagementArch for X86_64MMArch {
         boot_callbacks()
             .early_init_memory_blocks()
             .expect("init memory area failed");
-
-        debug!("bootstrap info: {:?}", unsafe { BOOTSTRAP_MM_INFO });
+        debug!("bootstrap info: {:#x?}", unsafe { BOOTSTRAP_MM_INFO });
         debug!("phys[0]=virt[0x{:x}]", unsafe {
             MMArch::phys_2_virt(PhysAddr::new(0)).unwrap().data()
         });
 
         // 初始化内存管理器
         unsafe { allocator_init() };
-
+        Self::enable_kernel_wp();
         send_to_default_serial8250_port("x86 64 mm init done\n\0".as_bytes());
     }
 
@@ -366,10 +369,35 @@ impl MemoryManagementArch for X86_64MMArch {
     const PAGE_WRITE: usize = 0;
     const PAGE_WRITE_EXEC: usize = 0;
     const PAGE_EXEC: usize = 0;
+
+    /// 启用 内核态的 Write Protect
+    /// 这样即使在内核态,CPU也会检查页面的写保护位
+    /// 防止内核错误地写入只读页面
+    fn enable_kernel_wp() {
+        unsafe {
+            use x86::controlregs::{cr0, cr0_write, Cr0};
+            let mut cr0_val = cr0();
+            cr0_val.insert(Cr0::CR0_WRITE_PROTECT);
+            cr0_write(cr0_val);
+            // log::debug!("CR0.WP bit enabled for kernel write protection");
+        }
+    }
+
+    /// 禁用 内核态的 Write Protect
+    fn disable_kernel_wp() {
+        unsafe {
+            use x86::controlregs::{cr0, cr0_write, Cr0};
+            let mut cr0_val = cr0();
+            cr0_val.remove(Cr0::CR0_WRITE_PROTECT);
+            cr0_write(cr0_val);
+            // log::debug!("CR0.WP bit disabled for kernel write protection");
+        }
+    }
 }
 
 /// 获取保护标志的映射表
 ///
+/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/x86/mm/pgprot.c#8
 ///
 /// ## 返回值
 /// - `[usize; 16]`: 长度为16的映射表
@@ -681,7 +709,7 @@ pub unsafe fn kernel_page_flags<A: MemoryManagementArch>(virt: VirtAddr) -> Entr
     if virt.data() >= info.kernel_code_start && virt.data() < info.kernel_code_end {
         // Remap kernel code  execute
         return EntryFlags::new().set_execute(true).set_write(true);
-    } else if virt.data() >= info.kernel_data_end && virt.data() < info.kernel_rodata_end {
+    } else if virt.data() >= info.kernel_rodata_start && virt.data() < info.kernel_rodata_end {
         // Remap kernel rodata read only
         return EntryFlags::new().set_execute(true);
     } else {

+ 3 - 3
kernel/src/arch/x86_64/process/kthread.rs

@@ -9,7 +9,7 @@ use crate::{
     process::{
         fork::CloneFlags,
         kthread::{kernel_thread_bootstrap_stage2, KernelThreadCreateInfo, KernelThreadMechanism},
-        Pid, ProcessManager,
+        ProcessManager, RawPid,
     },
 };
 
@@ -22,7 +22,7 @@ impl KernelThreadMechanism {
     pub fn __inner_create(
         info: &Arc<KernelThreadCreateInfo>,
         clone_flags: CloneFlags,
-    ) -> Result<Pid, SystemError> {
+    ) -> Result<RawPid, SystemError> {
         // WARNING: If create failed, we must drop the info manually or it will cause memory leak. (refcount will not decrease when create failed)
         let create_info: *const KernelThreadCreateInfo =
             KernelThreadCreateInfo::generate_unsafe_arc_ptr(info.clone());
@@ -44,7 +44,7 @@ impl KernelThreadMechanism {
             unsafe { KernelThreadCreateInfo::parse_unsafe_arc_ptr(create_info) };
         })?;
 
-        ProcessManager::find(pid)
+        ProcessManager::find_task_by_vpid(pid)
             .unwrap()
             .set_name(info.name().clone());
 

+ 2 - 2
kernel/src/arch/x86_64/process/syscall.rs

@@ -92,13 +92,13 @@ impl Syscall {
             ARCH_SET_FS => {
                 arch_info.fsbase = arg2;
                 // 如果是当前进程则直接写入寄存器
-                if pcb.pid() == ProcessManager::current_pcb().pid() {
+                if pcb.raw_pid() == ProcessManager::current_pcb().raw_pid() {
                     unsafe { arch_info.restore_fsbase() }
                 }
             }
             ARCH_SET_GS => {
                 arch_info.gsbase = arg2;
-                if pcb.pid() == ProcessManager::current_pcb().pid() {
+                if pcb.raw_pid() == ProcessManager::current_pcb().raw_pid() {
                     unsafe { arch_info.restore_gsbase() }
                 }
             }

+ 2 - 2
kernel/src/arch/x86_64/syscall/mod.rs

@@ -52,7 +52,7 @@ macro_rules! syscall_return {
         $regs.rax = ret as u64;
 
         if $show {
-            let pid = ProcessManager::current_pcb().pid();
+            let pid = ProcessManager::current_pcb().raw_pid();
             debug!("syscall return:pid={:?},ret= {:?}\n", pid, ret as isize);
         }
 
@@ -88,7 +88,7 @@ pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) {
         frame.r9 as usize,
     ];
     mfence();
-    let pid = ProcessManager::current_pcb().pid();
+    let pid = ProcessManager::current_pcb().raw_pid();
     let show = false;
     // let show = if syscall_num != SYS_SCHED && pid.data() >= 9{
     //     true

+ 1 - 0
kernel/src/bpf/helper/consts.rs

@@ -10,3 +10,4 @@ pub const HELPER_TRACE_PRINTF: u32 = 6;
 pub const HELPER_MAP_PUSH_ELEM: u32 = 87;
 pub const HELPER_MAP_POP_ELEM: u32 = 88;
 pub const HELPER_MAP_PEEK_ELEM: u32 = 89;
+pub const HELPER_PROBE_READ_USER_STR: u32 = 114;

+ 46 - 7
kernel/src/bpf/helper/mod.rs

@@ -6,6 +6,7 @@ use crate::bpf::map::{BpfCallBackFn, BpfMap};
 use crate::include::bindings::linux_bpf::BPF_F_CURRENT_CPU;
 use crate::libs::lazy_init::Lazy;
 use crate::smp::core::smp_get_processor_id;
+use crate::syscall::user_access::check_and_clone_cstr;
 use crate::time::Instant;
 use alloc::{collections::BTreeMap, sync::Arc};
 use core::ffi::c_void;
@@ -89,12 +90,12 @@ pub fn perf_event_output(
 
 /// See https://ebpf-docs.dylanreimerink.nl/linux/helper-function/bpf_probe_read/
 fn raw_bpf_probe_read(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) -> i64 {
-    log::info!(
-        "raw_bpf_probe_read, dst:{:x}, size:{}, unsafe_ptr: {:x}",
-        dst as usize,
-        size,
-        unsafe_ptr as usize
-    );
+    // log::info!(
+    //     "raw_bpf_probe_read, dst:{:x}, size:{}, unsafe_ptr: {:x}",
+    //     dst as usize,
+    //     size,
+    //     unsafe_ptr as usize
+    // );
     let (dst, src) = unsafe {
         let dst = core::slice::from_raw_parts_mut(dst as *mut u8, size as usize);
         let src = core::slice::from_raw_parts(unsafe_ptr as *const u8, size as usize);
@@ -111,7 +112,7 @@ fn raw_bpf_probe_read(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) ->
 /// bytes from kernel space address unsafe_ptr and
 /// store the data in dst.
 pub fn bpf_probe_read(dst: &mut [u8], src: &[u8]) -> Result<()> {
-    log::info!("bpf_probe_read: len: {}", dst.len());
+    // log::info!("bpf_probe_read: len: {}", dst.len());
     dst.copy_from_slice(src);
     Ok(())
 }
@@ -305,6 +306,38 @@ pub fn bpf_ktime_get_ns() -> u64 {
     (Instant::now().total_micros() * 1000) as u64
 }
 
+/// Copy a NULL terminated string from an unsafe user address unsafe_ptr to dst.
+/// The size should include the terminating NULL byte. In case the string length is smaller than size,
+/// the target is not padded with further NULL bytes. If the string length is larger than size,
+/// just size-1 bytes are copied and the last byte is set to NULL.
+///
+/// On success, the strictly positive length of the output string, including the trailing NULL character. On error, a negative value
+///
+/// See https://docs.ebpf.io/linux/helper-function/bpf_probe_read_user_str/
+unsafe fn raw_probe_read_user_str(dst: *mut c_void, size: u32, unsafe_ptr: *const c_void) -> i64 {
+    // log::info!(
+    //     "<raw_probe_read_user_str>: dst:{:x}, size:{}, unsafe_ptr: {:x}",
+    //     dst as usize,
+    //     size,
+    //     unsafe_ptr as usize
+    // );
+    let dst = core::slice::from_raw_parts_mut(dst as *mut u8, size as usize);
+    let res = probe_read_user_str(dst, unsafe_ptr as *const u8);
+    match res {
+        Ok(len) => len as i64,
+        Err(e) => e as i64,
+    }
+}
+
+pub fn probe_read_user_str(dst: &mut [u8], src: *const u8) -> Result<usize> {
+    let str = check_and_clone_cstr(src, None).unwrap();
+    let len = str.as_bytes().len();
+    let copy_len = len.min(dst.len() - 1); // Leave space for NULL terminator
+    dst[..copy_len].copy_from_slice(&str.as_bytes()[..copy_len]);
+    dst[copy_len] = 0; // Null-terminate the string
+    Ok(copy_len + 1) // Return length including NULL terminator
+}
+
 pub static BPF_HELPER_FUN_SET: Lazy<BTreeMap<u32, RawBPFHelperFn>> = Lazy::new();
 
 /// Initialize the helper functions.
@@ -341,6 +374,12 @@ pub fn init_helper_functions() {
         map.insert(HELPER_MAP_PUSH_ELEM, define_func!(raw_map_push_elem));
         map.insert(HELPER_MAP_POP_ELEM, define_func!(raw_map_pop_elem));
         map.insert(HELPER_MAP_PEEK_ELEM, define_func!(raw_map_peek_elem));
+
+        // User access helpers
+        map.insert(
+            HELPER_PROBE_READ_USER_STR,
+            define_func!(raw_probe_read_user_str),
+        );
     }
     BPF_HELPER_FUN_SET.init(map);
 }

+ 2 - 2
kernel/src/debug/klog/mm.rs

@@ -4,7 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
 
 use klog_types::{AllocatorLog, AllocatorLogType, LogSource, MMLogChannel};
 
-use crate::{arch::CurrentTimeArch, libs::spinlock::SpinLock, process::Pid, time::TimeArch};
+use crate::{arch::CurrentTimeArch, libs::spinlock::SpinLock, process::RawPid, time::TimeArch};
 
 /// 全局的内存分配器日志通道
 ///
@@ -50,7 +50,7 @@ impl MMDebugLogManager {
     /// - `source`:日志来源
     /// - `pid`:日志来源的pid
     #[allow(dead_code)]
-    pub fn log(log_type: AllocatorLogType, source: LogSource, pid: Option<Pid>) {
+    pub fn log(log_type: AllocatorLogType, source: LogSource, pid: Option<RawPid>) {
         let id = __MM_DEBUG_LOG_IDA.lock_irqsave().alloc().unwrap();
         let log = AllocatorLog::new(
             id as u64,

+ 7 - 2
kernel/src/debug/panic/mod.rs

@@ -16,6 +16,8 @@ cfg_if! {
     }
 }
 
+const MAX_PANIC_COUNT: u8 = 2;
+
 #[derive(Debug)]
 struct PanicGuard;
 
@@ -39,7 +41,10 @@ impl Drop for PanicGuard {
 #[no_mangle]
 pub fn panic(info: &PanicInfo) -> ! {
     PANIC_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
-    error!("Kernel Panic Occurred.");
+    error!(
+        "Kernel Panic Occurred. raw_pid: {}",
+        process::ProcessManager::current_pid().data()
+    );
 
     match info.location() {
         Some(loc) => {
@@ -55,7 +60,7 @@ pub fn panic(info: &PanicInfo) -> ! {
         }
     }
     println!("Message:\n\t{}", info.message());
-    if PANIC_COUNTER.load(core::sync::atomic::Ordering::Relaxed) > 8 {
+    if PANIC_COUNTER.load(core::sync::atomic::Ordering::Relaxed) > MAX_PANIC_COUNT {
         println!(
             "Panic Counter: {}, too many panics, halt.",
             PANIC_COUNTER.load(core::sync::atomic::Ordering::Relaxed)

+ 23 - 10
kernel/src/debug/tracing/mod.rs

@@ -8,11 +8,13 @@ use crate::filesystem::kernfs::KernFSInode;
 use crate::filesystem::vfs::syscall::ModeType;
 use crate::filesystem::vfs::PollStatus;
 use crate::libs::spinlock::SpinLock;
-use crate::tracepoint::TracePointInfo;
+use crate::tracepoint::{TraceCmdLineCacheSnapshot, TracePointInfo};
 use alloc::string::ToString;
 use alloc::sync::Arc;
 use system_error::SystemError;
 
+pub use events::tracing_events_manager;
+
 static mut TRACING_ROOT_INODE: Option<Arc<KernFSInode>> = None;
 
 static TRACE_RAW_PIPE: SpinLock<crate::tracepoint::TracePipeRaw> =
@@ -22,6 +24,7 @@ static TRACE_CMDLINE_CACHE: SpinLock<crate::tracepoint::TraceCmdLineCache> =
     SpinLock::new(crate::tracepoint::TraceCmdLineCache::new(128));
 
 pub fn trace_pipe_push_raw_record(record: &[u8]) {
+    // log::debug!("trace_pipe_push_raw_record: {}", record.len());
     TRACE_RAW_PIPE.lock().push_event(record.to_vec());
 }
 
@@ -89,6 +92,13 @@ impl KernInodePrivateData {
             _ => None,
         };
     }
+
+    pub fn trace_saved_cmdlines(&mut self) -> Option<&mut TraceCmdLineCacheSnapshot> {
+        return match self {
+            KernInodePrivateData::TraceSavedCmdlines(cache) => Some(cache),
+            _ => None,
+        };
+    }
 }
 
 /// Initialize the debugfs tracing directory
@@ -108,15 +118,7 @@ pub fn init_debugfs_tracing() -> Result<(), SystemError> {
         Some(&TracingDirCallBack),
     )?;
 
-    // tracing_root.add_file(
-    //     "trace".to_string(),
-    //     ModeType::from_bits_truncate(0o444),
-    //     Some(4096),
-    //     None,
-    //     Some(&trace_pipe::TraceCallBack),
-    // )?;
-
-    tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider)?;
+    tracing_root.add_file_lazy("trace".to_string(), trace_pipe::kernel_inode_provider_trace)?;
 
     tracing_root.add_file(
         "trace_pipe".to_string(),
@@ -125,6 +127,17 @@ pub fn init_debugfs_tracing() -> Result<(), SystemError> {
         None,
         Some(&trace_pipe::TracePipeCallBack),
     )?;
+    tracing_root.add_file_lazy(
+        "saved_cmdlines".to_string(),
+        trace_pipe::kernel_inode_provider_saved_cmdlines,
+    )?;
+    tracing_root.add_file(
+        "saved_cmdlines_size".to_string(),
+        ModeType::from_bits_truncate(0o444),
+        None,
+        None,
+        Some(&trace_pipe::SavedCmdlinesSizeCallBack),
+    )?;
 
     events::init_events(events_root)?;
 

+ 120 - 3
kernel/src/debug/tracing/trace_pipe.rs

@@ -6,6 +6,7 @@ use crate::libs::wait_queue::WaitQueue;
 use crate::process::{ProcessFlags, ProcessManager};
 use crate::sched::SchedMode;
 use crate::tracepoint::{TraceEntryParser, TracePipeOps};
+use alloc::string::String;
 use core::fmt::Debug;
 use system_error::SystemError;
 
@@ -73,10 +74,14 @@ impl KernFSCallback for TraceCallBack {
     fn write(
         &self,
         _data: KernCallbackData,
-        _buf: &[u8],
+        buf: &[u8],
         _offset: usize,
     ) -> Result<usize, SystemError> {
-        Err(SystemError::EPERM)
+        if buf.len() == 1 {
+            let mut trace_raw_pipe = super::TRACE_RAW_PIPE.lock();
+            trace_raw_pipe.clear();
+        }
+        Ok(buf.len())
     }
 
     fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
@@ -84,7 +89,7 @@ impl KernFSCallback for TraceCallBack {
     }
 }
 
-pub fn kernel_inode_provider() -> KernFSInodeArgs {
+pub fn kernel_inode_provider_trace() -> KernFSInodeArgs {
     KernFSInodeArgs {
         mode: ModeType::from_bits_truncate(0o444),
         callback: Some(&TraceCallBack),
@@ -152,3 +157,115 @@ impl KernFSCallback for TracePipeCallBack {
         Ok(PollStatus::READ)
     }
 }
+
+#[derive(Debug)]
+pub struct SavedCmdlinesSizeCallBack;
+
+impl KernFSCallback for SavedCmdlinesSizeCallBack {
+    fn open(&self, _data: KernCallbackData) -> Result<(), SystemError> {
+        Ok(())
+    }
+
+    fn read(
+        &self,
+        _data: KernCallbackData,
+        buf: &mut [u8],
+        offset: usize,
+    ) -> Result<usize, SystemError> {
+        let max_record = super::TRACE_CMDLINE_CACHE.lock().max_record();
+        let str = format!("{}\n", max_record);
+        let str_bytes = str.as_bytes();
+        if offset >= str_bytes.len() {
+            return Ok(0); // Offset is beyond the length of the string
+        }
+        let len = buf.len().min(str_bytes.len() - offset);
+        buf[..len].copy_from_slice(&str_bytes[offset..offset + len]);
+        Ok(len)
+    }
+
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        let max_record_str = String::from_utf8_lossy(buf);
+        let max_record: usize = max_record_str
+            .trim()
+            .parse()
+            .map_err(|_| SystemError::EINVAL)?;
+        super::TRACE_CMDLINE_CACHE.lock().set_max_record(max_record);
+        Ok(buf.len())
+    }
+
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+}
+
+pub fn kernel_inode_provider_saved_cmdlines() -> KernFSInodeArgs {
+    KernFSInodeArgs {
+        mode: ModeType::from_bits_truncate(0o444),
+        callback: Some(&SavedCmdlinesSnapshotCallBack),
+        inode_type: KernInodeType::File,
+        size: Some(4096),
+        private_data: None,
+    }
+}
+
+#[derive(Debug)]
+pub struct SavedCmdlinesSnapshotCallBack;
+
+impl KernFSCallback for SavedCmdlinesSnapshotCallBack {
+    fn open(&self, mut data: KernCallbackData) -> Result<(), SystemError> {
+        let pri_data = data.private_data_mut();
+        let snapshot = super::TRACE_CMDLINE_CACHE.lock().snapshot();
+        pri_data.replace(KernInodePrivateData::TraceSavedCmdlines(snapshot));
+        Ok(())
+    }
+
+    fn read(
+        &self,
+        mut data: KernCallbackData,
+        buf: &mut [u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        let pri_data = data.private_data_mut().as_mut().unwrap();
+        let snapshot = pri_data.trace_saved_cmdlines().unwrap();
+
+        let mut copy_len = 0;
+        let mut peek_flag = false;
+        loop {
+            if let Some((pid, cmdline)) = snapshot.peek() {
+                let record_str = format!("{} {}\n", pid, String::from_utf8_lossy(cmdline));
+                if copy_len + record_str.len() > buf.len() {
+                    break;
+                }
+                let len = record_str.len();
+                buf[copy_len..copy_len + len].copy_from_slice(record_str.as_bytes());
+                copy_len += len;
+                peek_flag = true;
+            }
+            if peek_flag {
+                snapshot.pop(); // Remove the record after reading
+                peek_flag = false;
+            } else {
+                break; // No more records to read
+            }
+        }
+        Ok(copy_len)
+    }
+
+    fn write(
+        &self,
+        _data: KernCallbackData,
+        _buf: &[u8],
+        _offset: usize,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
+    }
+
+    fn poll(&self, _data: KernCallbackData) -> Result<PollStatus, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+}

+ 106 - 2
kernel/src/driver/base/block/gendisk.rs → kernel/src/driver/base/block/gendisk/mod.rs

@@ -3,18 +3,39 @@ use core::{
     sync::atomic::{AtomicU32, Ordering},
 };
 
-use alloc::sync::{Arc, Weak};
+use alloc::{
+    string::String,
+    sync::{Arc, Weak},
+};
 use hashbrown::HashMap;
 use system_error::SystemError;
 
+use crate::{
+    driver::base::device::device_number::DeviceNumber,
+    filesystem::{
+        devfs::{DevFS, DeviceINode},
+        vfs::{syscall::ModeType, utils::DName, IndexNode, Metadata},
+    },
+    libs::{rwlock::RwLock, spinlock::SpinLockGuard},
+};
+
 use super::block_device::{BlockDevice, BlockId, GeneralBlockRange, LBA_SIZE};
 
+const MINORS_PER_DISK: u32 = 256;
+
 #[derive(Debug)]
 pub struct GenDisk {
     bdev: Weak<dyn BlockDevice>,
     range: GeneralBlockRange,
     block_size_log2: u8,
     idx: Option<u32>,
+
+    device_num: DeviceNumber,
+
+    fs: RwLock<Weak<DevFS>>,
+    metadata: Metadata,
+    /// 对应/dev/下的设备名
+    name: DName,
 }
 
 impl GenDisk {
@@ -25,14 +46,35 @@ impl GenDisk {
         bdev: Weak<dyn BlockDevice>,
         range: GeneralBlockRange,
         idx: Option<u32>,
+        dev_name: DName,
     ) -> Arc<Self> {
         let bsizelog2 = bdev.upgrade().unwrap().blk_size_log2();
 
+        // 对应整块硬盘的情况
+        let id = idx.unwrap_or(0);
+        if id >= MINORS_PER_DISK {
+            panic!("GenDisk index out of range: {}", id);
+        }
+        let ptr = bdev.upgrade().unwrap();
+        let meta = ptr.blkdev_meta();
+        let major = meta.major;
+
+        let minor = meta.base_minor * MINORS_PER_DISK + id;
+        // log::info!("New gendisk: major: {}, minor: {}", major, minor);
+        let device_num = DeviceNumber::new(major, minor);
+
         return Arc::new(GenDisk {
             bdev,
             range,
             block_size_log2: bsizelog2,
             idx,
+            device_num,
+            fs: RwLock::new(Weak::default()),
+            metadata: Metadata::new(
+                crate::filesystem::vfs::FileType::BlockDevice,
+                ModeType::from_bits_truncate(0o755),
+            ),
+            name: dev_name,
         });
     }
 
@@ -120,7 +162,7 @@ impl GenDisk {
     }
 
     #[inline]
-    fn block_offset_2_disk_blkid(&self, block_offset: BlockId) -> BlockId {
+    pub fn block_offset_2_disk_blkid(&self, block_offset: BlockId) -> BlockId {
         self.range.lba_start + block_offset
     }
 
@@ -139,11 +181,73 @@ impl GenDisk {
         &self.range
     }
 
+    #[inline]
+    pub fn device_num(&self) -> DeviceNumber {
+        self.device_num
+    }
+
+    #[inline]
+    pub fn minor(&self) -> u32 {
+        self.device_num.minor()
+    }
+
     /// # sync
     /// 同步磁盘
     pub fn sync(&self) -> Result<(), SystemError> {
         self.block_device().sync()
     }
+
+    pub fn symlink_name(&self) -> String {
+        let major = self.device_num.major().data();
+        let minor = self.device_num.minor();
+        format!("{}:{}", major, minor)
+    }
+
+    pub fn block_size_log2(&self) -> u8 {
+        self.block_size_log2
+    }
+}
+
+impl IndexNode for GenDisk {
+    fn fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem> {
+        self.fs.read().upgrade().unwrap()
+    }
+    fn as_any_ref(&self) -> &dyn core::any::Any {
+        self
+    }
+    fn read_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &mut [u8],
+        _data: SpinLockGuard<crate::filesystem::vfs::FilePrivateData>,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
+    }
+    fn write_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &[u8],
+        _data: SpinLockGuard<crate::filesystem::vfs::FilePrivateData>,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::EPERM)
+    }
+    fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, system_error::SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+    fn metadata(&self) -> Result<crate::filesystem::vfs::Metadata, SystemError> {
+        Ok(self.metadata.clone())
+    }
+    fn dname(&self) -> Result<DName, SystemError> {
+        Ok(self.name.clone())
+    }
+}
+
+impl DeviceINode for GenDisk {
+    fn set_fs(&self, fs: alloc::sync::Weak<crate::filesystem::devfs::DevFS>) {
+        *self.fs.write() = fs;
+    }
 }
 
 #[derive(Default)]

+ 68 - 18
kernel/src/driver/base/block/manager.rs

@@ -1,4 +1,4 @@
-use core::fmt::Formatter;
+use core::{fmt::Formatter, sync::atomic::AtomicU32};
 
 use alloc::sync::Arc;
 use hashbrown::HashMap;
@@ -6,8 +6,15 @@ use system_error::SystemError;
 use unified_init::macros::unified_init;
 
 use crate::{
-    driver::base::{block::gendisk::GenDisk, device::DevName},
-    filesystem::mbr::MbrDiskPartionTable,
+    driver::base::{
+        block::gendisk::GenDisk,
+        device::{device_number::Major, DevName},
+    },
+    filesystem::{
+        devfs::devfs_register,
+        mbr::MbrDiskPartionTable,
+        vfs::{utils::DName, IndexNode},
+    },
     init::initcall::INITCALL_POSTCORE,
     libs::spinlock::{SpinLock, SpinLockGuard},
 };
@@ -39,12 +46,15 @@ pub struct BlockDevManager {
 
 struct InnerBlockDevManager {
     disks: HashMap<DevName, Arc<dyn BlockDevice>>,
+    /// 记录每个major对应的下一个可用的minor号
+    minors: HashMap<Major, AtomicU32>,
 }
 impl BlockDevManager {
     pub fn new() -> Self {
         BlockDevManager {
             inner: SpinLock::new(InnerBlockDevManager {
                 disks: HashMap::new(),
+                minors: HashMap::new(),
             }),
         }
     }
@@ -62,18 +72,18 @@ impl BlockDevManager {
         }
         inner.disks.insert(dev_name.clone(), dev.clone());
 
-        let mut out_remove = || {
+        // 检测分区表,并创建gendisk
+        let res = self.check_partitions(&dev);
+        if res.is_err() {
             inner.disks.remove(dev_name);
         };
-
-        // 检测分区表,并创建gendisk
-        self.check_partitions(&dev).inspect_err(|_| out_remove())?;
+        res?;
         Ok(())
     }
 
     /// 检测分区表,并创建gendisk
     fn check_partitions(&self, dev: &Arc<dyn BlockDevice>) -> Result<(), SystemError> {
-        if self.check_mbr(dev).is_ok() {
+        if self.try_register_disk_by_mbr(dev).is_ok() {
             return Ok(());
         }
 
@@ -81,11 +91,13 @@ impl BlockDevManager {
         self.register_entire_disk_as_gendisk(dev)
     }
 
-    fn check_mbr(&self, dev: &Arc<dyn BlockDevice>) -> Result<(), SystemError> {
+    fn try_register_disk_by_mbr(&self, dev: &Arc<dyn BlockDevice>) -> Result<(), SystemError> {
         let mbr = MbrDiskPartionTable::from_disk(dev.clone())?;
         let piter = mbr.partitions_raw();
+        let mut idx;
         for p in piter {
-            self.register_gendisk_with_range(dev, p.try_into()?)?;
+            idx = dev.blkdev_meta().inner().gendisks.alloc_idx();
+            self.register_gendisk_with_range(dev, p.try_into()?, idx)?;
         }
         Ok(())
     }
@@ -96,20 +108,29 @@ impl BlockDevManager {
         dev: &Arc<dyn BlockDevice>,
     ) -> Result<(), SystemError> {
         let range = dev.disk_range();
-        self.register_gendisk_with_range(dev, range)
+        self.register_gendisk_with_range(dev, range, GenDisk::ENTIRE_DISK_IDX)
     }
 
     fn register_gendisk_with_range(
         &self,
         dev: &Arc<dyn BlockDevice>,
         range: GeneralBlockRange,
+        idx: u32,
     ) -> Result<(), SystemError> {
         let weak_dev = Arc::downgrade(dev);
-        let gendisk = GenDisk::new(
-            weak_dev,
-            range,
-            Some(dev.blkdev_meta().inner().gendisks.alloc_idx()),
-        );
+
+        // 这里先拿到硬盘的设备名,然后在根据idx来生成gendisk的名字
+        // 如果是整个磁盘,则idx为 None,名字为/dev/sda
+        // 如果是分区,例如idx为1,则名字为/dev/sda1
+        // 以此类推
+        let dev_name = dev.dev_name();
+        let (idx, dev_name) = match idx {
+            GenDisk::ENTIRE_DISK_IDX => (None, DName::from(dev_name.name())),
+            id => (Some(id), DName::from(format!("{}{}", dev_name.name(), idx))),
+        };
+
+        let gendisk = GenDisk::new(weak_dev, range, idx, dev_name);
+        // log::info!("Registering gendisk");
         self.register_gendisk(dev, gendisk)
     }
 
@@ -130,6 +151,17 @@ impl BlockDevManager {
         dev.callback_gendisk_registered(&gendisk).inspect_err(|_| {
             meta_inner.gendisks.remove(&idx);
         })?;
+
+        // 注册到devfs
+        let dname = gendisk.dname()?;
+        devfs_register(dname.as_ref(), gendisk.clone()).map_err(|e| {
+            log::error!(
+                "Failed to register gendisk {:?} to devfs: {:?}",
+                dname.as_ref(),
+                e
+            );
+            e
+        })?;
         Ok(())
     }
 
@@ -204,28 +236,46 @@ impl BlockDevManager {
 
         Some((path, partno))
     }
+
+    /// 获取对应major下一个可用的minor号
+    pub(self) fn next_minor(&self, major: Major) -> u32 {
+        let mut inner = self.inner();
+        let base = inner
+            .minors
+            .entry(major)
+            .or_insert_with(|| AtomicU32::new(0));
+        let base_minor = base.load(core::sync::atomic::Ordering::SeqCst);
+        base.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
+        base_minor
+    }
 }
 
 pub struct BlockDevMeta {
     pub devname: DevName,
+    pub major: Major,
+    pub base_minor: u32,
     inner: SpinLock<InnerBlockDevMeta>,
 }
 
 pub struct InnerBlockDevMeta {
     pub gendisks: GenDiskMap,
+    pub dev_idx: usize,
 }
 
 impl BlockDevMeta {
-    pub fn new(devname: DevName) -> Self {
+    pub fn new(devname: DevName, major: Major) -> Self {
         BlockDevMeta {
             devname,
+            major,
+            base_minor: block_dev_manager().next_minor(major),
             inner: SpinLock::new(InnerBlockDevMeta {
                 gendisks: GenDiskMap::new(),
+                dev_idx: 0, // 默认索引为0
             }),
         }
     }
 
-    fn inner(&self) -> SpinLockGuard<InnerBlockDevMeta> {
+    pub(crate) fn inner(&self) -> SpinLockGuard<InnerBlockDevMeta> {
         self.inner.lock()
     }
 }

+ 21 - 0
kernel/src/driver/base/device/device_number.rs

@@ -1,3 +1,8 @@
+use core::{
+    fmt::Display,
+    hash::{Hash, Hasher},
+};
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
 pub struct Major(u32);
 
@@ -24,6 +29,10 @@ impl Major {
     pub const UNIX98_PTY_SLAVE_MAJOR: Self =
         Self::new(Self::UNIX98_PTY_MASTER_MAJOR.0 + Self::UNIX98_PTY_MAJOR_COUNT.0);
 
+    /// Disk
+    pub const AHCI_BLK_MAJOR: Self = Self::new(8);
+    pub const VIRTIO_BLK_MAJOR: Self = Self::new(254);
+
     pub const HVC_MAJOR: Self = Self::new(229);
 
     pub const fn new(x: u32) -> Self {
@@ -34,6 +43,12 @@ impl Major {
     }
 }
 
+impl Hash for Major {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.hash(state); // 使用 Major 内部的 u32 值来计算哈希值
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct DeviceNumber {
     data: u32,
@@ -84,3 +99,9 @@ impl From<u32> for DeviceNumber {
         Self { data: x }
     }
 }
+
+impl Display for DeviceNumber {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{}:{}", self.major().data(), self.minor())
+    }
+}

+ 5 - 0
kernel/src/driver/base/device/mod.rs

@@ -142,6 +142,11 @@ impl DevName {
     pub fn id(&self) -> usize {
         return self.id;
     }
+
+    #[inline]
+    pub fn name(&self) -> &str {
+        return self.name.as_ref();
+    }
 }
 
 impl core::fmt::Debug for DevName {

+ 57 - 3
kernel/src/driver/block/virtio_blk.rs

@@ -25,6 +25,7 @@ use crate::{
             class::Class,
             device::{
                 bus::Bus,
+                device_number::Major,
                 driver::{Driver, DriverCommonData},
                 DevName, Device, DeviceCommonData, DeviceId, DeviceType, IdTable,
             },
@@ -40,10 +41,15 @@ use crate::{
         },
     },
     exception::{irqdesc::IrqReturn, IrqNumber},
-    filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
+    filesystem::{
+        devfs::{DevFS, DeviceINode},
+        kernfs::KernFSInode,
+        mbr::MbrDiskPartionTable,
+        vfs::{syscall::ModeType, IndexNode, Metadata},
+    },
     init::initcall::INITCALL_POSTCORE,
     libs::{
-        rwlock::{RwLockReadGuard, RwLockWriteGuard},
+        rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
         spinlock::{SpinLock, SpinLockGuard},
     },
 };
@@ -158,6 +164,9 @@ pub struct VirtIOBlkDevice {
     inner: SpinLock<InnerVirtIOBlkDevice>,
     locked_kobj_state: LockedKObjectState,
     self_ref: Weak<Self>,
+
+    fs: RwLock<Weak<DevFS>>,
+    metadata: Metadata,
 }
 
 impl Debug for VirtIOBlkDevice {
@@ -191,7 +200,7 @@ impl VirtIOBlkDevice {
         let mut device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
         device_inner.enable_interrupts();
         let dev = Arc::new_cyclic(|self_ref| Self {
-            blkdev_meta: BlockDevMeta::new(devname),
+            blkdev_meta: BlockDevMeta::new(devname, Major::VIRTIO_BLK_MAJOR),
             self_ref: self_ref.clone(),
             dev_id,
             locked_kobj_state: LockedKObjectState::default(),
@@ -203,6 +212,11 @@ impl VirtIOBlkDevice {
                 kobject_common: KObjectCommonData::default(),
                 irq,
             }),
+            fs: RwLock::new(Weak::default()),
+            metadata: Metadata::new(
+                crate::filesystem::vfs::FileType::BlockDevice,
+                ModeType::from_bits_truncate(0o755),
+            ),
         });
 
         Some(dev)
@@ -213,6 +227,45 @@ impl VirtIOBlkDevice {
     }
 }
 
+impl IndexNode for VirtIOBlkDevice {
+    fn fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem> {
+        todo!()
+    }
+    fn as_any_ref(&self) -> &dyn core::any::Any {
+        self
+    }
+    fn read_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &mut [u8],
+        _data: SpinLockGuard<crate::filesystem::vfs::FilePrivateData>,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+    fn write_at(
+        &self,
+        _offset: usize,
+        _len: usize,
+        _buf: &[u8],
+        _data: SpinLockGuard<crate::filesystem::vfs::FilePrivateData>,
+    ) -> Result<usize, SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+    fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, system_error::SystemError> {
+        Err(SystemError::ENOSYS)
+    }
+    fn metadata(&self) -> Result<crate::filesystem::vfs::Metadata, SystemError> {
+        Ok(self.metadata.clone())
+    }
+}
+
+impl DeviceINode for VirtIOBlkDevice {
+    fn set_fs(&self, fs: alloc::sync::Weak<crate::filesystem::devfs::DevFS>) {
+        *self.fs.write() = fs;
+    }
+}
+
 impl BlockDevice for VirtIOBlkDevice {
     fn dev_name(&self) -> &DevName {
         &self.blkdev_meta.devname
@@ -342,6 +395,7 @@ impl VirtIODevice for VirtIOBlkDevice {
 
     fn set_virtio_device_index(&self, index: VirtIODeviceIndex) {
         self.inner().virtio_index = Some(index);
+        self.blkdev_meta.inner().dev_idx = index.into();
     }
 
     fn virtio_device_index(&self) -> Option<VirtIODeviceIndex> {

+ 2 - 1
kernel/src/driver/disk/ahci/ahcidisk.rs

@@ -6,6 +6,7 @@ use crate::driver::base::block::manager::BlockDevMeta;
 use crate::driver::base::class::Class;
 use crate::driver::base::device::bus::Bus;
 
+use crate::driver::base::device::device_number::Major;
 use crate::driver::base::device::driver::Driver;
 use crate::driver::base::device::{DevName, Device, DeviceType, IdTable};
 use crate::driver::base::kobject::{KObjType, KObject, KObjectState};
@@ -381,7 +382,7 @@ impl LockedAhciDisk {
         let devname = scsi_manager().alloc_id().ok_or(SystemError::EBUSY)?;
         // 构建磁盘结构体
         let result: Arc<LockedAhciDisk> = Arc::new_cyclic(|self_ref| LockedAhciDisk {
-            blkdev_meta: BlockDevMeta::new(devname),
+            blkdev_meta: BlockDevMeta::new(devname, Major::AHCI_BLK_MAJOR),
             inner: SpinLock::new(AhciDisk {
                 partitions: Vec::new(),
                 ctrl_num,

+ 6 - 4
kernel/src/driver/tty/pty/unix98pty.rs

@@ -12,12 +12,13 @@ use crate::{
         devpts::DevPtsFs,
         epoll::EPollEventType,
         vfs::{
-            file::FileMode, syscall::ModeType, FilePrivateData, FileType, MountFS, ROOT_INODE,
+            file::FileMode, syscall::ModeType, FilePrivateData, FileType, MountFS,
             VFS_MAX_FOLLOW_SYMLINK_TIMES,
         },
     },
     libs::spinlock::SpinLockGuard,
     mm::VirtAddr,
+    process::ProcessManager,
     syscall::user_access::UserBufferWriter,
 };
 
@@ -216,11 +217,11 @@ impl TtyOperation for Unix98PtyDriverInner {
 
     fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> {
         let driver = tty.core().driver();
-
+        let root_inode = ProcessManager::current_mntns().root_inode();
         if tty.core().driver().tty_driver_sub_type() == TtyDriverSubType::PtySlave {
             driver.ttys().remove(&tty.core().index());
             let pts_root_inode =
-                ROOT_INODE().lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
+                root_inode.lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
             let _ = pts_root_inode.unlink(&tty.core().index().to_string());
         }
 
@@ -250,8 +251,9 @@ pub fn ptmx_open(
     mut data: SpinLockGuard<FilePrivateData>,
     mode: &FileMode,
 ) -> Result<(), SystemError> {
+    let root_inode = ProcessManager::current_mntns().root_inode();
     let pts_root_inode =
-        ROOT_INODE().lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
+        root_inode.lookup_follow_symlink("/dev/pts", VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
 
     let fs = pts_root_inode
         .fs()

+ 45 - 11
kernel/src/driver/tty/tty_core.rs

@@ -19,13 +19,14 @@ use crate::{
         wait_queue::EventWaitQueue,
     },
     mm::VirtAddr,
-    process::{process_group::Pgid, session::Sid, ProcessControlBlock},
+    process::{pid::Pid, ProcessControlBlock},
     syscall::user_access::{UserBufferReader, UserBufferWriter},
 };
 
 use super::{
     termios::{ControlMode, PosixTermios, Termios, TtySetTermiosOpt, WindowSize},
     tty_driver::{TtyCorePrivateField, TtyDriver, TtyDriverSubType, TtyDriverType, TtyOperation},
+    tty_job_control::TtyJobCtrlManager,
     tty_ldisc::{
         ntty::{NTtyData, NTtyLinediscipline},
         TtyLineDiscipline,
@@ -69,7 +70,7 @@ impl TtyCore {
             port: RwLock::new(None),
             index,
             vc_index: AtomicUsize::new(usize::MAX),
-            ctrl: SpinLock::new(TtyContorlInfo::default()),
+            ctrl: SpinLock::new(TtyControlInfo::default()),
             closing: AtomicBool::new(false),
             flow: SpinLock::new(TtyFlowState::default()),
             link: RwLock::default(),
@@ -279,21 +280,35 @@ impl TtyCore {
 }
 
 #[derive(Debug, Default)]
-pub struct TtyContorlInfo {
+pub struct TtyControlInfo {
     /// 当前会话的SId
-    pub session: Option<Sid>,
+    pub session: Option<Arc<Pid>>,
     /// 前台进程组id
-    pub pgid: Option<Pgid>,
+    pub pgid: Option<Arc<Pid>>,
 
     /// packet模式下使用,目前未用到
     pub pktstatus: TtyPacketStatus,
     pub packet: bool,
 }
 
-impl TtyContorlInfo {
+impl TtyControlInfo {
     pub fn set_info_by_pcb(&mut self, pcb: Arc<ProcessControlBlock>) {
-        self.session = Some(pcb.sid());
-        self.pgid = Some(pcb.pgid());
+        self.session = pcb.task_session();
+        self.pgid = pcb.task_pgrp();
+    }
+
+    /// 清除当前session的pid
+    ///
+    /// 如果当前session已经死了,则将其清除。
+    pub fn clear_dead_session(&mut self) {
+        if self.session.is_none() {
+            return;
+        }
+
+        let clean = self.session.as_ref().map(|s| s.dead()).unwrap();
+        if clean {
+            self.session = None;
+        }
     }
 }
 
@@ -324,7 +339,7 @@ pub struct TtyCoreData {
     /// 端口
     port: RwLock<Option<Arc<dyn TtyPort>>>,
     /// 前台进程
-    ctrl: SpinLock<TtyContorlInfo>,
+    ctrl: SpinLock<TtyControlInfo>,
     /// 是否正在关闭
     closing: AtomicBool,
     /// 流控状态
@@ -400,12 +415,23 @@ impl TtyCoreData {
         self.count.load(Ordering::SeqCst)
     }
 
+    pub fn count_valid(&self) -> bool {
+        let cnt = self.count();
+        // 暂时认为有效的count范围是(0, usize::MAX / 2)
+        cnt > 0 && cnt < usize::MAX / 2
+    }
+
     #[inline]
     pub fn add_count(&self) {
         self.count
             .fetch_add(1, core::sync::atomic::Ordering::SeqCst);
     }
 
+    pub fn dec_count(&self) -> usize {
+        self.count
+            .fetch_sub(1, core::sync::atomic::Ordering::SeqCst)
+    }
+
     #[inline]
     pub fn read_wq(&self) -> &EventWaitQueue {
         &self.read_wq
@@ -417,7 +443,7 @@ impl TtyCoreData {
     }
 
     #[inline]
-    pub fn contorl_info_irqsave(&self) -> SpinLockGuard<TtyContorlInfo> {
+    pub fn contorl_info_irqsave(&self) -> SpinLockGuard<TtyControlInfo> {
         self.ctrl.lock_irqsave()
     }
 
@@ -624,7 +650,15 @@ impl TtyOperation for TtyCore {
     }
 
     fn close(&self, tty: Arc<TtyCore>) -> Result<(), SystemError> {
-        self.core().tty_driver.driver_funcs().close(tty)
+        let r = self.core().tty_driver.driver_funcs().close(tty.clone());
+        self.core().dec_count();
+        // let cnt = self.core().count();
+        // log::debug!("TtyCore close: count: {cnt}, tty: {:?}", tty.core().name());
+        if !self.core().count_valid() {
+            // 如果计数为0或者无效,表示tty已经关闭
+            TtyJobCtrlManager::remove_session_tty(&tty);
+        }
+        r
     }
 
     fn resize(&self, tty: Arc<TtyCore>, winsize: WindowSize) -> Result<(), SystemError> {

+ 70 - 12
kernel/src/driver/tty/tty_device.rs

@@ -1,3 +1,5 @@
+use core::fmt::Debug;
+
 use alloc::{
     string::{String, ToString},
     sync::{Arc, Weak},
@@ -97,7 +99,6 @@ pub enum PtyType {
     Pts,
 }
 
-#[derive(Debug)]
 #[cast_to([sync] Device)]
 pub struct TtyDevice {
     name: String,
@@ -142,6 +143,37 @@ impl TtyDevice {
         };
         Ok(tty)
     }
+
+    /// tty_open_current_tty - get locked tty of current task
+    #[inline(never)]
+    fn open_current_tty(
+        &self,
+        dev_num: DeviceNumber,
+        data: &mut FilePrivateData,
+    ) -> Option<Arc<TtyCore>> {
+        // log::debug!("open_current_tty: dev_num: {}", dev_num);
+        if dev_num != DeviceNumber::new(Major::TTYAUX_MAJOR, 0) {
+            // log::debug!("Not a tty device, dev_num: {}", dev_num);
+            return None;
+        }
+
+        let current_tty = TtyJobCtrlManager::get_current_tty()?;
+
+        if let FilePrivateData::Tty(tty_priv) = data {
+            tty_priv.mode.insert(FileMode::O_NONBLOCK);
+        }
+
+        current_tty.reopen().ok()?;
+        Some(current_tty)
+    }
+}
+
+impl Debug for TtyDevice {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        f.debug_struct("TtyDevice")
+            .field("name", &self.name)
+            .finish()
+    }
 }
 
 impl PollableInode for TtyDevice {
@@ -178,18 +210,24 @@ impl IndexNode for TtyDevice {
         mut data: SpinLockGuard<FilePrivateData>,
         mode: &crate::filesystem::vfs::file::FileMode,
     ) -> Result<(), SystemError> {
-        if let FilePrivateData::Tty(_) = &*data {
-            return Ok(());
-        }
         if self.tty_type == TtyType::Pty(PtyType::Ptm) {
             return ptmx_open(data, mode);
         }
         let dev_num = self.metadata()?.raw_dev;
+        // log::debug!(
+        //     "TtyDevice::open: dev_num: {}, current pid: {}",
+        //     dev_num,
+        //     ProcessManager::current_pid()
+        // );
+        let mut tty = self.open_current_tty(dev_num, &mut data);
+        if tty.is_none() {
+            let (index, driver) =
+                TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?;
+
+            tty = Some(driver.open_tty(Some(index))?);
+        }
 
-        let (index, driver) =
-            TtyDriverManager::lookup_tty_driver(dev_num).ok_or(SystemError::ENODEV)?;
-
-        let tty = driver.open_tty(Some(index))?;
+        let tty = tty.unwrap();
 
         // 设置privdata
         *data = FilePrivateData::Tty(TtyFilePrivateData {
@@ -197,6 +235,8 @@ impl IndexNode for TtyDevice {
             mode: *mode,
         });
 
+        tty.core().contorl_info_irqsave().clear_dead_session();
+
         let ret = tty.open(tty.core());
         if let Err(err) = ret {
             if err == SystemError::ENOSYS {
@@ -214,7 +254,12 @@ impl IndexNode for TtyDevice {
         {
             let pcb = ProcessManager::current_pcb();
             let pcb_tty = pcb.sig_info_irqsave().tty();
-            if pcb_tty.is_none() && tty.core().contorl_info_irqsave().session.is_none() {
+
+            let cond1 = pcb_tty.is_none();
+            let _cond2 = tty.core().contorl_info_irqsave().session.is_none();
+
+            // 注意!!这里为了debug,临时把cond2的判断去掉了,其实要cond1 && cond2才对
+            if cond1 {
                 TtyJobCtrlManager::proc_set_tty(tty);
             }
         }
@@ -344,6 +389,7 @@ impl IndexNode for TtyDevice {
         } else {
             return Err(SystemError::EIO);
         };
+
         drop(data);
         tty.close(tty.clone())
     }
@@ -601,6 +647,14 @@ impl TtyFilePrivateData {
 #[unified_init(INITCALL_DEVICE)]
 #[inline(never)]
 pub fn tty_init() -> Result<(), SystemError> {
+    let tty_device = TtyDevice::new(
+        "tty".to_string(),
+        IdTable::new(
+            String::from("tty"),
+            Some(DeviceNumber::new(Major::TTYAUX_MAJOR, 0)),
+        ),
+        TtyType::Tty,
+    );
     let console = TtyDevice::new(
         "console".to_string(),
         IdTable::new(
@@ -610,9 +664,13 @@ pub fn tty_init() -> Result<(), SystemError> {
         TtyType::Tty,
     );
 
-    // 将设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面
-    device_register(console.clone())?;
-    devfs_register(&console.name.clone(), console)?;
+    let devs = [tty_device, console];
+
+    for dev in devs {
+        // 将设备注册到devfs,TODO:这里console设备应该与tty在一个设备group里面
+        device_register(dev.clone())?;
+        devfs_register(&dev.name.clone(), dev)?;
+    }
 
     serial_init()?;
 

+ 6 - 0
kernel/src/driver/tty/tty_driver.rs

@@ -55,6 +55,12 @@ impl TtyDriverManager {
     pub fn lookup_tty_driver(dev_num: DeviceNumber) -> Option<(usize, Arc<TtyDriver>)> {
         let drivers_guard = TTY_DRIVERS.lock();
         for driver in drivers_guard.iter() {
+            // log::debug!(
+            //     "driver.major: {}, minor_start: {}, device_count: {}",
+            //     driver.major.data(),
+            //     driver.minor_start,
+            //     driver.device_count
+            // );
             let base = DeviceNumber::new(driver.major, driver.minor_start);
             if dev_num < base || dev_num.data() > base.data() + driver.device_count {
                 continue;

+ 161 - 54
kernel/src/driver/tty/tty_job_control.rs

@@ -4,7 +4,10 @@ use system_error::SystemError;
 use crate::{
     arch::ipc::signal::{SigSet, Signal},
     mm::VirtAddr,
-    process::{process_group::Pgid, Pid, ProcessFlags, ProcessManager},
+    process::{
+        pid::{Pid, PidType},
+        ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, RawPid,
+    },
     syscall::user_access::{UserBufferReader, UserBufferWriter},
 };
 
@@ -20,47 +23,75 @@ impl TtyJobCtrlManager {
 
         let mut ctrl = core.contorl_info_irqsave();
         ctrl.set_info_by_pcb(pcb.clone());
+
         drop(ctrl);
 
         let mut singal = pcb.sig_info_mut();
         singal.set_tty(Some(tty.clone()));
     }
 
+    /// ### 清除进程的tty
+    ///
+    /// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#75
+    pub fn proc_clear_tty(pcb: &Arc<ProcessControlBlock>) {
+        let mut singal = pcb.sig_info_mut();
+        Self::__proc_clear_tty(&mut singal);
+    }
+
+    pub fn __proc_clear_tty(wguard: &mut ProcessSignalInfo) {
+        // log::debug!("Clearing tty");
+        wguard.set_tty(None);
+    }
+
+    pub fn remove_session_tty(tty: &Arc<TtyCore>) {
+        let mut ctrl = tty.core().contorl_info_irqsave();
+        ctrl.session = None;
+    }
+
     /// ### 检查tty
+    ///
+    /// check for POSIX terminal changes
+    ///
+    /// Reference: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#33
     pub fn tty_check_change(tty: Arc<TtyCore>, sig: Signal) -> Result<(), SystemError> {
         let pcb = ProcessManager::current_pcb();
-
-        if pcb.sig_info_irqsave().tty().is_none()
-            || !Arc::ptr_eq(&pcb.sig_info_irqsave().tty().unwrap(), &tty)
-        {
+        let current_tty = pcb.sig_info_irqsave().tty();
+        if current_tty.is_none() || !Arc::ptr_eq(&current_tty.unwrap(), &tty) {
             return Ok(());
         }
 
-        let pgid = pcb.pgid();
+        let pgid = pcb.task_pgrp();
 
         let ctrl = tty.core().contorl_info_irqsave();
-        let tty_pgid = ctrl.pgid;
+        let tty_pgid = ctrl.pgid.clone();
         drop(ctrl);
 
-        if tty_pgid.is_some() && tty_pgid.unwrap() != pgid {
-            if pcb
-                .sig_info_irqsave()
-                .sig_blocked()
-                .contains(SigSet::from(sig))
-                || pcb.sig_struct_irqsave().handlers[sig as usize - 1].is_ignore()
-            {
+        // log::debug!(
+        //     "tty_check_change: pid: {},pgid: {:?}, tty_pgid: {:?}",
+        //     pcb.raw_pid().data(),
+        //     pgid.as_ref().map(|p| p.pid_vnr().data()),
+        //     tty_pgid.as_ref().map(|p| p.pid_vnr().data())
+        // );
+        if tty_pgid.is_some() && tty_pgid != pgid {
+            let pgid = pgid.unwrap();
+            if Self::sig_is_ignored(sig) {
                 // 忽略该信号
                 if sig == Signal::SIGTTIN {
                     return Err(SystemError::EIO);
                 }
             } else if ProcessManager::is_current_pgrp_orphaned() {
+                log::debug!("tty_check_change: orphaned pgrp");
                 return Err(SystemError::EIO);
             } else {
-                crate::ipc::kill::kill_process_group(pgid, sig)?;
+                crate::ipc::kill::kill_process_group(&pgid, sig)?;
                 ProcessManager::current_pcb()
                     .flags()
                     .insert(ProcessFlags::HAS_PENDING_SIGNAL);
-                log::debug!("job_ctrl_ioctl: kill. pgid: {pgid}, tty_pgid: {tty_pgid:?}");
+                log::debug!(
+                    "job_ctrl_ioctl: kill. pgid: {}, tty_pgid: {:?}",
+                    pgid.pid_vnr().data(),
+                    tty_pgid.map(|p| p.pid_vnr().data())
+                );
                 return Err(SystemError::ERESTARTSYS);
             }
         }
@@ -68,6 +99,13 @@ impl TtyJobCtrlManager {
         Ok(())
     }
 
+    fn sig_is_ignored(sig: Signal) -> bool {
+        let pcb = ProcessManager::current_pcb();
+        let siginfo_guard = pcb.sig_info_irqsave();
+        siginfo_guard.sig_blocked().contains(SigSet::from(sig))
+            || pcb.sig_struct_irqsave().handler(sig).unwrap().is_ignore()
+    }
+
     pub fn job_ctrl_ioctl(
         real_tty: Arc<TtyCore>,
         cmd: u32,
@@ -77,35 +115,57 @@ impl TtyJobCtrlManager {
             TtyIoctlCmd::TIOCSPGRP => Self::tiocspgrp(real_tty, arg),
             TtyIoctlCmd::TIOCGPGRP => Self::tiocgpgrp(real_tty, arg),
             TtyIoctlCmd::TIOCGSID => Self::tiocgsid(real_tty, arg),
-            TtyIoctlCmd::TIOCSCTTY => Self::tiocsctty(real_tty),
+            TtyIoctlCmd::TIOCSCTTY => Self::tiocsctty(real_tty, arg),
             _ => {
                 return Err(SystemError::ENOIOCTLCMD);
             }
         }
     }
 
-    fn tiocsctty(real_tty: Arc<TtyCore>) -> Result<usize, SystemError> {
+    // https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#tiocsctty
+    fn tiocsctty(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
         let current = ProcessManager::current_pcb();
-        // log::debug!("job_ctrl_ioctl: TIOCSCTTY,current: {:?}", current.pid());
-        if current.is_session_leader()
-            && real_tty.core().contorl_info_irqsave().session.unwrap() == current.sid()
-        {
-            return Ok(0);
-        }
+        let siginfo_guard = current.sig_info_irqsave();
 
-        if !current.is_session_leader() || current.sig_info_irqsave().tty().is_some() {
+        // 只有会话首进程才能设置控制终端
+        if !siginfo_guard.is_session_leader {
             return Err(SystemError::EPERM);
         }
 
-        //todo 权限检查?
-        // https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#tiocsctty
-        if let Some(sid) = real_tty.core().contorl_info_irqsave().session {
-            //todo 目前只有一个tty设备,所以选择复用1号进程的tty,因此修改1号进程的tty暂时被允许
-            if sid != Pid::new(1) {
+        // 如果当前进程已经有控制终端,则返回错误(除非是同一个tty且会话相同)
+        if let Some(current_tty) = siginfo_guard.tty() {
+            if Arc::ptr_eq(&current_tty, &real_tty)
+                && current.task_session() == real_tty.core().contorl_info_irqsave().session
+            {
+                // 如果已经是当前tty且会话相同,直接返回成功
+                return Ok(0);
+            } else {
+                // 已经有其他控制终端,返回错误
                 return Err(SystemError::EPERM);
             }
         }
 
+        drop(siginfo_guard);
+
+        let tty_ctrl_guard = real_tty.core().contorl_info_irqsave();
+
+        if let Some(ref sid) = tty_ctrl_guard.session {
+            // 如果当前进程是会话首进程,且tty的会话是当前进程的会话,则允许设置
+            if current.task_session() == Some(sid.clone()) {
+                // 这是正常情况:会话首进程要设置自己会话的tty为控制终端
+            } else {
+                // tty被其他会话占用,需要强制标志或CAP_SYS_ADMIN权限
+                // todo: 这里要补充对CAP_SYS_ADMIN的检查
+                if arg == 1 {
+                    Self::session_clear_tty(sid.clone());
+                } else {
+                    return Err(SystemError::EPERM);
+                }
+            }
+        }
+
+        drop(tty_ctrl_guard);
+
         Self::proc_set_tty(real_tty);
         Ok(0)
     }
@@ -119,25 +179,21 @@ impl TtyJobCtrlManager {
             return Err(SystemError::ENOTTY);
         }
 
+        let pgid = real_tty.core().contorl_info_irqsave().pgid.clone();
+        let pgrp = pgid.map(|p| p.pid_vnr()).unwrap_or(RawPid::new(0)).data();
+        // log::debug!("pid: {},tiocgpgrp: {}", current.raw_pid().data(), pgrp);
         let mut user_writer = UserBufferWriter::new(
             VirtAddr::new(arg).as_ptr::<i32>(),
             core::mem::size_of::<i32>(),
             true,
         )?;
 
-        user_writer.copy_one_to_user(
-            &(real_tty
-                .core()
-                .contorl_info_irqsave()
-                .pgid
-                .unwrap_or(Pid::new(1))
-                .data() as i32),
-            0,
-        )?;
+        user_writer.copy_one_to_user(&(pgrp as i32), 0)?;
 
         return Ok(0);
     }
 
+    /// Get session ID
     fn tiocgsid(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
         // log::debug!("job_ctrl_ioctl: TIOCGSID");
         let current = ProcessManager::current_pcb();
@@ -151,8 +207,10 @@ impl TtyJobCtrlManager {
         if guard.session.is_none() {
             return Err(SystemError::ENOTTY);
         }
-        let sid = guard.session.unwrap();
+        let session = guard.session.clone();
+        // 先释放guard,免得阻塞了
         drop(guard);
+        let sid = session.unwrap().pid_vnr();
 
         let mut user_writer = UserBufferWriter::new(
             VirtAddr::new(arg).as_ptr::<i32>(),
@@ -170,6 +228,7 @@ impl TtyJobCtrlManager {
             Ok(_) => {}
             Err(e) => {
                 if e == SystemError::EIO {
+                    log::debug!("sss-1");
                     return Err(SystemError::ENOTTY);
                 }
                 return Err(e);
@@ -182,32 +241,80 @@ impl TtyJobCtrlManager {
             true,
         )?;
 
-        let pgrp = user_reader.read_one_from_user::<i32>(0)?;
+        let pgrp_nr = *user_reader.read_one_from_user::<i32>(0)?;
 
         let current = ProcessManager::current_pcb();
 
         let mut ctrl = real_tty.core().contorl_info_irqsave();
 
-        if current.sig_info_irqsave().tty().is_none()
-            || !Arc::ptr_eq(
-                &current.sig_info_irqsave().tty().clone().unwrap(),
-                &real_tty,
-            )
-            || ctrl.session.is_none()
-            || ctrl.session.unwrap() != current.sid()
         {
-            return Err(SystemError::ENOTTY);
+            // if current.sig_info_irqsave().tty().is_none()
+            //     || !Arc::ptr_eq(
+            //         &current.sig_info_irqsave().tty().clone().unwrap(),
+            //         &real_tty,
+            //     )
+            //     || ctrl.session != current.task_session()
+            // {
+            //     log::debug!("sss-2");
+            //     return Err(SystemError::ENOTTY);
+            // }
+
+            // 拆分判断条件以便调试
+            let current_tty = current.sig_info_irqsave().tty();
+            let condition1 = current_tty.is_none();
+
+            let condition2 = if let Some(ref tty) = current_tty {
+                !Arc::ptr_eq(tty, &real_tty)
+            } else {
+                false // 如果 tty 为 None,这个条件就不用检查了
+            };
+
+            let condition3 = ctrl.session != current.task_session();
+
+            if condition1 || condition2 || condition3 {
+                if condition1 {
+                    log::debug!("sss-2: 失败原因 - 当前进程没有关联的 tty");
+                } else if condition2 {
+                    log::debug!("sss-2: 失败原因 - 当前进程的 tty 与目标 tty 不匹配");
+                } else if condition3 {
+                    log::debug!("sss-2: 失败原因 - 会话不匹配");
+                }
+                return Err(SystemError::ENOTTY);
+            }
         }
+        let pgrp =
+            ProcessManager::find_vpid(RawPid::new(pgrp_nr as usize)).ok_or(SystemError::ESRCH)?;
 
-        let pg = ProcessManager::find_process_group(Pgid::from(*pgrp as usize));
-        if pg.is_none() {
-            return Err(SystemError::ESRCH);
-        } else if !Arc::ptr_eq(&pg.unwrap().session().unwrap(), &current.session().unwrap()) {
+        if Self::session_of_pgrp(&pgrp) != current.task_session() {
             return Err(SystemError::EPERM);
         }
 
-        ctrl.pgid = Some(Pid::from(*pgrp as usize));
+        ctrl.pgid = Some(pgrp);
 
         return Ok(0);
     }
+
+    fn session_of_pgrp(pgrp: &Arc<Pid>) -> Option<Arc<Pid>> {
+        let mut p = pgrp.pid_task(PidType::PGID);
+        if p.is_none() {
+            // this should not be None
+            p = pgrp.pid_task(PidType::PID);
+        }
+        let p = p.unwrap();
+
+        let sid = p.task_session();
+
+        return sid;
+    }
+
+    pub(super) fn session_clear_tty(sid: Arc<Pid>) {
+        // 清除会话的tty
+        for task in sid.tasks_iter(PidType::SID) {
+            TtyJobCtrlManager::proc_clear_tty(&task);
+        }
+    }
+
+    pub fn get_current_tty() -> Option<Arc<TtyCore>> {
+        ProcessManager::current_pcb().sig_info_irqsave().tty()
+    }
 }

+ 10 - 3
kernel/src/driver/tty/tty_ldisc/ntty.rs

@@ -787,9 +787,10 @@ impl NTtyData {
     ) {
         // 先处理信号
         let ctrl_info = tty.core().contorl_info_irqsave();
-        let pg = ctrl_info.pgid;
+        let pg = ctrl_info.pgid.clone();
+        drop(ctrl_info);
         if let Some(pg) = pg {
-            let _ = crate::ipc::kill::kill_process_group(pg, signal);
+            let _ = crate::ipc::kill::kill_process_group(&pg, signal);
         }
 
         if !termios.local_mode.contains(LocalMode::NOFLSH) {
@@ -1018,7 +1019,13 @@ impl NTtyData {
         };
 
         // 找到eol的坐标
-        let tmp = self.read_flags.next_index(tail);
+        // 注意:next_index可能不包括起始位置,所以我们需要手动检查tail位置
+
+        let tmp: Option<usize> = if self.read_flags.get(tail).unwrap_or(false) {
+            Some(tail)
+        } else {
+            self.read_flags.next_index(tail)
+        };
         // 找到的话即为坐标,未找到的话即为NTTY_BUFSIZE
         let mut eol = if let Some(tmp) = tmp { tmp } else { size };
         if eol > size {

+ 4 - 0
kernel/src/driver/tty/tty_port.rs

@@ -90,6 +90,10 @@ pub trait TtyPort: Sync + Send + Debug {
         EventPoll::wakeup_epoll(tty.core().eptiems(), pollflag)?;
         ret
     }
+
+    fn internal_tty(&self) -> Option<Arc<TtyCore>> {
+        self.port_data().internal_tty()
+    }
 }
 
 #[derive(Debug)]

+ 2 - 2
kernel/src/driver/tty/virtual_terminal/virtual_console.rs

@@ -13,7 +13,7 @@ use crate::{
         tty::{console::ConsoleSwitch, ConsoleFont, KDMode},
     },
     libs::{font::FontDesc, rwlock::RwLock},
-    process::Pid,
+    process::RawPid,
 };
 
 use super::{
@@ -91,7 +91,7 @@ pub struct VirtualConsoleData {
 
     pub cursor_blink_ms: u16,
 
-    pub pid: Option<Pid>,
+    pub pid: Option<RawPid>,
     pub index: usize,
 
     pub vc_state: VirtualConsoleState,

+ 4 - 2
kernel/src/driver/virtio/virtio.rs

@@ -36,8 +36,9 @@ fn virtio_probe() -> Result<(), SystemError> {
 fn virtio_probe_pci() {
     let virtio_list = virtio_device_search();
     for virtio_device in virtio_list {
-        let dev_id = virtio_device.common_header.device_id;
-        let dev_id = DeviceId::new(None, Some(format!("{dev_id}"))).unwrap();
+        let bdf: String = virtio_device.common_header.bus_device_function.into();
+        let dev_id = DeviceId::new(None, Some(bdf)).unwrap();
+        // log::info!("virtio device id: probe {:?}", dev_id.id());
         match PciTransport::new::<HalImpl>(virtio_device.clone(), dev_id.clone()) {
             Ok(mut transport) => {
                 debug!(
@@ -100,6 +101,7 @@ fn virtio_device_search() -> Vec<Arc<PciDeviceStructureGeneralDevice>> {
     for device in result {
         let standard_device = device.as_standard_device().unwrap();
         let header = &standard_device.common_header;
+        // log::info!("header: {:?}", header);
         if header.device_id >= 0x1000 && header.device_id <= 0x103F {
             virtio_list.push(standard_device);
         }

+ 124 - 23
kernel/src/filesystem/devfs/mod.rs

@@ -3,18 +3,16 @@ pub mod null_dev;
 pub mod zero_dev;
 
 use super::vfs::{
-    file::FileMode,
-    syscall::ModeType,
-    utils::DName,
-    vcore::{generate_inode_id, ROOT_INODE},
-    FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Magic, Metadata, SuperBlock,
+    file::FileMode, syscall::ModeType, utils::DName, vcore::generate_inode_id, FilePrivateData,
+    FileSystem, FileType, FsInfo, IndexNode, Magic, Metadata, SuperBlock,
 };
 use crate::{
-    driver::base::device::device_number::DeviceNumber,
+    driver::base::{block::gendisk::GenDisk, device::device_number::DeviceNumber},
     libs::{
         once::Once,
         spinlock::{SpinLock, SpinLockGuard},
     },
+    process::ProcessManager,
     time::PosixTimeSpec,
 };
 use alloc::{
@@ -143,7 +141,7 @@ impl DevFS {
                     .unwrap();
 
                 // 特殊处理 tty 设备,挂载在 /dev 下
-                if name.starts_with("tty") && name.len() > 3 {
+                if name.starts_with("tty") && name.len() >= 3 {
                     dev_root_inode.add_dev(name, device.clone())?;
                 } else if name.starts_with("hvc") && name.len() > 3 {
                     // 特殊处理 hvc 设备,挂载在 /dev 下
@@ -174,7 +172,23 @@ impl DevFS {
                     .downcast_ref::<LockedDevFSInode>()
                     .unwrap();
 
-                dev_block_inode.add_dev(name, device.clone())?;
+                if name.starts_with("vd") && name.len() > 2 {
+                    // 虚拟磁盘设备挂载在 /dev 下
+                    dev_root_inode.add_dev(name, device.clone())?;
+                    let path = format!("/dev/{}", name);
+                    let symlink_name = device
+                        .as_any_ref()
+                        .downcast_ref::<GenDisk>()
+                        .unwrap()
+                        .symlink_name();
+
+                    dev_block_inode.add_dev_symlink(&path, &symlink_name)?;
+                } else if name.starts_with("nvme") {
+                    // NVMe设备挂载在 /dev 下
+                    dev_root_inode.add_dev(name, device.clone())?;
+                } else {
+                    dev_block_inode.add_dev(name, device.clone())?;
+                }
                 device.set_fs(dev_block_inode.0.lock().fs.clone());
             }
             FileType::KvmDevice => {
@@ -258,6 +272,8 @@ pub struct DevFSInode {
     metadata: Metadata,
     /// 目录名
     dname: DName,
+    /// 当前inode的数据部分(仅供symlink使用)
+    data: Vec<u8>,
 }
 
 impl DevFSInode {
@@ -294,6 +310,7 @@ impl DevFSInode {
             },
             fs: Weak::default(),
             dname: DName::default(),
+            data: Vec::new(),
         };
     }
 }
@@ -333,6 +350,28 @@ impl LockedDevFSInode {
         return Ok(());
     }
 
+    /// # 在devfs中添加一个符号链接
+    ///
+    /// ## 参数
+    /// - `path`: 符号链接指向的路径
+    /// - `symlink_name`: 符号链接的名称
+    pub fn add_dev_symlink(&self, path: &str, symlink_name: &str) -> Result<(), SystemError> {
+        let new_inode = self.create_with_data(
+            symlink_name,
+            FileType::SymLink,
+            ModeType::from_bits_truncate(0o777),
+            0,
+        )?;
+
+        let buf = path.as_bytes();
+        let len = buf.len();
+        new_inode
+            .downcast_ref::<LockedDevFSInode>()
+            .unwrap()
+            .write_at(0, len, buf, SpinLock::new(FilePrivateData::Unused).lock())?;
+        Ok(())
+    }
+
     pub fn remove(&self, name: &str) -> Result<(), SystemError> {
         let x = self
             .0
@@ -351,7 +390,7 @@ impl LockedDevFSInode {
         name: &str,
         file_type: FileType,
         mode: ModeType,
-        data: usize,
+        dev: usize,
     ) -> Result<Arc<dyn IndexNode>, SystemError> {
         if guard.metadata.file_type != FileType::Dir {
             return Err(SystemError::ENOTDIR);
@@ -382,10 +421,11 @@ impl LockedDevFSInode {
                 nlinks: 1,
                 uid: 0,
                 gid: 0,
-                raw_dev: DeviceNumber::from(data as u32),
+                raw_dev: DeviceNumber::from(dev as u32),
             },
             fs: guard.fs.clone(),
             dname: name.clone(),
+            data: Vec::new(),
         })));
 
         // 初始化inode的自引用的weak指针
@@ -541,27 +581,84 @@ impl IndexNode for LockedDevFSInode {
         return Ok(());
     }
 
-    /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写
+    /// 读设备 - 应该调用设备的函数读写,而不是通过文件系统读写,仅支持符号链接的读取
     fn read_at(
         &self,
-        _offset: usize,
-        _len: usize,
-        _buf: &mut [u8],
+        offset: usize,
+        len: usize,
+        buf: &mut [u8],
         _data: SpinLockGuard<FilePrivateData>,
     ) -> Result<usize, SystemError> {
-        error!("DevFS: read_at is not supported!");
-        Err(SystemError::ENOSYS)
+        let meta = self.metadata()?;
+        match meta.file_type {
+            FileType::SymLink => {
+                if buf.len() < len {
+                    return Err(SystemError::EINVAL);
+                }
+                // 加锁
+                let inode = self.0.lock();
+
+                // 检查当前inode是否为一个文件夹,如果是的话,就返回错误
+                if inode.metadata.file_type == FileType::Dir {
+                    return Err(SystemError::EISDIR);
+                }
+
+                let start = inode.data.len().min(offset);
+                let end = inode.data.len().min(offset + len);
+
+                // buffer空间不足
+                if buf.len() < (end - start) {
+                    return Err(SystemError::ENOBUFS);
+                }
+
+                // 拷贝数据
+                let src = &inode.data[start..end];
+                buf[0..src.len()].copy_from_slice(src);
+                return Ok(src.len());
+            }
+            _ => {
+                error!("DevFS: read_at is not supported!");
+                Err(SystemError::ENOSYS)
+            }
+        }
     }
 
-    /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写
+    /// 写设备 - 应该调用设备的函数读写,而不是通过文件系统读写,仅支持符号链接的写入
     fn write_at(
         &self,
-        _offset: usize,
-        _len: usize,
-        _buf: &[u8],
+        offset: usize,
+        len: usize,
+        buf: &[u8],
         _data: SpinLockGuard<FilePrivateData>,
     ) -> Result<usize, SystemError> {
-        Err(SystemError::ENOSYS)
+        let meta = self.metadata()?;
+        match meta.file_type {
+            FileType::SymLink => {
+                if buf.len() < len {
+                    return Err(SystemError::EINVAL);
+                }
+                let mut inode = self.0.lock();
+
+                if inode.metadata.file_type == FileType::Dir {
+                    return Err(SystemError::EISDIR);
+                }
+
+                let data: &mut Vec<u8> = &mut inode.data;
+
+                // 如果文件大小比原来的大,那就resize这个数组
+                if offset + len > data.len() {
+                    data.resize(offset + len, 0);
+                }
+
+                let target = &mut data[offset..offset + len];
+                target.copy_from_slice(&buf[0..len]);
+                return Ok(len);
+            }
+            _ => {
+                error!("DevFS: read_at is not supported!");
+                Err(SystemError::ENOSYS)
+            }
+        }
     }
 
     fn parent(&self) -> Result<Arc<dyn IndexNode>, SystemError> {
@@ -586,7 +683,10 @@ pub trait DeviceINode: IndexNode {
 /// @brief 获取devfs实例的强类型不可变引用
 macro_rules! devfs_exact_ref {
     () => {{
-        let devfs_inode: Result<Arc<dyn IndexNode>, SystemError> = ROOT_INODE().find("dev");
+        let devfs_inode: Result<Arc<dyn IndexNode>, SystemError> =
+            crate::process::ProcessManager::current_mntns()
+                .root_inode()
+                .find("dev");
         if let Err(e) = devfs_inode {
             error!("failed to get DevFS ref. errcode = {:?}", e);
             return Err(SystemError::ENOENT);
@@ -623,7 +723,8 @@ pub fn devfs_init() -> Result<(), SystemError> {
         // 创建 devfs 实例
         let devfs: Arc<DevFS> = DevFS::new();
         // devfs 挂载
-        ROOT_INODE()
+        let root_inode = ProcessManager::current_mntns().root_inode();
+        root_inode
             .mkdir("dev", ModeType::from_bits_truncate(0o755))
             .expect("Unabled to find /dev")
             .mount(devfs)

Some files were not shown because too many files changed in this diff