Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .github/actions/build-capstone/action.yml

This file was deleted.

67 changes: 63 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
branches: [ master ]
workflow_dispatch:

permissions:
contents: read

jobs:
test-callgrind:
strategy:
Expand Down Expand Up @@ -44,17 +47,13 @@ jobs:
build-essential \
automake \
autoconf \
cmake \
libc6-dev \
gdb \
docbook \
docbook-xsl \
docbook-xml \
xsltproc

- name: Build Capstone (cycle-estimation decoder)
uses: ./.github/actions/build-capstone

- name: Run autogen
run: ./autogen.sh

Expand All @@ -67,6 +66,10 @@ jobs:
- name: Build Valgrind
run: make -j$(nproc)

# The vendored build must not write anything into the submodule checkout.
- name: Check the Capstone submodule is clean
run: test -z "$(git -C third_party/capstone status --porcelain --untracked-files=all)"

- name: Build test dependencies
run: |
make -C tests arch_test os_test true
Expand All @@ -84,3 +87,59 @@ jobs:
with:
name: callgrind-test-logs-${{ matrix.runner.ubuntu-version }}
path: callgrind/tests/*.log

# `make` builds the vendored submodule; this guards the other supported path,
# --with-capstone=PATH, which debian/rules forwards CAPSTONE_DIR to.
build-with-prebuilt-capstone:
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Update apt-get cache
run: sudo apt-get update

- name: Install build dependencies
run: |
sudo apt-get install -y \
build-essential \
automake \
autoconf \
cmake \
libc6-dev

# Not the distribution's libcapstone-dev: a Valgrind tool links
# -nodefaultlibs and runs without glibc's %fs TLS, so the decoder has to
# be built without stack-protector and without fortify, which no distro
# package is.
- name: Build Capstone outside the source tree
run: |
cmake -S third_party/capstone -B "$RUNNER_TEMP/capstone-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="$RUNNER_TEMP/capstone" \
-DCMAKE_C_FLAGS="-fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -fPIC"
cmake --build "$RUNNER_TEMP/capstone-build" -j"$(nproc)"
cmake --install "$RUNNER_TEMP/capstone-build"

- name: Run autogen
run: ./autogen.sh

- name: Configure
run: ./configure --enable-only64bit --with-capstone="$RUNNER_TEMP/capstone"

- name: Build Valgrind
run: make -j$(nproc)

- name: Check cycle estimation
run: |
./vg-in-place --tool=callgrind --cycle-estimation=yes \
--callgrind-out-file=/dev/null /bin/true 2>&1 | grep -q 'Events : Ir Ct Cl'
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

5 changes: 0 additions & 5 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
8 changes: 2 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2567,7 +2567,13 @@ 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-obj/

# install prefix of a Capstone built by hand for --with-capstone
/.capstone

# fake CodSpeed benchmark fixture binary (compiled from testdata/llsc_tzconvert_bench.c)
Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
5 changes: 5 additions & 0 deletions autogen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ 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: check out the Capstone decoder that Callgrind's cycle estimation
# links against, unless a prebuilt one was provided or it is already there.
if test -z "$CAPSTONE_DIR" && test ! -f third_party/capstone/cs.c ; then
run git submodule update --init third_party/capstone
fi
else
echo "skipping: git configuration"
fi
4 changes: 2 additions & 2 deletions callgrind/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
callgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = $(LTO_CFLAGS) \
$(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) $(CALLGRIND_CFLAGS_COMMON) \
@CAPSTONE_CFLAGS@
@CAPSTONE_CFLAGS@ @CODSPEED_C_STD@
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 = \
Expand Down
20 changes: 16 additions & 4 deletions callgrind/cycledecode_capstone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -91,10 +92,11 @@ 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 buffer-overflow guard calls fprintf(stderr, ...), which
* GCC folds into fwrite only when builtins are enabled -- and Valgrind's tool
* CFLAGS pass -fno-builtin. Both are defined, so the tool links against a
* Capstone compiled either way. Valgrind has no FILE* layer, so stderr is a
* sentinel and the bytes are routed to the Valgrind log fd. */
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)
Expand All @@ -103,6 +105,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;
}
Comment thread
moha-bekh marked this conversation as resolved.

size_t strlen(const char* s) { return vgPlain_strlen(s); }
int strcmp(const char* a, const char* b) { return vgPlain_strcmp(a, b); }
Expand All @@ -118,6 +129,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 -*/
Expand Down
36 changes: 6 additions & 30 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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: C dialect for the Callgrind tool. See m4/codspeed_capstone.m4.
CODSPEED_C_STD_GNU17

AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 2 additions & 32 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,21 @@
system:
let
pkgs = import nixpkgs { inherit system; };

# Capstone for the Callgrind cycle-estimation decoder, built the same way
# as the CI workflows (see .github/workflows): x86 + arm64 only, static.
#
# Valgrind tools run without glibc's %fs TLS and link -nodefaultlibs, so
# Capstone must be built without stack-protector (its %fs:0x28 canary
# read faults at runtime) and without fortify (pulls __*_chk libc
# symbols); hardeningDisable drops both. Limiting the architectures also
# drops the non-x86/arm64 instruction printers that reference libc
# symbols (e.g. XCore's strtol) the tool does not shim.
capstone = pkgs.capstone.overrideAttrs (old: {
cmakeFlags = (old.cmakeFlags or [ ]) ++ [
"-DCAPSTONE_ARCHITECTURE_DEFAULT=OFF"
"-DCAPSTONE_X86_SUPPORT=ON"
"-DCAPSTONE_ARM64_SUPPORT=ON"
];
hardeningDisable = (old.hardeningDisable or [ ]) ++ [
"stackprotector"
"fortify"
"fortify3"
];
});
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.
packages.capstone = capstone;

devShells.default = pkgs.mkShell {
# Valgrind tool objects link -nodefaultlibs and run without glibc's %fs
# TLS, so the toolchain must not inject stack-protector or fortify
# (__*_chk) into them. The compiler wrapper otherwise re-adds these
# over our -fno-stack-protector / -D_FORTIFY_SOURCE=0 flags.
# over our -fno-stack-protector / -D_FORTIFY_SOURCE=0 flags. This
# covers the vendored Capstone too, which is compiled into the tool.
hardeningDisable = [
"stackprotector"
"fortify"
"fortify3"
];

packages = [
capstone
pkgs.python3
pkgs.uv
pkgs.autoconf
Expand All @@ -62,10 +36,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}";
};
}
);
Expand Down
Loading
Loading