const std = @import("std"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const gloves_module = b.createModule(.{ .root_source_file = b.path("src/gloves.zig"), .target = target, .optimize = optimize, .link_libc = true, }); const elfo = b.addExecutable(.{ .name = "elfo-pretty", .root_module = b.createModule(.{ .root_source_file = b.path("src/elfo-pretty.zig"), .target = target, .optimize = optimize, }), }); const capstone_lib = capstone(b, .{ .optimize = optimize, .target = target, }); const frida_lib = gum_stalker(b, .{ .optimize = optimize, .target = target, }); frida_lib.step.dependOn(&capstone_lib.step); frida_lib.root_module.linkLibrary(capstone_lib); b.installArtifact(capstone_lib); b.installArtifact(frida_lib); elfo.root_module.linkLibrary(capstone_lib); elfo.root_module.addImport("capstone", capstone_lib.root_module); const gloves = b.addExecutable(.{ .name = "gloves", .root_module = gloves_module, }); b.installArtifact(elfo); b.installArtifact(gloves); const run_elfo_cmd = b.addRunArtifact(elfo); const run_elfo_step = b.step("elfo", "See the pretty elfo!"); run_elfo_step.dependOn(&run_elfo_cmd.step); const run_gloves_cmd = b.addRunArtifact(gloves); const run_gloves_step = b.step("gloves", "See the pretty gloves!"); run_gloves_step.dependOn(&run_gloves_cmd.step); // TODO: add flag to run on gdb } fn gum_stalker(b: *std.Build, opts: struct { target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, }) *std.Build.Step.Compile { const dep = b.dependency("frida-gum", .{}); const capstone_dep = b.dependency("capstone", .{}); // stub gumenumtypes.h — normally generated by gnome.mkenums const wf = b.addWriteFiles(); _ = wf.add("gum/gumenumtypes.h", \\#ifndef __GUM_ENUM_TYPES_H__ \\#define __GUM_ENUM_TYPES_H__ \\#include \\G_BEGIN_DECLS \\GType gum_elf_type_get_type (void) G_GNUC_CONST; \\#define GUM_TYPE_ELF_TYPE (gum_elf_type_get_type ()) \\GType gum_elf_osabi_get_type (void) G_GNUC_CONST; \\#define GUM_TYPE_ELF_OSABI (gum_elf_osabi_get_type ()) \\GType gum_elf_machine_get_type (void) G_GNUC_CONST; \\#define GUM_TYPE_ELF_MACHINE (gum_elf_machine_get_type ()) \\GType gum_elf_source_mode_get_type (void) G_GNUC_CONST; \\#define GUM_TYPE_ELF_SOURCE_MODE (gum_elf_source_mode_get_type ()) \\G_END_DECLS \\#endif ); // C-only module (translate-c can't handle GLib's _Pragma macros) const c_mod = b.createModule(.{ .target = opts.target, .optimize = opts.optimize, .link_libc = true, }); // include paths for C source compilation c_mod.addIncludePath(dep.path("")); c_mod.addIncludePath(dep.path("gum")); c_mod.addIncludePath(dep.path("gum/arch-x86")); c_mod.addIncludePath(dep.path("gum/arch-arm")); c_mod.addIncludePath(dep.path("gum/arch-arm64")); c_mod.addIncludePath(dep.path("gum/arch-mips")); c_mod.addIncludePath(dep.path("gum/backend-linux/include")); c_mod.addIncludePath(dep.path("gum/backend-elf")); c_mod.addIncludePath(dep.path("gum/backend-posix")); c_mod.addIncludePath(dep.path("libs")); c_mod.addIncludePath(dep.path("libs/gum/heap")); c_mod.addIncludePath(dep.path("libs/gum/prof")); c_mod.addIncludePath(capstone_dep.path("include/capstone")); c_mod.addIncludePath(capstone_dep.path("include")); c_mod.addIncludePath(wf.getDirectory()); // system libraries c_mod.linkSystemLibrary("glib-2.0", .{}); c_mod.linkSystemLibrary("gobject-2.0", .{}); // config defines — replaces meson's config.h + add_project_arguments // platform / arch c_mod.addCMacro("HAVE_LINUX", "1"); c_mod.addCMacro("HAVE_I386", "1"); c_mod.addCMacro("HAVE_ELF", "1"); c_mod.addCMacro("HAVE_GLIBC", "1"); // frida-gum options c_mod.addCMacro("GUM_STATIC", "1"); c_mod.addCMacro("GUM_USE_SYSTEM_ALLOC", "1"); c_mod.addCMacro("FRIDA_VERSION", "\"16.x\""); // compiler feature detection c_mod.addCMacro("HAVE_SYNC_LOCK", "1"); c_mod.addCMacro("HAVE_CLEAR_CACHE", "1"); c_mod.addCMacro("HAVE_CLTZ", "1"); c_mod.addCMacro("HAVE_POPCOUNT", "1"); c_mod.addCMacro("HAVE_PACK_PRAGMA", "1"); // system headers c_mod.addCMacro("HAVE_ELF_H", "1"); c_mod.addCMacro("HAVE_LINK_H", "1"); c_mod.addCMacro("HAVE_STDINT_H", "1"); c_mod.addCMacro("HAVE_SYS_AUXV_H", "1"); c_mod.addCMacro("HAVE_ASM_PRCTL_H", "1"); c_mod.addCMacro("HAVE_SYS_USER_H", "1"); // system functions / types c_mod.addCMacro("HAVE_MADVISE", "1"); c_mod.addCMacro("HAVE_LONG_DOUBLE", "1"); c_mod.addCMacro("HAVE_LONG_LONG_INT", "1"); c_mod.addCMacro("HAVE_UNSIGNED_LONG_LONG_INT", "1"); c_mod.addCMacro("HAVE_PTHREAD_ATTR_GETSTACK", "1"); c_mod.addCMacro("HAVE_PTHREAD_SETNAME_NP", "1"); // NOTE: HAVE_FRIDA_GLIB omitted — system GLib lacks frida's patches // capstone compat (frida-gum uses capstone 5 type names) c_mod.addCMacro("CAPSTONE_ARM_COMPAT_HEADER", "1"); c_mod.addCMacro("CAPSTONE_AARCH64_COMPAT_HEADER", "1"); c_mod.addCMacro("CAPSTONE_SYSTEMZ_COMPAT_HEADER", "1"); // GLib / compiler flags c_mod.addCMacro("_GNU_SOURCE", "1"); c_mod.addCMacro("G_LOG_DOMAIN", "\"Frida\""); c_mod.addCMacro("GLIB_VERSION_MIN_REQUIRED", "GLIB_VERSION_2_56"); c_mod.addCMacro("G_DISABLE_DEPRECATED", ""); // core + arch writers (unconditional in upstream meson) c_mod.addCSourceFiles(.{ .root = dep.path("gum"), .files = &.{ "gum.c", "gumapiresolver.c", "gumbacktracer.c", "gumcloak.c", "gumcodeallocator.c", "gumcodesegment.c", // gumdarwingrafter.c and gumdarwinmodule.c omitted (darwin only) "gumelfmodule.c", "gumeventsink.c", "gumexceptor.c", "gumheapapi.c", "guminterceptor.c", "guminvocationcontext.c", "guminvocationlistener.c", "gumkernel.c", "gumleb.c", "gumlibc.c", "gummemory.c", "gummemorymap.c", "gummetalarray.c", "gummetalhash.c", "gummoduleapiresolver.c", "gummodulemap.c", "gumprintf.c", "gumprocess.c", "gumthreadregistry.c", "gummodule.c", "gummodulefacade.c", "gummoduleregistry.c", "gumreturnaddress.c", "gumspinlock.c", "gumstalker.c", "gumswiftapiresolver.c", // arch writers (x86 only — arm/arm64/mips need frida's capstone fork) "arch-x86/gumx86writer.c", "arch-x86/gumx86relocator.c", "arch-x86/gumx86reader.c", // x86 backend "arch-x86/gumx86backtracer.c", "backend-x86/gumcpucontext-x86.c", "backend-x86/gumprocess-x86.c", "backend-x86/guminterceptor-x86.c", "backend-x86/gumstalker-x86.c", // linux + posix backend "backend-linux/gummemory-linux.c", "backend-posix/gummemory-posix.c", "backend-linux/gumprocess-linux.c", "backend-linux/gumthreadregistry-linux.c", "backend-linux/gummoduleregistry-linux.c", "backend-linux/gummodule-linux.c", "backend-posix/gumtls-posix.c", "backend-posix/gumexceptor-posix.c", "backend-posix/gummemoryaccessmonitor-posix.c", // elf backend "backend-elf/gummodule-elf.c", "backend-elf/gummoduleregistry-elf.c", }, }); // x86 assembly glue c_mod.addAssemblyFile(dep.path("gum/backend-x86/gumstalker-x86-glue.S")); const stalker_lib = b.addLibrary(.{ .name = "gumstalker", .linkage = .static, .root_module = c_mod, }); stalker_lib.installHeadersDirectory(capstone_dep.path("include/capstone"), "capstone", .{}); stalker_lib.installHeader(capstone_dep.path("include/platform.h"), "capstone/platform.h"); return stalker_lib; } fn capstone(b: *std.Build, opts: struct { target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, }) *std.Build.Step.Compile { const capstone_dep = b.dependency("capstone", .{}); const translate_c = b.addTranslateC(.{ .root_source_file = capstone_dep.path("include/capstone/capstone.h"), .target = opts.target, .optimize = opts.optimize, .link_libc = true, }); // translate const c_mod = translate_c.createModule(); const capstone_lib = b.addLibrary(.{ .name = "capstone", .linkage = .static, .root_module = c_mod, }); capstone_lib.root_module.addIncludePath(capstone_dep.path("include")); capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone")); capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone/X86")); capstone_lib.root_module.addIncludePath(capstone_dep.path("include/capstone/ARM")); capstone_lib.installHeadersDirectory(capstone_dep.path("include/capstone"), "capstone", .{}); capstone_lib.installHeader(capstone_dep.path("include/platform.h"), "capstone/platform.h"); if (opts.optimize == .Debug) capstone_lib.root_module.addCMacro("CAPSTONE_DEBUG", ""); capstone_lib.root_module.addCMacro("CAPSTONE_HAS_X86", ""); capstone_lib.root_module.addCMacro("CAPSTONE_HAS_ARM", ""); capstone_lib.root_module.addCMacro("CAPSTONE_HAS_AArch64", ""); capstone_lib.root_module.addCMacro("CAPSTONE_BUILD_CSTOOL", "OFF"); capstone_lib.root_module.addCMacro("CAPSTONE_USE_SYS_DYN_MEM", "1"); capstone_lib.root_module.addCMacro("CAPSTONE_BUILD_DIET", "1"); capstone_lib.root_module.addCMacro("CAPSTONE_X86_REDUCE", "1"); capstone_lib.root_module.addCSourceFiles(.{ .root = capstone_dep.path(""), .files = common_sources }); capstone_lib.root_module.addCSourceFiles(.{ .root = capstone_dep.path("arch/ARM"), .files = &.{ "ARMBaseInfo.c", "ARMDisassembler.c", "ARMDisassemblerExtension.c", "ARMInstPrinter.c", "ARMMapping.c", "ARMModule.c", }, }); capstone_lib.root_module.addCSourceFiles(.{ .root = capstone_dep.path("arch/X86"), .files = &.{ "X86Disassembler.c", "X86DisassemblerDecoder.c", "X86IntelInstPrinter.c", "X86ATTInstPrinter.c", "X86InstPrinterCommon.c", "X86Mapping.c", "X86Module.c", }, }); return capstone_lib; } const common_sources: []const []const u8 = &.{ "cs.c", "Mapping.c", "MCInst.c", "MCInstrDesc.c", "MCInstPrinter.c", "MCRegisterInfo.c", "SStream.c", "utils.c", }; // .AArch64 // .ARC // .ARM // .Alpha // .BPF // .EVM // .HPPA // .LoongArch // .M680X // .M68K // .MOS65XX // .Mips // .PowerPC // .RISCV // .SH // .Sparc // .SystemZ // .TMS320C64x // .TriCore // .WASM // .X86 // .XCore // .Xtensa