4187 Commits
Author SHA1 Message Date
Suyash Mahar 53f74f09dc Fix -vm_allow_smaller dividing the size pointer (#8186)
`vmm_place_vmcode()` computed the shrink step as `size / 16` where size
is a `size_t` pointer, so the step was derived from a stack address and
the "don't go too small" check always broke out of the loop. A failed
vmcode reservation therefore never retried with a smaller size. Use
`*size` instead.
2026-10-09 12:45:55 -07:00
Bin Wang 8a73e0c690 i#8159: Probe rseq length 64 and align test struct (#8185)
This PR fixes two bugs identified in #8159:

- The `api.rseq` test register an rseq with `sizeof(*tls_rseq)` which is
64, but the address is only 32-aligned. The fix is to add
`__attribute__((aligned(64)))` to the declaration.
- After adding `__attribute__((aligned(64)))`, our `try_struct_rseq()`
still cannot find it. This is because the linux kernel requires
`rseq_len` to match the registered length (64), and we were not testing
64 in `try_struct_rseq()`.

Also added a print on registration failure in
`api.rseq/api.rseq_splitvma` to help with debugging in the future.

Tested on my local workstation with kernel 7.1.6 and glibc 2.43
- Before: `api.rseq` fails at assertion `res == 0 || (res == -1 && errno
== ENOSYS)`.
- Now: `api.rseq` fails at assertion `restarts > 0`, like the other
tests in #8159.

Issue: #8159
2026-10-09 09:14:06 -07:00
Bin Wang 650b415b84 I#8174: Search rseq in neighboring VMAs (#8177)
When DynamoRIO attaches to a running application, it must locate the
application’s previously registered `struct rseq` in static TLS. Naming
TLS pages or changing their memory attributes can split the allocation
into multiple VMAs. Searching only the VMA containing the thread pointer
can therefore miss valid registrations. This PR extends attach-time
discovery to neighboring mappings to handle split TLS allocations.

- Search adjacent read-write mappings, stopping at gaps or non-writable
mappings. Limit extensions to 1 MB from the thread pointer while
preserving the full search of its containing mapping.
- Search outward from the thread pointer on both sides together so both
static TLS and struct pthread are checked before reaching the stack.
- Fix an off-by-one in `try_struct_rseq()` so re-registration uses the
matched registration size.
- Add a new test `api.rseq_splitvma` which places the registered `struct
rseq` in a separate VMA using `PR_SET_VMA_ANON_NAME` (with a
`MADV_DONTFORK` fallback), reproducing the original attach failure
without this fix and passing with it.

Fixes #8174
2026-10-08 11:53:05 -07:00
Bin Wang 9fe0764ea3 i#8021 kernel: Generate obj list for the kernel module by reusing CORE_SRCS/ARCH_SRCS (#8172)
This PR is a follow up on #8169. Instead of hardcoding the kernel module
object file list, we are reusing existing `CORE_SRCS` and `ARCH_SRCS` to
generate the object file list. Overall, the current process is easier to
maintain and less error prone. It's also easier to replicate in a
different build system. The trade-offs are there are some files we don't
actually need getting pulled in, so the build time is slightly longer
(<10s longer) and the built `.ko` file is slightly larger (~130KB larger
with DEBUG ON, ~20KB larger with DEBUG OFF).

- Use existing `CORE_SRCS` and `ARCH_SRCS` defined in
`core/CMakeLists.txt` for kernel module object file list generation.
- Prevent `emit_utils.c` from being included in `ARCH_SRCS` twice when
`ARCH_NAME` and `ARCH_NAME_SHARED` are the same in
`core/CMakeLists.txt`. This isn't a bug per se: both CMake and kbuild
can handle duplicate files. I just thought this would be cleaner and
less confusing.
- Disable annotations (by `undef ANNOTATIONS`) in `configure.cmake.h`.
- Use `limits_wrapper.h` in `core/hotpatch.c`.
- Remove redundant `lib/dr_annotations.h` in `core/jit_opt.c`.

Issue: #8021
2026-10-07 14:21:33 -07:00
Bin Wang a522a50558 i#8021 kernel: Move module build rules into a shared Kbuild (#8169)
In our internal system we need to support a different build system where
CMake is not available. This PR moves several module build rules from
CMake into a checked-in Kbuild so different build systems can share the
same implementation by supplying a prepared source tree, generated
headers, and an object list.

- Replace `Kbuild.in` with a checked-in `Kbuild`. CMake generates
`dr_objs` in a separate `Kbuild.sources` file.
- Make Kbuild paths relative to the module build tree. CMake prepares
this tree using symlinks to sources and generated headers.
- Move shared include paths, defines, and C/assembly flags from CMake
into Kbuild.
- Move `x86.asm` → `x86.S` preprocessing and placeholder replacement
into Kbuild.
- Move development stub generation into Kbuild. Generate weak stubs with
function declarations from the component objects before linking,
allowing the module to build in one Kbuild invocation.
- Select assembly flags for GNU `as` or LLVM’s integrated assembler.
- Keep the existing kernel source list and add a TODO to generate the
object list from the shared core source lists.

Issue: #8021
Fixes #8112
2026-10-06 11:03:53 -07:00
Suyash Mahar 172ac29731 i#8117: Validate shared ELF mappings during module scan (#8122)
During the initial address-space scan, DynamoRIO can mistake a read-only
MAP_SHARED view of an ELF file (for example, `r--s`) for a loaded
module. It then projects the ELF’s PT_LOAD segments into its internal
module map even when those segments are not actually mapped there.

This PR:

- Validates shared ELF candidates by requiring their executable PT_LOAD
segments to be mapped at the expected addresses and file offsets from
the same file.
- Adds regression coverage for one-page and full-span flat views, plus a
valid shared PT_LOAD layout.

The validation is limited to MAP_SHARED mappings as standard ELF loaders
typically map PT_LOAD segments with MAP_PRIVATE, so normal loaded
modules do not take this path.

Fixes #8117
2026-10-05 11:30:33 -07:00
Jack Gallagher 2bc48cd10f i#7585 AArch64 selfmod: Fix TestAllocWE regression (#8157)
After recently enabling -hw_cache_consistency on AArch64 the test
security-common.TestAllocWE started failing on Linux >= 5.13 when run on
recent AArch64 hardware.

Issue: #7585
2026-10-01 07:26:32 +01:00
Bin Wang 2b5cc022cc i#4103 clang-tidy: Fixes misc-include-cleaner warnings (#8156)
Fixes misc-include-cleaner warnings seen when importing recent changes
into our environment:
- `core/unix/signal_linux_x86.c`: Includes `proc.h` for `XCR0_*
andarch_exports.h` for `ZMM_ENABLED()`.
- `core/lib/instrument.c`: Includes `dr_project_wide_defines.h` for
`BUFFER_SIZE_ELEMENTS` and `NULL_TERMINATE_BUFFER`.
- `core/lib/instrument.c`: Calls `d_r_snprintf()` and `d_r_strstr()`
directly in `report_client_lib_load_error()`. include-cleaner maps any
macro named like a C standard library function to the libc header, so
the `snprintf` and `strstr` macros in `globals.h` are reported as
needing `<stdio.h>` and `<string.h>`. Using the underlying names
resolves them to their declarations in `globals.h`.
- `suite/tests/linux/sigcontext.c`: Includes `dr_project_wide_defines.h`
for `TESTANY`.

clang-tidy with misc-include-cleaner no longer reports these warnings on
the changed lines.

Issue: #4103
2026-09-30 11:07:15 -07:00
Bin Wang 92c0123464 i#8021 kernel: Flx clang errors when building the kernel module (#8154)
Building the kernel module with clang fails with `-Werror`. This PR
fixes two errors while keeping the gcc builds working.

- `kernel_interface.h`: clang does not support the `gnu_printf` format
archetype (`-Wignored-attributes`). Use `__printf__` instead, which is
portable across both gcc and clang.
- `instrument.c`: clang inlines `add_client_lib()` into
`instrument_load_client_libs()`. That combines the 2 KiB option buffer
with the 3 KiB error-message buffers from the load-failure path and
exceeds the module's `-Wframe-larger-than=4096`:

  ```      
error: stack frame size (5176) exceeds limit (4096) in
'instrument_load_client_libs' [-Werror,-Wframe-larger-than]
  ```

Move the load-failure reporting into a NOINLINE helper
(`report_client_lib_load_error()`) so those buffers are on the stack
only when a client library fails to load. No functional change.

Issue: #8021
2026-09-29 22:16:50 -07:00
Bin Wang d3f40b0ff7 i#8021 kernel: Advance kernel module initialization through loader setup (#8145)
Follow up on #8123. This PR adds CPU-local DR state and the kernel OS
hooks needed to advance the module initialization through OS,
configuration heap, initial-stack, and loader setup code. Initialization
now stops before `d_r_arch_init()`.

- Add a fixed 1 KiB per-CPU buffer, with allocation and lifetime managed
by the Linux module loader.
- Validate storage capacity and alignment during `d_r_os_init()`.
- Implement local-state and dcontext accessors.
- Add a no-op `os_loader_init_prologue()`. Linux has already loaded and
relocated the module; kernel client loading remains future work.

Issue: #8021
2026-09-28 18:36:09 -07:00
ZheWang 953202802a i#3544: Save vector registers with LMUL=1 for any VLEN <= 256 (#8074)
The vector register save/restore paths (append_save_simd_reg,
append_restore_simd_reg, insert_push_all_registers, and
insert_pop_all_registers) copied eight registers at a time with LMUL=8.
An LMUL=8 group store packs the eight registers contiguously, so
register N's bytes land at &simd[N] only when VLEN is exactly 256 bits
and fills a whole dr_simd_t slot. On any other VLEN the mcontext layout
contract VREG_OFFSET(reg) == &simd[reg - VR0] is broken.

Copy one register at a time with LMUL=1 instead, so each register's
vlenb bytes always land in the low bytes of its own dr_simd_t slot for
any supported VLEN <= 256 bits.

Issue: #3544
2026-09-28 11:38:28 -07:00
Bin Wang 60b05e5195 i#7996: Preserve the signal frame’s XSAVE state bitmap (#8150)
On x86 Linux with recent Intel CPUs (e.g., Xeon 8573C and 6973P-C),
`XCR0` can contain state components, such as AMX tile data, that are
absent from a particular signal frame. Copying all `XCR0` bits into that
frame's `XSAVE` bitmap can cause `sigreturn` to fail. This PR preserves
the frame's bitmap while marking the register state DynamoRIO actually
writes.

Fixes #7996
2026-09-28 11:09:26 -07:00
Jack Gallagher 3cf4f96537 i#7585 AArch64 selfmod: Fix state corruption bug (#8128)
This commit fixes two related state corruption bugs.

When hw_cache_consistency is enabled DynamoRIO sets writable/executable
pages to read-only in order to detect any writes to code regions. If
these writes occurred whilst app state was spilled, the signal handler
failed to restore app state before returning to d_r_dispatch, which
caused app state corruption.

Similarly, if this fault happened on an instruction that uses the stolen
register, we would enter the signal handler with the stolen register
restored to its app state. The signal handler assumed it contained the
tls pointer and left things in a corrupt state.

Discovered while testing simple Java commands with hw_cache_consistency
enabled on AArch64:
    drrun -- javac HelloWorld.java

With this bug fixed I am not aware of any other issues with
hw_cache_consistency on AArch64 so this commit also turns
hw_cache_consistency on by deafult on AArch64.

Issue: #7585
Fixes #2055, #5771
2026-09-25 10:16:10 +01:00
Derek Bruening d1094c126e i#8138: Silence privload, VDSO, and vmareas messages (#8139)
Silences a spurious curiosity about the recursion depth of private
module loading by adding a missing decrement: it was really reaching
only depth 3 for 21 modules, but complained about reaching depth 20.

Silences a spurious curiosity that a module is the VDSO by adding a
check for soname staring with "linux-gate.so".

Silences a vmareas assert on a size 0 mmap by adding an early exit.

Issue: #8138, #6152
Fixes #8138
2026-09-24 19:06:52 -04:00
Derek Bruening 63ec6a7f9a i#8125 a64 opt: Invert redzone check (#8135)
Inverts the drmemtrace trace buffer redzone check. Instead of re-setting
the buffer to 0 every time and the redzone to -1 and identifying when to
output by reading a non-0 value, we set the redzone to hold a sentinel
record value: the value 1, which would be a load/store of the address 1,
which seems pretty unlikely (we do see 0 in prefetches). If it does
happen, we'll just output early; the output code is updated here to
clobber the 1 so the same record won't trigger again.

For online, with 12-byte records, we set the 1st pointer-sized bytes to
the sentinel 1 and the final 4 to 0. This is a write to 0, which should
also be rare.

For 32-bit, we have to keep the memset, as loads and stores assume the
top word is already zeroed, but 32-bit is not a performance priority.

Changing the clean call skip is pretty simple on arm; on x86 it adds a
redirection jump. The filter mode change checks that leverage the
redzone check are more complicated and we change those to branches that
skip over the other skips.

On SPECCPU2017 INT this provides a 2% performance improvement, but it
enables larger buffer sizes without paying a memset cost. A future
update will make the main thread's buffer 8x larger, which is a 14%
no-i/o improvement and half that with LZ4 output.

Issue: #8125
2026-09-24 19:06:21 -04:00
Bin Wang 0293afa454 i#8021 kernel: Advance kernel module initialization through modules_init() (#8123)
Previously in #8096, we implemented
`dynamorio_app_init_part_one_options()` in `dynamorio_app_init()` to
parse and initialize DynamoRIO runtime options when loading the kernel
module.

This PR advances kernel module initialization into part two of
`dynamorio_app_init()` through `modules_init()` (including VMM/heap, VM
areas, decoder, processor, and module initialization). The rest of part
two is left for follow-up PRs to keep this one relatively small and
reviewable.

- Call `dynamorio_app_init()` from `dynamorio_module_init()`, and add a
temporary kernel-only early return after `modules_init()` in
`dynamorio_app_init_part_two_finalize()`.
- Resolve kernel `_text` and `_end` symbols to implement
`get_application_base()` and `get_application_end()`.
- Change default heap size to 256MB and allocate heap as RWX
(`PAGE_KERNEL_EXEC`). Implement `os_heap_reserve_in_region()`,
`os_heap_commit()`, `os_heap_decommit()`, and
`os_heap_get_commit_limit()`.
- Update `os_check_option_compatibility()` to configure VMM placement
for the pre-allocated module heap (`reachable_heap`, `vm_base_near_app`,
`vmm_block_size`, and clamping `vm_size`) and disable reset options via
`DISABLE_RESET()`.
- Switch `LINUX_KERNEL` from `HAVE_MEMINFO_MAPS` to
`HAVE_MEMINFO_QUERY`, implement `is_readable_without_exception*()` using
`copy_from_{user,kernel}_nofault()`, and stub out `all_memory_areas`
helpers.
- Implement `os_modules_init()`/`exit()`, `report_diagnostics()`, and
`diagnost_exit()` as no-ops in kernel mode.

Issue: #8021
2026-09-24 14:43:45 -07:00
Derek Bruening c71f56643d i#8136: Ignore rseq committing store side effects (#8137)
On the first execution, we need to nop out a store's memory operations
but not its register side effects if it's mid-sequence: but not if it's
the final instruction (committing store). We relax the existing fatal
error on a store with multiple destinations if it's the final
instruction.

Adds a test case that fails without the fix.

Also tested on our internal application where this was first hit.

Fixes #8136
2026-09-24 16:45:24 -04:00
Bin Wang d53efb2f19 i#8131: Return CPU id plus one for kernel thread id helpers (#8132)
Kernel thread ID helpers return CPU numbers, which can be zero and
collide with `INVALID_THREAD_ID`. In debug builds, when module
initialization happens on CPU 0, DR will mistake an unowned mutex (whose
`owner` equals `INVALID_THREAD_ID`) for a mutex owned by the current
CPU, causing heap initialization to fail.

- Change `d_r_get_thread_id()` to return CPU ID plus one, and have
`get_sys_thread_id()` use the same helper.
- Add XXX comments about alternative approaches.
- Link issue #8131 to the existing XXX comments above
`INVALID_THREAD_ID`.

Fixes #8131
2026-09-21 18:36:37 -07:00
Derek Bruening a51df51418 i#8125 a64 opt: Optimize memcpy and memset-non-zero (#8130)
Adds simple 16-byte-aligned loop optimizations to our memcpy and
memset-to-non-zero asm routines.
Our versions are still 50% slower than libc, but they are 10x faster
than before and shouldn't be bottlenecks anymore.

Before:
```
our_memcpy_time: size=1 time=0
libc_memcpy_time: size=1 time=0
our_memcpy_time: size=4 time=0
libc_memcpy_time: size=4 time=1
our_memcpy_time: size=128 time=4
libc_memcpy_time: size=128 time=0
our_memcpy_time: size=512 time=17
libc_memcpy_time: size=512 time=1
our_memcpy_time: size=8192 time=261
libc_memcpy_time: size=8192 time=12
our_memcpy_time: size=20480 time=650
libc_memcpy_time: size=20480 time=31

our_memset_time: 635
libc_memset_time: 30
```

After:
```
our_memcpy_time: size=1 time=0
libc_memcpy_time: size=1 time=0
our_memcpy_time: size=4 time=0
libc_memcpy_time: size=4 time=1
our_memcpy_time: size=128 time=0
libc_memcpy_time: size=128 time=0
our_memcpy_time: size=512 time=2
libc_memcpy_time: size=512 time=1
our_memcpy_time: size=8192 time=17
libc_memcpy_time: size=8192 time=13
our_memcpy_time: size=20480 time=42
libc_memcpy_time: size=20480 time=31

our_memset_time: 58
libc_memset_time: 31
```

We already have tests of memcpy in core_unit_tests from io.c.

Issue: #8125
2026-09-21 13:39:56 -04:00
Derek Bruening dcd8185559 i#8125 a64 opt: Optimize memset with DV ZVA (#8127)
Adds a fastpath to the AArch64 memset using DC ZVA when setting to 0.
This speeds up drmemtrace by 2.3x on SPECCPU (see
https://github.com/DynamoRIO/dynamorio/issues/8125#issuecomment-5722352941),
as drmemtrace zeroes out its trace buffer for its redzone scheme. This
was a major cause of why AArch64 drmemtrace was so much slower than x86
drmemtrace.

Adds memset unit tests.

The core_unit_tests memset times compared to libc with the -1 removed
(so just 0) went from:
```
our_memset_time: 751
libc_memset_time: 12
```
To:
```
our_memset_time: 18
libc_memset_time: 11
```

Adding back the -1 it went from:
```
our_memset_time: 1458
libc_memset_time: 31
```
to:
```
our_memset_time: 635
libc_memset_time: 30
```

Further tested by successfully running SPECCPU (results at
https://github.com/DynamoRIO/dynamorio/issues/8125#issuecomment-5722352941).

Issue: #8125
2026-09-21 12:45:55 -04:00
Derek Bruening d9cf598ee3 i#4913 elide++: Add elision support for GPR add, sub, indexing (#8120)
Extends the drmemtrace offline trace elision optimizations to support
any general-purpose base register being modified by an add, a subtract,
an x86 LEA, or an arm pre-indexed or post-indexed addressing mode.

This was measured to speed up x86 SPECCPU2017 INT by 2.3%: so a modest
speedup on top of stack push/pop elision which is already in place.

Adds test cases to burst_traceopts.

Adds test cases to raw2trace_unit_tests, which required adding
convenience macros for INSTR_CREATE_{ld,st}{r,p}_imm_{pre,post}index().

AArch64 still does not elide stack pointer bases: that is under #4898
and will be resolved separately, but it needs this pre-and-post-indexed
tracking in order to work.

Issue: #4913
2026-09-18 16:10:34 -04:00
Jack Gallagher 21252f3512 i#7585 AArch64 selfmod: Implement sandboxing (#8103)
Implement an AArch64 version of insert_selfmod_sandbox() modelled after
the x86 version.

The existing AArch64 self-modifying code support works by mangling ic
cache maintenance instructions to flush code cache fragments containing
invalidated addresses. This works fine for code which uses ic
instructions but there are two cases where cache maintenance
instructions are not required which this does not address:
- Hardware with coherent icaches where software is not required to
perform explicit cache maintenance.
 - Concurrent Modification and Execution of Instructions (CMODX).

Sandboxing adds support for these cases by adding a check for
modifications at the beginning for fragments corresponding to writable
memory.

The new behaviour is currently off by default on AArch64 but can be
enabled with the -hw_cache_consistency option. From my testing I believe
that the new mangling code is correct but I have seem some app data
corruption crashes stemming from the signal handling code where an app
writes to a page that DR has made read-only to detect writes. I am
intending for fix this issue in a separate PR. Once this is fixed and
further testing shows no more bugs -hw_cache_consistency will become the
new default behaviour on AArch64.

AI tools were used to prototype and debug parts of this commit but all
generated code has been reviewed and revised by me. The documentation
changes are handwritten.

Issues: #2055, #5771, #7585
2026-09-16 08:43:09 +01:00
Bin Wang 76c5170fcd i#8021: Add DR options parsing in the kernel module init (#8096)
- Add an `options` module parameter to accept DynamoRIO options on
`insmod` and initialize them via `dynamorio_app_init_part_one_options()`
during module init.
- Added functions in `core/kernel_linux/os.c` that
`dynamorio_app_init_part_one_options()` depends on. They are exercised
by the init path and tested in the insmod CI.
- Implement `kernel_setenv()` for saving the options value. 
- Implement `os_check_option_compatibility()` to enforce kernel-mode
options constraints.
- Update the kernel module insmod workflow to build with both
`-DDEBUG=ON` and `OFF`, and verify that runtime options (`-loglevel 2`)
are parsed and logged correctly in the debug build.

On configuration lookup: the shared init path still performs it, but
`os_open()` is intentionally not implemented in kernel mode and returns
`INVALID_FILE` unconditionally. So no config file can be found and
options can only be set using the module parameter.

The kernel-mode options constraints implemented in
`os_check_option_compatibility()` are mostly copied from drk and may
need future adjustments. For example, #8116 tracks CPU-private fragment
restrictions (`shared_bbs`, `shared_traces`, `coarse_units`).

This initial implementation only supports setting options at module load
time. Dynamic updates and per-process options are tracked by #8115.

Issue: #8021
2026-09-14 13:45:54 -07:00
Suyash Mahar aa12773ddb i#8087: Fix visibility of safe-read assembly labels (#8107)
The safe-read labels are hidden in assembly but not in their C
declarations. On ARM, this creates GOT-based address references that can
become stale when BOLT moves `safe_read_asm()`, preventing fault
recovery.

Mark the declarations hidden to generate direct references to ensure no
GOT entries are created for them. Tested on a large internal application
that uses BOLT.

Fixes #8087
2026-09-14 13:05:14 -07:00
Derek Bruening a19f42101c i#4914 repstr bounds: Add 8-byte repstr creation macros (#8106)
Adds the missing 8-byte versions INSTR_CREATE macros for MOVS, CMPS,
SCAS and their repeating counterparts, along with the 8-byte repeating
versions of STOS and LODS. Simplifies the memory sizes used in the
macros to avoid confusion by removing rex8.

Adds test case to api.ir_x86.

These are wanted to build tests for the drmemtrace repstr bound
optimizations.

Issue: #4914
2026-09-10 15:37:33 -04:00
Abhinav Anil Sharma 9209788cb9 i#8100: Try rseq_len value range in glibc struct rseq search (#8101)
Fixes glibc struct rseq detection heuristic, which is broken after
recent kernel changes that increased the size of the struct
(https://lwn.net/Articles/885818). This affects DR mid-run attach uses
where DR did not have a chance to observe glibc's original rseq syscall
that registered its struct.

The struct rseq was 32 bytes with padding before, which was supposed to
be passed as rseq_len to the rseq syscall. Now rseq_len may be
getauxval(AT_RSEQ_FEATURE_SIZE), so we need to try multiple sizes. As we
do not want to depend on the getauxval library call in DR code, we
hardcode the value actually seen in a more recent environment where the
prior try_struct_rseq failed.

See https://lwn.net/Articles/1033957/ for more details.

Fixes: #8100
2026-09-08 18:30:48 -04:00
Bin Wang 8aaa876bd3 i#8097: Rebuild kernel module when headers change (#8099)
Replace the output-based custom command with an always-run target, so
kbuild checks source and header dependencies on every build.
Prebviously, header-only edits will not trigger a rebuild, which leaves
a stale .ko file.

Note that this doesn't mean every `cmake --target dynamorio_module`
rebuilds everything from scratch: kbuild itself still tracks
dependencies and re-compiles only affected ordinary objects. In other
words, the changes in this PR simply delegate dependencies tracking to
Kbuild.

Fixes #8097
2026-09-08 11:39:28 -07:00
Bin Wang a55426cdb6 I#8021: Set up integration test for DynamoRIO kernel module (#8090)
- Set up a new GitHub workflow that (1) builds the kernel module against
the kernel inside the runner, and (2) loads/unloads the kernel module
and checks whether the expected logs are printed in `dmesg`

- Disable objtool validation with `OBJECT_FILES_NON_STANDARD := y` when
building the kernel module.
Our x86.asm doesn't adhere to kernel objtool/SLS conventions. The GitHub
runner kernel has `CONFIG_OBJTOOL_WERROR` enabled, so objtool reports
issues as errors instead of warnings.

- Add -mfunction-return=keep flag when compiling the kernel module. 
By default the kernel build system adds `-mfunction-return=thunk-extern`
for Spectre mitigation, which generates `jmp __x86_return_thunk` instead
of `ret` for every function return. When objtool validation is disabled,
it doesn't generate the `.return_sites` section in the ELF section,
which is needed for the mitigation to work. `-mfunction-return=keep`
tells gcc to generate `ret` instead of `jmp __x86_return_thunk`.

- Switch to `__vmalloc_node_range` for kernel module heap allocation.
Before we were only testing again kernel 6.6, and the GitHub runner has
a newer kernel which has `module_alloc()` removed. After some research I
come to the conclusion that across 6.6+ LTS kernels,
`__vmalloc_node_range` is the only reliable API to allocate writable
memory within the 2GB reach of kernel text
(`MODULES_VADDR..MODULES_END`). Alternatives:
  - `module_alloc()`: Removed in 6.10. Returns RW+NX.
- `execmem_alloc()`: Introduced in 6.10. Returns RW+NX in 6.10-6.12, but
read-only-execute (ROX) in 6.13+.
  - `execmem_alloc_rw()`: Introduced in 6.14. Returns RW+NX.


- Auto-generate weak stubs for undefined symbols so the module loads
during incremental development (`generate_stubs.cmake`). When
`Module.symvers` is present, the build runs `nm -u` on the composite
object, filters out kernel-exported symbols, and generates a weak
`BUG()` stub for each remaining symbol — so an unexpected call at
runtime fails loudly with a kernel oops. When `Module.symvers` is
absent, stub generation is skipped and the build relies on
`KBUILD_MODPOST_WARN=1` for compile-only testing.

Issue: #8021.
2026-09-04 14:22:55 -07:00
Jeevan NandBin Wang f9ea8b20ce i#8076: Fix query_time_seconds() inconsistency in kernel build (#8094)
The kernel implementation of query_time_seconds() currently returns
seconds since the Unix Epoch (1970-01-01), while DR's documented
cross-platform contract uses seconds since 1601-01-01.

This causes the kernel build to return a different time base from the
user-space implementation.

Moves UTC_TO_EPOCH_SECONDS to os_shared.h making it available to both
the Unix and Linux kernel implementations, and converts the kernel
query_time_seconds() result to the 1601-based time.

No changes are made to the existing Unix implementations of
query_time_millis() or query_time_micros().

Fixes #8076

---------

Co-authored-by: Bin Wang <[email protected]>
2026-09-04 08:07:12 -07:00
Derek Bruening aee08a1323 i#8092: Mark RDSSPQ as predicated (#8093)
Fixes a crash in drmemtrace due to RDSSPQ being treated as always
writing its destination register, when it's a nop if CET is unsupported.

Tested on SPECCPU 2017 omnetpp and leela, which both hit SIGILL without
this fix and work with it.

Fixes #8092
2026-09-03 11:20:17 -07:00
Bin Wang 105f47e54f i#8021: Implement kernel module init/exit with symbol resolution and heap reservation (#8075)
- Resolve `kallsyms_lookup_name` at runtime via kprobe, then use it to
resolve `module_alloc`.
- Reserve a heap region via `module_alloc`, and release it on module
exit.
- Add `MODULE_DESCRIPTION` and `MODULE_AUTHOR`.

Issue: #8021
2026-09-01 07:54:03 -07:00
donfucius 0cd3d84e20 i#8082: Fix heap overflow in nt_get_context64_size on non-XSTATE CPUs (#8083)
## Summary
Fix heap overflow risk in `nt_get_context64_size()` on non-XSTATE CPUs.

`RtlGetExtendedContextLength(CONTEXT_XSTATE)` can fail on non-XSTATE
paths.
This change checks availability/success of that query and falls back to
`sizeof(CONTEXT_64) + 16` when unavailable, avoiding undersized
allocation
and out-of-bounds write in later context handling.

## Root cause
`nt_get_context64_size()` assumed extended context query success and
could
cache a too-small size (effectively 16 bytes) on failure paths in
release
builds.

## Fix
- Guard `RtlGetExtendedContextLength` usage.
- Require successful NTSTATUS and valid returned length for extended
path.
- Fallback to non-extended `CONTEXT_64` size + alignment headroom.

Issue: https://github.com/DynamoRIO/dynamorio/issues/8082
2026-08-31 23:34:25 -07:00
donfucius b81b41cb47 i#8070: Fix NULL deref of RtlGetExtendedContextLength on non-AVX CPUs (#8071)
The extended-context `ntdll` function pointers are only resolved when
`YMM_ENABLED()` (in `nt_get_context_extended_functions()`), so on
CPUs/OS without AVX support they remain `NULL`. `nt_get_context_size()`
previously called `ntdll_RtlGetExtendedContextLength()` unconditionally,
crashing with an indirect call to address 0 (e.g., in
`postsys_CreateUserProcess()` when an app creates a child process).

Restructure `nt_get_context_size()` to check `TESTALL(CONTEXT_XSTATE,
flags)`, mirroring `nt_initialize_context()`. When `CONTEXT_XSTATE` is
not requested (such as on non-AVX systems where `CONTEXT_DR_STATE` omits
it), fall back to `sizeof(CONTEXT)` plus alignment headroom, avoiding
the `NULL` dereference.

Verified on real hardware (Celeron J1900, no AVX, Win10 1809): before
the fix every child-spawning app crashed 100% under `drrun`; after the
fix child following works in both release and `-debug` builds. CI cannot
cover this (needs non-AVX hardware), so verification was manual.

AI assistance disclosure: root-cause analysis and the patch were
developed with AI assistance; I reviewed the change and verified it
manually on the affected hardware.

Fixes #8070
Issue: #6763
2026-08-26 21:10:02 -07:00
ZheWang de0b0c1bd0 i#3544: OPFVF vector-FP scalar operand decoding as FP register (#8057)
The OPFVF vector floating-point instructions (OP-V major opcode with
funct3=3'b101, e.g. vfadd.vf, vfmv.s.f, vfmerge.vfm) encode their scalar
operand in the rs1 field as a floating-point register (f0-f31), per the
RISC-V V spec. Their ISL entries in core/ir/riscv64/isl/v.txt declared
this operand as rs1, which selects the integer-register decoder
(decode_rs1_opnd -> DR_REG_X0+) instead of the floating-point decoder
(decode_rs1fp_opnd -> DR_REG_F0+). As a result the scalar FP operand was
decoded from the wrong register file.

Issue: #3544
2026-08-26 15:29:51 -07:00
Bin Wang 51937e4dcc i#8021: Include source files in arch/ and arch/x86/ as dependencies for kernel module (#8064)
- Include source files in `core/arch/`, `core/arch/x86/`, and `core/lib`
as dependencies for the kernel module.
- Resolve missing header by using wrapper headers or excluding headers
that don't have a kernel equivalent.
- Exclude logic that doesn't apply in the kernel space.
- Fix wrong return values in `dr_nudge_client_ex()` in
`core/lib/instrument.c`.
- Replicate assembly processing logic from `cpp2asm_support.cmake` in
`core/kernel_linux/CMakeLists.txt` because `cpp2asm_support.cmake`
cannot be used directly with kbuild.

Issue: #8021
2026-08-25 11:06:15 -07:00
Bin Wang e9884061d0 i#1947: Add support for Intel CET instructions (#7916)
- Add decoding/encoding support for Intel CET instructions.
- Ignore endbr64/endbr32/rdssp in drcpusim, as they decode as nop on
older CPUs.
- Removed an outdated comment about how gdb handles lfence.
- Use ext # directly for existing group 18/19 since they don't match
Intel SDM.

Fixes #1947
Fixes #4040
Fixes #5109
2026-08-19 22:39:55 -07:00
Bin Wang bd4d8aa6a1 i#8021: Include source files in ir/ and ir/x86/ as dependencies for kernel module (#8049)
- Include source files as dependencies for kernel module:
- 3 remaining files in `core/`: `translate.c`, `utils.c`, and
`vmareas.c`.
    - Relevant files in `core/ir/`
    - Relevant files in `core/ir/x86/`
- Exclude functions and logic that don't apply in kernel space, such as
rseq and floating point arithmetic.
- Update include headers. This includes using wrapper headers or
excluding headers that don't have an equivalent in kernel.
- Some bug fixes that are uncovered by Kbuild compiler flags.

Issue: #8021
2026-08-17 14:51:36 -07:00
Bin Wang fcacba79aa i#8021: Fix wrong return value in instr_predicate_triggered (#8055)
As discussed in #8049:

> This was flagged by `-Werror=enum-conversion`. Upon a closer look I
think it's wrong to return `false` (equivalent to
`DR_PRED_TRIGGER_NOPRED`) here. I think the logic here is that there is
pred but DR cannot check if it matches or not, so it should return
DR_PRED_TRIGGER_UNKNOWN.

Issue: #8021
2026-08-17 12:01:32 -07:00
Jack Gallagher b7f32c071a i#8050 Fix selfmod tests on AArch64 (#8051)
There was a flaw with AArch64 version of the selfmod tests. The test
functions work by modifying the immediate value of a later mov
instruction and observing which value was moved.

AArch64 requires explicit synchronisation to guarantee that the
modification is seen by the CPU and the updated instruction is executed.
The tests implemented this by calling `tools_clear_icache()` after the
modification. However this undermines the test because DR detects the
call as a control transfer instruction and ends the block before we get
to the instruction being modified. By the time DR gets to decode and
translate the modified instruction it has already been modified. The
original instruction was never translated and placed in the code cache
so the test doesn't actually prove that the modification was handled
properly.

We can fix this by inlining the cache flush code and ensuring that there
are no CTIs in between the code modification write and the modified
instruction.

To this end I have also lifted the restriction requiring isb to be the
last instruction of a block. This was added as part of the AArch64
selfmod mechanism which mangled ic cvau instructions to store the
address range being flushed and mangled isb to do a sideline exit and
perform the actual code cache flush. This mechanism has since been
changed to directly flush the code cache on ic cvau and isb no longer
has any special mangling so we don't need it to be the last instruction.

Fixes #8050
2026-08-17 08:27:35 +01:00
Tejash Gupta 65a7480ad5 i#2073: fix confusing sizeof(XSP_SZ) usage (#8053)
XSP_SZ is already defined as `(ssize_t)sizeof(reg_t)`, i.e. the stack
pointer width in bytes. Several call sites wrote `sizeof(XSP_SZ)`,
which actually computes `sizeof(ssize_t)` rather than the intended
value. As noted in the issue discussion, this happens to be
numerically equal on every currently supported platform (`ssize_t`
and `reg_t` are always pointer-width), so it is not a functional bug,
but it reads as one and is worth cleaning up.

Replace `sizeof(XSP_SZ)` with `XSP_SZ` at all three call sites
(core/ir/opnd.h x2, core/unix/native_elf.c x3 occurrences on 3 lines).

Fixes: #2073
2026-08-16 22:23:14 -04:00
Suyash Mahar 5ba42078a0 i#8034: Make native_exec_is_back_from_native check more robust to avoid BOLT induced crashes (#8035)
native_exec_is_back_from_native() bounds its
range check with the hard-coded
MAX_NATIVE_RETSTACK * BACK_FROM_NATIVE_RETSTUB_SIZE
(40 bytes) rather than the actual extent of the retstub region.

Bound the check by
back_from_native_retstubs_end - back_from_native_retstubs instead.
On x86 this is equivalent, the asm emits MAX_NATIVE_RETSTACK
stubs and native_exec_init() already asserts
end == start + MAX_NATIVE_RETSTACK * BACK_FROM_NATIVE_RETSTUB_SIZE.

Fixes #8034
2026-08-14 11:46:06 -07:00
Derek Bruening 05e316505b i#8043: Remove w suffix from Intel style (#8045)
Removes the 'w' suffix from iret, pushf, popf, pusha, and popa, since
these do not have a suffix at that size in the Intel manual nor in xed.

Fixes #8043
2026-08-07 16:05:30 -04:00
Bin Wang 18e7b34cc2 i#8038: Remove XXX comments as they are no longer planned (#8042)
Per offline discussion, we think it's better to have one set of public
headers for both user space release and kernel release. Therefore, it's
acceptable to have `#ifdef`s in the public headers for conditionally
including system header, and the optimization in #8038 is no longer
plan. This PR removes the XXX comments referring #8038.

Issue: #8038
2026-08-06 20:54:03 -07:00
Bin Wang 436da3609c i#8021: Include source files in core/ as dependencies for kernel module (#8025)
- Update `core/kernel_linux/CMakeLists.txt`:
  - Include source files in `core/` as dependencies for kernel module.
- Define `LINUX_KERNEL`, `DYNAMORIO_INTERNAL`,
`DR_DO_NOT_DEFINE_MAX_MIN`
  - Add `-Wframe-larger-than=4096`
- Update include headers in source files under `core/`. This includes
using wrapper headers (e.g., `stdarg_wrapper.h`) or excluding headers
that don't have an equivalent in kernel (e.g., `math.h`).
- Exclude floating point arithmetic and user space specific logic (e.g.,
signal handling, rseq) from kernel build.
- Optimize frame stack in `options.c` to make frame less than 4KB.

Issue: #8021
2026-08-03 12:12:14 -07:00
Derek Bruening 82d9da3f91 i#8001 shared defs: Share TEST* and BUFFER* macros (#8030)
Shares TESTANY, TESTALL, and BUFFER_SIZE_ELEMENTS and related defines,
in dr_project_wide_defines.h, eliminating duplication in many places.

Removes ext/ext_utils.h which becomes empty after this change.

Issue: #8001
2026-08-03 12:52:58 -04:00
Derek Bruening f88e38abc3 i#8001 shared defs: Use TESTANY instead of TEST (#8032)
In preparation of moving the TEST* defines into
dr_project_wide_headers.h, we replace all uses of TEST with the
equivalent TESTANY. Although we avoid exposing
dr_project_wide_headers.h in DR_API headers, it is exposed in
drmemtrace's headers where TEST causes collisions with third-party code
such as googletest.

Issue: #8001
2026-07-30 11:39:13 -04:00
Derek Bruening 3280e26f0e i#8001 shared defs: Add project-wide header with ALIGN* macros (#8007)
Adds a new top-level header common/dr_project_wide_defines.h that is
shared across all domains to avoid duplication.

This PR moves just the ALIGN* macros into this header. More shared
defines will be moved in further installments.

The new header is installed into the drmemtrace export dir as A) we're
already exporting utils.h which includes it and B) otherwise we have to
duplicate some defines in trace_entry.h. However, I first tried
duplicating and not including utils.h in trace_entry.h, which revealed
several missing headers in clients/drcachesim/ files. I left those
additions in this PR though they could be separated out.

The new header includes stdint.h to avoid depending on DR API integer
defines, which caused a Windows build issue which was resolved by
removing defines we had added to libdwarf.h back when we supported
VS2008 which did not have stdint.h. Those added defines are removed
here.

Issue: #8001
2026-07-27 17:12:12 -04:00
Bin Wang 6242d1d825 i#8021: Relocate Kbuild output to binary directory (#8023)
The Kbuild support added in #8020 builds the kernel module and
intermediate output alongside the source files. As we have discussed,
this pollutes the project directory and differs how CMake normally
isolates build output. This PR relocates the output to the binary
directory (i.e., `build/core/kernel_linux`) by
- Generate the Kbuild file in the binary directory.
- Mirror required source files in the binary directory using symlink.

Issue: #8021
2026-07-24 15:14:57 -07:00
Bin Wang e44c791e50 i#8021: Bootstrap kernel module build support (#8020)
- Add a boilerplate kernel module as placeholder.
- Add CMake build support for building the kernel module. Note that
CMake still need to create a Makefile and run make, which is the only
supported way to drive Kbuild. However, all the configuration (source
file list, flags, and defines) are done in CMake.
- Added a CI workflow definition for building the kernel module.

By default, Kbuild places the final `.ko` and intermediate build
artifacts (`.o`, `.mod.c`, etc.) alongside the module's source files.
This pollutes the project directory and differs from how CMake normally
isolates build output. We might want the artifacts to land in the
`build/` directory instead in the future. However, Kbuild's
external-module support ties build output directly to the `M=` source
directory.
[`KBUILD_EXTMOD_OUTPUT`](https://docs.kernel.org/6.13/kbuild/kbuild.html#kbuild-extmod-output)
does what we want, but it's only available in kernel 6.13+. So we'd need
to copy the source files into build/ before invoking Kbuild. Leaving
this for a future PR.

Issue: #8021
2026-07-22 22:43:17 -07:00
Bin Wang cca42665b0 i#8018: Remove dead code block in core/ir/x86/encode.c (#8019)
Remove a dead code block inside `core/ir/x86/encode.c` guarded by `#if
DEBUG_DISABLE` since `DEBUG_DISABLE` is never defined in the project
other than this place.

Fixes #8018
2026-07-21 10:21:08 -07:00