authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-09 11:05:52+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-09 20:36:58+01:00
log601600dec981e41d43bb72113d9284cbb9e1d9ae
tree37700f6fddc1a1012eac0518e387e15762af6a9b
parenta28340405392b4a0a687e668406a067be1ae5e3c

macho: parsing Trie now takes a reader and returns bytes read


2 files changed, 79 insertions(+), 87 deletions(-)

src/link/MachO.zig+1-1
......@@ -1806,7 +1806,7 @@ fn writeExportTrie(self: *MachO) !void {
18061806 try trie.put(.{
18071807 .name = name,
18081808 .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr,
1809 .export_flags = 0, // TODO workout creation of export flags
1809 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
18101810 });
18111811 }
18121812
src/link/MachO/Trie.zig+78-86
......@@ -39,27 +39,6 @@ const testing = std.testing;
3939const assert = std.debug.assert;
4040const Allocator = mem.Allocator;
4141
42pub const Symbol = struct {
43 name: []const u8,
44 vmaddr_offset: u64,
45 export_flags: u64,
46};
47
48pub const Edge = struct {
49 from: *Node,
50 to: *Node,
51 label: []u8,
52
53 fn deinit(self: *Edge, allocator: *Allocator) void {
54 self.to.deinit(allocator);
55 allocator.destroy(self.to);
56 allocator.free(self.label);
57 self.from = undefined;
58 self.to = undefined;
59 self.label = undefined;
60 }
61};
62
6342pub const Node = struct {
6443 base: *Trie,
6544
......@@ -80,6 +59,22 @@ pub const Node = struct {
8059
8160 node_dirty: bool = true,
8261
62 /// Edge connecting to nodes in the trie.
63 pub const Edge = struct {
64 from: *Node,
65 to: *Node,
66 label: []u8,
67
68 fn deinit(self: *Edge, allocator: *Allocator) void {
69 self.to.deinit(allocator);
70 allocator.destroy(self.to);
71 allocator.free(self.label);
72 self.from = undefined;
73 self.to = undefined;
74 self.label = undefined;
75 }
76 };
77
8378 fn deinit(self: *Node, allocator: *Allocator) void {
8479 for (self.edges.items) |*edge| {
8580 edge.deinit(allocator);
......@@ -131,10 +126,12 @@ pub const Node = struct {
131126 }
132127
133128 /// Recursively parses the node from the input byte stream.
134 fn read(self: *Node, allocator: *Allocator, reader: anytype) Trie.ReadError!void {
129 fn read(self: *Node, allocator: *Allocator, reader: anytype) Trie.ReadError!usize {
135130 self.node_dirty = true;
131 const trie_offset = try reader.context.getPos();
132 self.trie_offset = trie_offset;
136133
137 self.trie_offset = try reader.context.getPos();
134 var nread: usize = 0;
138135
139136 const node_size = try leb.readULEB128(u64, reader);
140137 if (node_size > 0) {
......@@ -154,9 +151,13 @@ pub const Node = struct {
154151 const nedges = try reader.readByte();
155152 self.base.node_count += nedges;
156153
154 nread += (try reader.context.getPos()) - trie_offset;
155
157156 var i: usize = 0;
158157 while (i < nedges) : (i += 1) {
159 var label = blk: {
158 const edge_start_pos = try reader.context.getPos();
159
160 const label = blk: {
160161 var label_buf = std.ArrayList(u8).init(allocator);
161162 while (true) {
162163 const next = try reader.readByte();
......@@ -168,20 +169,24 @@ pub const Node = struct {
168169 };
169170
170171 const seek_to = try leb.readULEB128(u64, reader);
171 const cur_pos = try reader.context.getPos();
172 const return_pos = try reader.context.getPos();
173
174 nread += return_pos - edge_start_pos;
172175 try reader.context.seekTo(seek_to);
173176
174177 const node = try allocator.create(Node);
175178 node.* = .{ .base = self.base };
176179
177 try node.read(allocator, reader);
180 nread += try node.read(allocator, reader);
178181 try self.edges.append(allocator, .{
179182 .from = self,
180183 .to = node,
181184 .label = label,
182185 });
183 try reader.context.seekTo(cur_pos);
186 try reader.context.seekTo(return_pos);
184187 }
188
189 return nread;
185190 }
186191
187192 /// Writes this node to a byte stream.
......@@ -301,10 +306,23 @@ pub fn init(allocator: *Allocator) Trie {
301306 return .{ .allocator = allocator };
302307}
303308
309/// Export symbol that is to be placed in the trie.
310pub const ExportSymbol = struct {
311 /// Name of the symbol.
312 name: []const u8,
313
314 /// Offset of this symbol's virtual memory address from the beginning
315 /// of the __TEXT segment.
316 vmaddr_offset: u64,
317
318 /// Export flags of this exported symbol.
319 export_flags: u64,
320};
321
304322/// Insert a symbol into the trie, updating the prefixes in the process.
305323/// This operation may change the layout of the trie by splicing edges in
306324/// certain circumstances.
307pub fn put(self: *Trie, symbol: Symbol) !void {
325pub fn put(self: *Trie, symbol: ExportSymbol) !void {
308326 try self.createRoot();
309327 const node = try self.root.?.put(self.allocator, symbol.name);
310328 node.terminal_info = .{
......@@ -356,7 +374,7 @@ const ReadError = error{
356374};
357375
358376/// Parse the trie from a byte stream.
359pub fn read(self: *Trie, reader: anytype) ReadError!void {
377pub fn read(self: *Trie, reader: anytype) ReadError!usize {
360378 try self.createRoot();
361379 return self.root.?.read(self.allocator, reader);
362380}
......@@ -533,60 +551,34 @@ test "write Trie to a byte stream" {
533551 }
534552}
535553
536// test "parse Trie from byte stream" {
537// var gpa = testing.allocator;
538
539// const in_buffer = [_]u8{
540// 0x0,
541// 0x1,
542// 0x5f,
543// 0x0,
544// 0x5,
545// 0x0,
546// 0x2,
547// 0x5f,
548// 0x6d,
549// 0x68,
550// 0x5f,
551// 0x65,
552// 0x78,
553// 0x65,
554// 0x63,
555// 0x75,
556// 0x74,
557// 0x65,
558// 0x5f,
559// 0x68,
560// 0x65,
561// 0x61,
562// 0x64,
563// 0x65,
564// 0x72,
565// 0x0,
566// 0x21,
567// 0x6d,
568// 0x61,
569// 0x69,
570// 0x6e,
571// 0x0,
572// 0x25,
573// 0x2,
574// 0x0,
575// 0x0,
576// 0x0,
577// 0x3,
578// 0x0,
579// 0x80,
580// 0x20,
581// 0x0,
582// };
583// var stream = std.io.fixedBufferStream(in_buffer[0..]);
584// var trie = Trie.init(gpa);
585// defer trie.deinit();
586// try trie.fromByteStream(&stream);
587
588// var out_buffer = try trie.writeULEB128Mem();
589// defer gpa.free(out_buffer);
590
591// testing.expect(mem.eql(u8, in_buffer[0..], out_buffer));
592// }
554test "parse Trie from byte stream" {
555 var gpa = testing.allocator;
556
557 const in_buffer = [_]u8{
558 0x0, 0x1, // node root
559 0x5f, 0x0, 0x5, // edge '_'
560 0x0, 0x2, // non-terminal node
561 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, // edge '_mh_execute_header'
562 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x21, // edge '_mh_execute_header'
563 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x25, // edge 'main'
564 0x2, 0x0, 0x0, 0x0, // terminal node
565 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node
566 };
567
568 var in_stream = std.io.fixedBufferStream(in_buffer[0..]);
569 var trie = Trie.init(gpa);
570 defer trie.deinit();
571 const nread = try trie.read(in_stream.reader());
572
573 testing.expect(nread == in_buffer.len);
574
575 try trie.finalize();
576
577 var out_buffer = try gpa.alloc(u8, trie.size);
578 defer gpa.free(out_buffer);
579 var out_stream = std.io.fixedBufferStream(out_buffer);
580 const nwritten = try trie.write(out_stream.writer());
581
582 testing.expect(nwritten == trie.size);
583 testing.expect(mem.eql(u8, in_buffer[0..], out_buffer));
584}