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) {...@@ -51,17 +51,6 @@ const Opcode = enum(u8) {
51 pub const hi_user = 0x3f;51 pub const hi_user = 0x3f;
52};52};
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
65pub const Instruction = union(Opcode) {54pub const Instruction = union(Opcode) {
66 advance_loc: struct {55 advance_loc: struct {
67 delta: u8,56 delta: u8,
...@@ -147,12 +136,11 @@ pub const Instruction = union(Opcode) {...@@ -147,12 +136,11 @@ pub const Instruction = union(Opcode) {
147 },136 },
148137
149 pub fn read(138 pub fn read(
150 stream: *std.io.FixedBufferStream,139 reader: *std.io.BufferedReader,
151 addr_size_bytes: u8,140 addr_size_bytes: u8,
152 endian: std.builtin.Endian,141 endian: std.builtin.Endian,
153 ) !Instruction {142 ) !Instruction {
154 const reader = stream.reader();143 switch (try reader.takeByte()) {
155 switch (try reader.readByte()) {
156 Opcode.lo_inline...Opcode.hi_inline => |opcode| {144 Opcode.lo_inline...Opcode.hi_inline => |opcode| {
157 const e: Opcode = @enumFromInt(opcode & 0b11000000);145 const e: Opcode = @enumFromInt(opcode & 0b11000000);
158 const value: u6 = @intCast(opcode & 0b111111);146 const value: u6 = @intCast(opcode & 0b111111);
...@@ -163,7 +151,7 @@ pub const Instruction = union(Opcode) {...@@ -163,7 +151,7 @@ pub const Instruction = union(Opcode) {
163 .offset => .{151 .offset => .{
164 .offset = .{152 .offset = .{
165 .register = value,153 .register = value,
166 .offset = try leb.readUleb128(u64, reader),154 .offset = try reader.takeLeb128(u64),
167 },155 },
168 },156 },
169 .restore => .{157 .restore => .{
...@@ -175,121 +163,84 @@ pub const Instruction = union(Opcode) {...@@ -175,121 +163,84 @@ pub const Instruction = union(Opcode) {
175 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {163 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
176 const e: Opcode = @enumFromInt(opcode);164 const e: Opcode = @enumFromInt(opcode);
177 return switch (e) {165 return switch (e) {
178 .advance_loc,166 .advance_loc, .offset, .restore => unreachable,
179 .offset,167 .nop => .nop,
180 .restore,168 .set_loc => .{ .set_loc = .{
181 => unreachable,169 .address = switch (addr_size_bytes) {
182 .nop => .{ .nop = {} },170 2 => try reader.takeInt(u16, endian),
183 .set_loc => .{171 4 => try reader.takeInt(u32, endian),
184 .set_loc = .{172 8 => try reader.takeInt(u64, endian),
185 .address = switch (addr_size_bytes) {173 else => return error.InvalidAddrSize,
186 2 => try reader.readInt(u16, endian),174 },
187 4 => try reader.readInt(u32, endian),175 } },
188 8 => try reader.readInt(u64, endian),176 .advance_loc1 => .{ .advance_loc1 = .{
189 else => return error.InvalidAddrSize,177 .delta = try reader.takeByte(),
190 },178 } },
191 },179 .advance_loc2 => .{ .advance_loc2 = .{
192 },180 .delta = try reader.takeInt(u16, endian),
193 .advance_loc1 => .{181 } },
194 .advance_loc1 = .{ .delta = try reader.readByte() },182 .advance_loc4 => .{ .advance_loc4 = .{
195 },183 .delta = try reader.takeInt(u32, endian),
196 .advance_loc2 => .{184 } },
197 .advance_loc2 = .{ .delta = try reader.readInt(u16, endian) },185 .offset_extended => .{ .offset_extended = .{
198 },186 .register = try reader.takeLeb128(u8),
199 .advance_loc4 => .{187 .offset = try reader.takeLeb128(u64),
200 .advance_loc4 = .{ .delta = try reader.readInt(u32, endian) },188 } },
201 },189 .restore_extended => .{ .restore_extended = .{
202 .offset_extended => .{190 .register = try reader.takeLeb128(u8),
203 .offset_extended = .{191 } },
204 .register = try leb.readUleb128(u8, reader),192 .undefined => .{ .undefined = .{
205 .offset = try leb.readUleb128(u64, reader),193 .register = try reader.takeLeb128(u8),
206 },194 } },
207 },195 .same_value => .{ .same_value = .{
208 .restore_extended => .{196 .register = try reader.takeLeb128(u8),
209 .restore_extended = .{197 } },
210 .register = try leb.readUleb128(u8, reader),198 .register => .{ .register = .{
211 },199 .register = try reader.takeLeb128(u8),
212 },200 .target_register = try reader.takeLeb128(u8),
213 .undefined => .{201 } },
214 .undefined = .{202 .remember_state => .remember_state,
215 .register = try leb.readUleb128(u8, reader),203 .restore_state => .restore_state,
216 },204 .def_cfa => .{ .def_cfa = .{
217 },205 .register = try reader.takeLeb128(u8),
218 .same_value => .{206 .offset = try reader.takeLeb128(u64),
219 .same_value = .{207 } },
220 .register = try leb.readUleb128(u8, reader),208 .def_cfa_register => .{ .def_cfa_register = .{
221 },209 .register = try reader.takeLeb128(u8),
222 },210 } },
223 .register => .{211 .def_cfa_offset => .{ .def_cfa_offset = .{
224 .register = .{212 .offset = try reader.takeLeb128(u64),
225 .register = try leb.readUleb128(u8, reader),213 } },
226 .target_register = try leb.readUleb128(u8, reader),214 .def_cfa_expression => .{ .def_cfa_expression = .{
227 },215 .block = try reader.take(try reader.takeLeb128(usize)),
228 },216 } },
229 .remember_state => .{ .remember_state = {} },217 .expression => .{ .expression = .{
230 .restore_state => .{ .restore_state = {} },218 .register = try reader.takeLeb128(u8),
231 .def_cfa => .{219 .block = try reader.take(try reader.takeLeb128(usize)),
232 .def_cfa = .{220 } },
233 .register = try leb.readUleb128(u8, reader),221 .offset_extended_sf => .{ .offset_extended_sf = .{
234 .offset = try leb.readUleb128(u64, reader),222 .register = try reader.takeLeb128(u8),
235 },223 .offset = try reader.takeLeb128(i64),
236 },224 } },
237 .def_cfa_register => .{225 .def_cfa_sf => .{ .def_cfa_sf = .{
238 .def_cfa_register = .{226 .register = try reader.takeLeb128(u8),
239 .register = try leb.readUleb128(u8, reader),227 .offset = try reader.takeLeb128(i64),
240 },228 } },
241 },229 .def_cfa_offset_sf => .{ .def_cfa_offset_sf = .{
242 .def_cfa_offset => .{230 .offset = try reader.takeLeb128(i64),
243 .def_cfa_offset = .{231 } },
244 .offset = try leb.readUleb128(u64, reader),232 .val_offset => .{ .val_offset = .{
245 },233 .register = try reader.takeLeb128(u8),
246 },234 .offset = try reader.takeLeb128(u64),
247 .def_cfa_expression => .{235 } },
248 .def_cfa_expression = .{236 .val_offset_sf => .{ .val_offset_sf = .{
249 .block = try readBlock(stream),237 .register = try reader.takeLeb128(u8),
250 },238 .offset = try reader.takeLeb128(i64),
251 },239 } },
252 .expression => .{240 .val_expression => .{ .val_expression = .{
253 .expression = .{241 .register = try reader.takeLeb128(u8),
254 .register = try leb.readUleb128(u8, reader),242 .block = try reader.take(try reader.takeLeb128(usize)),
255 .block = try readBlock(stream),243 } },
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 },
293 };244 };
294 },245 },
295 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,246 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{...@@ -68,14 +68,14 @@ pub const Error = error{
68/// Expressions can be decoded for non-native address size and endianness,68/// Expressions can be decoded for non-native address size and endianness,
69/// but can only be executed if the current target matches the configuration.69/// but can only be executed if the current target matches the configuration.
70pub fn StackMachine(comptime options: Options) type {70pub fn StackMachine(comptime options: Options) type {
71 const addr_type = switch (options.addr_size) {71 const Address = switch (options.addr_size) {
72 2 => u16,72 2 => u16,
73 4 => u32,73 4 => u32,
74 8 => u64,74 8 => u64,
75 else => @compileError("Unsupported address size of " ++ options.addr_size),75 else => @compileError("Unsupported address size of " ++ options.addr_size),
76 };76 };
7777
78 const addr_type_signed = switch (options.addr_size) {78 const SignedAddress = switch (options.addr_size) {
79 2 => i16,79 2 => i16,
80 4 => i32,80 4 => i32,
81 8 => i64,81 8 => i64,
...@@ -86,7 +86,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -86,7 +86,7 @@ pub fn StackMachine(comptime options: Options) type {
86 const Self = @This();86 const Self = @This();
8787
88 const Operand = union(enum) {88 const Operand = union(enum) {
89 generic: addr_type,89 generic: Address,
90 register: u8,90 register: u8,
91 type_size: u8,91 type_size: u8,
92 branch_offset: i16,92 branch_offset: i16,
...@@ -101,38 +101,38 @@ pub fn StackMachine(comptime options: Options) type {...@@ -101,38 +101,38 @@ pub fn StackMachine(comptime options: Options) type {
101 block: []const u8,101 block: []const u8,
102 register_type: struct {102 register_type: struct {
103 register: u8,103 register: u8,
104 type_offset: addr_type,104 type_offset: Address,
105 },105 },
106 const_type: struct {106 const_type: struct {
107 type_offset: addr_type,107 type_offset: Address,
108 value_bytes: []const u8,108 value_bytes: []const u8,
109 },109 },
110 deref_type: struct {110 deref_type: struct {
111 size: u8,111 size: u8,
112 type_offset: addr_type,112 type_offset: Address,
113 },113 },
114 };114 };
115115
116 const Value = union(enum) {116 const Value = union(enum) {
117 generic: addr_type,117 generic: Address,
118118
119 // Typed value with a maximum size of a register119 // Typed value with a maximum size of a register
120 regval_type: struct {120 regval_type: struct {
121 // Offset of DW_TAG_base_type DIE121 // Offset of DW_TAG_base_type DIE
122 type_offset: addr_type,122 type_offset: Address,
123 type_size: u8,123 type_size: u8,
124 value: addr_type,124 value: Address,
125 },125 },
126126
127 // Typed value specified directly in the instruction stream127 // Typed value specified directly in the instruction stream
128 const_type: struct {128 const_type: struct {
129 // Offset of DW_TAG_base_type DIE129 // Offset of DW_TAG_base_type DIE
130 type_offset: addr_type,130 type_offset: Address,
131 // Backed by the instruction stream131 // Backed by the instruction stream
132 value_bytes: []const u8,132 value_bytes: []const u8,
133 },133 },
134134
135 pub fn asIntegral(self: Value) !addr_type {135 pub fn asIntegral(self: Value) !Address {
136 return switch (self) {136 return switch (self) {
137 .generic => |v| v,137 .generic => |v| v,
138138
...@@ -147,7 +147,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -147,7 +147,7 @@ pub fn StackMachine(comptime options: Options) type {
147 else => return error.InvalidIntegralTypeSize,147 else => return error.InvalidIntegralTypeSize,
148 };148 };
149149
150 return std.math.cast(addr_type, value) orelse error.TruncatedIntegralType;150 return std.math.cast(Address, value) orelse error.TruncatedIntegralType;
151 },151 },
152 };152 };
153 }153 }
...@@ -167,119 +167,87 @@ pub fn StackMachine(comptime options: Options) type {...@@ -167,119 +167,87 @@ pub fn StackMachine(comptime options: Options) type {
167 const int_info = @typeInfo(@TypeOf(value)).int;167 const int_info = @typeInfo(@TypeOf(value)).int;
168 if (@sizeOf(@TypeOf(value)) > options.addr_size) {168 if (@sizeOf(@TypeOf(value)) > options.addr_size) {
169 return .{ .generic = switch (int_info.signedness) {169 return .{ .generic = switch (int_info.signedness) {
170 .signed => @bitCast(@as(addr_type_signed, @truncate(value))),170 .signed => @bitCast(@as(SignedAddress, @truncate(value))),
171 .unsigned => @truncate(value),171 .unsigned => @truncate(value),
172 } };172 } };
173 } else {173 } else {
174 return .{ .generic = switch (int_info.signedness) {174 return .{ .generic = switch (int_info.signedness) {
175 .signed => @bitCast(@as(addr_type_signed, @intCast(value))),175 .signed => @bitCast(@as(SignedAddress, @intCast(value))),
176 .unsigned => @intCast(value),176 .unsigned => @intCast(value),
177 } };177 } };
178 }178 }
179 }179 }
180180
181 pub fn readOperand(stream: *std.io.FixedBufferStream, opcode: u8, context: Context) !?Operand {181 pub fn readOperand(reader: *std.io.BufferedReader, opcode: u8, context: Context) !?Operand {
182 const reader = stream.reader();
183 return switch (opcode) {182 return switch (opcode) {
184 OP.addr => generic(try reader.readInt(addr_type, options.endian)),183 OP.addr => generic(try reader.takeInt(Address, options.endian)),
185 OP.call_ref => switch (context.format) {184 OP.call_ref => switch (context.format) {
186 .@"32" => generic(try reader.readInt(u32, options.endian)),185 .@"32" => generic(try reader.takeInt(u32, options.endian)),
187 .@"64" => generic(try reader.readInt(u64, options.endian)),186 .@"64" => generic(try reader.takeInt(u64, options.endian)),
188 },187 },
189 OP.const1u,188 OP.const1u,
190 OP.pick,189 OP.pick,
191 => generic(try reader.readByte()),190 => generic(try reader.takeByte()),
192 OP.deref_size,191 OP.deref_size,
193 OP.xderef_size,192 OP.xderef_size,
194 => .{ .type_size = try reader.readByte() },193 => .{ .type_size = try reader.takeByte() },
195 OP.const1s => generic(try reader.readByteSigned()),194 OP.const1s => generic(try reader.takeByteSigned()),
196 OP.const2u,195 OP.const2u,
197 OP.call2,196 OP.call2,
198 => generic(try reader.readInt(u16, options.endian)),197 => generic(try reader.takeInt(u16, options.endian)),
199 OP.call4 => generic(try reader.readInt(u32, options.endian)),198 OP.call4 => generic(try reader.takeInt(u32, options.endian)),
200 OP.const2s => generic(try reader.readInt(i16, options.endian)),199 OP.const2s => generic(try reader.takeInt(i16, options.endian)),
201 OP.bra,200 OP.bra,
202 OP.skip,201 OP.skip,
203 => .{ .branch_offset = try reader.readInt(i16, options.endian) },202 => .{ .branch_offset = try reader.takeInt(i16, options.endian) },
204 OP.const4u => generic(try reader.readInt(u32, options.endian)),203 OP.const4u => generic(try reader.takeInt(u32, options.endian)),
205 OP.const4s => generic(try reader.readInt(i32, options.endian)),204 OP.const4s => generic(try reader.takeInt(i32, options.endian)),
206 OP.const8u => generic(try reader.readInt(u64, options.endian)),205 OP.const8u => generic(try reader.takeInt(u64, options.endian)),
207 OP.const8s => generic(try reader.readInt(i64, options.endian)),206 OP.const8s => generic(try reader.takeInt(i64, options.endian)),
208 OP.constu,207 OP.constu,
209 OP.plus_uconst,208 OP.plus_uconst,
210 OP.addrx,209 OP.addrx,
211 OP.constx,210 OP.constx,
212 OP.convert,211 OP.convert,
213 OP.reinterpret,212 OP.reinterpret,
214 => generic(try leb.readUleb128(u64, reader)),213 => generic(try reader.takeLeb128(u64)),
215 OP.consts,214 OP.consts,
216 OP.fbreg,215 OP.fbreg,
217 => generic(try leb.readIleb128(i64, reader)),216 => generic(try reader.takeLeb128(i64)),
218 OP.lit0...OP.lit31 => |n| generic(n - OP.lit0),217 OP.lit0...OP.lit31 => |n| generic(n - OP.lit0),
219 OP.reg0...OP.reg31 => |n| .{ .register = n - OP.reg0 },218 OP.reg0...OP.reg31 => |n| .{ .register = n - OP.reg0 },
220 OP.breg0...OP.breg31 => |n| .{ .base_register = .{219 OP.breg0...OP.breg31 => |n| .{ .base_register = .{
221 .base_register = n - OP.breg0,220 .base_register = n - OP.breg0,
222 .offset = try leb.readIleb128(i64, reader),221 .offset = try reader.takeLeb128(i64),
223 } },222 } },
224 OP.regx => .{ .register = try leb.readUleb128(u8, reader) },223 OP.regx => .{ .register = try reader.takeLeb128(u8) },
225 OP.bregx => blk: {224 OP.bregx => .{ .base_register = .{
226 const base_register = try leb.readUleb128(u8, reader);225 .base_register = try reader.takeLeb128(u8),
227 const offset = try leb.readIleb128(i64, reader);226 .offset = try reader.takeLeb128(i64),
228 break :blk .{ .base_register = .{227 } },
229 .base_register = base_register,228 OP.regval_type => .{ .register_type = .{
230 .offset = offset,229 .register = try reader.takeLeb128(u8),
231 } };230 .type_offset = try reader.takeLeb128(Address),
232 },231 } },
233 OP.regval_type => blk: {232 OP.piece => .{ .composite_location = .{
234 const register = try leb.readUleb128(u8, reader);233 .size = try reader.takeLeb128(u64),
235 const type_offset = try leb.readUleb128(addr_type, reader);234 .offset = 0,
236 break :blk .{ .register_type = .{235 } },
237 .register = register,236 OP.bit_piece => .{ .composite_location = .{
238 .type_offset = type_offset,237 .size = try reader.takeLeb128(u64),
239 } };238 .offset = try reader.takeLeb128(i64),
240 },239 } },
241 OP.piece => .{240 OP.implicit_value, OP.entry_value => .{
242 .composite_location = .{241 .block = try reader.take(try reader.takeLeb128(usize)),
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 },
282 },242 },
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 } },
283 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,251 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,
284 else => null,252 else => null,
285 };253 };
...@@ -291,10 +259,11 @@ pub fn StackMachine(comptime options: Options) type {...@@ -291,10 +259,11 @@ pub fn StackMachine(comptime options: Options) type {
291 allocator: std.mem.Allocator,259 allocator: std.mem.Allocator,
292 context: Context,260 context: Context,
293 initial_value: ?usize,261 initial_value: ?usize,
294 ) Error!?Value {262 ) anyerror!?Value {
295 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });263 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
296 var stream: std.io.FixedBufferStream = .{ .buffer = expression };264 var reader: std.io.BufferedReader = undefined;
297 while (try self.step(&stream, allocator, context)) {}265 reader.initFixed(expression);
266 while (try self.step(&reader, allocator, context)) {}
298 if (self.stack.items.len == 0) return null;267 if (self.stack.items.len == 0) return null;
299 return self.stack.items[self.stack.items.len - 1];268 return self.stack.items[self.stack.items.len - 1];
300 }269 }
...@@ -302,16 +271,19 @@ pub fn StackMachine(comptime options: Options) type {...@@ -302,16 +271,19 @@ pub fn StackMachine(comptime options: Options) type {
302 /// Reads an opcode and its operands from `stream`, then executes it271 /// Reads an opcode and its operands from `stream`, then executes it
303 pub fn step(272 pub fn step(
304 self: *Self,273 self: *Self,
305 stream: *std.io.FixedBufferStream,274 reader: *std.io.BufferedReader,
306 allocator: std.mem.Allocator,275 allocator: std.mem.Allocator,
307 context: Context,276 context: Context,
308 ) Error!bool {277 ) anyerror!bool {
309 if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != native_endian)278 if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian)
310 @compileError("Execution of non-native address sizes / endianness is not supported");279 @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 };
313 if (options.call_frame_context and !isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;285 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);
315 switch (opcode) {287 switch (opcode) {
316288
317 // 2.5.1.1: Literal Encodings289 // 2.5.1.1: Literal Encodings
...@@ -397,7 +369,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -397,7 +369,7 @@ pub fn StackMachine(comptime options: Options) type {
397 try self.stack.append(allocator, .{369 try self.stack.append(allocator, .{
398 .regval_type = .{370 .regval_type = .{
399 .type_offset = register_type.type_offset,371 .type_offset = register_type.type_offset,
400 .type_size = @sizeOf(addr_type),372 .type_size = @sizeOf(Address),
401 .value = value,373 .value = value,
402 },374 },
403 });375 });
...@@ -455,7 +427,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -455,7 +427,7 @@ pub fn StackMachine(comptime options: Options) type {
455 const size = switch (opcode) {427 const size = switch (opcode) {
456 OP.deref,428 OP.deref,
457 OP.xderef,429 OP.xderef,
458 => @sizeOf(addr_type),430 => @sizeOf(Address),
459 OP.deref_size,431 OP.deref_size,
460 OP.xderef_size,432 OP.xderef_size,
461 => operand.?.type_size,433 => operand.?.type_size,
...@@ -475,7 +447,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -475,7 +447,7 @@ pub fn StackMachine(comptime options: Options) type {
475 }) return error.InvalidExpression;447 }) return error.InvalidExpression;
476 }448 }
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) {
479 1 => @as(*const u8, @ptrFromInt(addr)).*,451 1 => @as(*const u8, @ptrFromInt(addr)).*,
480 2 => @as(*const u16, @ptrFromInt(addr)).*,452 2 => @as(*const u16, @ptrFromInt(addr)).*,
481 4 => @as(*const u32, @ptrFromInt(addr)).*,453 4 => @as(*const u32, @ptrFromInt(addr)).*,
...@@ -544,7 +516,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -544,7 +516,7 @@ pub fn StackMachine(comptime options: Options) type {
544 if (self.stack.items.len < 2) return error.InvalidExpression;516 if (self.stack.items.len < 2) return error.InvalidExpression;
545 const b = try self.stack.pop().?.asIntegral();517 const b = try self.stack.pop().?.asIntegral();
546 self.stack.items[self.stack.items.len - 1] = .{518 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),
548 };520 };
549 },521 },
550 OP.mod => {522 OP.mod => {
...@@ -590,14 +562,14 @@ pub fn StackMachine(comptime options: Options) type {...@@ -590,14 +562,14 @@ pub fn StackMachine(comptime options: Options) type {
590 if (self.stack.items.len < 2) return error.InvalidExpression;562 if (self.stack.items.len < 2) return error.InvalidExpression;
591 const b = try self.stack.pop().?.asIntegral();563 const b = try self.stack.pop().?.asIntegral();
592 self.stack.items[self.stack.items.len - 1] = .{564 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),
594 };566 };
595 },567 },
596 OP.plus_uconst => {568 OP.plus_uconst => {
597 if (self.stack.items.len == 0) return error.InvalidExpression;569 if (self.stack.items.len == 0) return error.InvalidExpression;
598 const constant = operand.?.generic;570 const constant = operand.?.generic;
599 self.stack.items[self.stack.items.len - 1] = .{571 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),
601 };573 };
602 },574 },
603 OP.shl => {575 OP.shl => {
...@@ -670,15 +642,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -670,15 +642,7 @@ pub fn StackMachine(comptime options: Options) type {
670 break :blk try self.stack.pop().?.asIntegral() != 0;642 break :blk try self.stack.pop().?.asIntegral() != 0;
671 } else true;643 } else true;
672644
673 if (condition) {645 if (condition) reader.seekBy(branch_offset) catch return error.InvalidExpression;
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 }
682 },646 },
683 OP.call2,647 OP.call2,
684 OP.call4,648 OP.call4,
...@@ -722,7 +686,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -722,7 +686,7 @@ pub fn StackMachine(comptime options: Options) type {
722 .generic => |v| .{686 .generic => |v| .{
723 .regval_type = .{687 .regval_type = .{
724 .type_offset = type_offset,688 .type_offset = type_offset,
725 .type_size = @sizeOf(addr_type),689 .type_size = @sizeOf(Address),
726 .value = v,690 .value = v,
727 },691 },
728 },692 },
...@@ -756,8 +720,9 @@ pub fn StackMachine(comptime options: Options) type {...@@ -756,8 +720,9 @@ pub fn StackMachine(comptime options: Options) type {
756 if (isOpcodeRegisterLocation(block[0])) {720 if (isOpcodeRegisterLocation(block[0])) {
757 if (context.thread_context == null) return error.IncompleteExpressionContext;721 if (context.thread_context == null) return error.IncompleteExpressionContext;
758722
759 var block_stream: std.io.FixedBufferStream = .{ .buffer = block };723 var block_reader: std.io.BufferedReader = undefined;
760 const register = (try readOperand(&block_stream, block[0], context)).?.register;724 block_reader.initFixed(block);
725 const register = (try readOperand(&block_reader, block[0], context)).?.register;
761 const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);726 const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);
762 try self.stack.append(allocator, .{ .generic = value });727 try self.stack.append(allocator, .{ .generic = value });
763 } else {728 } else {
...@@ -778,14 +743,13 @@ pub fn StackMachine(comptime options: Options) type {...@@ -778,14 +743,13 @@ pub fn StackMachine(comptime options: Options) type {
778 return error.UnknownExpressionOpcode;743 return error.UnknownExpressionOpcode;
779 },744 },
780 }745 }
781746 return true;
782 return stream.pos < stream.buffer.len;
783 }747 }
784 };748 };
785}749}
786750
787pub fn Builder(comptime options: Options) type {751pub fn Builder(comptime options: Options) type {
788 const addr_type = switch (options.addr_size) {752 const Address = switch (options.addr_size) {
789 2 => u16,753 2 => u16,
790 4 => u32,754 4 => u32,
791 8 => u64,755 8 => u64,
...@@ -888,9 +852,9 @@ pub fn Builder(comptime options: Options) type {...@@ -888,9 +852,9 @@ pub fn Builder(comptime options: Options) type {
888 try writer.writeAll(value_bytes);852 try writer.writeAll(value_bytes);
889 }853 }
890854
891 pub fn writeAddr(writer: anytype, value: addr_type) !void {855 pub fn writeAddr(writer: anytype, value: Address) !void {
892 try writer.writeByte(OP.addr);856 try writer.writeByte(OP.addr);
893 try writer.writeInt(addr_type, value, options.endian);857 try writer.writeInt(Address, value, options.endian);
894 }858 }
895859
896 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {860 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {
lib/std/debug/FixedBufferReader.zig+7-8
...@@ -51,22 +51,21 @@ pub fn readIntChecked(...@@ -51,22 +51,21 @@ pub fn readIntChecked(
51 return fbr.readInt(T);51 return fbr.readInt(T);
52}52}
5353
54pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {54pub fn readLeb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
55 var br: std.io.BufferedReader = undefined;55 var br: std.io.BufferedReader = undefined;
56 br.initFixed(fbr.buf);56 br.initFixed(fbr.buf);
57 br.seek = fbr.pos;57 br.seek = fbr.pos;
58 const result = br.takeUleb128(T);58 const result = br.takeLeb128(T);
59 fbr.pos = br.seek;59 fbr.pos = br.seek;
60 return @errorCast(result);60 return @errorCast(result);
61}61}
6262
63pub fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
64 return fbr.readLeb128(T);
65}
66
63pub fn readIleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {67pub fn readIleb128(fbr: *FixedBufferReader, comptime T: type) Error!T {
64 var br: std.io.BufferedReader = undefined;68 return fbr.readLeb128(T);
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);
70}69}
7170
72pub fn readAddress(fbr: *FixedBufferReader, format: std.dwarf.Format) Error!u64 {71pub 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 {...@@ -2025,18 +2025,15 @@ pub const VirtualMachine = struct {
2025 assert(self.cie_row == null);2025 assert(self.cie_row == null);
2026 if (pc < fde.pc_begin or pc >= fde.pc_begin + fde.pc_range) return error.AddressOutOfRange;2026 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;2028 var readers: [2]std.io.BufferedReader = undefined;
20292029 readers[0].initFixed(cie.initial_instructions);
2030 var cie_stream: std.io.BufferedReader = undefined;2030 readers[1].initFixed(fde.instructions);
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 };
20352031
2036 for (&streams, 0..) |stream, i| {2032 var prev_row: Row = self.current_row;
2037 while (stream.seek < stream.storageBuffer().len) {2033 for (&readers, [2]bool{ true, false }) |*reader, is_initial| {
2038 const instruction = try std.debug.Dwarf.call_frame.Instruction.read(stream, addr_size_bytes, endian);2034 while (reader.seek < reader.storageBuffer().len) {
2039 prev_row = try self.step(allocator, cie, i == 0, instruction);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);
2040 if (pc < fde.pc_begin + self.current_row.offset) return prev_row;2037 if (pc < fde.pc_begin + self.current_row.offset) return prev_row;
2041 }2038 }
2042 }2039 }
lib/std/io/BufferedReader.zig+74-92
...@@ -164,6 +164,21 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!...@@ -164,6 +164,21 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
164 @panic("TODO");164 @panic("TODO");
165}165}
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
167/// Returns the next `n` bytes from `unbuffered_reader`, filling the buffer as182/// Returns the next `n` bytes from `unbuffered_reader`, filling the buffer as
168/// necessary.183/// necessary.
169///184///
...@@ -176,12 +191,31 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!...@@ -176,12 +191,31 @@ fn passthru_posReadVec(ctx: ?*anyopaque, data: []const []u8, off: u64) anyerror!
176/// is returned instead.191/// is returned instead.
177///192///
178/// See also:193/// See also:
194/// * `peekAll`
179/// * `toss`195/// * `toss`
180pub fn peek(br: *BufferedReader, n: usize) anyerror![]u8 {196pub 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 {
181 const list = &br.storage.buffer;215 const list = &br.storage.buffer;
182 assert(n <= list.capacity);216 assert(n <= list.capacity);
183 try fill(br, n);217 try br.fill(n);
184 return list.items[br.seek..][0..n];218 return list.items[br.seek..];
185}219}
186220
187/// Skips the next `n` bytes from the stream, advancing the seek position. This221/// 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...@@ -563,93 +597,41 @@ pub fn takeEnum(br: *BufferedReader, comptime Enum: type, endian: std.builtin.En
563 return std.meta.intToEnum(Enum, int);597 return std.meta.intToEnum(Enum, int);
564}598}
565599
566/// Read a single unsigned LEB128 value from the given reader as type T,600/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
567/// or error.Overflow if the value cannot fit.601pub fn takeLeb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
568pub fn takeUleb128(br: *std.io.BufferedReader, comptime T: type) anyerror!T {602 const result_info = @typeInfo(Result).int;
569 const U = if (@typeInfo(T).int.bits < 8) u8 else T;603 return std.math.cast(Result, try br.takeMultipleOf7Leb128(@Type(.{ .int = .{
570 const ShiftT = std.math.Log2Int(U);604 .signedness = result_info.signedness,
571605 .bits = std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
572 const max_group = (@typeInfo(U).int.bits + 6) / 7;606 } }))) orelse error.Overflow;
573607}
574 var value: U = 0;608
575 var group: ShiftT = 0;609fn takeMultipleOf7Leb128(br: *BufferedReader, comptime Result: type) anyerror!Result {
576610 const result_info = @typeInfo(Result).int;
577 while (group < max_group) : (group += 1) {611 comptime assert(result_info.bits % 7 == 0);
578 const byte = try br.takeByte();612 var remaining_bits: std.math.Log2IntCeil(Result) = result_info.bits;
579613 const UnsignedResult = @Type(.{ .int = .{
580 const ov = @shlWithOverflow(@as(U, byte & 0x7f), group * 7);614 .signedness = .unsigned,
581 if (ov[1] != 0) return error.Overflow;615 .bits = result_info.bits,
582616 } });
583 value |= ov[0];617 var result: UnsignedResult = 0;
584 if (byte & 0x80 == 0) break;618 var fits = true;
585 } else {619 while (true) {
586 return error.Overflow;620 const buffer: []const packed struct(u8) { bits: u7, more: bool } = @ptrCast(try br.peekAll(1));
587 }621 for (buffer, 1..) |byte, len| {
588622 if (remaining_bits > 0) {
589 // only applies in the case that we extended to u8623 result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) | @shrExact(result, 7);
590 if (U != T) {624 remaining_bits -= 7;
591 if (value > std.math.maxInt(T)) return error.Overflow;625 } else if (fits) fits = switch (result_info.signedness) {
592 }626 .signed => @as(i7, @bitCast(byte.bits)) == @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))),
593627 .unsigned => byte.bits == 0,
594 return @truncate(value);628 };
595}629 if (byte.more) continue;
596630 br.toss(len);
597/// Read a single signed LEB128 value from the given reader as type T,631 return if (fits) @as(Result, @bitCast(result)) >> remaining_bits else error.Overflow;
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;
641 }632 }
642 } else {633 br.toss(buffer.len);
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;
650 }634 }
651
652 return @truncate(result);
653}635}
654636
655test initFixed {637test initFixed {
...@@ -669,6 +651,10 @@ test peek {...@@ -669,6 +651,10 @@ test peek {
669 return error.Unimplemented;651 return error.Unimplemented;
670}652}
671653
654test peekAll {
655 return error.Unimplemented;
656}
657
672test toss {658test toss {
673 return error.Unimplemented;659 return error.Unimplemented;
674}660}
...@@ -766,10 +752,6 @@ test takeEnum {...@@ -766,10 +752,6 @@ test takeEnum {
766 return error.Unimplemented;752 return error.Unimplemented;
767}753}
768754
769test takeUleb128 {755test takeLeb128 {
770 return error.Unimplemented;
771}
772
773test takeIleb128 {
774 return error.Unimplemented;756 return error.Unimplemented;
775}757}