`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.
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
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
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
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: #8021Fixes#8112
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
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
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
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
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
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
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
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: #7585Fixes#2055, #5771
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, #6152Fixes#8138
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
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
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
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
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
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
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
- 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
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
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
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
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
- 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.
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]>
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
- 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
## 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
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
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
- 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
- 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#1947Fixes#4040Fixes#5109
- 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
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
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
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
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
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
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
- 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
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
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
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
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
- 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
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