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 {...@@ -1806,7 +1806,7 @@ fn writeExportTrie(self: *MachO) !void {
1806 try trie.put(.{1806 try trie.put(.{
1807 .name = name,1807 .name = name,
1808 .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr,1808 .vmaddr_offset = symbol.n_value - text_segment.inner.vmaddr,
1809 .export_flags = 0, // TODO workout creation of export flags1809 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
1810 });1810 });
1811 }1811 }
18121812
src/link/MachO/Trie.zig+78-86
...@@ -39,27 +39,6 @@ const testing = std.testing;...@@ -39,27 +39,6 @@ const testing = std.testing;
39const assert = std.debug.assert;39const assert = std.debug.assert;
40const Allocator = mem.Allocator;40const 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
63pub const Node = struct {42pub const Node = struct {
64 base: *Trie,43 base: *Trie,
6544
...@@ -80,6 +59,22 @@ pub const Node = struct {...@@ -80,6 +59,22 @@ pub const Node = struct {
8059
81 node_dirty: bool = true,60 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
83 fn deinit(self: *Node, allocator: *Allocator) void {78 fn deinit(self: *Node, allocator: *Allocator) void {
84 for (self.edges.items) |*edge| {79 for (self.edges.items) |*edge| {
85 edge.deinit(allocator);80 edge.deinit(allocator);
...@@ -131,10 +126,12 @@ pub const Node = struct {...@@ -131,10 +126,12 @@ pub const Node = struct {
131 }126 }
132127
133 /// Recursively parses the node from the input byte stream.128 /// 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 {
135 self.node_dirty = true;130 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
139 const node_size = try leb.readULEB128(u64, reader);136 const node_size = try leb.readULEB128(u64, reader);
140 if (node_size > 0) {137 if (node_size > 0) {
...@@ -154,9 +151,13 @@ pub const Node = struct {...@@ -154,9 +151,13 @@ pub const Node = struct {
154 const nedges = try reader.readByte();151 const nedges = try reader.readByte();
155 self.base.node_count += nedges;152 self.base.node_count += nedges;
156153
154 nread += (try reader.context.getPos()) - trie_offset;
155
157 var i: usize = 0;156 var i: usize = 0;
158 while (i < nedges) : (i += 1) {157 while (i < nedges) : (i += 1) {
159 var label = blk: {158 const edge_start_pos = try reader.context.getPos();
159
160 const label = blk: {
160 var label_buf = std.ArrayList(u8).init(allocator);161 var label_buf = std.ArrayList(u8).init(allocator);
161 while (true) {162 while (true) {
162 const next = try reader.readByte();163 const next = try reader.readByte();
...@@ -168,20 +169,24 @@ pub const Node = struct {...@@ -168,20 +169,24 @@ pub const Node = struct {
168 };169 };
169170
170 const seek_to = try leb.readULEB128(u64, reader);171 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;
172 try reader.context.seekTo(seek_to);175 try reader.context.seekTo(seek_to);
173176
174 const node = try allocator.create(Node);177 const node = try allocator.create(Node);
175 node.* = .{ .base = self.base };178 node.* = .{ .base = self.base };
176179
177 try node.read(allocator, reader);180 nread += try node.read(allocator, reader);
178 try self.edges.append(allocator, .{181 try self.edges.append(allocator, .{
179 .from = self,182 .from = self,
180 .to = node,183 .to = node,
181 .label = label,184 .label = label,
182 });185 });
183 try reader.context.seekTo(cur_pos);186 try reader.context.seekTo(return_pos);
184 }187 }
188
189 return nread;
185 }190 }
186191
187 /// Writes this node to a byte stream.192 /// Writes this node to a byte stream.
...@@ -301,10 +306,23 @@ pub fn init(allocator: *Allocator) Trie {...@@ -301,10 +306,23 @@ pub fn init(allocator: *Allocator) Trie {
301 return .{ .allocator = allocator };306 return .{ .allocator = allocator };
302}307}
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
304/// Insert a symbol into the trie, updating the prefixes in the process.322/// Insert a symbol into the trie, updating the prefixes in the process.
305/// This operation may change the layout of the trie by splicing edges in323/// This operation may change the layout of the trie by splicing edges in
306/// certain circumstances.324/// certain circumstances.
307pub fn put(self: *Trie, symbol: Symbol) !void {325pub fn put(self: *Trie, symbol: ExportSymbol) !void {
308 try self.createRoot();326 try self.createRoot();
309 const node = try self.root.?.put(self.allocator, symbol.name);327 const node = try self.root.?.put(self.allocator, symbol.name);
310 node.terminal_info = .{328 node.terminal_info = .{
...@@ -356,7 +374,7 @@ const ReadError = error{...@@ -356,7 +374,7 @@ const ReadError = error{
356};374};
357375
358/// Parse the trie from a byte stream.376/// 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 {
360 try self.createRoot();378 try self.createRoot();
361 return self.root.?.read(self.allocator, reader);379 return self.root.?.read(self.allocator, reader);
362}380}
...@@ -533,60 +551,34 @@ test "write Trie to a byte stream" {...@@ -533,60 +551,34 @@ test "write Trie to a byte stream" {
533 }551 }
534}552}
535553
536// test "parse Trie from byte stream" {554test "parse Trie from byte stream" {
537// var gpa = testing.allocator;555 var gpa = testing.allocator;
538556
539// const in_buffer = [_]u8{557 const in_buffer = [_]u8{
540// 0x0,558 0x0, 0x1, // node root
541// 0x1,559 0x5f, 0x0, 0x5, // edge '_'
542// 0x5f,560 0x0, 0x2, // non-terminal node
543// 0x0,561 0x5f, 0x6d, 0x68, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, // edge '_mh_execute_header'
544// 0x5,562 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x0, 0x21, // edge '_mh_execute_header'
545// 0x0,563 0x6d, 0x61, 0x69, 0x6e, 0x0, 0x25, // edge 'main'
546// 0x2,564 0x2, 0x0, 0x0, 0x0, // terminal node
547// 0x5f,565 0x3, 0x0, 0x80, 0x20, 0x0, // terminal node
548// 0x6d,566 };
549// 0x68,567
550// 0x5f,568 var in_stream = std.io.fixedBufferStream(in_buffer[0..]);
551// 0x65,569 var trie = Trie.init(gpa);
552// 0x78,570 defer trie.deinit();
553// 0x65,571 const nread = try trie.read(in_stream.reader());
554// 0x63,572
555// 0x75,573 testing.expect(nread == in_buffer.len);
556// 0x74,574
557// 0x65,575 try trie.finalize();
558// 0x5f,576
559// 0x68,577 var out_buffer = try gpa.alloc(u8, trie.size);
560// 0x65,578 defer gpa.free(out_buffer);
561// 0x61,579 var out_stream = std.io.fixedBufferStream(out_buffer);
562// 0x64,580 const nwritten = try trie.write(out_stream.writer());
563// 0x65,581
564// 0x72,582 testing.expect(nwritten == trie.size);
565// 0x0,583 testing.expect(mem.eql(u8, in_buffer[0..], out_buffer));
566// 0x21,584}
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// }