-
Notifications
You must be signed in to change notification settings - Fork 5
Update to Zig 0.14.1 including ManagedIter #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
320a085
57dee56
8d79486
f55459d
b5a3769
36ecfb5
3e0f5b8
a704610
93044d1
6f3fb09
13641db
1bc2966
74352fd
2bb1a02
fd7c930
1934069
3746dd4
2e9786e
767e955
dbde91c
facb0c4
d1649ef
42c1072
ef38def
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| const builtin = @import("builtin"); | ||
| const std = @import("std"); | ||
|
|
||
| const cs = @import("capstone-c"); | ||
|
|
||
| const err = @import("error.zig"); | ||
| const insn = @import("insn.zig"); | ||
| const setup = @import("setup.zig"); | ||
| const enums = @import("enums.zig"); | ||
| const impl = @import("impl.zig"); | ||
|
|
||
| const iter = @import("iter.zig"); | ||
|
|
||
| const Iter = iter.Iter; | ||
| const IterManaged = iter.IterManaged; | ||
|
|
||
| native: impl.Handle, | ||
|
|
||
| // To avoid heap allocations... | ||
| const TmpStorage = blk: { | ||
| if (builtin.single_threaded) { | ||
| break :blk struct { | ||
| var detail: insn.Detail = std.mem.zeroes(insn.Detail); | ||
| var ins: insn.Insn = std.mem.zeroes(insn.Insn); | ||
| fn getIns() *insn.Insn { | ||
| ins.detail = &detail; | ||
| return &ins; | ||
| } | ||
| }; | ||
| } else { | ||
| break :blk struct { | ||
| threadlocal var detail: insn.Detail = std.mem.zeroes(insn.Detail); | ||
| threadlocal var ins: insn.Insn = std.mem.zeroes(insn.Insn); | ||
| fn getIns() *insn.Insn { | ||
| ins.detail = &detail; | ||
| return &ins; | ||
| } | ||
| }; | ||
| } | ||
| }; | ||
|
|
||
| const Self = @This(); | ||
|
|
||
| pub const Options = struct { | ||
| /// Assembly output syntax | ||
| syntax: enums.Syntax = .DEFAULT, | ||
| /// Break down instruction structure into details | ||
| detail: bool = false, | ||
| /// Skip data when disassembling. Then engine is in SKIPDATA mode. | ||
| skipdata: bool = false, | ||
| /// Customize instruction mnemonic | ||
| /// Must be valid till the handle is closed if set. | ||
| mnemonic: []const MnemonicOption = &.{}, | ||
| /// print immediate operands in unsigned form | ||
| unsigned: bool = false, | ||
| /// ARM, prints branch immediates without offset. | ||
| no_branch_offset: bool = false, | ||
|
|
||
| /// cs_opt_mnem | ||
| pub const MnemonicOption = extern struct { | ||
| id: c_uint, | ||
| mnemonic: [*:0]const u8, | ||
| }; | ||
| }; | ||
|
|
||
| pub fn init(arch: enums.Arch, mode: enums.Mode, options: Options) !Self { | ||
| const handle = try impl.open(arch, mode); | ||
|
|
||
| if (options.syntax != .DEFAULT) { | ||
| try impl.option(handle, .SYNTAX, @intFromEnum(options.syntax)); | ||
| } | ||
|
|
||
| if (options.detail) { | ||
| try impl.option(handle, .DETAIL, cs.CS_OPT_ON); | ||
| } | ||
|
|
||
| if (options.skipdata) { | ||
| try impl.option(handle, .SKIPDATA, cs.CS_OPT_ON); | ||
| } | ||
|
|
||
| if (options.unsigned) { | ||
| try impl.option(handle, .UNSIGNED, cs.CS_OPT_ON); | ||
| } | ||
|
|
||
| if (options.no_branch_offset) { | ||
| try impl.option(handle, .NO_BRANCH_OFFSET, cs.CS_OPT_ON); | ||
| } | ||
|
|
||
| if (options.mnemonic.len > 0) { | ||
| try impl.option(handle, .MNEMONIC, @intFromPtr(options.mnemonic.ptr)); | ||
| } | ||
|
|
||
| return Self{ .native = handle }; | ||
| } | ||
|
|
||
| /// Allocates using the cs_malloc function or the user defined one which is set through cs_option/setup.initCapstone(Manually). | ||
| /// Should be freed using cs_free, capstone provided free function or the user defined one if set through option. | ||
| pub fn disasm(self: Self, code: []const u8, address: usize, count: usize) err.CapstoneError![]insn.Insn { | ||
| return impl.disasm(self.native, code, address, count); | ||
| } | ||
|
|
||
| /// Copies using zig user-land allocator and frees the cs_malloc'd memory. | ||
| pub fn disasmAlloc(self: Self, allocator: std.mem.Allocator, code: []const u8, address: usize, count: usize) ![]insn.Insn { | ||
| const disass = try impl.disasm(self.native, code, address, count); | ||
| defer impl.free(disass); | ||
| return allocator.dupe(insn.Insn, disass); | ||
| } | ||
|
|
||
| /// Uses global/threadlocal storage to avoid heap allocations for the single Insn struct. | ||
| pub fn disasmIter(self: Self, code: []const u8, address: u64) Iter { | ||
| return Iter.init(self.native, code, address, @ptrCast(TmpStorage.getIns())); | ||
| } | ||
|
|
||
| pub fn deinit(self: *Self) void { | ||
| impl.close(&self.native) catch |e| { | ||
| std.debug.print("Failed to close handle: {any}\n", .{impl.strerror(e)}); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't use debug print here, instead: std.io.getStdErr().writer().print("Failed to close handle: {any}\n", .{impl.strerror(e)});
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm so
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct. :D |
||
| }; | ||
| } | ||
|
|
||
| test "with options" { | ||
| const code = "\x75\x14"; | ||
|
|
||
| var handle = try init(.X86, .@"64", .{ | ||
| .syntax = .INTEL, | ||
| .detail = true, | ||
| .mnemonic = &.{.{ .id = cs.X86_INS_JNE, .mnemonic = "jnz" }}, | ||
| }); | ||
| defer handle.deinit(); | ||
|
|
||
| const disass = try handle.disasm(code, 0x1000, 0); | ||
| defer impl.free(disass); | ||
|
|
||
| try std.testing.expectEqual(1, disass.len); | ||
| try std.testing.expect(disass[0].detail != null); | ||
| try std.testing.expectEqualStrings("jnz", disass[0].mnemonic[0..3]); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,13 +3,26 @@ const cs = @import("capstone-c"); | |
| const Insn = @import("insn.zig").Insn; | ||
| const Handle = cs.csh; | ||
|
|
||
| // The Iterator for traversing the disassembler | ||
| /// The Iterator for traversing the disassembler | ||
| pub const Iter = struct { | ||
|
IamSanjid marked this conversation as resolved.
Outdated
|
||
| handle: Handle, | ||
| code: []const u8, | ||
| original_code: []const u8, | ||
| original_address: u64, | ||
| address: u64, | ||
| insn: [*]Insn, | ||
|
|
||
| pub fn init(handle: Handle, code: []const u8, address: u64, insn: [*]Insn) Iter { | ||
| return Iter{ | ||
| .handle = handle, | ||
| .code = code, | ||
| .original_code = code, | ||
| .original_address = address, | ||
| .address = address, | ||
| .insn = insn, | ||
| }; | ||
| } | ||
|
|
||
|
IamSanjid marked this conversation as resolved.
Outdated
|
||
| // Consumes the iterator and goes to the next | ||
| pub fn next(self: *Iter) ?*Insn { | ||
| if (cs.cs_disasm_iter(self.handle, @ptrCast(&self.code.ptr), @ptrCast(&self.code.len), &self.address, @ptrCast(self.insn))) { | ||
|
|
@@ -21,13 +34,36 @@ pub const Iter = struct { | |
| } | ||
| } | ||
|
|
||
| // Clean up the iter | ||
| pub fn deinit(self: Iter) void { | ||
| cs.cs_free(@ptrCast(self.insn), 1); | ||
| pub fn reset(self: *Iter) void { | ||
| self.address = self.original_address; | ||
| self.code = self.original_code; | ||
| } | ||
| }; | ||
|
|
||
| /// The Iterator for traversing the disassembler, but **allocates** space using capstone malloc. | ||
| pub const IterManaged = struct { | ||
| inner: Iter, | ||
| insn: [*]Insn, | ||
|
|
||
| pub fn init(handle: Handle, code: []const u8, address: u64) IterManaged { | ||
| const insn: [*]Insn = @ptrCast(cs.cs_malloc(handle)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, this seems a bit fishy, i believe i have forgotten to implement an abstraction for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually the cs_malloc doesn't return any error... https://github.com/capstone-engine/capstone/blob/280b749e84adca4177b7525504e55be4d8c74e44/cs.c#L1429 ow wait I mean it doesn't return the error directly but it does set the error to the handle, hmm ye the managed iter needs to return error too
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i was thinking about wrapping the type for it. pub fn allocInsn(handle: Handle) ![*]Insn {
const insn: ?[*]Insn = @ptrCast(cs.cs_malloc(handle));
return if(insn) |i| i else error.OutOfMemory;
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think ye we should just replace the pub fn malloc(handle: Handle) [*]insn.Insn {
return @ptrCast(cs.cs_malloc(handle));
}this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
and by the way shouldn't we return a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not tooo familiar with capstone, hence i tried and kept it as close to C as possible. |
||
| return .{ | ||
| .inner = Iter.init(handle, code, address, insn), | ||
| .insn = insn, | ||
| }; | ||
| } | ||
|
|
||
| // Consumes the iterator and goes to the next | ||
| pub fn next(self: *IterManaged) ?*Insn { | ||
| return self.inner.next(); | ||
| } | ||
|
|
||
| /// Returns the current address | ||
| pub fn address(self: Iter) u64 { | ||
| return self.address; | ||
| pub fn reset(self: *IterManaged) void { | ||
| self.inner.reset(); | ||
| } | ||
|
|
||
| // Clean up the iter | ||
| pub fn deinit(self: IterManaged) void { | ||
| cs.cs_free(@ptrCast(self.insn), 1); | ||
| } | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.