From f60ddbb5300be5fe05394fd51f8944f777e07323 Mon Sep 17 00:00:00 2001 From: Mohamed Date: Thu, 3 Sep 2026 15:07:37 +0200 Subject: [PATCH 1/2] build: build the vendored Capstone from the autotools build Callgrind's cycle estimation links a static Capstone, which until now had to be built by hand before Valgrind: configure hard-failed unless it was given --with-capstone=PATH or CAPSTONE_DIR. That put the same cmake invocation in a wrapper script and in a CI action, where the two copies of the required compiler flags could drift apart, and every new consumer had to repeat it. Compile the submodule as an automake convenience library instead, so a plain `./autogen.sh && ./configure && make && make install` is the whole build. --with-capstone (or CAPSTONE_DIR) stays as an override for a prebuilt decoder, which the Debian packaging still wires through, but nothing needs it any more: the Nix dev shell no longer sets it either. The submodule sources are compiled through one-line stub units in third_party/capstone-stubs/ rather than where they live. Automake is configured with subdir-objects, so it writes an object next to its source, and Valgrind only builds in-tree: compiling them in place would drop objects, .deps directories and .dirstamp files into the capstone checkout and leave the submodule permanently reported as dirty. The stubs keep every build artefact in this repository, where .gitignore covers it, instead of asking git to look away from a submodule that is genuinely being written to. The CodSpeed logic lives in files of its own (m4/codspeed_capstone.m4 and third_party/Makefile.am), leaving three one-line touch points in upstream files -- the macro call, an AC_CONFIG_FILES entry and a SUBDIRS entry -- in place of the 28-line block this removes from configure.ac, so rebasing onto upstream conflicts on single lines. Two things the wrapper script was hiding, now handled by the build system: - The tool CFLAGS pass -fno-builtin, so GCC no longer folds Capstone's fprintf(stderr, "...") guard into fwrite. The tool shimmed only fwrite and thus only linked by accident of that optimisation; shim fprintf and strcat explicitly, and compile Capstone -DNDEBUG as its own Release build does so assert() does not pull in __assert_fail. - CFLAGS=-std=gnu17 was passed by the script alone, so builds through debian/rules or nix never got it. AC_PROG_CC picks gnu23 on GCC 15+, under which glibc 2.42+ defines strchr/strrchr/strstr as _Generic macros that clash with Callgrind's own definitions. Pin it in configure instead. Co-Authored-By: Claude Opus 5 (1M context) --- .github/actions/build-capstone/action.yml | 25 ---- .github/workflows/ci.yml | 4 - .github/workflows/codspeed.yml | 5 - .github/workflows/release.yml | 8 +- .gitignore | 9 +- Makefile.am | 1 + autogen.sh | 10 ++ callgrind/cycledecode_capstone.c | 25 +++- configure.ac | 36 +----- debian/rules | 5 +- flake.nix | 9 +- m4/codspeed_capstone.m4 | 73 ++++++++++++ third_party/Makefile.am | 109 ++++++++++++++++++ third_party/capstone-stubs/AArch64BaseInfo.c | 2 + .../capstone-stubs/AArch64Disassembler.c | 2 + .../capstone-stubs/AArch64InstPrinter.c | 2 + third_party/capstone-stubs/AArch64Mapping.c | 2 + third_party/capstone-stubs/AArch64Module.c | 2 + third_party/capstone-stubs/MCInst.c | 2 + third_party/capstone-stubs/MCInstrDesc.c | 2 + third_party/capstone-stubs/MCRegisterInfo.c | 2 + third_party/capstone-stubs/Mapping.c | 2 + third_party/capstone-stubs/SStream.c | 2 + .../capstone-stubs/X86ATTInstPrinter.c | 2 + third_party/capstone-stubs/X86Disassembler.c | 2 + .../capstone-stubs/X86DisassemblerDecoder.c | 2 + .../capstone-stubs/X86InstPrinterCommon.c | 2 + .../capstone-stubs/X86IntelInstPrinter.c | 2 + third_party/capstone-stubs/X86Mapping.c | 2 + third_party/capstone-stubs/X86Module.c | 2 + third_party/capstone-stubs/cs.c | 2 + third_party/capstone-stubs/utils.c | 2 + 32 files changed, 274 insertions(+), 83 deletions(-) delete mode 100644 .github/actions/build-capstone/action.yml create mode 100644 m4/codspeed_capstone.m4 create mode 100644 third_party/Makefile.am create mode 100644 third_party/capstone-stubs/AArch64BaseInfo.c create mode 100644 third_party/capstone-stubs/AArch64Disassembler.c create mode 100644 third_party/capstone-stubs/AArch64InstPrinter.c create mode 100644 third_party/capstone-stubs/AArch64Mapping.c create mode 100644 third_party/capstone-stubs/AArch64Module.c create mode 100644 third_party/capstone-stubs/MCInst.c create mode 100644 third_party/capstone-stubs/MCInstrDesc.c create mode 100644 third_party/capstone-stubs/MCRegisterInfo.c create mode 100644 third_party/capstone-stubs/Mapping.c create mode 100644 third_party/capstone-stubs/SStream.c create mode 100644 third_party/capstone-stubs/X86ATTInstPrinter.c create mode 100644 third_party/capstone-stubs/X86Disassembler.c create mode 100644 third_party/capstone-stubs/X86DisassemblerDecoder.c create mode 100644 third_party/capstone-stubs/X86InstPrinterCommon.c create mode 100644 third_party/capstone-stubs/X86IntelInstPrinter.c create mode 100644 third_party/capstone-stubs/X86Mapping.c create mode 100644 third_party/capstone-stubs/X86Module.c create mode 100644 third_party/capstone-stubs/cs.c create mode 100644 third_party/capstone-stubs/utils.c diff --git a/.github/actions/build-capstone/action.yml b/.github/actions/build-capstone/action.yml deleted file mode 100644 index ef837a772..000000000 --- a/.github/actions/build-capstone/action.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Build Capstone (cycle-estimation decoder) -description: >- - Build the static Capstone that Callgrind cycle estimation links against, and - export its install prefix as CAPSTONE_DIR for later steps. - -runs: - using: composite - steps: - - shell: bash - run: | - CS_SRC="$GITHUB_WORKSPACE/third_party/capstone" - CS_PREFIX="$GITHUB_WORKSPACE/.capstone" - cmake -S "$CS_SRC" -B "$CS_SRC/build" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCAPSTONE_ARCHITECTURE_DEFAULT=OFF \ - -DCAPSTONE_X86_SUPPORT=ON \ - -DCAPSTONE_ARM64_SUPPORT=ON \ - -DCAPSTONE_BUILD_SHARED_LIBS=OFF \ - -DCAPSTONE_BUILD_CSTOOL=OFF \ - -DCMAKE_INSTALL_LIBDIR=lib \ - -DCMAKE_INSTALL_PREFIX="$CS_PREFIX" \ - -DCMAKE_C_FLAGS="-fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -fPIC" - cmake --build "$CS_SRC/build" -j"$(nproc)" - cmake --install "$CS_SRC/build" - echo "CAPSTONE_DIR=$CS_PREFIX" >> "$GITHUB_ENV" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56254b955..074b50b2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,6 @@ jobs: build-essential \ automake \ autoconf \ - cmake \ libc6-dev \ gdb \ docbook \ @@ -52,9 +51,6 @@ jobs: docbook-xml \ xsltproc - - name: Build Capstone (cycle-estimation decoder) - uses: ./.github/actions/build-capstone - - name: Run autogen run: ./autogen.sh diff --git a/.github/workflows/codspeed.yml b/.github/workflows/codspeed.yml index fc41edf9d..4a0b5628a 100644 --- a/.github/workflows/codspeed.yml +++ b/.github/workflows/codspeed.yml @@ -72,17 +72,12 @@ jobs: build-essential \ automake \ autoconf \ - cmake \ gdb \ docbook \ docbook-xsl \ docbook-xml \ xsltproc - - name: Build Capstone (cycle-estimation decoder) - if: steps.valgrind-cache.outputs.cache-hit != 'true' && matrix.valgrind == 'local' - uses: ./.github/actions/build-capstone - - name: Build Valgrind (${{ matrix.valgrind }}) if: steps.valgrind-cache.outputs.cache-hit != 'true' run: just build ${{ matrix.valgrind }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3850a7da..5f639d782 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,20 +36,16 @@ jobs: - name: Install packaging deps run: sudo apt-get install -y build-essential devscripts debhelper dh-make - name: Install build deps - run: sudo apt-get install -y debhelper-compat gdb mpi-default-dev pkgconf cmake docbook docbook-xsl docbook-xml xsltproc + run: sudo apt-get install -y debhelper-compat gdb mpi-default-dev pkgconf docbook docbook-xsl docbook-xml xsltproc - name: Configure GPG Key run: echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - # debian/rules forwards $CAPSTONE_DIR to configure via --with-capstone. - - name: Build Capstone (cycle-estimation decoder) - uses: ./.github/actions/build-capstone - - name: Build the deb package id: build_deb run: | - debuild -e CAPSTONE_DIR --no-tgz-check -nc + debuild --no-tgz-check -nc echo "asset-path=$(find .. -name 'valgrind_*.deb')" >> "$GITHUB_OUTPUT" env: DEBEMAIL: ${{ vars.MAINTAINER_EMAIL }} diff --git a/.gitignore b/.gitignore index 838091b5b..1ec88864f 100644 --- a/.gitignore +++ b/.gitignore @@ -2566,7 +2566,14 @@ test-suite.log # autoconf backup /configure~ -# Capstone build install prefix (built from the third_party/capstone submodule) +# /third_party/ (vendored Capstone, built by third_party/Makefile.am) +/third_party/Makefile +/third_party/Makefile.in +/third_party/libcapstone.a +/third_party/capstone-stubs/.deps +/third_party/capstone-stubs/.dirstamp + +# install prefix of a Capstone built by hand for --with-capstone /.capstone # fake CodSpeed benchmark fixture binary (compiled from testdata/llsc_tzconvert_bench.c) diff --git a/Makefile.am b/Makefile.am index 6c5b9f5b6..176317a5d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ EXP_TOOLS = \ # Put docs last because building the HTML is slow and we want to get # everything else working before we try it. SUBDIRS = \ + third_party \ include \ VEX \ coregrind \ diff --git a/autogen.sh b/autogen.sh index 5de086b1a..257b6e284 100755 --- a/autogen.sh +++ b/autogen.sh @@ -20,6 +20,16 @@ run autoconf if git rev-parse --is-inside-work-tree > /dev/null 2>&1 ; then echo "running: git configuration" git config blame.ignoreRevsFile .git-blame-ignore-revs + # CodSpeed: the vendored Capstone decoder that Callgrind's cycle estimation + # links against. A clone without --recurse-submodules leaves it empty. + # Not fatal: a build using --with-capstone=PATH (or CAPSTONE_DIR) needs no + # submodule, and must still work in a sandbox with no network. configure + # reports the empty submodule if neither is available. + echo "running: git submodule update --init third_party/capstone" + if ! git submodule update --init third_party/capstone ; then + echo "warning: could not check out third_party/capstone." + echo "warning: pass --with-capstone=PATH to configure to use a prebuilt Capstone." + fi else echo "skipping: git configuration" fi diff --git a/callgrind/cycledecode_capstone.c b/callgrind/cycledecode_capstone.c index 31033bf73..b17d25a9e 100644 --- a/callgrind/cycledecode_capstone.c +++ b/callgrind/cycledecode_capstone.c @@ -55,6 +55,7 @@ extern char* vgPlain_strncpy(char* d, const char* s, unsigned long n); extern char* vgPlain_strchr(const char* s, char c); extern char* vgPlain_strrchr(const char* s, char c); extern char* vgPlain_strstr(const char* h, const char* n); +extern char* vgPlain_strcat(char* d, const char* s); static const char* const CLG_CD_CC = "clg.cycledecode"; @@ -91,10 +92,16 @@ int printf(const char* fmt, ...) } int puts(const char* s) { return printf("%s\n", s); } -/* Capstone's SStream references stderr/fwrite on a buffer-overflow guard in the - * op_str text path (which this code never reads). Valgrind has no FILE* layer, - * so stderr is a sentinel and fwrite routes the bytes to the Valgrind log fd, - * making such an overflow visible rather than swallowed. */ +/* Capstone's SStream references stderr/fprintf on a buffer-overflow guard in + * the op_str text path (which this code never reads). Valgrind has no FILE* + * layer, so stderr is a sentinel and these route the bytes to the Valgrind log + * fd, making such an overflow visible rather than swallowed. + * + * Both fprintf and fwrite are needed: the guard calls fprintf, which GCC folds + * into fwrite for a format string with no conversions, but only when builtins + * are enabled. Valgrind's tool CFLAGS pass -fno-builtin, so whether the object + * ends up referencing fprintf or fwrite depends on how Capstone was compiled. + * Defining both keeps the tool linkable either way. */ extern int vgPlain_write(int fd, const void* buf, int count); FILE* stderr = 0; size_t fwrite(const void* p, size_t size, size_t nmemb, FILE* f) @@ -103,6 +110,15 @@ size_t fwrite(const void* p, size_t size, size_t nmemb, FILE* f) vgPlain_write(2, p, (int)(size * nmemb)); return nmemb; } +int fprintf(FILE* f, const char* fmt, ...) +{ + (void)f; + va_list ap; + va_start(ap, fmt); + unsigned int r = vgPlain_vprintf(fmt, ap); + va_end(ap); + return (int)r; +} size_t strlen(const char* s) { return vgPlain_strlen(s); } int strcmp(const char* a, const char* b) { return vgPlain_strcmp(a, b); } @@ -118,6 +134,7 @@ char* strncpy(char* d, const char* s, size_t n) char* strchr(const char* s, int c) { return vgPlain_strchr(s, (char)c); } char* strrchr(const char* s, int c) { return vgPlain_strrchr(s, (char)c); } char* strstr(const char* h, const char* n) { return vgPlain_strstr(h, n); } +char* strcat(char* d, const char* s) { return vgPlain_strcat(d, s); } /*------------------------------------------------------------*/ /*--- Capstone handle: open / decode -*/ diff --git a/configure.ac b/configure.ac index 4275bb3c5..37181b612 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,9 @@ AC_PROG_CC AS_IF([test "x$ac_cv_prog_cc_c11" = "xno"], [AC_MSG_ERROR([Valgrind relies on a C compiler supporting C11])]) +# CodSpeed: pin the C dialect. See m4/codspeed_capstone.m4. +CODSPEED_C_STD_GNU17 + AC_PROG_CPP AC_PROG_CXX AC_PROG_RANLIB @@ -1122,36 +1125,8 @@ AC_ARG_WITH(tmpdir, AC_DEFINE_UNQUOTED(VG_TMPDIR, "$tmpdir", [Temporary files directory]) AC_SUBST(VG_TMPDIR, [$tmpdir]) -#---------------------------------------------------------------------------- -# CodSpeed: mandatory Capstone for Callgrind per-instruction cycle estimation -#---------------------------------------------------------------------------- -# Callgrind's primary (native) tool is always built with the Capstone decoder -# and a generated cost table (x86 or arm64, selected at compile time), enabling -# --cycle-estimation=yes. The decoder location comes from --with-capstone=PATH -# or, when omitted, the CAPSTONE_DIR environment variable (`nix develop` sets -# it). A build without Capstone is not supported and fails here. -AC_ARG_WITH(capstone, - [ --with-capstone=PATH Path to the Capstone decoder install used for - Callgrind cycle estimation (Cy/Cl). Defaults to the - CAPSTONE_DIR environment variable (amd64/arm64)], - [capstone_dir="$withval"], - [capstone_dir="$CAPSTONE_DIR"]) - -if test -z "$capstone_dir"; then - AC_MSG_ERROR([Capstone is required for Callgrind cycle estimation. Pass --with-capstone=PATH or set CAPSTONE_DIR (`nix develop` provides it).]) -fi -if test ! -f "$capstone_dir/lib/libcapstone.a" \ - -o ! -f "$capstone_dir/include/capstone/capstone.h"; then - AC_MSG_ERROR([--with-capstone=$capstone_dir: libcapstone.a or capstone.h not found]) -fi -# Fortify off: the tool links -nodefaultlibs, so glibc's __*_chk fortify -# wrappers are unavailable, and our libc shims (sprintf/snprintf/...) must -# be real definitions, not fortify macro-expansions. -CAPSTONE_CFLAGS="-DCLG_WITH_CAPSTONE -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -I$capstone_dir/include" -CAPSTONE_LIBS="$capstone_dir/lib/libcapstone.a" -AC_MSG_NOTICE([Callgrind cycle estimation enabled with Capstone at $capstone_dir]) -AC_SUBST(CAPSTONE_CFLAGS) -AC_SUBST(CAPSTONE_LIBS) +# CodSpeed: Capstone decoder for Callgrind cycle estimation. See m4/codspeed_capstone.m4. +CODSPEED_CAPSTONE #---------------------------------------------------------------------------- # Detect xcode path @@ -5790,6 +5765,7 @@ CFLAGS=$safe_CFLAGS AC_CONFIG_FILES([ Makefile VEX/Makefile:Makefile.vex.in + third_party/Makefile valgrind.spec valgrind.pc glibc-2.X.supp diff --git a/debian/rules b/debian/rules index c7caefdfe..07fc9a2c8 100644 --- a/debian/rules +++ b/debian/rules @@ -28,8 +28,9 @@ CONFARGS = \ --enable-only64bit \ --with-gdbscripts-dir=/usr/share/gdb/auto-load -# Callgrind cycle estimation requires Capstone; the release workflow builds a -# static decoder and exports its prefix as CAPSTONE_DIR. +# Callgrind cycle estimation needs Capstone. The build compiles the vendored +# third_party/capstone submodule by default; CAPSTONE_DIR, when set, points at a +# prebuilt decoder to use instead. ifneq ($(CAPSTONE_DIR),) CONFARGS += --with-capstone=$(CAPSTONE_DIR) endif diff --git a/flake.nix b/flake.nix index 277c0c31d..c4968cbfd 100644 --- a/flake.nix +++ b/flake.nix @@ -36,8 +36,9 @@ }); in { - # Expose the pinned Capstone so the autotools build and scripts can find - # it via `nix build .#capstone` or the CAPSTONE_DIR env var below. + # Expose the pinned Capstone for the builds that want a prebuilt decoder + # rather than the vendored submodule: `nix build .#capstone`, then pass it + # to configure as --with-capstone=PATH (or CAPSTONE_DIR). packages.capstone = capstone; devShells.default = pkgs.mkShell { @@ -62,10 +63,6 @@ pkgs.gcc pkgs.pkg-config ]; - - # Consumed by configure (--with-capstone), the LUT generator, and the - # standalone cycledecode test. Point them at the hardening-free build. - CAPSTONE_DIR = "${capstone}"; }; } ); diff --git a/m4/codspeed_capstone.m4 b/m4/codspeed_capstone.m4 new file mode 100644 index 000000000..533a6431a --- /dev/null +++ b/m4/codspeed_capstone.m4 @@ -0,0 +1,73 @@ +# codspeed_capstone.m4 -- CodSpeed additions to Valgrind's configure. + +# CODSPEED_CAPSTONE +# ----------------- +# Locate the Capstone decoder that Callgrind's per-instruction cycle +# estimation (--cycle-estimation=yes) links against, and export +# CAPSTONE_CFLAGS / CAPSTONE_LIBS for callgrind/Makefile.am. +# +# By default the vendored submodule in third_party/capstone is compiled by +# third_party/Makefile.am as part of `make`, so a plain +# `./autogen.sh && ./configure && make && make install` is all that is needed. +# --with-capstone=PATH (or the CAPSTONE_DIR environment variable, which `nix +# develop` sets) selects a prebuilt Capstone install instead. +AC_DEFUN([CODSPEED_CAPSTONE], [ +AC_ARG_WITH([capstone], + [AS_HELP_STRING([--with-capstone=PATH], + [use a prebuilt Capstone install for Callgrind cycle estimation instead + of the vendored third_party/capstone submodule. Defaults to the + CAPSTONE_DIR environment variable])], + [capstone_dir="$withval"], + [capstone_dir="$CAPSTONE_DIR"]) + +AM_CONDITIONAL([BUILD_VENDORED_CAPSTONE], [test -z "$capstone_dir"]) + +if test -z "$capstone_dir"; then + # Built by third_party/Makefile.am. Note there is deliberately no check + # for libcapstone.a here: it does not exist yet at configure time. + if test ! -f "$srcdir/third_party/capstone/cs.c"; then + AC_MSG_ERROR([third_party/capstone is empty. Run: + git submodule update --init third_party/capstone +or pass --with-capstone=PATH to use a prebuilt Capstone.]) + fi + CAPSTONE_INCLUDES='-I$(top_srcdir)/third_party/capstone/include' + CAPSTONE_LIBS='$(top_builddir)/third_party/libcapstone.a' + AC_MSG_NOTICE([Callgrind cycle estimation enabled with the vendored Capstone]) +else + if test ! -f "$capstone_dir/lib/libcapstone.a" \ + -o ! -f "$capstone_dir/include/capstone/capstone.h"; then + AC_MSG_ERROR([--with-capstone=$capstone_dir: libcapstone.a or capstone.h not found]) + fi + CAPSTONE_INCLUDES="-I$capstone_dir/include" + CAPSTONE_LIBS="$capstone_dir/lib/libcapstone.a" + AC_MSG_NOTICE([Callgrind cycle estimation enabled with Capstone at $capstone_dir]) +fi + +# Fortify off: the tool links -nodefaultlibs, so glibc's __*_chk fortify +# wrappers are unavailable, and our libc shims (sprintf/snprintf/...) must +# be real definitions, not fortify macro-expansions. +CAPSTONE_CFLAGS="-DCLG_WITH_CAPSTONE -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 $CAPSTONE_INCLUDES" +AC_SUBST([CAPSTONE_CFLAGS]) +AC_SUBST([CAPSTONE_LIBS]) +]) + +# CODSPEED_C_STD_GNU17 +# -------------------- +# Pin the C dialect to gnu17. +# +# AC_PROG_CC under Autoconf 2.70+ selects the newest dialect the compiler +# supports, which is -std=gnu23 on GCC 15+. Under C23, glibc 2.42+ defines +# strchr/strrchr/strstr as _Generic macros, which clash with Callgrind's own +# definitions of those symbols. Appending to CFLAGS is enough to win: Autoconf +# puts its own -std= into $CC, and CFLAGS comes later on the command line. +# +# Must be called after AC_PROG_CC. +AC_DEFUN([CODSPEED_C_STD_GNU17], [ +AC_MSG_CHECKING([whether $CC accepts -std=gnu17]) +codspeed_save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -std=gnu17" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + CFLAGS="$codspeed_save_CFLAGS"]) +]) diff --git a/third_party/Makefile.am b/third_party/Makefile.am new file mode 100644 index 000000000..030898f91 --- /dev/null +++ b/third_party/Makefile.am @@ -0,0 +1,109 @@ +include $(top_srcdir)/Makefile.all.am + +# CodSpeed: the vendored Capstone decoder used by Callgrind's per-instruction +# cycle estimation, built as a convenience library so that a plain `make` +# produces everything Valgrind needs. Skipped when configure was given +# --with-capstone=PATH (or CAPSTONE_DIR), which points at a prebuilt Capstone. +if BUILD_VENDORED_CAPSTONE + +noinst_LIBRARIES = libcapstone.a + +# The submodule sources are not compiled where they live. Automake is +# configured with subdir-objects, so it writes an object next to its source -- +# and in an in-tree build (the only kind Valgrind supports) that is inside the +# capstone checkout, which git would then permanently report as dirty. The .o +# files are covered by Capstone's own .gitignore, but the .deps directories and +# .dirstamp files automake drops beside them are not, and that .gitignore +# belongs to upstream Capstone, not to us. +# +# So each unit below is a one-line stub that #includes the matching +# submodule source, and every build artefact lands in capstone-stubs/, which +# belongs to this repository and is gitignored here. Capstone's own quoted +# #includes still resolve against its own directories, since a quoted include +# is looked up relative to the file that holds the directive. +# +# Only x86 and arm64 are compiled in. This is not just about size: the +# instruction printers for the other targets reference libc symbols that a +# Valgrind tool does not shim, so linking them breaks the tool. +libcapstone_a_SOURCES = \ + capstone-stubs/cs.c \ + capstone-stubs/MCInst.c \ + capstone-stubs/MCInstrDesc.c \ + capstone-stubs/MCRegisterInfo.c \ + capstone-stubs/Mapping.c \ + capstone-stubs/SStream.c \ + capstone-stubs/utils.c \ + capstone-stubs/X86ATTInstPrinter.c \ + capstone-stubs/X86Disassembler.c \ + capstone-stubs/X86DisassemblerDecoder.c \ + capstone-stubs/X86InstPrinterCommon.c \ + capstone-stubs/X86IntelInstPrinter.c \ + capstone-stubs/X86Mapping.c \ + capstone-stubs/X86Module.c \ + capstone-stubs/AArch64BaseInfo.c \ + capstone-stubs/AArch64Disassembler.c \ + capstone-stubs/AArch64InstPrinter.c \ + capstone-stubs/AArch64Mapping.c \ + capstone-stubs/AArch64Module.c + +# The same preprocessor state Capstone's own CMake build produces for +# -DCAPSTONE_ARCHITECTURE_DEFAULT=OFF -DCAPSTONE_X86_SUPPORT=ON +# -DCAPSTONE_ARM64_SUPPORT=ON: the arch loop emits both CAPSTONE__SUPPORT +# and CAPSTONE_HAS_, and CAPSTONE_USE_DEFAULT_ALLOC defaults to ON. +# Callgrind replaces the allocator at runtime via cs_option(CS_OPT_MEM). +libcapstone_a_CPPFLAGS = \ + -I$(srcdir)/capstone/include \ + -DCAPSTONE_X86_SUPPORT \ + -DCAPSTONE_HAS_X86 \ + -DCAPSTONE_ARM64_SUPPORT \ + -DCAPSTONE_HAS_ARM64 \ + -DCAPSTONE_USE_SYS_DYN_MEM + +# Capstone is linked into the primary (native) Callgrind tool, so it must be +# compiled with that platform's flags. AM_CFLAGS_BASE already carries +# -fno-stack-protector (a canary read faults in a tool, which runs without +# glibc's TLS) and the right word size; fortify is turned off here for the +# same reason as in CAPSTONE_CFLAGS. -w because this is third-party code whose +# warnings are not ours to fix. +# +# -DNDEBUG matches what Capstone's own CMake Release build sets, and is load +# bearing: assert() would pull in __assert_fail, which a tool cannot resolve. +libcapstone_a_CFLAGS = \ + $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) \ + -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \ + -DNDEBUG \ + -w + +endif + +# Ship the decoder in `make dist` tarballs: they are unpacked outside a git +# checkout, where the submodule cannot be initialised. Only the stubs above +# are _SOURCES, so everything they pull in has to be named here; listing the +# two arch directories also picks up the .inc tables those sources #include. +# Only the compiled-in architectures are shipped, so this stays at ~18M of the +# submodule's 76M. +EXTRA_DIST = \ + capstone/cs.c \ + capstone/MCInst.c \ + capstone/MCInstrDesc.c \ + capstone/MCRegisterInfo.c \ + capstone/Mapping.c \ + capstone/SStream.c \ + capstone/utils.c \ + capstone/include \ + capstone/arch/X86 \ + capstone/arch/AArch64 \ + capstone/LEB128.h \ + capstone/MCDisassembler.h \ + capstone/MCFixedLenDisassembler.h \ + capstone/MCInst.h \ + capstone/MCInstrDesc.h \ + capstone/MCRegisterInfo.h \ + capstone/Mapping.h \ + capstone/MathExtras.h \ + capstone/SStream.h \ + capstone/cs_priv.h \ + capstone/cs_simple_types.h \ + capstone/utils.h \ + capstone/LICENSE.TXT \ + capstone/LICENSE_LLVM.TXT diff --git a/third_party/capstone-stubs/AArch64BaseInfo.c b/third_party/capstone-stubs/AArch64BaseInfo.c new file mode 100644 index 000000000..33ea3081a --- /dev/null +++ b/third_party/capstone-stubs/AArch64BaseInfo.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/AArch64/AArch64BaseInfo.c" diff --git a/third_party/capstone-stubs/AArch64Disassembler.c b/third_party/capstone-stubs/AArch64Disassembler.c new file mode 100644 index 000000000..ffb6ce8c1 --- /dev/null +++ b/third_party/capstone-stubs/AArch64Disassembler.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/AArch64/AArch64Disassembler.c" diff --git a/third_party/capstone-stubs/AArch64InstPrinter.c b/third_party/capstone-stubs/AArch64InstPrinter.c new file mode 100644 index 000000000..4d30287a5 --- /dev/null +++ b/third_party/capstone-stubs/AArch64InstPrinter.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/AArch64/AArch64InstPrinter.c" diff --git a/third_party/capstone-stubs/AArch64Mapping.c b/third_party/capstone-stubs/AArch64Mapping.c new file mode 100644 index 000000000..d547bc5e4 --- /dev/null +++ b/third_party/capstone-stubs/AArch64Mapping.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/AArch64/AArch64Mapping.c" diff --git a/third_party/capstone-stubs/AArch64Module.c b/third_party/capstone-stubs/AArch64Module.c new file mode 100644 index 000000000..bf10e0297 --- /dev/null +++ b/third_party/capstone-stubs/AArch64Module.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/AArch64/AArch64Module.c" diff --git a/third_party/capstone-stubs/MCInst.c b/third_party/capstone-stubs/MCInst.c new file mode 100644 index 000000000..99b7ed2b0 --- /dev/null +++ b/third_party/capstone-stubs/MCInst.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/MCInst.c" diff --git a/third_party/capstone-stubs/MCInstrDesc.c b/third_party/capstone-stubs/MCInstrDesc.c new file mode 100644 index 000000000..a3bf14de7 --- /dev/null +++ b/third_party/capstone-stubs/MCInstrDesc.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/MCInstrDesc.c" diff --git a/third_party/capstone-stubs/MCRegisterInfo.c b/third_party/capstone-stubs/MCRegisterInfo.c new file mode 100644 index 000000000..184513c5c --- /dev/null +++ b/third_party/capstone-stubs/MCRegisterInfo.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/MCRegisterInfo.c" diff --git a/third_party/capstone-stubs/Mapping.c b/third_party/capstone-stubs/Mapping.c new file mode 100644 index 000000000..4c537a963 --- /dev/null +++ b/third_party/capstone-stubs/Mapping.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/Mapping.c" diff --git a/third_party/capstone-stubs/SStream.c b/third_party/capstone-stubs/SStream.c new file mode 100644 index 000000000..b6377c80b --- /dev/null +++ b/third_party/capstone-stubs/SStream.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/SStream.c" diff --git a/third_party/capstone-stubs/X86ATTInstPrinter.c b/third_party/capstone-stubs/X86ATTInstPrinter.c new file mode 100644 index 000000000..a52937c59 --- /dev/null +++ b/third_party/capstone-stubs/X86ATTInstPrinter.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86ATTInstPrinter.c" diff --git a/third_party/capstone-stubs/X86Disassembler.c b/third_party/capstone-stubs/X86Disassembler.c new file mode 100644 index 000000000..4834687a2 --- /dev/null +++ b/third_party/capstone-stubs/X86Disassembler.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86Disassembler.c" diff --git a/third_party/capstone-stubs/X86DisassemblerDecoder.c b/third_party/capstone-stubs/X86DisassemblerDecoder.c new file mode 100644 index 000000000..3614a8224 --- /dev/null +++ b/third_party/capstone-stubs/X86DisassemblerDecoder.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86DisassemblerDecoder.c" diff --git a/third_party/capstone-stubs/X86InstPrinterCommon.c b/third_party/capstone-stubs/X86InstPrinterCommon.c new file mode 100644 index 000000000..ff24dbf92 --- /dev/null +++ b/third_party/capstone-stubs/X86InstPrinterCommon.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86InstPrinterCommon.c" diff --git a/third_party/capstone-stubs/X86IntelInstPrinter.c b/third_party/capstone-stubs/X86IntelInstPrinter.c new file mode 100644 index 000000000..b7aa5d160 --- /dev/null +++ b/third_party/capstone-stubs/X86IntelInstPrinter.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86IntelInstPrinter.c" diff --git a/third_party/capstone-stubs/X86Mapping.c b/third_party/capstone-stubs/X86Mapping.c new file mode 100644 index 000000000..bdf6e2ceb --- /dev/null +++ b/third_party/capstone-stubs/X86Mapping.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86Mapping.c" diff --git a/third_party/capstone-stubs/X86Module.c b/third_party/capstone-stubs/X86Module.c new file mode 100644 index 000000000..6e157b2a3 --- /dev/null +++ b/third_party/capstone-stubs/X86Module.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/arch/X86/X86Module.c" diff --git a/third_party/capstone-stubs/cs.c b/third_party/capstone-stubs/cs.c new file mode 100644 index 000000000..731d2dbb7 --- /dev/null +++ b/third_party/capstone-stubs/cs.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/cs.c" diff --git a/third_party/capstone-stubs/utils.c b/third_party/capstone-stubs/utils.c new file mode 100644 index 000000000..444f6b3fe --- /dev/null +++ b/third_party/capstone-stubs/utils.c @@ -0,0 +1,2 @@ +/* Stub translation unit: see third_party/Makefile.am. */ +#include "../capstone/utils.c" From 9cea895b633489b2612e73ed86c98788128974fe Mon Sep 17 00:00:00 2001 From: Mohamed Date: Fri, 4 Sep 2026 15:20:01 +0200 Subject: [PATCH 2/2] build(callgrind): relink the tool when Capstone is rebuilt CAPSTONE_LIBS is named in callgrind's _LDADD but not in its _DEPENDENCIES, and automake cannot tell that a configure substitution expands to a file, so it derived no dependency of its own either. Rebuilding the decoder therefore left callgrind- linked against the previous archive, silently, until something else forced a relink. Add it to the _DEPENDENCIES line the fork already sets for the primary platform. The secondary platform has no Capstone and needs nothing. Co-Authored-By: Claude Opus 5 (1M context) --- callgrind/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/callgrind/Makefile.am b/callgrind/Makefile.am index 1e5bcb97d..257c3da06 100644 --- a/callgrind/Makefile.am +++ b/callgrind/Makefile.am @@ -67,7 +67,7 @@ callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = $(LTO_CFLAGS) \ $(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) $(CALLGRIND_CFLAGS_COMMON) \ @CAPSTONE_CFLAGS@ callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \ - $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@) + $(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@) @CAPSTONE_LIBS@ callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD = \ $(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@) @CAPSTONE_LIBS@ callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS = \