diff options
| -rw-r--r-- | build.zig | 53 | ||||
| -rw-r--r-- | build.zig.zon | 4 | ||||
| -rw-r--r-- | spell.zig | 28 | ||||
| -rw-r--r-- | src/elfo.zig (renamed from src/elfo-pretty.zig) | 40 | ||||
| -rw-r--r-- | tests/test.zig | 8 |
5 files changed, 85 insertions, 48 deletions
@@ -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); +} |
