diff --git a/.github/workflows/build_deb.yml b/.github/workflows/build_deb.yml deleted file mode 100644 index 3caf6a0c28..0000000000 --- a/.github/workflows/build_deb.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Build Debian Package - -on: workflow_dispatch - -jobs: - build: - name: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: true - - - name: Build Debian Package - working-directory: ./packages/deb - run: ./setup.sh "$(git describe --tags --abbrev=0)" - - - name: Run sanity checks on the Debian package - working-directory: ./packages/deb - run: | - ./check_capstone.sh ./libcapstone-dev.deb "$(git describe --tags --abbrev=0)" - - - uses: actions/upload-artifact@v4 - with: - path: ./packages/deb/libcapstone-dev.deb diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index d818270ca8..e6a7de1381 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -15,6 +15,29 @@ jobs: with: submodules: true + - name: Make setup.sh and check_capstone.sh are executable + run: | + chmod +x ./packages/deb/setup.sh + chmod +x ./packages/deb/check_capstone.sh + + - name: Build Debian Package + working-directory: ./packages/deb + run: ./setup.sh ${{ github.event.release.tag_name }} + + - name: Run sanity checks on the Debian package + working-directory: ./packages/deb + run: | + ./check_capstone.sh ./libcapstone-dev_${{ github.event.release.tag_name }}_amd64.deb + + - name: Upload debian package to release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.event.release.tag_name }} + files: | + ./packages/deb/*.deb + - name: Create archive id: archive run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 950a67f3d4..b4c77a7996 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,9 +19,16 @@ endif() # https://cmake.org/cmake/help/latest/policy/CMP0042.html cmake_policy(SET CMP0042 NEW) -project(capstone - VERSION 6.0 -) +# Check if VERSION is provided externally, otherwise default to 6.0.0 +if(NOT DEFINED PROJECT_VERSION) + set(PROJECT_VERSION "6.0.0") +endif() + +# Extract the major, minor, and patch versions +string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" PROJECT_VERSION_BASE ${PROJECT_VERSION}) + +# Set the project version without the pre-release identifier +project(capstone VERSION ${PROJECT_VERSION_BASE}) set(UNIX_COMPILER_OPTIONS -Werror -Wall -Warray-bounds -Wshift-negative-value -Wreturn-type -Wformat -Wmissing-braces -Wunused-function -Warray-bounds -Wunused-variable -Wparentheses -Wint-in-bool-context -Wmisleading-indentation) @@ -855,7 +862,6 @@ source_group("Include\\Xtensa" FILES ${HEADERS_XTENSA}) ## installation if(CAPSTONE_INSTALL) include(GNUInstallDirs) - install(FILES ${HEADERS_COMMON} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/capstone) install(FILES ${HEADERS_INC} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/capstone/inc) diff --git a/HACK.TXT b/HACK.TXT new file mode 100644 index 0000000000..76c56551fc --- /dev/null +++ b/HACK.TXT @@ -0,0 +1,108 @@ +Code structure +-------------- + +Capstone source is organized as followings. + +. <- core engine + README + COMPILE.TXT etc +├── arch <- code handling disasm engine for each arch +│   ├── AArch64 <- ARM64 (aka ARMv8) engine +│   ├── ARM <- ARM engine +│   ├── BPF <- Berkeley Packet Filter engine +│   ├── EVM <- Ethereum engine +│   ├── M680X <- M680X engine +│   ├── M68K <- M68K engine +│   ├── Mips <- Mips engine +│   ├── MOS65XX <- MOS65XX engine +│   ├── PowerPC <- PowerPC engine +│   ├── RISCV <- RISCV engine +│   ├── SH <- SH engine +│   ├── Sparc <- Sparc engine +│   ├── SystemZ <- SystemZ engine +│   ├── TMS320C64x <- TMS320C64x engine +│   ├── TriCore <- TriCore engine +│   └── WASM <- WASM engine +├── bindings <- all bindings are under this dir +│   ├── java <- Java bindings + test code +│   ├── ocaml <- Ocaml bindings + test code +│   └── python <- Python bindings + test code +├── contrib <- Code contributed by community to help Capstone integration +├── cstool <- Cstool +├── docs <- Documentation +├── include <- API headers in C language (*.h) +├── msvc <- Microsoft Visual Studio support (for Windows compile) +├── packages <- Packages for Linux/OSX/BSD. +├── windows <- Windows support (for Windows kernel driver compile) +├── suite <- Development test tools - for Capstone developers only +├── tests <- Test code (in C language) +└── xcode <- Xcode support (for MacOSX compile) + + +Follow instructions in COMPILE.TXT for how to compile and run test code. + +Note: if you find some strange bugs, it is recommended to firstly clean +the code and try to recompile/reinstall again. This can be done with: + + $ ./make.sh + $ sudo ./make.sh install + +Then test Capstone with cstool, for example: + + $ cstool x32 "90 91" + +At the same time, for Java/Ocaml/Python bindings, be sure to always use +the bindings coming with the core to avoid potential incompatibility issue +with older versions. +See bindings//README for detail instructions on how to compile & +install the bindings. + + +Coding style +------------ +- C code follows Linux kernel coding style, using tabs for indentation. +- Python code uses 4 spaces for indentation. + + +Adding an architecture +---------------------- + +Obviously, you first need to write all the logic and put it in a new directory arch/newarch +Then, you have to modify other files. +(You can look for one architecture such as EVM in these files to get what you need to do) + +Integrate: +- cs.c +- cstool/cstool.c +- cstool/cstool_newarch.c: print the architecture specific details +- include/capstone/capstone.h +- include/capstone/newarch.h: create this file to export all specifics about the new architecture + +Compile: +- CMakeLists.txt +- Makefile +- config.mk + +Tests: +- tests/Makefile +- tests/test_basic.c +- tests/test_detail.c +- tests/test_iter.c +- tests/test_newarch.c +- suite/fuzz/platform.c: add the architecture and its modes to the list of fuzzed platforms +- suite/capstone_get_setup.c +- suite/MC/newarch/mode.mc: samples +- suite/test_corpus.py: correspondence between architecture and mode as text and architecture number for fuzzing + +Bindings: +- bindings/Makefile +- bindings/const_generator.py: add the header file and the architecture +- bindings/python/Makefile +- bindings/python/capstone/__init__.py +- bindings/python/capstone/newarch.py: define the python structures +- bindings/python/capstone/newarch_const.py: generate this file +- bindings/python/test_newarch.py: create a basic decoding test +- bindings/python/test_all.py + +Docs: +- README.md +- HACK.txt +- CREDITS.txt: add your name diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000000..0dabdc749e --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,31 @@ +This is the software license for Capstone disassembly framework. +Capstone has been designed & implemented by Nguyen Anh Quynh + +See http://www.capstone-engine.org for further information. + +Copyright (c) 2013, COSEINC. +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 the developer(s) 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 THE COPYRIGHT HOLDER 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. diff --git a/capstone.pc.in b/capstone.pc.in index 533a23493a..b6f5fb8d79 100644 --- a/capstone.pc.in +++ b/capstone.pc.in @@ -11,4 +11,3 @@ archive=${libdir}/libcapstone.a Libs: -L${libdir} -lcapstone Libs.private: -L${libdir} -l:libcapstone.a Cflags: -I${includedir} -I${includedir}/capstone -archs=@CAPSTONE_ARCHITECTURES@ diff --git a/packages/deb/Dockerfile b/packages/deb/Dockerfile index ba833b1870..e6e8ce8a2f 100644 --- a/packages/deb/Dockerfile +++ b/packages/deb/Dockerfile @@ -16,7 +16,8 @@ WORKDIR /capstone/ # Using cmake, see BUILDING.md file # For debug build change "Release" to "Debug" -RUN cmake -B build -DCMAKE_BUILD_TYPE=Release -DCAPSTONE_BUILD_SHARED_LIBS=1 +ARG VERSION +RUN cmake -B build -DCMAKE_BUILD_TYPE=Release -DCAPSTONE_BUILD_SHARED_LIBS=1 -DPROJECT_VERSION=${VERSION} -DCMAKE_INSTALL_PREFIX=/usr RUN cmake --build build # List files before cmake install @@ -26,6 +27,7 @@ RUN cmake --build build RUN mkdir -p /package-root/usr/include/capstone/ RUN mkdir -p /package-root/usr/lib/pkgconfig/ RUN mkdir -p /package-root/usr/bin/ +RUN mkdir -p /package-root/usr/share/doc/libcapstone-dev # Run cmake install RUN cmake --install build --prefix /package-root/usr/ @@ -36,18 +38,29 @@ RUN cmake --install build --prefix /package-root/usr/ # Create DEBIAN directory and control file COPY ./packages/deb/control /package-root/DEBIAN/control -# Update capstone.pc file with the correct version and remove archs field -# Update control file with the correct version +# Copy documentation over +COPY ./ChangeLog /package-root/usr/share/doc/libcapstone-dev +COPY ./CREDITS.TXT /package-root/usr/share/doc/libcapstone-dev +COPY ./HACK.TXT /package-root/usr/share/doc/libcapstone-dev +COPY ./LICENSE.TXT /package-root/usr/share/doc/libcapstone-dev +COPY ./README.md /package-root/usr/share/doc/libcapstone-dev +COPY ./SPONSORS.TXT /package-root/usr/share/doc/libcapstone-dev + +# Generate MD5 checksums for all files and save to DEBIAN/md5sums +RUN cd /package-root && \ + find . -type f ! -path './DEBIAN/*' -exec md5sum {} + | sed 's| \./| |' > /package-root/DEBIAN/md5sums + +# Update control file with the correct information ARG VERSION +RUN INSTALLED_SIZE=$(du -sk /package-root | cut -f1) && \ + sed -i "s/^Installed-Size:.*/Installed-Size: ${INSTALLED_SIZE}/" /package-root/DEBIAN/control RUN sed -i "s/^Version:.*/Version: ${VERSION}/" /package-root/DEBIAN/control -RUN sed -i "s/^Version:.*/Version: ${VERSION}/" /package-root/usr/lib/pkgconfig/capstone.pc -RUN sed -i "/^archs=/d" /package-root/usr/lib/pkgconfig/capstone.pc # Add triggers script to run ldconfig after installation COPY ./packages/deb/triggers /package-root/DEBIAN/triggers # Build the package -RUN fakeroot dpkg-deb --build /package-root /libcapstone-dev.deb +RUN fakeroot dpkg-deb --build /package-root /libcapstone-dev_${VERSION}_amd64.deb # The user can now extract the .deb file from the container with something like # docker run --rm -v $(pwd):/out packager bash -c "cp /libcapstone-dev.deb /out" diff --git a/packages/deb/README.md b/packages/deb/README.md deleted file mode 100644 index fc79aa4e0e..0000000000 --- a/packages/deb/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Incomplete Debian package implementation. -It can be used to generate an easily installable Capstone, but misses a lot of -mandatory things to add it in the Debian repos (`debian/control` is incomplete, no dependencies added etc.). - -You can build the package by dispatching the `Build Debian Package` workflow or executing the commands in the `Dockerfile`. -It assumes the current commit is tagged and `"$(git describe --tags --abbrev=0)"` returns a valid version number. -The package is uploaded as artifact. diff --git a/packages/deb/check_capstone.sh b/packages/deb/check_capstone.sh index 4460f41846..deb791b4d4 100755 --- a/packages/deb/check_capstone.sh +++ b/packages/deb/check_capstone.sh @@ -1,9 +1,13 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2024 Andrew Quijano +# Contact: andrewquijano92@gmail.com + #!/bin/bash +set -eu -# Usage: ./check_capstone_pc.sh +# Usage: ./check_capstone_pc.sh DEB_FILE=$1 -EXPECTED_VERSION=$2 # Check if the deb file exists if [[ ! -f "$DEB_FILE" ]]; then @@ -17,38 +21,16 @@ TEMP_DIR=$(mktemp -d) # Extract the deb file dpkg-deb -x "$DEB_FILE" "$TEMP_DIR" -# Path to the capstone.pc file -CAPSTONE_PC="$TEMP_DIR/usr/lib/pkgconfig/capstone.pc" - # Check if the capstone.pc file exists +CAPSTONE_PC="$TEMP_DIR/usr/lib/x86_64-linux-gnu/pkgconfig/capstone.pc" if [[ ! -f "$CAPSTONE_PC" ]]; then echo "capstone.pc file not found in the package!" rm -rf "$TEMP_DIR" exit 1 fi -# Remove leading 'v' if present, e. g. v1.5.1 -> 1.5.1 -if [[ "$EXPECTED_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - EXPECTED_VERSION=${EXPECTED_VERSION:1} -fi - -# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 -if [[ ! "$EXPECTED_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "ERROR: Version must be in the format X.Y.Z" - exit 1 -fi - - -# Check the version in the capstone.pc file -ACTUAL_VERSION=$(grep "^Version:" "$CAPSTONE_PC" | awk '{print $2}') -if [[ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]]; then - echo "Version mismatch! Expected: $EXPECTED_VERSION, Found: $ACTUAL_VERSION" - rm -rf "$TEMP_DIR" - exit 1 -fi - # Check if libcapstone.a is included in the package -LIBCAPSTONE_A="$TEMP_DIR/usr/lib/libcapstone.a" +LIBCAPSTONE_A="$TEMP_DIR/usr/lib/x86_64-linux-gnu/libcapstone.a" if [[ ! -f "$LIBCAPSTONE_A" ]]; then echo "libcapstone.a not found in the package!" rm -rf "$TEMP_DIR" @@ -56,7 +38,7 @@ if [[ ! -f "$LIBCAPSTONE_A" ]]; then fi # Check if libcapstone.so is included in the package -LIBCAPSTONE_SO="$TEMP_DIR/usr/lib/libcapstone.so" +LIBCAPSTONE_SO="$TEMP_DIR/usr/lib/x86_64-linux-gnu/libcapstone.so" if [[ ! -f "$LIBCAPSTONE_SO" ]]; then echo "libcapstone.so not found in the package!" rm -rf "$TEMP_DIR" diff --git a/packages/deb/control b/packages/deb/control index 97e7aa26b4..440f21547c 100644 --- a/packages/deb/control +++ b/packages/deb/control @@ -1,8 +1,25 @@ -Package: capstone +Package: libcapstone-dev +Source: capstone Version: -Architecture: all +Architecture: amd64 Maintainer: Rot127 -Description: Capstone is a lightweight multi-platform, multi-architecture disassembly framework. - Capstone supports the following frameworks; - Alpha, BPF, Ethereum VM, HPPA, LoongArch, M68K, M680X, Mips, MOS65XX, PPC, RISC-V(rv32G/rv64G), - SH, Sparc, SystemZ, TMS320C64X, TriCore, Webassembly, XCore and X86. +Original-Maintainer: Debian Security Tools +Installed-Size: +Depends: libc6 (>= 2.2.5) +Section: libdevel +Priority: optional +Multi-Arch: same +Homepage: https://www.capstone-engine.org/ +Description: lightweight multi-architecture disassembly framework - devel files + Capstone is a lightweight multi-platform, multi-architecture disassembly + framework. These are the development headers and libraries. + Features: + - Support hardware architectures: AArch64, ARM, Alpha, BPF, EVM, HPPA, LongArch, M680X, M68K, MOS65XX, Mips, PowerPC, RISCV, SH, Sparc, SystemZ, TMS320C64x, TriCore, WASM, x86, XCore, Xtensa. + - Clean/simple/lightweight/intuitive architecture-neutral API. + - Provide details on disassembled instructions (called "decomposer" by some + others). + - Provide some semantics of the disassembled instruction, such as list of + implicit registers read & written. + - Thread-safe by design. + - Special support for embedding into firmware or OS kernel. + - Distributed under the open source BSD license. diff --git a/packages/deb/setup.sh b/packages/deb/setup.sh index a3595dfd2c..6c7f71bb45 100755 --- a/packages/deb/setup.sh +++ b/packages/deb/setup.sh @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: MIT +# Copyright (C) 2024 Andrew Quijano +# Contact: andrewquijano92@gmail.com + # !/bin/bash set -eu @@ -33,10 +37,10 @@ if [[ "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then version=${version:1} fi -# Check if the version follows the format X.Y.Z, e. g. 1.5.1 or 1.9.1 -if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "ERROR: Version must be in the format X.Y.Z" - exit 1 +# Check if the version follows the format for Debian Packages +if [[ ! "$version" =~ ^[0-9]+(.[0-9]+)*(-[A-Za-z0-9]+)?$ ]]; then + echo "ERROR: Version must be in a valid Debian package format" + exit 1 fi # Now build the packager container from that @@ -45,7 +49,7 @@ docker build -f ./packages/deb/Dockerfile -t packager --build-arg VERSION="${ver popd # Copy deb file out of container to host -docker run --rm -v $(pwd):/out packager bash -c "cp /libcapstone-dev.deb /out" +docker run --rm -v $(pwd):/out packager bash -c "cp /*.deb /out" # Check which files existed before and after 'make install' was executed. # docker run --rm -v $(pwd):/out packager bash -c "cp /before-install.txt /out"