authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-04-10 00:50:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:26-07:00
logd76c8d0bd2305ff5c45653702dd92505e3fb8f6a
treef21b7848886a367fc9b2add1ac54f54ab4682373
parent9dc0b4a98f8efe2d249db74ebe52c6880570b7cc

Dwarf: cleanup and port to new `std.io.BufferedReader` API


5 files changed, 256 insertions(+), 363 deletions(-)

lib/std/debug/Dwarf/call_frame.zig+81-130
......@@ -51,17 +51,6 @@ const Opcode = enum(u8) {
5151 pub const hi_user = 0x3f;
5252};
5353
54fn readBlock(stream: *std.io.FixedBufferStream) ![]const u8 {
55 const reader = stream.reader();
56 const block_len = try leb.readUleb128(usize, reader);
57 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
58
59 const block = stream.buffer[stream.pos..][0..block_len];
60 reader.context.pos += block_len;
61
62 return block;
63}
64
6554pub const Instruction = union(Opcode) {
6655 advance_loc: struct {
6756 delta: u8,
......@@ -147,12 +136,11 @@ pub const Instruction = union(Opcode) {
147136 },
148137
149138 pub fn read(
150 stream: *std.io.FixedBufferStream,
139 reader: *std.io.BufferedReader,
151140 addr_size_bytes: u8,
152141 endian: std.builtin.Endian,
153142 ) !Instruction {
154 const reader = stream.reader();
155 switch (try reader.readByte()) {
143 switch (try reader.takeByte()) {
156144 Opcode.lo_inline...Opcode.hi_inline => |opcode| {
157145 const e: Opcode = @enumFromInt(opcode & 0b11000000);
158146 const value: u6 = @intCast(opcode & 0b111111);
......@@ -163,7 +151,7 @@ pub const Instruction = union(Opcode) {
163151 .offset => .{
164152 .offset = .{
165153 .register = value,
166 .offset = try leb.readUleb128(u64, reader),
154 .offset = try reader.takeLeb128(u64),
167155 },
168156 },
169157 .restore => .{
......@@ -175,121 +163,84 @@ pub const Instruction = union(Opcode) {
175163 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
176164 const e: Opcode = @enumFromInt(opcode);
177165 return switch (e) {
178 .advance_loc,
179 .offset,
180 .restore,
181 => unreachable,
182 .nop => .{ .nop = {} },
183 .set_loc => .{
184 .set_loc = .{
185 .address = switch (addr_size_bytes) {
186 2 => try reader.readInt(u16, endian),
187 4 => try reader.readInt(u32, endian),
188 8 => try reader.readInt(u64, endian),
189 else => return error.InvalidAddrSize,
190 },
191 },
192 },
193 .advance_loc1 => .{
194 .advance_loc1 = .{ .delta = try reader.readByte() },
195 },
196 .advance_loc2 => .{
197 .advance_loc2 = .{ .delta = try reader.readInt(u16, endian) },
198 },
199 .advance_loc4 => .{
200 .advance_loc4 = .{ .delta = try reader.readInt(u32, endian) },
201 },
202 .offset_extended => .{
203 .offset_extended = .{
204 .register = try leb.readUleb128(u8, reader),
205 .offset = try leb.readUleb128(u64, reader),
206 },
207 },
208 .restore_extended => .{
209 .restore_extended = .{
210 .register = try leb.readUleb128(u8, reader),
211 },
212 },
213 .undefined => .{
214 .undefined = .{
215 .register = try leb.readUleb128(u8, reader),
216 },
217 },
218 .same_value => .{
219 .same_value = .{
220 .register = try leb.readUleb128(u8, reader),
221 },
222 },
223 .register => .{
224 .register = .{
225 .register = try leb.readUleb128(u8, reader),
226 .target_register = try leb.readUleb128(u8, reader),
227 },
228 },
229 .remember_state => .{ .remember_state = {} },
230 .restore_state => .{ .restore_state = {} },
231 .def_cfa => .{
232 .def_cfa = .{
233 .register = try leb.readUleb128(u8, reader),
234 .offset = try leb.readUleb128(u64, reader),
235 },
236 },
237 .def_cfa_register => .{
238 .def_cfa_register = .{
239 .register = try leb.readUleb128(u8, reader),
240 },
241 },
242 .def_cfa_offset => .{
243 .def_cfa_offset = .{
244 .offset = try leb.readUleb128(u64, reader),
245 },
246 },
247 .def_cfa_expression => .{
248 .def_cfa_expression = .{
249 .block = try readBlock(stream),
250 },
251 },
252 .expression => .{
253 .expression = .{
254 .register = try leb.readUleb128(u8, reader),
255 .block = try readBlock(stream),
256 },
257 },
258 .offset_extended_sf => .{
259 .offset_extended_sf = .{
260 .register = try leb.readUleb128(u8, reader),
261 .offset = try leb.readIleb128(i64, reader),
262 },
263 },
264 .def_cfa_sf => .{
265 .def_cfa_sf = .{
266 .register = try leb.readUleb128(u8, reader),
267 .offset = try leb.readIleb128(i64, reader),
268 },
269 },
270 .def_cfa_offset_sf => .{
271 .def_cfa_offset_sf = .{
272 .offset = try leb.readIleb128(i64, reader),
273 },
274 },
275 .val_offset => .{
276 .val_offset = .{
277 .register = try leb.readUleb128(u8, reader),
278 .offset = try leb.readUleb128(u64, reader),
279 },
280 },
281 .val_offset_sf => .{
282 .val_offset_sf = .{
283 .register = try leb.readUleb128(u8, reader),
284 .offset = try leb.readIleb128(i64, reader),
285 },
286 },
287 .val_expression => .{
288 .val_expression = .{
289 .register = try leb.readUleb128(u8, reader),
290 .block = try readBlock(stream),
291 },
292 },
166 .advance_loc, .offset, .restore => unreachable,
167 .nop => .nop,
168 .set_loc => .{ .set_loc = .{
169 .address = switch (addr_size_bytes) {
170 2 => try reader.takeInt(u16, endian),
171 4 => try reader.takeInt(u32, endian),
172 8 => try reader.takeInt(u64, endian),
173 else => return error.InvalidAddrSize,
174 },
175 } },
176 .advance_loc1 => .{ .advance_loc1 = .{
177 .delta = try reader.takeByte(),
178 } },
179 .advance_loc2 => .{ .advance_loc2 = .{
180 .delta = try reader.takeInt(u16, endian),
181 } },
182 .advance_loc4 => .{ .advance_loc4 = .{
183 .delta = try reader.takeInt(u32, endian),
184 } },
185 .offset_extended => .{ .offset_extended = .{
186 .register = try reader.takeLeb128(u8),
187 .offset = try reader.takeLeb128(u64),
188 } },
189 .restore_extended => .{ .restore_extended = .{
190 .register = try reader.takeLeb128(u8),
191 } },
192 .undefined => .{ .undefined = .{
193 .register = try reader.takeLeb128(u8),
194 } },
195 .same_value => .{ .same_value = .{
196 .register = try reader.takeLeb128(u8),
197 } },
198 .register => .{ .register = .{
199 .register = try reader.takeLeb128(u8),
200 .target_register = try reader.takeLeb128(u8),
201 } },
202 .remember_state => .remember_state,
203 .restore_state => .restore_state,
204 .def_cfa => .{ .def_cfa = .{
205 .register = try reader.takeLeb128(u8),
206 .offset = try reader.takeLeb128(u64),
207 } },
208 .def_cfa_register => .{ .def_cfa_register = .{
209 .register = try reader.takeLeb128(u8),
210 } },
211 .def_cfa_offset => .{ .def_cfa_offset = .{
212 .offset = try reader.takeLeb128(u64),
213 } },
214 .def_cfa_expression => .{ .def_cfa_expression = .{
215 .block = try reader.take(try reader.takeLeb128(usize)),
216 } },
217 .expression => .{ .expression = .{
218 .register = try reader.takeLeb128(u8),
219 .block = try reader.take(try reader.takeLeb128(usize)),
220 } },
221 .offset_extended_sf => .{ .offset_extended_sf = .{
222 .register = try reader.takeLeb128(u8),
223 .offset = try reader.takeLeb128(i64),
224 } },
225 .def_cfa_sf => .{ .def_cfa_sf = .{
226 .register = try reader.takeLeb128(u8),
227 .offset = try reader.takeLeb128(i64),
228 } },
229 .def_cfa_offset_sf => .{ .def_cfa_offset_sf = .{
230 .offset = try reader.takeLeb128(i64),
231 } },
232 .val_offset => .{ .val_offset = .{
233 .register = try reader.takeLeb128(u8),
234 .offset = try reader.takeLeb128(u64),
235 } },
236 .val_offset_sf => .{ .val_offset_sf = .{
237 .register = try reader.takeLeb128(u8),
238 .offset = try reader.takeLeb128(i64),
239 } },
240 .val_expression => .{ .val_expression = .{
241 .register = try reader.takeLeb128(u8),
242 .block = try reader.take(try reader.takeLeb128(usize)),
243 } },
293244 };
294245 },
295246 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
lib/std/debug/Dwarf/expression.zig+86-122
......@@ -68,14 +68,14 @@ pub const Error = error{
6868/// Expressions can be decoded for non-native address size and endianness,
6969/// but can only be executed if the current target matches the configuration.
7070pub fn StackMachine(comptime options: Options) type {
71 const addr_type = switch (options.addr_size) {
71 const Address = switch (options.addr_size) {
7272 2 => u16,
7373 4 => u32,
7474 8 => u64,
7575 else => @compileError("Unsupported address size of " ++ options.addr_size),
7676 };
7777
78 const addr_type_signed = switch (options.addr_size) {
78 const SignedAddress = switch (options.addr_size) {
7979 2 => i16,
8080 4 => i32,
8181 8 => i64,
......@@ -86,7 +86,7 @@ pub fn StackMachine(comptime options: Options) type {
8686 const Self = @This();
8787
8888 const Operand = union(enum) {
89 generic: addr_type,
89 generic: Address,
9090 register: u8,
9191 type_size: u8,
9292 branch_offset: i16,
......@@ -101,38 +101,38 @@ pub fn StackMachine(comptime options: Options) type {
101101 block: []const u8,
102102 register_type: struct {
103103 register: u8,
104 type_offset: addr_type,
104 type_offset: Address,
105105 },
106106 const_type: struct {
107 type_offset: addr_type,
107 type_offset: Address,
108108 value_bytes: []const u8,
109109 },
110110 deref_type: struct {
111111 size: u8,
112 type_offset: addr_type,
112 type_offset: Address,
113113 },
114114 };
115115
116116 const Value = union(enum) {
117 generic: addr_type,
117 generic: Address,
118118
119119 // Typed value with a maximum size of a register
120120 regval_type: struct {
121121 // Offset of DW_TAG_base_type DIE
122 type_offset: addr_type,
122 type_offset: Address,
123123 type_size: u8,
124 value: addr_type,
124 value: Address,
125125 },
126126
127127 // Typed value specified directly in the instruction stream
128128 const_type: struct {
129129 // Offset of DW_TAG_base_type DIE
130 type_offset: addr_type,
130 type_offset: Address,
131131 // Backed by the instruction stream
132132 value_bytes: []const u8,
133133 },
134134
135 pub fn asIntegral(self: Value) !addr_type {
135 pub fn asIntegral(self: Value) !Address {
136136 return switch (self) {
137137 .generic => |v| v,
138138
......@@ -147,7 +147,7 @@ pub fn StackMachine(comptime options: Options) type {
147147 else => return error.InvalidIntegralTypeSize,
148148 };
149149
150 return std.math.cast(addr_type, value) orelse error.TruncatedIntegralType;
150 return std.math.cast(Address, value) orelse error.TruncatedIntegralType;
151151 },
152152 };
153153 }
......@@ -167,119 +167,87 @@ pub fn StackMachine(comptime options: Options) type {
167167 const int_info = @typeInfo(@TypeOf(value)).int;
168168 if (@sizeOf(@TypeOf(value)) > options.addr_size) {
169169 return .{ .generic = switch (int_info.signedness) {
170 .signed => @bitCast(@as(addr_type_signed, @truncate(value))),
170 .signed => @bitCast(@as(SignedAddress, @truncate(value))),
171171 .unsigned => @truncate(value),
172172 } };
173173 } else {
174174 return .{ .generic = switch (int_info.signedness) {
175 .signed => @bitCast(@as(addr_type_signed, @intCast(value))),
175 .signed => @bitCast(@as(SignedAddress, @intCast(value))),
176176 .unsigned => @intCast(value),
177177 } };
178178 }
179179 }
180180
181 pub fn readOperand(stream: *std.io.FixedBufferStream, opcode: u8, context: Context) !?Operand {
182 const reader = stream.reader();
181 pub fn readOperand(reader: *std.io.BufferedReader, opcode: u8, context: Context) !?Operand {
183182 return switch (opcode) {
184 OP.addr => generic(try reader.readInt(addr_type, options.endian)),
183 OP.addr => generic(try reader.takeInt(Address, options.endian)),
185184 OP.call_ref => switch (context.format) {
186 .@"32" => generic(try reader.readInt(u32, options.endian)),
187 .@"64" => generic(try reader.readInt(u64, options.endian)),
185 .@"32" => generic(try reader.takeInt(u32, options.endian)),
186 .@"64" => generic(try reader.takeInt(u64, options.endian)),
188187 },
189188 OP.const1u,
190189 OP.pick,
191 => generic(try reader.readByte()),
190 => generic(try reader.takeByte()),
192191 OP.deref_size,
193192 OP.xderef_size,
194 => .{ .type_size = try reader.readByte() },
195 OP.const1s => generic(try reader.readByteSigned()),
193 => .{ .type_size = try reader.takeByte() },
194 OP.const1s => generic(try reader.takeByteSigned()),
196195 OP.const2u,
197196 OP.call2,
198 => generic(try reader.readInt(u16, options.endian)),
199 OP.call4 => generic(try reader.readInt(u32, options.endian)),
200 OP.const2s => generic(try reader.readInt(i16, options.endian)),
197 => generic(try reader.takeInt(u16, options.endian)),
198 OP.call4 => generic(try reader.takeInt(u32, options.endian)),
199 OP.const2s => generic(try reader.takeInt(i16, options.endian)),
201200 OP.bra,
202201 OP.skip,
203 => .{ .branch_offset = try reader.readInt(i16, options.endian) },
204 OP.const4u => generic(try reader.readInt(u32, options.endian)),
205 OP.const4s => generic(try reader.readInt(i32, options.endian)),
206 OP.const8u => generic(try reader.readInt(u64, options.endian)),
207 OP.const8s => generic(try reader.readInt(i64, options.endian)),
202 => .{ .branch_offset = try reader.takeInt(i16, options.endian) },
203 OP.const4u => generic(try reader.takeInt(u32, options.endian)),
204 OP.const4s => generic(try reader.takeInt(i32, options.endian)),
205 OP.const8u => generic(try reader.takeInt(u64, options.endian)),
206 OP.const8s => generic(try reader.takeInt(i64, options.endian)),
208207 OP.constu,
209208 OP.plus_uconst,
210209 OP.addrx,
211210 OP.constx,
212211 OP.convert,
213212 OP.reinterpret,
214 => generic(try leb.readUleb128(u64, reader)),
213 => generic(try reader.takeLeb128(u64)),
215214 OP.consts,
216215 OP.fbreg,
217 => generic(try leb.readIleb128(i64, reader)),
216 => generic(try reader.takeLeb128(i64)),
218217 OP.lit0...OP.lit31 => |n| generic(n - OP.lit0),
219218 OP.reg0...OP.reg31 => |n| .{ .register = n - OP.reg0 },
220219 OP.breg0...OP.breg31 => |n| .{ .base_register = .{
221220 .base_register = n - OP.breg0,
222 .offset = try leb.readIleb128(i64, reader),
221 .offset = try reader.takeLeb128(i64),
223222 } },
224 OP.regx => .{ .register = try leb.readUleb128(u8, reader) },
225 OP.bregx => blk: {
226 const base_register = try leb.readUleb128(u8, reader);
227 const offset = try leb.readIleb128(i64, reader);
228 break :blk .{ .base_register = .{
229 .base_register = base_register,
230 .offset = offset,
231 } };
232 },
233 OP.regval_type => blk: {
234 const register = try leb.readUleb128(u8, reader);
235 const type_offset = try leb.readUleb128(addr_type, reader);
236 break :blk .{ .register_type = .{
237 .register = register,
238 .type_offset = type_offset,
239 } };
240 },
241 OP.piece => .{
242 .composite_location = .{
243 .size = try leb.readUleb128(u8, reader),
244 .offset = 0,
245 },
246 },
247 OP.bit_piece => blk: {
248 const size = try leb.readUleb128(u8, reader);
249 const offset = try leb.readIleb128(i64, reader);
250 break :blk .{ .composite_location = .{
251 .size = size,
252 .offset = offset,
253 } };
254 },
255 OP.implicit_value, OP.entry_value => blk: {
256 const size = try leb.readUleb128(u8, reader);
257 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
258 const block = stream.buffer[stream.pos..][0..size];
259 stream.pos += size;
260 break :blk .{
261 .block = block,
262 };
263 },
264 OP.const_type => blk: {
265 const type_offset = try leb.readUleb128(addr_type, reader);
266 const size = try reader.readByte();
267 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
268 const value_bytes = stream.buffer[stream.pos..][0..size];
269 stream.pos += size;
270 break :blk .{ .const_type = .{
271 .type_offset = type_offset,
272 .value_bytes = value_bytes,
273 } };
274 },
275 OP.deref_type,
276 OP.xderef_type,
277 => .{
278 .deref_type = .{
279 .size = try reader.readByte(),
280 .type_offset = try leb.readUleb128(addr_type, reader),
281 },
223 OP.regx => .{ .register = try reader.takeLeb128(u8) },
224 OP.bregx => .{ .base_register = .{
225 .base_register = try reader.takeLeb128(u8),
226 .offset = try reader.takeLeb128(i64),
227 } },
228 OP.regval_type => .{ .register_type = .{
229 .register = try reader.takeLeb128(u8),
230 .type_offset = try reader.takeLeb128(Address),
231 } },
232 OP.piece => .{ .composite_location = .{
233 .size = try reader.takeLeb128(u64),
234 .offset = 0,
235 } },
236 OP.bit_piece => .{ .composite_location = .{
237 .size = try reader.takeLeb128(u64),
238 .offset = try reader.takeLeb128(i64),
239 } },
240 OP.implicit_value, OP.entry_value => .{
241 .block = try reader.take(try reader.takeLeb128(usize)),
282242 },
243 OP.const_type => .{ .const_type = .{
244 .type_offset = try reader.takeLeb128(Address),
245 .value_bytes = try reader.take(try reader.takeByte()),
246 } },
247 OP.deref_type, OP.xderef_type => .{ .deref_type = .{
248 .size = try reader.takeByte(),
249 .type_offset = try reader.takeLeb128(Address),
250 } },
283251 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,
284252 else => null,
285253 };
......@@ -291,10 +259,11 @@ pub fn StackMachine(comptime options: Options) type {
291259 allocator: std.mem.Allocator,
292260 context: Context,
293261 initial_value: ?usize,
294 ) Error!?Value {
262 ) anyerror!?Value {
295263 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
296 var stream: std.io.FixedBufferStream = .{ .buffer = expression };
297 while (try self.step(&stream, allocator, context)) {}
264 var reader: std.io.BufferedReader = undefined;
265 reader.initFixed(expression);
266 while (try self.step(&reader, allocator, context)) {}
298267 if (self.stack.items.len == 0) return null;
299268 return self.stack.items[self.stack.items.len - 1];
300269 }
......@@ -302,16 +271,19 @@ pub fn StackMachine(comptime options: Options) type {
302271 /// Reads an opcode and its operands from `stream`, then executes it
303272 pub fn step(
304273 self: *Self,
305 stream: *std.io.FixedBufferStream,
274 reader: *std.io.BufferedReader,
306275 allocator: std.mem.Allocator,
307276 context: Context,
308 ) Error!bool {
309 if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != native_endian)
277 ) anyerror!bool {
278 if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian)
310279 @compileError("Execution of non-native address sizes / endianness is not supported");
311280
312 const opcode = try stream.reader().readByte();
281 const opcode = reader.takeByte() catch |err| switch (err) {
282 error.EndOfStream => return false,
283 else => |e| return @errorCast(e),
284 };
313285 if (options.call_frame_context and !isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
314 const operand = try readOperand(stream, opcode, context);
286 const operand = try readOperand(reader, opcode, context);
315287 switch (opcode) {
316288
317289 // 2.5.1.1: Literal Encodings
......@@ -397,7 +369,7 @@ pub fn StackMachine(comptime options: Options) type {
397369 try self.stack.append(allocator, .{
398370 .regval_type = .{
399371 .type_offset = register_type.type_offset,
400 .type_size = @sizeOf(addr_type),
372 .type_size = @sizeOf(Address),
401373 .value = value,
402374 },
403375 });
......@@ -455,7 +427,7 @@ pub fn StackMachine(comptime options: Options) type {
455427 const size = switch (opcode) {
456428 OP.deref,
457429 OP.xderef,
458 => @sizeOf(addr_type),
430 => @sizeOf(Address),
459431 OP.deref_size,
460432 OP.xderef_size,
461433 => operand.?.type_size,
......@@ -475,7 +447,7 @@ pub fn StackMachine(comptime options: Options) type {
475447 }) return error.InvalidExpression;
476448 }
477449
478 const value: addr_type = std.math.cast(addr_type, @as(u64, switch (size) {
450 const value: Address = std.math.cast(Address, @as(u64, switch (size) {
479451 1 => @as(*const u8, @ptrFromInt(addr)).*,
480452 2 => @as(*const u16, @ptrFromInt(addr)).*,
481453 4 => @as(*const u32, @ptrFromInt(addr)).*,
......@@ -544,7 +516,7 @@ pub fn StackMachine(comptime options: Options) type {
544516 if (self.stack.items.len < 2) return error.InvalidExpression;
545517 const b = try self.stack.pop().?.asIntegral();
546518 self.stack.items[self.stack.items.len - 1] = .{
547 .generic = try std.math.sub(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
519 .generic = try std.math.sub(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
548520 };
549521 },
550522 OP.mod => {
......@@ -590,14 +562,14 @@ pub fn StackMachine(comptime options: Options) type {
590562 if (self.stack.items.len < 2) return error.InvalidExpression;
591563 const b = try self.stack.pop().?.asIntegral();
592564 self.stack.items[self.stack.items.len - 1] = .{
593 .generic = try std.math.add(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
565 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
594566 };
595567 },
596568 OP.plus_uconst => {
597569 if (self.stack.items.len == 0) return error.InvalidExpression;
598570 const constant = operand.?.generic;
599571 self.stack.items[self.stack.items.len - 1] = .{
600 .generic = try std.math.add(addr_type, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
572 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
601573 };
602574 },
603575 OP.shl => {
......@@ -670,15 +642,7 @@ pub fn StackMachine(comptime options: Options) type {
670642 break :blk try self.stack.pop().?.asIntegral() != 0;
671643 } else true;
672644
673 if (condition) {
674 const new_pos = std.math.cast(
675 usize,
676 try std.math.add(isize, @as(isize, @intCast(stream.pos)), branch_offset),
677 ) orelse return error.InvalidExpression;
678
679 if (new_pos < 0 or new_pos > stream.buffer.len) return error.InvalidExpression;
680 stream.pos = new_pos;
681 }
645 if (condition) reader.seekBy(branch_offset) catch return error.InvalidExpression;
682646 },
683647 OP.call2,
684648 OP.call4,
......@@ -722,7 +686,7 @@ pub fn StackMachine(comptime options: Options) type {
722686 .generic => |v| .{
723687 .regval_type = .{
724688 .type_offset = type_offset,
725 .type_size = @sizeOf(addr_type),
689 .type_size = @sizeOf(Address),
726690 .value = v,
727691 },
728692 },
......@@ -756,8 +720,9 @@ pub fn StackMachine(comptime options: Options) type {
756720 if (isOpcodeRegisterLocation(block[0])) {
757721 if (context.thread_context == null) return error.IncompleteExpressionContext;
758722
759 var block_stream: std.io.FixedBufferStream = .{ .buffer = block };
760 const register = (try readOperand(&block_stream, block[0], context)).?.register;
723 var block_reader: std.io.BufferedReader = undefined;
724 block_reader.initFixed(block);
725 const register = (try readOperand(&block_reader, block[0], context)).?.register;
761726 const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);
762727 try self.stack.append(allocator, .{ .generic = value });
763728 } else {
......@@ -778,14 +743,13 @@ pub fn StackMachine(comptime options: Options) type {
778743 return error.UnknownExpressionOpcode;
779744 },
780745 }
781
782 return stream.pos < stream.buffer.len;
746 return true;
783747 }
784748 };
785749}
786750
787751pub fn Builder(comptime options: Options) type {
788 const addr_type = switch (options.addr_size) {
752 const Address = switch (options.addr_size) {
789753 2 => u16,
790754 4 => u32,
791755 8 => u64,
......@@ -888,9 +852,9 @@ pub fn Builder(comptime options: Options) type {
888852 try writer.writeAll(value_bytes);
889853 }
890854
891 pub fn writeAddr(writer: anytype, value: addr_type) !void {
855 pub fn writeAddr(writer: anytype, value: Address) !void {
892856 try writer.writeByte(OP.addr);
893 try writer.writeInt(addr_type, value, options.endian);
857 try writer.writeInt(Address, value, options.endian);
894858 }
895859
896860 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {
lib/std/debug/FixedBufferReader.zig+7-8
......@@ -51,22 +51,21 @@ pub fn readIntChecked(
5151 return fbr.readInt(T);
5252}
5353
54pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
54pub fn readLeb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
5555 var br: std.io.BufferedReader = undefined;
5656 br.initFixed(fbr.buf);
5757 br.seek = fbr.pos;
58 const result = br.takeUleb128(T);
58 const result = br.takeLeb128(T);
5959 fbr.pos = br.seek;
6060 return @errorCast(result);
6161}
6262
63pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
64 return fbr.readLeb128(T);
65}
66
6367pub fn readIleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
64 var br: std.io.BufferedReader = undefined;
65 br.initFixed(fbr.buf);
66 br.seek = fbr.pos;
67 const result = br.takeIleb128(T);
68 fbr.pos = br.seek;
69 return @errorCast(result);
68 return fbr.readLeb128(T);
7069}
7170
7271pub fn readAddress(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64 {
lib/std/debug/SelfInfo.zig+8-11
......@@ -2025,18 +2025,15 @@ pub const VirtualMachine = struct {
20252025 assert(self.cie_row == null);
20262026 if (pc < fde.pc_begin or pc >= fde.pc_begin + fde.pc_range) return error.AddressOutOfRange;
20272027
2028 var prev_row: Row = self.current_row;
2029
2030 var cie_stream: std.io.BufferedReader = undefined;
2031 cie_stream.initFixed(cie.initial_instructions);
2032 var fde_stream: std.io.BufferedReader = undefined;
2033 fde_stream.initFixed(fde.instructions);
2034 const streams: [2]*std.io.BufferedReader = .{ &cie_stream, &fde_stream };
2028 var readers: [2]std.io.BufferedReader = undefined;
2029 readers[0].initFixed(cie.initial_instructions);
2030 readers[1].initFixed(fde.instructions);
20352031
2036 for (&streams, 0..) |stream, i| {
2037 while (stream.seek < stream.storageBuffer().len) {
2038 const instruction = try std.debug.Dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);
2039 prev_row = try self.step(allocator, cie, i == 0, instruction);
2032 var prev_row: Row = self.current_row;
2033 for (&readers, [2]bool{ true, false }) |*reader, is_initial| {
2034 while (reader.seek < reader.storageBuffer().len) {
2035 const instruction = try std.debug.Dwarf.call_frame.Instruction.read(reader, addr_size_bytes, endian);
2036 prev_row = try self.step(allocator, cie, is_initial, instruction);
20402037 if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
20412038 }
20422039 }
lib/std/io/BufferedReader.zig+74-92
......@@ -164,6 +164,21 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
164164 @panic("TODO");
165165}
166166
167pub fn seekBy(br: *BufferedReader, seek_by: i64) anyerror!void {
168 if (seek_by < 0) try br.seekBackwardBy(@abs(seek_by)) else try br.seekForwardBy(@abs(seek_by));
169}
170
171pub fn seekBackwardBy(br: *BufferedReader, seek_by: u64) anyerror!void {
172 if (seek_by > br.storage.buffer.items.len - br.seek) return error.Unseekable; // TODO
173 br.seek += @abs(seek_by);
174}
175
176pub fn seekForwardBy(br: *BufferedReader, seek_by: u64) anyerror!void {
177 const seek, const need_unbuffered_seek = @subWithOverflow(br.seek, @abs(seek_by));
178 if (need_unbuffered_seek > 0) return error.Unseekable; // TODO
179 br.seek = seek;
180}
181
167182/// Returns the next `n` bytes from `unbuffered_reader`, filling the buffer as
168183/// necessary.
169184///
......@@ -176,12 +191,31 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
176191/// is returned instead.
177192///
178193/// See also:
194/// * `peekAll`
179195/// * `toss`
180196pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 {
197 return (try br.peekAll(n))[0..n];
198}
199
200/// Returns the next buffered bytes from `unbuffered_reader`, after filling the buffer
201/// with at least `n` bytes.
202///
203/// Invalidates previously returned values from `peek`.
204///
205/// Asserts that the `BufferedReader` was initialized with a buffer capacity at
206/// least as big as `n`.
207///
208/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
209/// is returned instead.
210///
211/// See also:
212/// * `peek`
213/// * `toss`
214pub fn peekAll(br: *BufferedReader, n: usize) anyerror![]u8 {
181215 const list = &br.storage.buffer;
182216 assert(n <= list.capacity);
183 try fill(br, n);
184 return list.items[br.seek..][0..n];
217 try br.fill(n);
218 return list.items[br.seek..];
185219}
186220
187221/// Skips the next `n` bytes from the stream, advancing the seek position. This
......@@ -563,93 +597,41 @@ pub fn takeEnum(br: *BufferedReader, comptime Enum: type, endian: std.builtin.En
563597 return std.meta.intToEnum(Enum, int);
564598}
565599
566/// Read a single unsigned LEB128 value from the given reader as type T,
567/// or error.Overflow if the value cannot fit.
568pub fn takeUleb128(br: *std.io.BufferedReader, comptime T: type) anyerror!T {
569 const U = if (@typeInfo(T).int.bits < 8) u8 else T;
570 const ShiftT = std.math.Log2Int(U);
571
572 const max_group = (@typeInfo(U).int.bits + 6) / 7;
573
574 var value: U = 0;
575 var group: ShiftT = 0;
576
577 while (group < max_group) : (group += 1) {
578 const byte = try br.takeByte();
579
580 const ov = @shlWithOverflow(@as(U, byte & 0x7f), group * 7);
581 if (ov[1] != 0) return error.Overflow;
582
583 value |= ov[0];
584 if (byte & 0x80 == 0) break;
585 } else {
586 return error.Overflow;
587 }
588
589 // only applies in the case that we extended to u8
590 if (U != T) {
591 if (value > std.math.maxInt(T)) return error.Overflow;
592 }
593
594 return @truncate(value);
595}
596
597/// Read a single signed LEB128 value from the given reader as type T,
598/// or `error.Overflow` if the value cannot fit.
599pub fn takeIleb128(br: *std.io.BufferedReader, comptime T: type) anyerror!T {
600 const S = if (@typeInfo(T).int.bits < 8) i8 else T;
601 const U = std.meta.Int(.unsigned, @typeInfo(S).int.bits);
602 const ShiftU = std.math.Log2Int(U);
603
604 const max_group = (@typeInfo(U).int.bits + 6) / 7;
605
606 var value = @as(U, 0);
607 var group = @as(ShiftU, 0);
608
609 while (group < max_group) : (group += 1) {
610 const byte = try br.takeByte();
611
612 const shift = group * 7;
613 const ov = @shlWithOverflow(@as(U, byte & 0x7f), shift);
614 if (ov[1] != 0) {
615 // Overflow is ok so long as the sign bit is set and this is the last byte
616 if (byte & 0x80 != 0) return error.Overflow;
617 if (@as(S, @bitCast(ov[0])) >= 0) return error.Overflow;
618
619 // and all the overflowed bits are 1
620 const remaining_shift = @as(u3, @intCast(@typeInfo(U).int.bits - @as(u16, shift)));
621 const remaining_bits = @as(i8, @bitCast(byte | 0x80)) >> remaining_shift;
622 if (remaining_bits != -1) return error.Overflow;
623 } else {
624 // If we don't overflow and this is the last byte and the number being decoded
625 // is negative, check that the remaining bits are 1
626 if ((byte & 0x80 == 0) and (@as(S, @bitCast(ov[0])) < 0)) {
627 const remaining_shift = @as(u3, @intCast(@typeInfo(U).int.bits - @as(u16, shift)));
628 const remaining_bits = @as(i8, @bitCast(byte | 0x80)) >> remaining_shift;
629 if (remaining_bits != -1) return error.Overflow;
630 }
631 }
632
633 value |= ov[0];
634 if (byte & 0x80 == 0) {
635 const needs_sign_ext = group + 1 < max_group;
636 if (byte & 0x40 != 0 and needs_sign_ext) {
637 const ones = @as(S, -1);
638 value |= @as(U, @bitCast(ones)) << (shift + 7);
639 }
640 break;
600/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
601pub fn takeLeb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
602 const result_info = @typeInfo(Result).int;
603 return std.math.cast(Result, try br.takeMultipleOf7Leb128(@Type(.{ .int = .{
604 .signedness = result_info.signedness,
605 .bits = std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
606 } }))) orelse error.Overflow;
607}
608
609fn takeMultipleOf7Leb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
610 const result_info = @typeInfo(Result).int;
611 comptime assert(result_info.bits % 7 == 0);
612 var remaining_bits: std.math.Log2IntCeil(Result) = result_info.bits;
613 const UnsignedResult = @Type(.{ .int = .{
614 .signedness = .unsigned,
615 .bits = result_info.bits,
616 } });
617 var result: UnsignedResult = 0;
618 var fits = true;
619 while (true) {
620 const buffer: []const packed struct(u8) { bits: u7, more: bool } = @ptrCast(try br.peekAll(1));
621 for (buffer, 1..) |byte, len| {
622 if (remaining_bits > 0) {
623 result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) | @shrExact(result, 7);
624 remaining_bits -= 7;
625 } else if (fits) fits = switch (result_info.signedness) {
626 .signed => @as(i7, @bitCast(byte.bits)) == @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))),
627 .unsigned => byte.bits == 0,
628 };
629 if (byte.more) continue;
630 br.toss(len);
631 return if (fits) @as(Result, @bitCast(result)) >> remaining_bits else error.Overflow;
641632 }
642 } else {
643 return error.Overflow;
644 }
645
646 const result = @as(S, @bitCast(value));
647 // Only applies if we extended to i8
648 if (S != T) {
649 if (result > std.math.maxInt(T) or result < std.math.minInt(T)) return error.Overflow;
633 br.toss(buffer.len);
650634 }
651
652 return @truncate(result);
653635}
654636
655637test initFixed {
......@@ -669,6 +651,10 @@ test peek {
669651 return error.Unimplemented;
670652}
671653
654test peekAll {
655 return error.Unimplemented;
656}
657
672658test toss {
673659 return error.Unimplemented;
674660}
......@@ -766,10 +752,6 @@ test takeEnum {
766752 return error.Unimplemented;
767753}
768754
769test takeUleb128 {
770 return error.Unimplemented;
771}
772
773test takeIleb128 {
755test takeLeb128 {
774756 return error.Unimplemented;
775757}