mirror of
https://github.com/pwndbg/linux-exploit-dev-env.git
synced 2026-11-13 18:59:53 -10:00
437 lines
15 KiB
Makefile
437 lines
15 KiB
Makefile
ifneq (,$(wildcard ./.env))
|
|
include .env
|
|
endif
|
|
|
|
ROOT_DIR := $(CURDIR)
|
|
OUT_DIR := $(ROOT_DIR)/out
|
|
SCRIPT_DIR := $(ROOT_DIR)/scripts
|
|
CONFIG_DIR := $(ROOT_DIR)/config
|
|
CLANG_DIR ?= $(ROOT_DIR)/toolchain/clang
|
|
|
|
CLANG_URL := https://github.com/llvm/llvm-project/releases/download/llvmorg-15.0.6/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
|
|
|
SHARED_DIR := $(ROOT_DIR)/shared
|
|
|
|
VERBOSE ?= 0
|
|
|
|
ARCH ?= x86_64
|
|
|
|
GREEN := $(shell tput setaf 2)
|
|
YELLOW := $(shell tput setaf 3)
|
|
NC := $(shell tput sgr0)
|
|
|
|
ifeq ($(ARCH),aarch64)
|
|
$(warning $(YELLOW)Incorrect architecture 'aarch64', using 'arm64' instead $(NC))
|
|
ARCH := arm64
|
|
else ifeq ($(ARCH),x86)
|
|
$(warning $(YELLOW)Incorrect architecture 'x86', using 'x86_64' instead $(NC))
|
|
ARCH := x86_64
|
|
else ifeq ($(filter x86_64 arm64 i386,$(ARCH)),)
|
|
$(error Invalid architecture $(ARCH))
|
|
endif
|
|
|
|
.PHONY: default
|
|
default: linux tools-vm
|
|
|
|
.PHONY: clean
|
|
clean: linux_clean tools-vm_clean
|
|
|
|
.PHONY: help
|
|
help:
|
|
@echo '$(GREEN)General Environment Variables:$(NC)'
|
|
@echo ' ARCH - Specify one of the supported architectures: x86_64, i386, arm64 (default: x86_64)'
|
|
@echo ' ACK - Set to 1 to build ACK instead of the Linux kernel. Does not need to be set for `ack` and `run-ack` targets (default: 0)'
|
|
@echo ' VERBOSE - Set to 1 to enable verbose output (default: 0)'
|
|
@echo ''
|
|
@echo '$(GREEN)Build/Config:$(NC)'
|
|
@echo ' Targets:'
|
|
@echo ' linux (default) - Build the Linux kernel'
|
|
@echo ' linux_defconfig - Run `make defconfig`'
|
|
@echo ' linux_menuconfig - Run `make menuconfig`'
|
|
@echo ' linux_modules - Build the Linux kernel modules'
|
|
@echo ' linux_debpkg - Creates a Debian package for the kernel'
|
|
@echo ' ack - Build the Android Common Kernel'
|
|
@echo ' tools-vm - Build linux/tools/vm'
|
|
@echo ''
|
|
@echo ' Environment Variables:'
|
|
@echo ' LINUX_DEFCONFIG - The defconfig to use when building the kernel (default: defconfig, ACK default: gki_defconfig)'
|
|
@echo ' LINUX_SRC - The path to the kernel source directory (default: linux, ACK default: ack/common)'
|
|
@echo ' LINUX_OUT - The path where the kernel build output should be stored (default: out/linux/$$ARCH, ACK default: out/ack/common/$$ARCH)'
|
|
@echo ' LINUX_CONFIG_FRAGMENT - A kernel config fragment to merge with the defconfig (default: config/config.fragment)'
|
|
@echo ''
|
|
@echo '$(GREEN)Clean:$(NC)'
|
|
@echo ' Targets:'
|
|
@echo ' clean - Clean output from default build targets'
|
|
@echo ' <target>_clean - Clean output for <target>, where <target> is one of: ack, linux, tools-vm, rootfs'
|
|
@echo ''
|
|
@echo '$(GREEN)Run/Debug:$(NC)'
|
|
@echo ' Targets:'
|
|
@echo ' run - Run QEMU with the built kernel and rootfs image'
|
|
@echo ' run-ack - Same as `run` but runs ACK instead'
|
|
@echo ''
|
|
@echo ' Environment Variables:'
|
|
@echo ' GDB - Set to 1 to start a gdbserver and wait for GDB when running QEMU (default: 0)'
|
|
@echo ' CPU - The number of CPUs to use when running QEMU (default: 4)'
|
|
@echo ' MEM - The memory size in MB to use when running QEMU (default: 1024)'
|
|
@echo ' QEMU_EXTRA_ARGS - Additional arguments to pass to QEMU (default: "")'
|
|
@echo ' QEMU_EXTRA_KERNEL_CMDLINE - Additional arguments to pass to the kernel (default: "")'
|
|
@echo ' QEMU_KERNEL_IMAGE - The path to the kernel image to run (x86_64/i386 default: $$LINUX_OUT/arch/$$ARCH/boot/bzImage, arm64 default: $$LINUX_OUT/arch/$$ARCH/boot/Image)'
|
|
@echo ' ROOTFS - The path to the rootfs image file (default: rootfs/alpine-$$ARCH.img)'
|
|
@echo ' ROOTFS_FORMAT - The format of the rootfs image file: raw, qcow2 (default: qcow2)'
|
|
@echo ' INITRD - Set to 1 to use the $$CPIO_FILE initramfs instead of the $$ROOTFS image as the rootfs, or specify the path to an alternative CPIO file (default: "")'
|
|
@echo ' RDINIT - The value of the `rdinit` kernel command line parameter (default: "", default if INITRD is set: /sbin/init)'
|
|
@echo ' ECHR - The value of the QEMU `-echr` flag (default: 1)'
|
|
@echo ' ROOT - The value of the `root` kernel command line parameter (default: /dev/vda)'
|
|
@echo ' RW - Whether to mount the rootfs as read-write or read-only: ro, rw (default: rw)'
|
|
@echo ' KASLR - Set to 1 to enable KASLR (default: 0)'
|
|
@echo ''
|
|
@echo '$(GREEN)rootfs:$(NC)'
|
|
@echo ' Targets:'
|
|
@echo ' rootfs-init - Extract the Alpine Linux rootfs to $$ROOTFS_DIR and then run the `rootfs-overlay` target'
|
|
@echo ' rootfs-overlay - Apply arch-specific changes to $$ROOTFS_DIR and run the `rootfs` target'
|
|
@echo ' rootfs - Run the `ext4` and `cpio` targets'
|
|
@echo ' ext4 - Build a $$ROOTFS $$ROOTFS_FORMAT (default qcow2) image with an ext4 filesystem from $$ROOTFS_DIR'
|
|
@echo ' cpio - Build a $$CPIO_FILE gzipped initramfs CPIO file from $$ROOTFS_DIR'
|
|
@echo ' initramfs - An alias for the `cpio` target'
|
|
@echo ' uncpio - Extract $$CPIO_FILE to $$ROOTFS_DIR'
|
|
@echo ' rootfs-mount - Mount $$ROOTFS image at /tmp/rootfs'
|
|
@echo ' rootfs-unmount - Unmount rootfs image from /tmp/rootfs'
|
|
@echo ' chroot - chroot into $$ROOTFS_DIR'
|
|
@echo ''
|
|
@echo ' Environment Variables:'
|
|
@echo ' EXT4_SIZE - The disk size of the rootfs image to build'
|
|
@echo ' ROOTFS_DIR - The directory to create the ext4 rootfs image and initramfs CPIO from (default: rootfs/alpine-$$ARCH)'
|
|
@echo ' ROOTFS - The path to the rootfs image file (default: rootfs/alpine-$$ARCH.img)'
|
|
@echo ' ROOTFS_FORMAT - The format of the rootfs image file: raw, qcow2 (default: qcow2)'
|
|
@echo ' CPIO_FILE - The path to the CPIO file to create (default: rootfs/alpine-$$ARCH.cpio.gz)'
|
|
@echo ''
|
|
@echo '$(GREEN)Miscellaneous:$(NC)'
|
|
@echo ' Targets:'
|
|
@echo ' linux_download - Downloads an archive of the Linux kernel source for the version specified in $$VERSION'
|
|
@echo ' linux_checkout - Checks out the version specified by $$VERSION of the linux kernel in $$LINUX_SRC'
|
|
@echo ''
|
|
@echo ' Environment Variables:'
|
|
@echo " VERSION - The version to download or checkout. For checkout only, if the third number in the version string is a 'y', the latest version of the kernel with that major and minor version is used. Examples: 5.10, 5.10.107, v5.10, 5.10.y, linux-5.10.y"
|
|
|
|
$(SHARED_DIR):
|
|
mkdir -p $(SHARED_DIR)
|
|
|
|
##
|
|
## Linux Kernel and Android Common Kernel
|
|
##
|
|
|
|
ACK_TARGETS := ack ack_clean run-ack
|
|
ACK ?= 0
|
|
|
|
ACK_SRC := $(ROOT_DIR)/ack/common
|
|
ACK_OUT := $(OUT_DIR)/ack/common/$(ARCH)
|
|
|
|
ifneq ($(filter $(ACK_TARGETS),$(MAKECMDGOALS)),)
|
|
ACK := 1
|
|
endif
|
|
|
|
# If we're building ACK instead of Linux, set the appropriate variables
|
|
ifeq ($(ACK),1)
|
|
LINUX_SRC ?= $(ACK_SRC)
|
|
LINUX_OUT ?= $(ACK_OUT)
|
|
LINUX_DEFCONFIG ?= gki_defconfig
|
|
else
|
|
LINUX_SRC ?= $(ROOT_DIR)/linux
|
|
LINUX_OUT ?= $(OUT_DIR)/linux/$(ARCH)
|
|
LINUX_DEFCONFIG ?= defconfig
|
|
endif
|
|
|
|
LINUX_CONFIG_FRAGMENT ?= $(CONFIG_DIR)/config.fragment
|
|
LINUX_OUT_MODULES_DEP := $(LINUX_OUT)/modules_install.stamp
|
|
LINUX_MODULES_INSTALL_PATH := $(LINUX_OUT)/modules_install
|
|
LINUX_CONFIG := $(LINUX_OUT)/.config
|
|
|
|
ifeq ($(ARCH),x86_64)
|
|
TARGET := x86_64-pc-linux-gnu
|
|
KERNEL_IMAGE := $(LINUX_OUT)/arch/$(ARCH)/boot/bzImage
|
|
else ifeq ($(ARCH),i386)
|
|
TARGET := i386-pc-linux-gnu
|
|
KERNEL_IMAGE := $(LINUX_OUT)/arch/$(ARCH)/boot/bzImage
|
|
else ifeq ($(ARCH),arm64)
|
|
TARGET := aarch64-linux-gnu
|
|
KERNEL_IMAGE := $(LINUX_OUT)/arch/$(ARCH)/boot/Image
|
|
endif
|
|
|
|
LINUX_MAKE := \
|
|
PATH=$(CLANG_DIR)/bin:$(PATH) \
|
|
$(MAKE) \
|
|
-C $(LINUX_SRC) \
|
|
ARCH=$(ARCH) \
|
|
CROSS_COMPILE=$(TARGET)- \
|
|
LLVM=1 LLVM_IAS=1 \
|
|
V=$(VERBOSE) \
|
|
O=$(LINUX_OUT) \
|
|
-j `nproc`
|
|
|
|
$(CLANG_DIR):
|
|
$(warning $(YELLOW)Clang directory $(CLANG_DIR) does not exist, downloading prebuilt binaries $(NC))
|
|
wget --no-verbose --show-progress $(CLANG_URL) -O clang.tar.xz
|
|
mkdir -p $(CLANG_DIR)
|
|
tar -xf clang.tar.xz -C $(CLANG_DIR) --strip-components=1
|
|
|
|
.PHONY: linux_defconfig
|
|
linux_defconfig $(LINUX_CONFIG): $(LINUX_CONFIG_FRAGMENT) | $(CLANG_DIR)
|
|
+ $(LINUX_MAKE) $(LINUX_DEFCONFIG)
|
|
KCONFIG_CONFIG=$(LINUX_CONFIG) \
|
|
$(LINUX_SRC)/scripts/kconfig/merge_config.sh \
|
|
-m \
|
|
$(LINUX_CONFIG) \
|
|
$(LINUX_CONFIG_FRAGMENT)
|
|
+ $(LINUX_MAKE) olddefconfig
|
|
$(SCRIPT_DIR)/check_merged_config.sh $(LINUX_CONFIG) $(LINUX_CONFIG_FRAGMENT)
|
|
|
|
.PHONY: linux_menuconfig
|
|
linux_menuconfig:
|
|
+ $(LINUX_MAKE) menuconfig
|
|
$(SCRIPT_DIR)/check_merged_config.sh $(LINUX_CONFIG) $(LINUX_CONFIG_FRAGMENT)
|
|
|
|
.PHONY: linux
|
|
linux $(KERNEL_IMAGE): $(LINUX_CONFIG) | $(CLANG_DIR)
|
|
+ $(LINUX_MAKE)
|
|
# Older versions of Linux don't have this script
|
|
ifneq (,$(wildcard ./.env))
|
|
$(LINUX_SRC)/scripts/clang-tools/gen_compile_commands.py -d $(LINUX_OUT)
|
|
endif
|
|
|
|
|
|
.PHONY: linux_modules
|
|
linux_modules $(LINUX_OUT_MODULES_DEP): $(KERNEL_IMAGE)
|
|
+ $(LINUX_MAKE) modules
|
|
+ $(LINUX_MAKE) INSTALL_MOD_PATH=$(LINUX_MODULES_INSTALL_PATH) modules_install
|
|
@find $(LINUX_MODULES_INSTALL_PATH) -type f | sort | \
|
|
xargs sha1sum > $(LINUX_OUT_MODULES_DEP).tmp
|
|
@cmp $(LINUX_OUT_MODULES_DEP).tmp $(LINUX_OUT_MODULES_DEP) || \
|
|
mv $(LINUX_OUT_MODULES_DEP).tmp $(LINUX_OUT_MODULES_DEP)
|
|
|
|
.PHONY: linux_clean
|
|
linux_clean:
|
|
+ $(LINUX_MAKE) mrproper
|
|
|
|
.PHONY: linux_download
|
|
linux_download:
|
|
ifndef VERSION
|
|
$(error VERSION environment variable is not defined)
|
|
endif
|
|
$(SCRIPT_DIR)/download_linux.sh $(VERSION) $(ACK)
|
|
|
|
.PHONY: linux_checkout
|
|
linux_checkout:
|
|
ifndef VERSION
|
|
$(error VERSION environment variable is not defined)
|
|
endif
|
|
$(SCRIPT_DIR)/checkout_linux.sh $(VERSION) $(LINUX_SRC)
|
|
|
|
# Use xz compression instead of zstd, as the latter is not supported by some
|
|
# versions of dpkg.
|
|
.PHONY: linux_debpkg
|
|
linux_debpkg: $(KERNEL_IMAGE)
|
|
+ $(LINUX_MAKE) KDEB_COMPRESS=xz bindeb-pkg
|
|
|
|
|
|
# These targets do the same thing as the `linux` targets, but because they're in
|
|
# `ACK_TARGETS`, the `ACK` variable is set to 1 and the ACK source and output
|
|
# directories are used instead of the Linux directories. The same thing can be
|
|
# achieved by setting the `ACK=1` environment variable, so these are just
|
|
# provided for convenience.
|
|
.PHONY: ack
|
|
ack: linux
|
|
|
|
.PHONY: ack_clean
|
|
ack_clean: linux_clean
|
|
|
|
# Because of how `tools/vm/Makefile` is designed, we can't use `$(LINUX_MAKE)`
|
|
# here, as specifying the `O` variable causes compilation errors, and `clang`
|
|
# won't properly cross-compile the binary so we need to use GCC
|
|
TOOLS_MAKE := $(MAKE) \
|
|
-C $(LINUX_SRC)/tools \
|
|
DESTDIR=$(SHARED_DIR) \
|
|
sbindir=/tools/$(ARCH)
|
|
|
|
# Assuming we're building on an x86 system, we should only set `CROSS_COMPILE`
|
|
# if we're building arm64.
|
|
ifeq ($(ARCH),arm64)
|
|
TOOLS_MAKE += CROSS_COMPILE=$(TARGET)-
|
|
endif
|
|
|
|
.PHONY: tools-vm
|
|
tools-vm: | $(SHARED_DIR)
|
|
+ $(TOOLS_MAKE) vm_install
|
|
|
|
.PHONY: tools-vm_clean
|
|
tools-vm_clean:
|
|
+ $(TOOLS_MAKE) vm_clean
|
|
rm -f $(SHARED_DIR)/tools/$(ARCH)/{page_owner_sort,page-types,slabinfo}
|
|
|
|
##
|
|
## Generate rootfs images
|
|
##
|
|
|
|
ROOTFS_PARENT_DIR := $(ROOT_DIR)/rootfs
|
|
ROOTFS ?= $(ROOTFS_PARENT_DIR)/$$(basename $(ROOTFS_DIR)).img
|
|
ROOTFS_FORMAT ?= qcow2
|
|
ROOTFS_DIR ?= $(ROOTFS_PARENT_DIR)/alpine-$(ARCH)
|
|
CPIO_FILE ?= $(ROOTFS_PARENT_DIR)/$$(basename $(ROOTFS_DIR)).cpio.gz
|
|
EXT4_SIZE ?= 1G
|
|
ifeq ($(SUDO),1)
|
|
SUDO := sudo
|
|
endif
|
|
|
|
# The user might set a relative path for `CPIO_FILE`, so we need to get the
|
|
# absolute path, as we need to reference it after we've changed directories
|
|
CPIO_FILE := $(shell realpath $(CPIO_FILE))
|
|
|
|
$(ROOTFS_DIR):
|
|
mkdir -p $(ROOTFS_DIR)
|
|
|
|
.PHONY: rootfs-init
|
|
rootfs-init: | $(ROOTFS_DIR)
|
|
tar -xf $(ROOTFS_PARENT_DIR)/alpine-minirootfs-*-$(ARCH).tar.gz -C $(ROOTFS_DIR)
|
|
$(MAKE) rootfs-overlay
|
|
|
|
.PHONY: rootfs-overlay
|
|
rootfs-overlay: | $(ROOTFS_DIR)
|
|
$(SUDO) cp -f -r $(CONFIG_DIR)/rootfs-overlay/. $(ROOTFS_DIR)
|
|
$(SUDO) $(SCRIPT_DIR)/arch_specific.sh $(ARCH) $(ROOTFS_DIR)
|
|
$(MAKE) rootfs
|
|
|
|
.PHONY: ext4
|
|
ext4: | $(ROOTFS_DIR)
|
|
dd if=/dev/zero of=$(ROOTFS) bs=1 count=0 seek=$(EXT4_SIZE)
|
|
$(SUDO) mkfs.ext4 -b 4096 -d $(ROOTFS_DIR) -F $(ROOTFS)
|
|
qemu-img convert -O $(ROOTFS_FORMAT) $(ROOTFS) $(ROOTFS).tmp
|
|
mv $(ROOTFS).tmp $(ROOTFS)
|
|
|
|
.PHONY: cpio initramfs
|
|
initramfs cpio: | $(ROOTFS_DIR)
|
|
(cd $(ROOTFS_DIR) && $(SUDO) find . -print0 \
|
|
| $(SUDO) cpio --null --create --verbose --format=newc) \
|
|
| gzip --best > $(CPIO_FILE)
|
|
|
|
.PHONY: uncpio
|
|
uncpio: | $(ROOTFS_DIR)
|
|
cd $(ROOTFS_DIR) && zcat $(CPIO_FILE) | $(SUDO) cpio --extract --make-directories --format=newc --no-absolute-filenames
|
|
|
|
.PHONY: rootfs
|
|
rootfs: ext4 cpio
|
|
|
|
.PHONY: rootfs-mount
|
|
rootfs-mount:
|
|
sudo modprobe nbd
|
|
sudo qemu-nbd -c /dev/nbd0 -f $(ROOTFS_FORMAT) $(ROOTFS)
|
|
mkdir -p /tmp/rootfs
|
|
sudo mount /dev/nbd0 /tmp/rootfs
|
|
|
|
.PHONY: rootfs-unmount
|
|
rootfs-unmount:
|
|
sudo umount /dev/nbd0
|
|
sudo qemu-nbd -d /dev/nbd0
|
|
|
|
.PHONY: chroot
|
|
chroot:
|
|
sudo chroot $(ROOTFS_DIR) /bin/sh
|
|
|
|
.PHONY: rootfs_clean
|
|
rootfs_clean:
|
|
$(SUDO) rm -rf $(ROOTFS_DIR)
|
|
$(SUDO) rm -f $(CPIO_FILE)
|
|
$(SUDO) rm -f $(ROOTFS)
|
|
|
|
##
|
|
## Run QEMU
|
|
##
|
|
|
|
CPU ?= 4
|
|
MEM ?= 1024
|
|
QEMU_EXTRA_ARGS ?=
|
|
QEMU_EXTRA_KERNEL_CMDLINE ?=
|
|
GDB ?= 0
|
|
INITRD ?=
|
|
RDINIT ?= /sbin/init
|
|
QEMU_KERNEL_IMAGE ?= $(KERNEL_IMAGE)
|
|
ECHR ?= 1
|
|
ROOT ?= /dev/vda
|
|
RW ?= rw
|
|
KASLR ?= 0
|
|
|
|
QEMU_KERNEL_CMDLINE := selinux=0
|
|
|
|
QEMU_ARGS := \
|
|
-m $(MEM) \
|
|
-smp $(CPU) \
|
|
-nographic \
|
|
-no-reboot \
|
|
-kernel $(QEMU_KERNEL_IMAGE) \
|
|
-netdev user,id=eth0,hostfwd=tcp::7777-:7777,hostfwd=tcp::2222-:22,hostfwd=tcp::2223-:23 -device virtio-net-pci,netdev=eth0 \
|
|
-virtfs local,security_model=mapped-xattr,path=$(SHARED_DIR),mount_tag=shared \
|
|
-echr $(ECHR) \
|
|
$(QEMU_EXTRA_ARGS)
|
|
|
|
ifneq ($(INITRD),)
|
|
ifeq ($(INITRD),1)
|
|
INITRD := $(CPIO_FILE)
|
|
endif
|
|
QEMU_KERNEL_CMDLINE += rdinit=$(RDINIT)
|
|
QEMU_ARGS += -initrd $(INITRD)
|
|
else
|
|
QEMU_ARGS += -drive file=$(ROOTFS),if=virtio,format=$(ROOTFS_FORMAT)
|
|
QEMU_KERNEL_CMDLINE += root=$(ROOT) $(RW)
|
|
endif
|
|
|
|
ifeq ($(GDB),1)
|
|
QEMU_ARGS += -s -S
|
|
endif
|
|
|
|
ifeq ($(ARCH),x86_64)
|
|
QEMU_BIN := qemu-system-x86_64
|
|
QEMU_KERNEL_CMDLINE += console=ttyS0 kpti no5lvl
|
|
|
|
QEMU_ARGS += -cpu kvm64,+smep,+smap
|
|
|
|
# We can't use KVM with GitHub Actions CI
|
|
ifneq ($(CI),true)
|
|
QEMU_ARGS += -accel kvm
|
|
endif
|
|
else ifeq ($(ARCH),i386)
|
|
QEMU_BIN := qemu-system-i386
|
|
QEMU_KERNEL_CMDLINE += console=ttyS0
|
|
else
|
|
QEMU_BIN := qemu-system-aarch64
|
|
QEMU_KERNEL_CMDLINE += console=ttyAMA0
|
|
|
|
QEMU_ARGS += \
|
|
-M virt \
|
|
-cpu cortex-a53 \
|
|
-semihosting-config enable=on,target=native
|
|
endif
|
|
|
|
ifeq ($(KASLR),0)
|
|
QEMU_KERNEL_CMDLINE += nokaslr
|
|
endif
|
|
|
|
QEMU_ARGS += -append "$(QEMU_KERNEL_CMDLINE) $(QEMU_EXTRA_KERNEL_CMDLINE)"
|
|
|
|
RUN_DEPS := $(QEMU_KERNEL_IMAGE)
|
|
|
|
.PHONY: run
|
|
run: $(RUN_DEPS) | $(SHARED_DIR)
|
|
@echo "$(GREEN)Running QEMU, press 'ctrl-a x' to quit $(NC)"
|
|
ifeq ($(GDB),1)
|
|
@echo "$(ARCH) $(ACK)" > $(OUT_DIR)/.gdb
|
|
@echo "$(GREEN)Waiting for GDB, attach with \`scripts/gdb.sh\` $(NC)"
|
|
|
|
ifdef TERMINAL_CMD
|
|
$(TERMINAL_CMD) $(SCRIPT_DIR)/gdb.sh
|
|
endif
|
|
|
|
endif
|
|
@echo ''
|
|
$(QEMU_BIN) $(QEMU_ARGS)
|
|
|
|
.PHONY: run-ack
|
|
run-ack: run
|