summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-02-19 23:21:06 -0300
committerGabriel Schneider <[email protected]>2026-02-19 23:21:06 -0300
commit169ba71c6ca54be373a3bbccf17ba199bba17ca8 (patch)
treeff7edd742f5e95f9e14e395434e124341696b7ab
parentcea7000b4c911166faa90a6d0516ca0f12920fbb (diff)
downloadcodenomicon-169ba71c6ca54be373a3bbccf17ba199bba17ca8.tar.gz
codenomicon-169ba71c6ca54be373a3bbccf17ba199bba17ca8.zip
added option to run with gdb
-rw-r--r--build.zig53
-rw-r--r--build.zig.zon4
-rw-r--r--spell.zig28
-rw-r--r--src/elfo.zig (renamed from src/elfo-pretty.zig)40
-rw-r--r--tests/test.zig8
5 files changed, 85 insertions, 48 deletions
diff --git a/build.zig b/build.zig
index 10055a2..7b1e650 100644
--- a/build.zig
+++ b/build.zig
@@ -12,11 +12,12 @@ pub fn build(b: *std.Build) !void {
});
const elfo = b.addExecutable(.{
- .name = "elfo-pretty",
+ .name = "elfo",
.root_module = b.createModule(.{
- .root_source_file = b.path("src/elfo-pretty.zig"),
+ .root_source_file = b.path("src/elfo.zig"),
.target = target,
.optimize = optimize,
+ .link_libc = true,
}),
});
@@ -47,15 +48,45 @@ pub fn build(b: *std.Build) !void {
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 gdb_opt = b.option(bool, "gdb", "Run executable under gdb") orelse false;
+ const comp_opts = b.addOptions();
+ comp_opts.addOption(bool, "gdb", gdb_opt);
- const run_gloves_cmd = b.addRunArtifact(gloves);
+ const unit_tests = b.addTest(.{
+ .root_module = b.createModule(.{
+ .optimize = optimize,
+ .target = target,
+ .root_source_file = b.path("tests/test.zig"),
+ }),
+ });
+
+ const test_step = b.step("test", "Test the library");
+
+ const run_elfo_step = b.step("elfo", "See the pretty elfo!");
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
+ const run_steps = [_]struct { *std.Build.Step, *std.Build.Step.Compile }{
+ .{ test_step, unit_tests },
+ .{ run_elfo_step, elfo },
+ .{ run_gloves_step, gloves },
+ };
+ const gdbscript = b.addWriteFile("gdbscript",
+ \\r
+ );
+
+ for (run_steps) |run| {
+ run.@"1".root_module.addOptions("meta", comp_opts);
+ if (gdb_opt) {
+ const run_gdb = b.addSystemCommand(&.{"gdb"});
+ run_gdb.addArg("-x");
+ run_gdb.addFileArg(gdbscript.getDirectory().path(b, "gdbscript"));
+ run_gdb.addArtifactArg(run.@"1");
+ run.@"0".dependOn(&run_gdb.step);
+ } else {
+ const run_unit = b.addRunArtifact(run.@"1");
+ run.@"0".dependOn(&run_unit.step);
+ }
+ }
}
fn gum_stalker(b: *std.Build, opts: struct {
@@ -87,7 +118,8 @@ fn gum_stalker(b: *std.Build, opts: struct {
// C-only module (translate-c can't handle GLib's _Pragma macros)
const c_mod = b.createModule(.{
.target = opts.target,
- .optimize = opts.optimize,
+ // .optimize = opts.optimize,
+ .optimize = .Debug,
.link_libc = true,
});
@@ -239,7 +271,8 @@ fn capstone(b: *std.Build, opts: struct {
const translate_c = b.addTranslateC(.{
.root_source_file = capstone_dep.path("include/capstone/capstone.h"),
.target = opts.target,
- .optimize = opts.optimize,
+ // .optimize = opts.optimize,
+ .optimize = .Debug,
.link_libc = true,
});
diff --git a/build.zig.zon b/build.zig.zon
index b63f625..4906467 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -6,6 +6,10 @@
.url = "git+https://github.com/capstone-engine/capstone?ref=6.0.0-Alpha6#484857da5dc67f7d0e0a01c36b0ebc37a349e0fd",
.hash = "N-V-__8AAI-jMgXy8ymEREsD2WbO6CpmH9mIpULsgYu3r56r",
},
+ .@"frida-gum" = .{
+ .url = "git+https://github.com/frida/frida-gum.git#7804914181117f05d20d3b143f7c13935658777f",
+ .hash = "N-V-__8AAFeo1AEV9-c5BwB6KQi5gLoDP-sj6d2duyERG2u-",
+ },
},
.paths = .{""},
.fingerprint = 0xdc1ade2e38c84164,
diff --git a/spell.zig b/spell.zig
deleted file mode 100644
index 5439a6c..0000000
--- a/spell.zig
+++ /dev/null
@@ -1,28 +0,0 @@
-const std = @import("std");
-const config = @import("config");
-const cs = @import("capstone");
-const elfo = @import("./src/elfo.zig");
-
-var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
-const alloc = gpa.allocator();
-
-// FIXME: call capstone on the sections
-// FIXME: missing reading the elf sections
-
-pub fn main() !void {
- std.debug.print("abracadabra! -> {s}\n", .{config.vessel});
- // std.debug.print("abracadabra! -> {x} {s}\n", .{ config.vessel_contents, config.vessel });
-
- var child = std.process.Child.init(&.{config.vessel}, alloc);
- try child.spawn();
- child.stdin_behavior = .Pipe;
- child.stdout_behavior = .Pipe;
- child.stderr_behavior = .Pipe;
-
- // var buf: [8]u8 = undefined;
-
- // const bytes = try child.stdout.?.read(&buf);
- // std.debug.print("stdout {x}\n", .{bytes});
-
- _ = try child.wait();
-}
diff --git a/src/elfo-pretty.zig b/src/elfo.zig
index 1482670..20f798a 100644
--- a/src/elfo-pretty.zig
+++ b/src/elfo.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const cs = @import("capstone");
+const meta_opts = @import("meta");
pub fn main(init: std.process.Init) !void {
var args = try init.minimal.args.iterateAllocator(init.gpa);
@@ -13,19 +14,15 @@ pub fn main(init: std.process.Init) !void {
// const mem_config: cs.cs_opt_mem = undefined;
// std.debug.assert(cs.cs_option(0, cs.CS_OPT_MEM, @intFromPtr(&mem_config)) == cs.CS_ERR_OK);
- var handle: usize = undefined;
- defer _ = cs.cs_close(@ptrCast(&handle));
- // TODO: read the arch from the elf so we open the equivalent capstone handle
- std.debug.assert(cs.cs_open(cs.CS_ARCH_X86, cs.CS_MODE_64, @ptrCast(&handle)) == cs.CS_ERR_OK);
+ if (meta_opts.gdb) @breakpoint();
try printElf(
init.gpa,
init.io,
args.next() orelse "./study-samples/split",
stderr.terminal(),
- handle,
.{
- // .show_unaddressable_sections = true,
+ .show_unaddressable_sections = true,
// .skip_sections_content = true,
},
);
@@ -36,7 +33,6 @@ pub fn printElf(
io: std.Io,
path: []const u8,
term: std.Io.Terminal,
- handle: usize,
options: struct {
show_unaddressable_sections: bool = false,
skip_sections_content: bool = false,
@@ -51,6 +47,20 @@ pub fn printElf(
var reader = f.reader(io, buffer);
const header = try std.elf.Header.read(&reader.interface);
+ var handle: usize = undefined;
+ defer _ = cs.cs_close(@ptrCast(&handle));
+ const opts: struct { arch: u64, mode: u64 } = switch (header.machine) {
+ .X86_64 => .{ .arch = cs.CS_ARCH_X86, .mode = cs.CS_MODE_64 },
+ // The arm mode isn't working with symbols on the .text section correctly
+ .ARM => .{ .arch = cs.CS_ARCH_ARM, .mode = cs.CS_MODE_ARM },
+ else => {
+ std.debug.print("found machine: {any}\n", .{header.machine});
+ @panic("unhandled arch");
+ },
+ };
+
+ std.debug.assert(cs.cs_open(@intCast(opts.arch), @intCast(opts.mode), @ptrCast(&handle)) == cs.CS_ERR_OK);
+
const shstrtab = blk: {
var section_it = header.iterateSectionHeaders(&reader);
var section_idx: u32 = 0;
@@ -143,7 +153,10 @@ pub fn printElf(
var section_it = header.iterateSectionHeaders(&reader);
while (try section_it.next()) |s| {
if (s.sh_type == std.elf.SHT_SYMTAB) {
- try bw.print("sym: {any}\n", .{s});
+
+ // x64: symtab: .{ .sh_name = 1, .sh_type = 2, .sh_flags = 0, .sh_addr = 0, .sh_offset = 4256, .sh_size = 1680, .sh_link = 27, .sh_info = 45, .sh_addralign = 8, .sh_entsize = 24 }
+ // arm32: .{ .sh_name = 1, .sh_type = 2, .sh_flags = 0, .sh_addr = 0, .sh_offset = 4264, .sh_size = 1856, .sh_link = 27, .sh_info = 87, .sh_addralign = 4, .sh_entsize = 16 }
+ try bw.print("symtab: {any}\n", .{s});
break :blk s;
}
}
@@ -154,13 +167,13 @@ pub fn printElf(
var section_it = header.iterateSectionHeaders(&reader);
while (try section_it.next()) |s| {
if (s.sh_type == std.elf.SHT_DYNSYM) {
- try bw.print("sym: {any}\n", .{s});
+ // try bw.print("sym: {any}\n", .{s});
break :blk s;
}
}
break :blk null;
};
- try bw.print("dynsym: {any}\n", .{dynsym});
+ // try bw.print("dynsym: {any}\n", .{dynsym});
var symbols_index = blk: {
var syms: std.ArrayList(SymbolRange) = try .initCapacity(gpa, 8);
@@ -319,6 +332,7 @@ fn allocComment(
std.debug.dumpHex(s);
break :blk 0;
};
+ // FIXME: this algorithm isn't working to find addresses "inside" symbols
if (v > 0) {
const idx = std.sort.lowerBound(SymbolRange, symbols, v, struct {
fn inner(a: u64, sym: SymbolRange) std.math.Order {
@@ -370,6 +384,12 @@ fn dumpInstr(
try term.setColor(.bright_green);
try bw.print("{s} ", .{instr.mnemonic});
try term.setColor(.reset);
+
+ const mnemonic_strlen: u64 = @intCast(std.mem.find(u8, &instr.mnemonic, &.{0}).?);
+ const mnemonic_pad: u64 = 10;
+ for (0..(mnemonic_pad - mnemonic_strlen)) |_| {
+ try bw.printAsciiChar(' ', .{});
+ }
try bw.print("{s}", .{instr.op_str});
const asm_comment = try allocComment(gpa, @ptrCast(@constCast(&instr.op_str)), symbols);
defer {
diff --git a/tests/test.zig b/tests/test.zig
new file mode 100644
index 0000000..8351b50
--- /dev/null
+++ b/tests/test.zig
@@ -0,0 +1,8 @@
+const std = @import("std");
+const opts = @import("meta");
+const assert = std.debug.assert;
+
+test "always pass" {
+ if (opts.gdb) @breakpoint();
+ assert(true);
+}