# **********************************************************
# Copyright (c) 2026 Google, Inc.  All rights reserved.
# **********************************************************

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
#   this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of Google, Inc. nor the names of its contributors may be
#   used to endorse or promote products derived from this software without
#   specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.

# Kbuild file for the DynamoRIO Linux kernel module. Install it at the root of a tree with
# the following layout and run `make -C <kernel build dir> M=<module root> modules`:
#
#   Kbuild                this file
#   Kbuild.sources        generated object list: dr_objs := core/.../*.o ...
#   configure.h           generated by DynamoRIO's configure step
#   configure_defines.h   generated by DynamoRIO's configure step
#   event_strings.h       generated by core/gen_event_strings.pl
#   common/...            DynamoRIO's common/ directory
#   core/...              DynamoRIO's core/ directory
#
# See CMakeLists.txt in this directory for more information.

obj-m += dynamorio_module.o

# The caller supplies object paths relative to this tree's root, excluding the
# generated core/kernel_linux/stubs.o.
include $(src)/Kbuild.sources

# stubs.c is generated from the other objects; see below.
dynamorio_module-y := $(dr_objs) core/kernel_linux/stubs.o

# Flags shared by C and assembly sources, including the x86.asm preprocessing below.
dr_flags := \
  -I$(src) \
  -I$(src)/common \
  -I$(src)/core \
  -I$(src)/core/include \
  -I$(src)/core/kernel_linux \
  -I$(src)/core/arch \
  -I$(src)/core/arch/x86 \
  -I$(src)/core/drlibc \
  -I$(src)/core/ir \
  -I$(src)/core/ir/x86 \
  -I$(src)/core/lib \
  -I$(src)/core/unix \
  -DLINUX_KERNEL \
  -DDYNAMORIO_INTERNAL \
  -DDR_DO_NOT_DEFINE_MAX_MIN

# Disable objtool checks for all objects in this directory. DynamoRIO assembly (x86.asm)
# and low-level code contain custom return sequences, stack switches, and trampolines
# that do not adhere to kernel objtool/SLS conventions.
OBJECT_FILES_NON_STANDARD := y

ccflags-y += $(dr_flags) -Wframe-larger-than=4096
ifdef CONFIG_X86
# Disable compiler-generated return thunks (__x86_return_thunk) since objtool
# is disabled for the module and won't generate the .return_sites section needed
# for runtime patching.
ccflags-y += -mfunction-return=keep
endif

asflags-y += $(dr_flags) -Xassembler --noexecstack
ifdef CONFIG_AS_IS_LLVM
# LLVM's integrated assembler (used for kernels built with LLVM=1) does not
# accept the GNU as options below. -masm=intel selects Intel syntax, which it
# parses without register prefixes.
asflags-y += -masm=intel
else
asflags-y += \
  -Xassembler -mmnemonic=intel \
  -Xassembler -msyntax=intel \
  -Xassembler -mnaked-reg \
  -Xassembler --64
endif

# Preprocess x86.asm into x86.S. This replicates the preprocessing logic from
# make/cpp2asm_support.cmake and make/CMake_asm.cmake, which cannot be used with Kbuild.
quiet_cmd_dr_cpp2asm = CPP2ASM $@
      cmd_dr_cpp2asm = \
  $(CPP) -Wp,-MMD,$(depfile) -P -x c $(dr_flags) -DCPP2ASM -o $@ $< && \
  sed -i -e 's/@N@/\n/g' -e 's/@P@/\#/g' -e 's/\#\#//g' $@

$(obj)/core/arch/x86/x86.S: $(src)/core/arch/x86/x86.asm FORCE \
  ; $(call if_changed_dep,dr_cpp2asm)

targets += core/arch/x86/x86.S
clean-files += core/arch/x86/x86.S

# Since the kernel module is still in development, many DynamoRIO symbols
# haven't been ported to the kernel build yet. To be able to load and test
# the kernel module during development, when Module.symvers is present,
# stubs.c is populated with weak stubs for symbols that are referenced but
# neither defined by the module nor exported by the kernel. Each stub simply
# calls BUG(), so if an unported function is reached during runtime it would
# fail loudly with a kernel oops.
#
# When Module.symvers is absent (e.g. an unbuilt kernel tree prepared with
# `make modules_prepare`), kernel exports can't be told apart from missing
# symbols, so stubs.c is left empty and modpost's unresolved symbol errors are
# turned into warnings (KBUILD_MODPOST_WARN=1) for compile-only testing.
#
# TODO i#8021: Remove the stubs and KBUILD_MODPOST_WARN once all required
# DynamoRIO symbols are fully implemented.
dr_symvers := $(wildcard $(objtree)/Module.symvers)
dr_stub_objs := $(addprefix $(obj)/,$(dr_objs))

ifneq ($(dr_symvers),)
quiet_cmd_dr_stubs = GEN     $@
      cmd_dr_stubs = \
  export LC_ALL=C; \
  $(NM) -u $(dr_stub_objs) > $@.nm; \
  awk '$$1 == "U" { print $$2 }' $@.nm | sort -u > $@.undef; \
  $(NM) --defined-only $(dr_stub_objs) > $@.nm; \
  { awk 'NF == 3 && $$2 ~ /[A-Z]/ { print $$3 }' $@.nm; \
    cut -f2 $(dr_symvers); \
    echo __this_module; } | sort -u > $@.def; \
  { echo '/* Auto-generated weak stubs for unported DynamoRIO symbols */'; \
    echo '\#include <linux/bug.h>'; \
    echo; \
    comm -23 $@.undef $@.def | \
      sed 's/.*/void &(void); void __attribute__((weak)) &(void) { BUG(); }/'; } > $@; \
  rm -f $@.nm $@.undef $@.def
else
KBUILD_MODPOST_WARN := 1
quiet_cmd_dr_stubs = GEN     $@
      cmd_dr_stubs = \
  echo '/* No stubs: $(objtree)/Module.symvers not found */' > $@
endif

$(obj)/core/kernel_linux/stubs.c: $(dr_stub_objs) $(dr_symvers) FORCE \
  ; $(call if_changed,dr_stubs)

targets += core/kernel_linux/stubs.c
clean-files += core/kernel_linux/stubs.c
