authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-05-07 17:04:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 16:35:29-07:00
log4607770a5792006d71e63e3f0f2a0fe9cecb07af
tree206650e0a524154bdbbdab7691de3493b326b157
parent4512f277849a7e1a0e221c051d654c58ecf771ae

std.debug.Dwarf.expression: partial rework

- use labeled continue - avoid anytype - avoid dependency on a "seeking" API - simpler, more optimal VM interpreter loop - progress decoupling from host machine - type safety for opcodes. see #15556

3 files changed, 775 insertions(+), 700 deletions(-)

lib/std/debug/Dwarf/expression.zig+555-486
...@@ -8,6 +8,7 @@ const OP = std.dwarf.OP;...@@ -8,6 +8,7 @@ const OP = std.dwarf.OP;
8const abi = std.debug.Dwarf.abi;8const abi = std.debug.Dwarf.abi;
9const mem = std.mem;9const mem = std.mem;
10const assert = std.debug.assert;10const assert = std.debug.assert;
11const Allocator = std.mem.Allocator;
1112
12/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.13/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.
13/// Callers should specify all the fields relevant to their context. If a field is required14/// Callers should specify all the fields relevant to their context. If a field is required
...@@ -41,8 +42,7 @@ pub const Options = struct {...@@ -41,8 +42,7 @@ pub const Options = struct {
41 call_frame_context: bool = false,42 call_frame_context: bool = false,
42};43};
4344
44// Explicitly defined to support executing sub-expressions45pub const RunError = error{
45pub const Error = error{
46 UnimplementedExpressionCall,46 UnimplementedExpressionCall,
47 UnimplementedOpcode,47 UnimplementedOpcode,
48 UnimplementedUserOpcode,48 UnimplementedUserOpcode,
...@@ -62,7 +62,12 @@ pub const Error = error{...@@ -62,7 +62,12 @@ pub const Error = error{
62 InvalidTypeLength,62 InvalidTypeLength,
6363
64 TruncatedIntegralType,64 TruncatedIntegralType,
65} || abi.RegBytesError || error{ EndOfStream, Overflow, OutOfMemory, DivisionByZero, ReadFailed };65
66 OutOfMemory,
67 EndOfStream,
68 Overflow,
69 DivisionByZero,
70} || abi.RegBytesError;
6671
67/// A stack machine that can decode and run DWARF expressions.72/// A stack machine that can decode and run DWARF expressions.
68/// Expressions can be decoded for non-native address size and endianness,73/// Expressions can be decoded for non-native address size and endianness,
...@@ -74,44 +79,16 @@ pub fn StackMachine(comptime options: Options) type {...@@ -74,44 +79,16 @@ pub fn StackMachine(comptime options: Options) type {
74 8 => u64,79 8 => u64,
75 else => @compileError("Unsupported address size of " ++ options.addr_size),80 else => @compileError("Unsupported address size of " ++ options.addr_size),
76 };81 };
77
78 const SignedAddress = switch (options.addr_size) {82 const SignedAddress = switch (options.addr_size) {
79 2 => i16,83 2 => i16,
80 4 => i32,84 4 => i32,
81 8 => i64,85 8 => i64,
82 else => @compileError("Unsupported address size of " ++ options.addr_size),86 else => @compileError("Unsupported address size of " ++ options.addr_size),
83 };87 };
84
85 return struct {88 return struct {
86 const Self = @This();89 stack: std.ArrayListUnmanaged(Value) = .empty,
8790
88 const Operand = union(enum) {91 const Self = @This();
89 generic: Address,
90 register: u8,
91 type_size: u8,
92 branch_offset: i16,
93 base_register: struct {
94 base_register: u8,
95 offset: i64,
96 },
97 composite_location: struct {
98 size: u64,
99 offset: i64,
100 },
101 block: []const u8,
102 register_type: struct {
103 register: u8,
104 type_offset: Address,
105 },
106 const_type: struct {
107 type_offset: Address,
108 value_bytes: []const u8,
109 },
110 deref_type: struct {
111 size: u8,
112 type_offset: Address,
113 },
114 };
11592
116 const Value = union(enum) {93 const Value = union(enum) {
117 generic: Address,94 generic: Address,
...@@ -132,7 +109,7 @@ pub fn StackMachine(comptime options: Options) type {...@@ -132,7 +109,7 @@ pub fn StackMachine(comptime options: Options) type {
132 value_bytes: []const u8,109 value_bytes: []const u8,
133 },110 },
134111
135 pub fn asIntegral(self: Value) !Address {112 fn asIntegral(self: Value) !Address {
136 return switch (self) {113 return switch (self) {
137 .generic => |v| v,114 .generic => |v| v,
138115
...@@ -151,185 +128,131 @@ pub fn StackMachine(comptime options: Options) type {...@@ -151,185 +128,131 @@ pub fn StackMachine(comptime options: Options) type {
151 },128 },
152 };129 };
153 }130 }
154 };
155131
156 stack: std.ArrayListUnmanaged(Value) = .empty,132 fn fromInt(int: anytype) Value {
133 const info = @typeInfo(@TypeOf(int)).int;
134 if (@sizeOf(@TypeOf(int)) > options.addr_size) {
135 return .{ .generic = switch (info.signedness) {
136 .signed => @bitCast(@as(SignedAddress, @truncate(int))),
137 .unsigned => @truncate(int),
138 } };
139 } else {
140 return .{ .generic = switch (info.signedness) {
141 .signed => @bitCast(@as(SignedAddress, @intCast(int))),
142 .unsigned => @intCast(int),
143 } };
144 }
145 }
146 };
157147
158 pub fn reset(self: *Self) void {148 pub fn reset(self: *Self) void {
159 self.stack.clearRetainingCapacity();149 self.stack.clearRetainingCapacity();
160 }150 }
161151
162 pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {152 pub fn deinit(self: *Self, allocator: Allocator) void {
163 self.stack.deinit(allocator);153 self.stack.deinit(allocator);
164 }154 }
165155
166 fn generic(value: anytype) Operand {
167 const int_info = @typeInfo(@TypeOf(value)).int;
168 if (@sizeOf(@TypeOf(value)) > options.addr_size) {
169 return .{ .generic = switch (int_info.signedness) {
170 .signed => @bitCast(@as(SignedAddress, @truncate(value))),
171 .unsigned => @truncate(value),
172 } };
173 } else {
174 return .{ .generic = switch (int_info.signedness) {
175 .signed => @bitCast(@as(SignedAddress, @intCast(value))),
176 .unsigned => @intCast(value),
177 } };
178 }
179 }
180
181 pub fn readOperand(reader: *std.io.BufferedReader, opcode: u8, context: Context) !?Operand {
182 return switch (opcode) {
183 OP.addr => generic(try reader.takeInt(Address, options.endian)),
184 OP.call_ref => switch (context.format) {
185 .@"32" => generic(try reader.takeInt(u32, options.endian)),
186 .@"64" => generic(try reader.takeInt(u64, options.endian)),
187 },
188 OP.const1u,
189 OP.pick,
190 => generic(try reader.takeByte()),
191 OP.deref_size,
192 OP.xderef_size,
193 => .{ .type_size = try reader.takeByte() },
194 OP.const1s => generic(try reader.takeByteSigned()),
195 OP.const2u,
196 OP.call2,
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)),
200 OP.bra,
201 OP.skip,
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)),
207 OP.constu,
208 OP.plus_uconst,
209 OP.addrx,
210 OP.constx,
211 OP.convert,
212 OP.reinterpret,
213 => generic(try reader.takeLeb128(u64)),
214 OP.consts,
215 OP.fbreg,
216 => generic(try reader.takeLeb128(i64)),
217 OP.lit0...OP.lit31 => |n| generic(n - OP.lit0),
218 OP.reg0...OP.reg31 => |n| .{ .register = n - OP.reg0 },
219 OP.breg0...OP.breg31 => |n| .{ .base_register = .{
220 .base_register = n - OP.breg0,
221 .offset = try reader.takeLeb128(i64),
222 } },
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)),
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 } },
251 OP.lo_user...OP.hi_user => return error.UnimplementedUserOpcode,
252 else => null,
253 };
254 }
255
256 pub fn run(156 pub fn run(
257 self: *Self,157 self: *Self,
258 expression: []const u8,158 expression: []const u8,
259 allocator: std.mem.Allocator,159 gpa: Allocator,
260 context: Context,160 context: Context,
261 initial_value: ?usize,161 initial_value: ?usize,
262 ) Error!?Value {162 ) RunError!?Value {
263 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });163 if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian) {
264 var reader: std.io.BufferedReader = undefined;164 // This restriction can be removed when the `@ptrFromInt` calls are removed.
265 reader.initFixed(@constCast(expression));
266 while (try self.step(&reader, allocator, context)) {}
267 if (self.stack.items.len == 0) return null;
268 return self.stack.items[self.stack.items.len - 1];
269 }
270
271 /// Reads an opcode and its operands from `stream`, then executes it
272 pub fn step(
273 self: *Self,
274 reader: *std.io.BufferedReader,
275 allocator: std.mem.Allocator,
276 context: Context,
277 ) Error!bool {
278 if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian)
279 @compileError("Execution of non-native address sizes / endianness is not supported");165 @compileError("Execution of non-native address sizes / endianness is not supported");
166 }
280167
281 const opcode = reader.takeByte() catch |err| switch (err) {168 const stack = &self.stack;
282 error.EndOfStream => return false,169 if (initial_value) |i| try stack.append(gpa, .{ .generic = i });
283 error.ReadFailed => return error.ReadFailed,
284 };
285 if (options.call_frame_context and !isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
286 const operand = try readOperand(reader, opcode, context);
287 switch (opcode) {
288170
171 var i: usize = 0;
172 // TODO: https://github.com/ziglang/zig/issues/15556
173 op: switch (nextOpcode(expression, &i)) {
289 // 2.5.1.1: Literal Encodings174 // 2.5.1.1: Literal Encodings
290 OP.lit0...OP.lit31,175 @intFromEnum(OP.lit0)...@intFromEnum(OP.lit31) => |n| {
291 OP.addr,176 try stack.append(gpa, .{ .generic = n - @intFromEnum(OP.lit0) });
292 OP.const1u,177 continue :op nextOpcode(expression, &i);
293 OP.const2u,178 },
294 OP.const4u,179 @intFromEnum(OP.addr) => {
295 OP.const8u,180 try stack.append(gpa, .fromInt(try nextInt(expression, &i, Address)));
296 OP.const1s,181 continue :op nextOpcode(expression, &i);
297 OP.const2s,182 },
298 OP.const4s,183 @intFromEnum(OP.const1u) => {
299 OP.const8s,184 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u8)));
300 OP.constu,185 continue :op nextOpcode(expression, &i);
301 OP.consts,186 },
302 => try self.stack.append(allocator, .{ .generic = operand.?.generic }),187 @intFromEnum(OP.const2u) => {
303188 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u16)));
304 OP.const_type => {189 continue :op nextOpcode(expression, &i);
305 const const_type = operand.?.const_type;190 },
306 try self.stack.append(allocator, .{ .const_type = .{191 @intFromEnum(OP.const4u) => {
307 .type_offset = const_type.type_offset,192 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u32)));
308 .value_bytes = const_type.value_bytes,193 continue :op nextOpcode(expression, &i);
194 },
195 @intFromEnum(OP.const8u) => {
196 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u64)));
197 continue :op nextOpcode(expression, &i);
198 },
199 @intFromEnum(OP.const1s) => {
200 try stack.append(gpa, .fromInt(try nextInt(expression, &i, i8)));
201 continue :op nextOpcode(expression, &i);
202 },
203 @intFromEnum(OP.const2s) => {
204 try stack.append(gpa, .fromInt(try nextInt(expression, &i, i16)));
205 continue :op nextOpcode(expression, &i);
206 },
207 @intFromEnum(OP.const4s) => {
208 try stack.append(gpa, .fromInt(try nextInt(expression, &i, i32)));
209 continue :op nextOpcode(expression, &i);
210 },
211 @intFromEnum(OP.const8s) => {
212 try stack.append(gpa, .fromInt(try nextInt(expression, &i, i64)));
213 continue :op nextOpcode(expression, &i);
214 },
215 @intFromEnum(OP.constu) => {
216 try stack.append(gpa, .fromInt(try nextLeb128(expression, &i, u64)));
217 continue :op nextOpcode(expression, &i);
218 },
219 @intFromEnum(OP.consts) => {
220 try stack.append(gpa, .fromInt(try nextLeb128(expression, &i, i64)));
221 continue :op nextOpcode(expression, &i);
222 },
223
224 @intFromEnum(OP.const_type) => {
225 if (options.call_frame_context) return error.InvalidCFAOpcode;
226 try stack.append(gpa, .{ .const_type = .{
227 .type_offset = try nextLeb128(expression, &i, Address),
228 .value_bytes = try nextSlice(expression, &i, try nextInt(expression, &i, u8)),
309 } });229 } });
230 continue :op nextOpcode(expression, &i);
310 },231 },
311232
312 OP.addrx,233 @intFromEnum(OP.addrx),
313 OP.constx,234 @intFromEnum(OP.constx),
314 => {235 => {
315 if (context.compile_unit == null) return error.IncompleteExpressionContext;236 if (options.call_frame_context) return error.InvalidCFAOpcode;
316 if (context.debug_addr == null) return error.IncompleteExpressionContext;237 const compile_unit = context.compile_unit orelse return error.IncompleteExpressionContext;
317 const debug_addr_index = operand.?.generic;238 const debug_addr = context.debug_addr orelse return error.IncompleteExpressionContext;
318 const offset = context.compile_unit.?.addr_base + debug_addr_index;239 const debug_addr_index = try nextLeb128(expression, &i, u64);
319 if (offset >= context.debug_addr.?.len) return error.InvalidExpression;240 const offset = compile_unit.addr_base + debug_addr_index;
320 const value = mem.readInt(usize, context.debug_addr.?[offset..][0..@sizeOf(usize)], native_endian);241 if (offset >= debug_addr.len) return error.InvalidExpression;
321 try self.stack.append(allocator, .{ .generic = value });242 const value = mem.readInt(Address, debug_addr[offset..][0..@sizeOf(Address)], options.endian);
243 try stack.append(gpa, .fromInt(value));
244 continue :op nextOpcode(expression, &i);
322 },245 },
323246
324 // 2.5.1.2: Register Values247 // 2.5.1.2: Register Values
325 OP.fbreg => {248 @intFromEnum(OP.fbreg) => {
326 if (context.compile_unit == null) return error.IncompleteExpressionContext;249 const compile_unit = context.compile_unit orelse return error.IncompleteExpressionContext;
327 if (context.compile_unit.?.frame_base == null) return error.IncompleteExpressionContext;250 const frame_base = compile_unit.frame_base orelse return error.IncompleteExpressionContext;
328251
329 const offset: i64 = @intCast(operand.?.generic);252 const offset = try nextLeb128(expression, &i, i64);
330 _ = offset;253 _ = offset;
331254
332 switch (context.compile_unit.?.frame_base.?.*) {255 switch (frame_base.*) {
333 .exprloc => {256 .exprloc => {
334 // TODO: Run this expression in a nested stack machine257 // TODO: Run this expression in a nested stack machine
335 return error.UnimplementedOpcode;258 return error.UnimplementedOpcode;
...@@ -345,344 +268,407 @@ pub fn StackMachine(comptime options: Options) type {...@@ -345,344 +268,407 @@ pub fn StackMachine(comptime options: Options) type {
345 else => return error.InvalidFrameBase,268 else => return error.InvalidFrameBase,
346 }269 }
347 },270 },
348 OP.breg0...OP.breg31,271 @intFromEnum(OP.breg0)...@intFromEnum(OP.breg31) => |n| {
349 OP.bregx,272 const thread_context = context.thread_context orelse return error.IncompleteExpressionContext;
350 => {273 const base_register = n - @intFromEnum(OP.breg0);
351 if (context.thread_context == null) return error.IncompleteExpressionContext;274 const offset = try nextLeb128(expression, &i, i64);
352275 const reg_bytes = try abi.regBytes(thread_context, base_register, context.reg_context);
353 const base_register = operand.?.base_register;276 const start_addr = mem.readInt(Address, reg_bytes[0..@sizeOf(Address)], options.endian);
354 var value: i64 = @intCast(mem.readInt(usize, (try abi.regBytes(277 try stack.append(gpa, .{
355 context.thread_context.?,278 .generic = std.math.addAny(Address, start_addr, offset) orelse
356 base_register.base_register,279 return error.InvalidExpression,
357 context.reg_context,280 });
358 ))[0..@sizeOf(usize)], native_endian));281 continue :op nextOpcode(expression, &i);
359 value += base_register.offset;282 },
360 try self.stack.append(allocator, .{ .generic = @intCast(value) });283 @intFromEnum(OP.bregx) => {
361 },284 const thread_context = context.thread_context orelse return error.IncompleteExpressionContext;
362 OP.regval_type => {285 const base_register = try nextLeb128(expression, &i, u8);
363 const register_type = operand.?.register_type;286 const offset = try nextLeb128(expression, &i, i64);
364 const value = mem.readInt(usize, (try abi.regBytes(287 const reg_bytes = try abi.regBytes(thread_context, base_register, context.reg_context);
365 context.thread_context.?,288 const start_addr = mem.readInt(Address, reg_bytes[0..@sizeOf(Address)], options.endian);
366 register_type.register,289 try stack.append(gpa, .{
367 context.reg_context,290 .generic = std.math.addAny(Address, start_addr, offset) orelse
368 ))[0..@sizeOf(usize)], native_endian);291 return error.InvalidExpression,
369 try self.stack.append(allocator, .{292 });
293 continue :op nextOpcode(expression, &i);
294 },
295 @intFromEnum(OP.regval_type) => {
296 if (options.call_frame_context) return error.InvalidCFAOpcode;
297 const thread_context = context.thread_context orelse return error.IncompleteExpressionContext;
298 const register = try nextLeb128(expression, &i, u8);
299 const type_offset = try nextLeb128(expression, &i, Address);
300 const reg_bytes = try abi.regBytes(thread_context, register, context.reg_context);
301 const value = mem.readInt(Address, reg_bytes[0..@sizeOf(Address)], options.endian);
302 try stack.append(gpa, .{
370 .regval_type = .{303 .regval_type = .{
371 .type_offset = register_type.type_offset,304 .type_offset = type_offset,
372 .type_size = @sizeOf(Address),305 .type_size = @sizeOf(Address),
373 .value = value,306 .value = value,
374 },307 },
375 });308 });
309 continue :op nextOpcode(expression, &i);
376 },310 },
377311
378 // 2.5.1.3: Stack Operations312 // 2.5.1.3: Stack Operations
379 OP.dup => {313 @intFromEnum(OP.dup) => {
380 if (self.stack.items.len == 0) return error.InvalidExpression;314 if (stack.items.len == 0) return error.InvalidExpression;
381 try self.stack.append(allocator, self.stack.items[self.stack.items.len - 1]);315 try stack.append(gpa, stack.items[stack.items.len - 1]);
316 continue :op nextOpcode(expression, &i);
382 },317 },
383 OP.drop => {318 @intFromEnum(OP.drop) => {
384 _ = self.stack.pop();319 _ = stack.pop();
320 continue :op nextOpcode(expression, &i);
385 },321 },
386 OP.pick, OP.over => {322 @intFromEnum(OP.pick) => {
387 const stack_index = if (opcode == OP.over) 1 else operand.?.generic;323 const stack_index = try nextInt(expression, &i, u8);
388 if (stack_index >= self.stack.items.len) return error.InvalidExpression;324 if (stack_index >= stack.items.len) return error.InvalidExpression;
389 try self.stack.append(allocator, self.stack.items[self.stack.items.len - 1 - stack_index]);325 try stack.append(gpa, stack.items[stack.items.len - 1 - stack_index]);
326 continue :op nextOpcode(expression, &i);
390 },327 },
391 OP.swap => {328 @intFromEnum(OP.over) => {
392 if (self.stack.items.len < 2) return error.InvalidExpression;329 if (stack.items.len < 2) return error.InvalidExpression;
393 mem.swap(Value, &self.stack.items[self.stack.items.len - 1], &self.stack.items[self.stack.items.len - 2]);330 try stack.append(gpa, stack.items[stack.items.len - 2]);
331 continue :op nextOpcode(expression, &i);
394 },332 },
395 OP.rot => {333 @intFromEnum(OP.swap) => {
396 if (self.stack.items.len < 3) return error.InvalidExpression;334 if (stack.items.len < 2) return error.InvalidExpression;
397 const first = self.stack.items[self.stack.items.len - 1];335 mem.swap(Value, &stack.items[stack.items.len - 1], &stack.items[stack.items.len - 2]);
398 self.stack.items[self.stack.items.len - 1] = self.stack.items[self.stack.items.len - 2];336 continue :op nextOpcode(expression, &i);
399 self.stack.items[self.stack.items.len - 2] = self.stack.items[self.stack.items.len - 3];
400 self.stack.items[self.stack.items.len - 3] = first;
401 },337 },
402 OP.deref,338 @intFromEnum(OP.rot) => {
403 OP.xderef,339 if (stack.items.len < 3) return error.InvalidExpression;
404 OP.deref_size,340 const first = stack.items[stack.items.len - 1];
405 OP.xderef_size,341 stack.items[stack.items.len - 1] = stack.items[stack.items.len - 2];
406 OP.deref_type,342 stack.items[stack.items.len - 2] = stack.items[stack.items.len - 3];
407 OP.xderef_type,343 stack.items[stack.items.len - 3] = first;
408 => {344 continue :op nextOpcode(expression, &i);
409 if (self.stack.items.len == 0) return error.InvalidExpression;345 },
410 const addr = try self.stack.items[self.stack.items.len - 1].asIntegral();346
411 const addr_space_identifier: ?usize = switch (opcode) {347 @intFromEnum(OP.deref_type) => {
412 OP.xderef,348 if (options.call_frame_context) return error.InvalidCFAOpcode;
413 OP.xderef_size,349 if (stack.items.len == 0) return error.InvalidExpression;
414 OP.xderef_type,350 const size = try nextInt(expression, &i, u8);
415 => blk: {351 const type_offset = try nextLeb128(expression, &i, Address);
416 _ = self.stack.pop();352 const addr = try stack.items[stack.items.len - 1].asIntegral();
417 if (self.stack.items.len == 0) return error.InvalidExpression;353 const loaded = try accessAddress(size, addr, context.memory_accessor);
418 break :blk try self.stack.items[self.stack.items.len - 1].asIntegral();354 stack.items[stack.items.len - 1] = .{
355 .regval_type = .{
356 .type_offset = type_offset,
357 .type_size = size,
358 .value = loaded,
419 },359 },
420 else => null,
421 };360 };
422361 continue :op nextOpcode(expression, &i);
362 },
363 @intFromEnum(OP.deref_size) => {
364 if (stack.items.len == 0) return error.InvalidExpression;
365 const addr = try stack.items[stack.items.len - 1].asIntegral();
366 const type_size = try nextInt(expression, &i, u8);
367 const loaded = try accessAddress(type_size, addr, context.memory_accessor);
368 stack.items[stack.items.len - 1] = .{ .generic = loaded };
369 continue :op nextOpcode(expression, &i);
370 },
371 @intFromEnum(OP.xderef_size) => {
372 if (stack.items.len < 2) return error.InvalidExpression;
373 const type_size = try nextInt(expression, &i, u8);
374 const addr = try stack.pop().?.asIntegral();
375 const addr_space_identifier = try stack.items[stack.items.len - 1].asIntegral();
423 // Usage of addr_space_identifier in the address calculation is implementation defined.376 // Usage of addr_space_identifier in the address calculation is implementation defined.
424 // This code will need to be updated to handle any architectures that utilize this.377 // This code will need to be updated to handle any architectures that utilize this.
425 _ = addr_space_identifier;378 _ = addr_space_identifier;
379 const loaded = try accessAddress(type_size, addr, context.memory_accessor);
380 stack.items[stack.items.len - 1] = .{ .generic = loaded };
381 continue :op nextOpcode(expression, &i);
382 },
383 @intFromEnum(OP.deref) => {
384 if (stack.items.len == 0) return error.InvalidExpression;
385 const addr = try stack.items[stack.items.len - 1].asIntegral();
386 const loaded = try accessAddress(@sizeOf(Address), addr, context.memory_accessor);
387 stack.items[stack.items.len - 1] = .{ .generic = loaded };
388 continue :op nextOpcode(expression, &i);
389 },
390 @intFromEnum(OP.xderef) => {
391 if (stack.items.len < 2) return error.InvalidExpression;
392 const addr = try stack.pop().?.asIntegral();
393 const addr_space_identifier = try stack.items[stack.items.len - 1].asIntegral();
394 // Usage of addr_space_identifier in the address calculation is implementation defined.
395 // This code will need to be updated to handle any architectures that utilize this.
396 _ = addr_space_identifier;
397 const loaded = try accessAddress(@sizeOf(Address), addr, context.memory_accessor);
398 stack.items[stack.items.len - 1] = .{ .generic = loaded };
399 continue :op nextOpcode(expression, &i);
400 },
426401
427 const size = switch (opcode) {402 @intFromEnum(OP.xderef_type),
428 OP.deref,403 => {
429 OP.xderef,404 if (stack.items.len < 2) return error.InvalidExpression;
430 => @sizeOf(Address),405 const addr = try stack.pop().?.asIntegral();
431 OP.deref_size,406 const addr_space_identifier = try stack.items[stack.items.len - 1].asIntegral();
432 OP.xderef_size,407 // Usage of addr_space_identifier in the address calculation is implementation defined.
433 => operand.?.type_size,408 // This code will need to be updated to handle any architectures that utilize this.
434 OP.deref_type,409 _ = addr_space_identifier;
435 OP.xderef_type,410 const size = try nextInt(expression, &i, u8);
436 => operand.?.deref_type.size,411 const type_offset = try nextLeb128(expression, &i, Address);
437 else => unreachable,412 const loaded = try accessAddress(size, addr, context.memory_accessor);
438 };413 stack.items[stack.items.len - 1] = .{
439414 .regval_type = .{
440 if (context.memory_accessor) |memory_accessor| {415 .type_offset = type_offset,
441 if (!switch (size) {416 .type_size = size,
442 1 => memory_accessor.load(u8, addr) != null,417 .value = loaded,
443 2 => memory_accessor.load(u16, addr) != null,
444 4 => memory_accessor.load(u32, addr) != null,
445 8 => memory_accessor.load(u64, addr) != null,
446 else => return error.InvalidExpression,
447 }) return error.InvalidExpression;
448 }
449
450 const value: Address = std.math.cast(Address, @as(u64, switch (size) {
451 1 => @as(*const u8, @ptrFromInt(addr)).*,
452 2 => @as(*const u16, @ptrFromInt(addr)).*,
453 4 => @as(*const u32, @ptrFromInt(addr)).*,
454 8 => @as(*const u64, @ptrFromInt(addr)).*,
455 else => return error.InvalidExpression,
456 })) orelse return error.InvalidExpression;
457
458 switch (opcode) {
459 OP.deref_type,
460 OP.xderef_type,
461 => {
462 self.stack.items[self.stack.items.len - 1] = .{
463 .regval_type = .{
464 .type_offset = operand.?.deref_type.type_offset,
465 .type_size = operand.?.deref_type.size,
466 .value = value,
467 },
468 };
469 },
470 else => {
471 self.stack.items[self.stack.items.len - 1] = .{ .generic = value };
472 },418 },
473 }419 };
420 continue :op nextOpcode(expression, &i);
474 },421 },
475 OP.push_object_address => {422 @intFromEnum(OP.push_object_address) => {
423 if (options.call_frame_context) return error.InvalidCFAOpcode;
476 // In sub-expressions, `push_object_address` is not meaningful (as per the424 // In sub-expressions, `push_object_address` is not meaningful (as per the
477 // spec), so treat it like a nop425 // spec), so treat it like a nop
478 if (!context.entry_value_context) {426 if (!context.entry_value_context) {
479 if (context.object_address == null) return error.IncompleteExpressionContext;427 if (context.object_address == null) return error.IncompleteExpressionContext;
480 try self.stack.append(allocator, .{ .generic = @intFromPtr(context.object_address.?) });428 try stack.append(gpa, .{ .generic = @intFromPtr(context.object_address.?) });
481 }429 }
482 },430 },
483 OP.form_tls_address => {431 @intFromEnum(OP.form_tls_address) => {
484 return error.UnimplementedOpcode;432 return error.UnimplementedOpcode;
485 },433 },
486 OP.call_frame_cfa => {434 @intFromEnum(OP.call_frame_cfa) => {
435 if (options.call_frame_context) return error.InvalidCFAOpcode;
487 if (context.cfa) |cfa| {436 if (context.cfa) |cfa| {
488 try self.stack.append(allocator, .{ .generic = cfa });437 try stack.append(gpa, .{ .generic = cfa });
489 } else return error.IncompleteExpressionContext;438 } else return error.IncompleteExpressionContext;
439 continue :op nextOpcode(expression, &i);
490 },440 },
491441
492 // 2.5.1.4: Arithmetic and Logical Operations442 // 2.5.1.4: Arithmetic and Logical Operations
493 OP.abs => {443 @intFromEnum(OP.abs) => {
494 if (self.stack.items.len == 0) return error.InvalidExpression;444 if (stack.items.len == 0) return error.InvalidExpression;
495 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());445 const value: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
496 self.stack.items[self.stack.items.len - 1] = .{446 stack.items[stack.items.len - 1] = .{
497 .generic = @abs(value),447 .generic = @abs(value),
498 };448 };
449 continue :op nextOpcode(expression, &i);
499 },450 },
500 OP.@"and" => {451 @intFromEnum(OP.@"and") => {
501 if (self.stack.items.len < 2) return error.InvalidExpression;452 if (stack.items.len < 2) return error.InvalidExpression;
502 const a = try self.stack.pop().?.asIntegral();453 const a = try stack.pop().?.asIntegral();
503 self.stack.items[self.stack.items.len - 1] = .{454 stack.items[stack.items.len - 1] = .{
504 .generic = a & try self.stack.items[self.stack.items.len - 1].asIntegral(),455 .generic = a & try stack.items[stack.items.len - 1].asIntegral(),
505 };456 };
457 continue :op nextOpcode(expression, &i);
506 },458 },
507 OP.div => {459 @intFromEnum(OP.div) => {
508 if (self.stack.items.len < 2) return error.InvalidExpression;460 if (stack.items.len < 2) return error.InvalidExpression;
509 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());461 const a: isize = @bitCast(try stack.pop().?.asIntegral());
510 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());462 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
511 self.stack.items[self.stack.items.len - 1] = .{463 stack.items[stack.items.len - 1] = .{
512 .generic = @bitCast(try std.math.divTrunc(isize, b, a)),464 .generic = @bitCast(try std.math.divTrunc(isize, b, a)),
513 };465 };
466 continue :op nextOpcode(expression, &i);
514 },467 },
515 OP.minus => {468 @intFromEnum(OP.minus) => {
516 if (self.stack.items.len < 2) return error.InvalidExpression;469 if (stack.items.len < 2) return error.InvalidExpression;
517 const b = try self.stack.pop().?.asIntegral();470 const b = try stack.pop().?.asIntegral();
518 self.stack.items[self.stack.items.len - 1] = .{471 stack.items[stack.items.len - 1] = .{
519 .generic = try std.math.sub(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),472 .generic = try std.math.sub(Address, try stack.items[stack.items.len - 1].asIntegral(), b),
520 };473 };
474 continue :op nextOpcode(expression, &i);
521 },475 },
522 OP.mod => {476 @intFromEnum(OP.mod) => {
523 if (self.stack.items.len < 2) return error.InvalidExpression;477 if (stack.items.len < 2) return error.InvalidExpression;
524 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());478 const a: isize = @bitCast(try stack.pop().?.asIntegral());
525 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());479 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
526 self.stack.items[self.stack.items.len - 1] = .{480 stack.items[stack.items.len - 1] = .{
527 .generic = @bitCast(@mod(b, a)),481 .generic = @bitCast(@mod(b, a)),
528 };482 };
483 continue :op nextOpcode(expression, &i);
529 },484 },
530 OP.mul => {485 @intFromEnum(OP.mul) => {
531 if (self.stack.items.len < 2) return error.InvalidExpression;486 if (stack.items.len < 2) return error.InvalidExpression;
532 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());487 const a: isize = @bitCast(try stack.pop().?.asIntegral());
533 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());488 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
534 self.stack.items[self.stack.items.len - 1] = .{489 stack.items[stack.items.len - 1] = .{
535 .generic = @bitCast(@mulWithOverflow(a, b)[0]),490 .generic = @bitCast(@mulWithOverflow(a, b)[0]),
536 };491 };
492 continue :op nextOpcode(expression, &i);
537 },493 },
538 OP.neg => {494 @intFromEnum(OP.neg) => {
539 if (self.stack.items.len == 0) return error.InvalidExpression;495 if (stack.items.len == 0) return error.InvalidExpression;
540 self.stack.items[self.stack.items.len - 1] = .{496 stack.items[stack.items.len - 1] = .{
541 .generic = @bitCast(497 .generic = @bitCast(
542 try std.math.negate(498 try std.math.negate(
543 @as(isize, @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral())),499 @as(isize, @bitCast(try stack.items[stack.items.len - 1].asIntegral())),
544 ),500 ),
545 ),501 ),
546 };502 };
503 continue :op nextOpcode(expression, &i);
547 },504 },
548 OP.not => {505 @intFromEnum(OP.not) => {
549 if (self.stack.items.len == 0) return error.InvalidExpression;506 if (stack.items.len == 0) return error.InvalidExpression;
550 self.stack.items[self.stack.items.len - 1] = .{507 stack.items[stack.items.len - 1] = .{
551 .generic = ~try self.stack.items[self.stack.items.len - 1].asIntegral(),508 .generic = ~try stack.items[stack.items.len - 1].asIntegral(),
552 };509 };
510 continue :op nextOpcode(expression, &i);
553 },511 },
554 OP.@"or" => {512 @intFromEnum(OP.@"or") => {
555 if (self.stack.items.len < 2) return error.InvalidExpression;513 if (stack.items.len < 2) return error.InvalidExpression;
556 const a = try self.stack.pop().?.asIntegral();514 const a = try stack.pop().?.asIntegral();
557 self.stack.items[self.stack.items.len - 1] = .{515 stack.items[stack.items.len - 1] = .{
558 .generic = a | try self.stack.items[self.stack.items.len - 1].asIntegral(),516 .generic = a | try stack.items[stack.items.len - 1].asIntegral(),
559 };517 };
518 continue :op nextOpcode(expression, &i);
560 },519 },
561 OP.plus => {520 @intFromEnum(OP.plus) => {
562 if (self.stack.items.len < 2) return error.InvalidExpression;521 if (stack.items.len < 2) return error.InvalidExpression;
563 const b = try self.stack.pop().?.asIntegral();522 const b = try stack.pop().?.asIntegral();
564 self.stack.items[self.stack.items.len - 1] = .{523 stack.items[stack.items.len - 1] = .{
565 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),524 .generic = try std.math.add(Address, try stack.items[stack.items.len - 1].asIntegral(), b),
566 };525 };
526 continue :op nextOpcode(expression, &i);
567 },527 },
568 OP.plus_uconst => {528 @intFromEnum(OP.plus_uconst) => {
569 if (self.stack.items.len == 0) return error.InvalidExpression;529 if (stack.items.len == 0) return error.InvalidExpression;
570 const constant = operand.?.generic;530 stack.items[stack.items.len - 1] = .{ .generic = std.math.addAny(
571 self.stack.items[self.stack.items.len - 1] = .{531 Address,
572 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),532 try nextLeb128(expression, &i, u64),
573 };533 try stack.items[stack.items.len - 1].asIntegral(),
534 ) orelse return error.Overflow };
535 continue :op nextOpcode(expression, &i);
574 },536 },
575 OP.shl => {537 @intFromEnum(OP.shl) => {
576 if (self.stack.items.len < 2) return error.InvalidExpression;538 if (stack.items.len < 2) return error.InvalidExpression;
577 const a = try self.stack.pop().?.asIntegral();539 const a = try stack.pop().?.asIntegral();
578 const b = try self.stack.items[self.stack.items.len - 1].asIntegral();540 const b = try stack.items[stack.items.len - 1].asIntegral();
579 self.stack.items[self.stack.items.len - 1] = .{541 stack.items[stack.items.len - 1] = .{
580 .generic = std.math.shl(usize, b, a),542 .generic = std.math.shl(usize, b, a),
581 };543 };
544 continue :op nextOpcode(expression, &i);
582 },545 },
583 OP.shr => {546 @intFromEnum(OP.shr) => {
584 if (self.stack.items.len < 2) return error.InvalidExpression;547 if (stack.items.len < 2) return error.InvalidExpression;
585 const a = try self.stack.pop().?.asIntegral();548 const a = try stack.pop().?.asIntegral();
586 const b = try self.stack.items[self.stack.items.len - 1].asIntegral();549 const b = try stack.items[stack.items.len - 1].asIntegral();
587 self.stack.items[self.stack.items.len - 1] = .{550 stack.items[stack.items.len - 1] = .{
588 .generic = std.math.shr(usize, b, a),551 .generic = std.math.shr(usize, b, a),
589 };552 };
553 continue :op nextOpcode(expression, &i);
590 },554 },
591 OP.shra => {555 @intFromEnum(OP.shra) => {
592 if (self.stack.items.len < 2) return error.InvalidExpression;556 if (stack.items.len < 2) return error.InvalidExpression;
593 const a = try self.stack.pop().?.asIntegral();557 const a = try stack.pop().?.asIntegral();
594 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());558 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
595 self.stack.items[self.stack.items.len - 1] = .{559 stack.items[stack.items.len - 1] = .{
596 .generic = @bitCast(std.math.shr(isize, b, a)),560 .generic = @bitCast(std.math.shr(isize, b, a)),
597 };561 };
562 continue :op nextOpcode(expression, &i);
598 },563 },
599 OP.xor => {564 @intFromEnum(OP.xor) => {
600 if (self.stack.items.len < 2) return error.InvalidExpression;565 if (stack.items.len < 2) return error.InvalidExpression;
601 const a = try self.stack.pop().?.asIntegral();566 const a = try stack.pop().?.asIntegral();
602 self.stack.items[self.stack.items.len - 1] = .{567 stack.items[stack.items.len - 1] = .{
603 .generic = a ^ try self.stack.items[self.stack.items.len - 1].asIntegral(),568 .generic = a ^ try stack.items[stack.items.len - 1].asIntegral(),
604 };569 };
570 continue :op nextOpcode(expression, &i);
605 },571 },
606572
607 // 2.5.1.5: Control Flow Operations573 // 2.5.1.5: Control Flow Operations
608 OP.le,574 @intFromEnum(OP.le) => {
609 OP.ge,575 try cmpOp(stack, .lte);
610 OP.eq,576 continue :op nextOpcode(expression, &i);
611 OP.lt,577 },
612 OP.gt,578 @intFromEnum(OP.ge) => {
613 OP.ne,579 try cmpOp(stack, .gte);
614 => {580 continue :op nextOpcode(expression, &i);
615 if (self.stack.items.len < 2) return error.InvalidExpression;581 },
616 const a = self.stack.pop().?;582 @intFromEnum(OP.eq) => {
617 const b = self.stack.items[self.stack.items.len - 1];583 try cmpOp(stack, .eq);
618584 continue :op nextOpcode(expression, &i);
619 if (a == .generic and b == .generic) {585 },
620 const a_int: isize = @bitCast(a.asIntegral() catch unreachable);586 @intFromEnum(OP.lt) => {
621 const b_int: isize = @bitCast(b.asIntegral() catch unreachable);587 try cmpOp(stack, .lt);
622 const result = @intFromBool(switch (opcode) {588 continue :op nextOpcode(expression, &i);
623 OP.le => b_int <= a_int,589 },
624 OP.ge => b_int >= a_int,590 @intFromEnum(OP.gt) => {
625 OP.eq => b_int == a_int,591 try cmpOp(stack, .gt);
626 OP.lt => b_int < a_int,592 continue :op nextOpcode(expression, &i);
627 OP.gt => b_int > a_int,593 },
628 OP.ne => b_int != a_int,594 @intFromEnum(OP.ne) => {
629 else => unreachable,595 try cmpOp(stack, .neq);
630 });596 continue :op nextOpcode(expression, &i);
631
632 self.stack.items[self.stack.items.len - 1] = .{ .generic = result };
633 } else {
634 // TODO: Load the types referenced by these values, find their comparison operator, and run it
635 return error.UnimplementedTypedComparison;
636 }
637 },597 },
638 OP.skip, OP.bra => {
639 const branch_offset = operand.?.branch_offset;
640 const condition = if (opcode == OP.bra) blk: {
641 if (self.stack.items.len == 0) return error.InvalidExpression;
642 break :blk try self.stack.pop().?.asIntegral() != 0;
643 } else true;
644598
645 if (condition) reader.seekBy(branch_offset) catch return error.InvalidExpression;599 @intFromEnum(OP.skip) => {
600 const branch_offset = try nextInt(expression, &i, i16);
601 i = std.math.addAny(usize, i, branch_offset) orelse return error.InvalidExpression;
602 continue :op nextOpcode(expression, &i);
646 },603 },
647 OP.call2,604 @intFromEnum(OP.bra) => {
648 OP.call4,605 const branch_offset = try nextInt(expression, &i, i16);
649 OP.call_ref,606 const condition = try (stack.pop() orelse return error.InvalidExpression).asIntegral();
650 => {607 if (condition != 0) {
651 const debug_info_offset = operand.?.generic;608 i = std.math.addAny(usize, i, branch_offset) orelse return error.InvalidExpression;
609 }
610 continue :op nextOpcode(expression, &i);
611 },
612 @intFromEnum(OP.call2) => {
613 if (options.call_frame_context) return error.InvalidCFAOpcode;
614 const debug_info_offset = nextInt(expression, &i, u16);
615 _ = debug_info_offset;
616 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it
617 // can be in a separate exe / shared object from the one containing this expression).
618 // Transfer control to the DW_AT_location attribute, with the current stack as input.
619 return error.UnimplementedExpressionCall;
620 },
621 @intFromEnum(OP.call4) => {
622 if (options.call_frame_context) return error.InvalidCFAOpcode;
623 const debug_info_offset = nextInt(expression, &i, u32);
624 _ = debug_info_offset;
625 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it
626 // can be in a separate exe / shared object from the one containing this expression).
627 // Transfer control to the DW_AT_location attribute, with the current stack as input.
628 return error.UnimplementedExpressionCall;
629 },
630 @intFromEnum(OP.call_ref) => {
631 if (options.call_frame_context) return error.InvalidCFAOpcode;
632 const debug_info_offset: u64 = switch (context.format) {
633 .@"32" => nextInt(expression, &i, u32),
634 .@"64" => nextInt(expression, &i, u64),
635 };
652 _ = debug_info_offset;636 _ = debug_info_offset;
653
654 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it637 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it
655 // can be in a separate exe / shared object from the one containing this expression).638 // can be in a separate exe / shared object from the one containing this expression).
656 // Transfer control to the DW_AT_location attribute, with the current stack as input.639 // Transfer control to the DW_AT_location attribute, with the current stack as input.
657
658 return error.UnimplementedExpressionCall;640 return error.UnimplementedExpressionCall;
659 },641 },
660642
661 // 2.5.1.6: Type Conversions643 // 2.5.1.6: Type Conversions
662 OP.convert => {644 @intFromEnum(OP.convert) => {
663 if (self.stack.items.len == 0) return error.InvalidExpression;645 if (options.call_frame_context) return error.InvalidCFAOpcode;
664 const type_offset = operand.?.generic;646
647 if (stack.items.len == 0) return error.InvalidExpression;
648 const type_offset = try nextLeb128(expression, &i, u64);
665649
666 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size650 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
667 const value = self.stack.items[self.stack.items.len - 1];651 const value = stack.items[stack.items.len - 1];
668 if (type_offset == 0) {652 if (type_offset == 0) {
669 self.stack.items[self.stack.items.len - 1] = .{ .generic = try value.asIntegral() };653 stack.items[stack.items.len - 1] = .{ .generic = try value.asIntegral() };
670 } else {654 } else {
671 // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator655 // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
672 // from the old type to the new type, run it.656 // from the old type to the new type, run it.
673 return error.UnimplementedTypeConversion;657 return error.UnimplementedTypeConversion;
674 }658 }
659 continue :op nextOpcode(expression, &i);
675 },660 },
676 OP.reinterpret => {661 @intFromEnum(OP.reinterpret) => {
677 if (self.stack.items.len == 0) return error.InvalidExpression;662 if (options.call_frame_context) return error.InvalidCFAOpcode;
678 const type_offset = operand.?.generic;663 if (stack.items.len == 0) return error.InvalidExpression;
664 const type_offset = try nextLeb128(expression, &i, u64);
679665
680 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size666 // TODO: Load the DW_TAG_base_type entries in context.compile_unit and verify both types are the same size
681 const value = self.stack.items[self.stack.items.len - 1];667 const value = stack.items[stack.items.len - 1];
682 if (type_offset == 0) {668 if (type_offset == 0) {
683 self.stack.items[self.stack.items.len - 1] = .{ .generic = try value.asIntegral() };669 stack.items[stack.items.len - 1] = .{ .generic = try value.asIntegral() };
684 } else {670 } else {
685 self.stack.items[self.stack.items.len - 1] = switch (value) {671 stack.items[stack.items.len - 1] = switch (value) {
686 .generic => |v| .{672 .generic => |v| .{
687 .regval_type = .{673 .regval_type = .{
688 .type_offset = type_offset,674 .type_offset = type_offset,
...@@ -705,45 +691,128 @@ pub fn StackMachine(comptime options: Options) type {...@@ -705,45 +691,128 @@ pub fn StackMachine(comptime options: Options) type {
705 },691 },
706 };692 };
707 }693 }
694 continue :op nextOpcode(expression, &i);
708 },695 },
709696
710 // 2.5.1.7: Special Operations697 // 2.5.1.7: Special Operations
711 OP.nop => {},698 @intFromEnum(OP.nop) => continue :op nextOpcode(expression, &i),
712 OP.entry_value => {699 @intFromEnum(OP.entry_value) => {
713 const block = operand.?.block;700 const block_len = try nextLeb128(expression, &i, usize);
714 if (block.len == 0) return error.InvalidSubExpression;701 if (block_len == 0) return error.InvalidSubExpression;
702 const block = try nextSlice(expression, &i, block_len);
715703
716 // TODO: The spec states that this sub-expression needs to observe the state (ie. registers)704 // TODO: The spec states that this sub-expression needs to observe the state (ie. registers)
717 // as it was upon entering the current subprogram. If this isn't being called at the705 // as it was upon entering the current subprogram. If this isn't being called at the
718 // end of a frame unwind operation, an additional ThreadContext with this state will be needed.706 // end of a frame unwind operation, an additional ThreadContext with this state will be needed.
719707
720 if (isOpcodeRegisterLocation(block[0])) {708 switch (block[0]) {
721 if (context.thread_context == null) return error.IncompleteExpressionContext;709 @intFromEnum(OP.reg0)...@intFromEnum(OP.reg31) => |n| {
710 const thread_context = context.thread_context orelse
711 return error.IncompleteExpressionContext;
712 const register = n - @intFromEnum(OP.reg0);
713 const reg_bytes = try abi.regBytes(thread_context, register, context.reg_context);
714 const value = mem.readInt(usize, reg_bytes[0..@sizeOf(usize)], options.endian);
715 try stack.append(gpa, .{ .generic = value });
716 continue :op nextOpcode(expression, &i);
717 },
718 @intFromEnum(OP.regx) => {
719 const thread_context = context.thread_context orelse
720 return error.IncompleteExpressionContext;
721 const register = try nextLeb128(expression, &i, u8);
722 const reg_bytes = try abi.regBytes(thread_context, register, context.reg_context);
723 const value = mem.readInt(usize, reg_bytes[0..@sizeOf(usize)], options.endian);
724 try stack.append(gpa, .{ .generic = value });
725 continue :op nextOpcode(expression, &i);
726 },
727 else => {
728 var stack_machine: Self = .{};
729 defer stack_machine.deinit(gpa);
730
731 var sub_context = context;
732 sub_context.entry_value_context = true;
733 const result = try stack_machine.run(block, gpa, sub_context, null);
734 try stack.append(gpa, result orelse return error.InvalidSubExpression);
735 continue :op nextOpcode(expression, &i);
736 },
737 }
738 },
722739
723 var block_reader: std.io.BufferedReader = undefined;740 @intFromEnum(OP.lo_user)...@intFromEnum(OP.hi_user) - 1 => return error.UnimplementedUserOpcode,
724 block_reader.initFixed(@constCast(block));
725 const register = (try readOperand(&block_reader, block[0], context)).?.register;
726 const value = mem.readInt(usize, (try abi.regBytes(context.thread_context.?, register, context.reg_context))[0..@sizeOf(usize)], native_endian);
727 try self.stack.append(allocator, .{ .generic = value });
728 } else {
729 var stack_machine: Self = .{};
730 defer stack_machine.deinit(allocator);
731741
732 var sub_context = context;742 // Repurposed for exiting the loop.
733 sub_context.entry_value_context = true;743 @intFromEnum(OP.hi_user) => {
734 const result = try stack_machine.run(block, allocator, sub_context, null);744 if (stack.items.len == 0) return null;
735 try self.stack.append(allocator, result orelse return error.InvalidSubExpression);745 return stack.items[stack.items.len - 1];
736 }
737 },746 },
738747
739 // These have already been handled by readOperand
740 OP.lo_user...OP.hi_user => unreachable,
741 else => {748 else => {
742 //std.debug.print("Unknown DWARF expression opcode: {x}\n", .{opcode});749 //std.debug.print("Unknown DWARF expression opcode: {x}\n", .{opcode});
743 return error.UnknownExpressionOpcode;750 return error.UnknownExpressionOpcode;
744 },751 },
745 }752 }
746 return true;753 comptime unreachable;
754 }
755
756 fn nextOpcode(expression: []const u8, i: *usize) u8 {
757 const index = i.*;
758 if (expression.len - index == 0) return @intFromEnum(OP.hi_user); // repurposed to indicate end
759 i.* = index + 1;
760 return expression[index];
761 }
762
763 fn nextInt(expression: []const u8, i: *usize, comptime I: type) !I {
764 const n = @divExact(@bitSizeOf(I), 8);
765 const slice = try nextSlice(expression, i, n);
766 return mem.readInt(I, slice[0..n], options.endian);
767 }
768
769 fn nextSlice(expression: []const u8, i: *usize, len: usize) ![]const u8 {
770 const index = i.*;
771 if (expression.len - index < len) return error.EndOfStream;
772 i.* = index + len;
773 return expression[index..][0..len];
774 }
775
776 fn nextLeb128(expression: []const u8, i: *usize, comptime I: type) !I {
777 var br: std.io.BufferedReader = undefined;
778 br.initFixed(@constCast(expression));
779 br.seek = i.*;
780 assert(br.seek <= br.end);
781 const result = br.takeLeb128(I) catch |err| switch (err) {
782 error.ReadFailed => unreachable,
783 else => |e| return e,
784 };
785 i.* = br.seek;
786 return result;
787 }
788
789 fn accessAddress(size: u8, addr: Address, accessor: ?*std.debug.MemoryAccessor) !Address {
790 if (accessor) |memory_accessor| {
791 switch (size) {
792 1 => if (memory_accessor.load(u8, addr) == null) return error.InvalidExpression,
793 2 => if (memory_accessor.load(u16, addr) == null) return error.InvalidExpression,
794 4 => if (memory_accessor.load(u32, addr) == null) return error.InvalidExpression,
795 8 => if (memory_accessor.load(u64, addr) == null) return error.InvalidExpression,
796 else => return error.InvalidExpression,
797 }
798 }
799 return switch (size) {
800 1 => std.math.cast(Address, @as(*const u8, @ptrFromInt(addr)).*),
801 2 => std.math.cast(Address, @as(*const u16, @ptrFromInt(addr)).*),
802 4 => std.math.cast(Address, @as(*const u32, @ptrFromInt(addr)).*),
803 8 => std.math.cast(Address, @as(*const u64, @ptrFromInt(addr)).*),
804 else => return error.InvalidExpression,
805 } orelse return error.InvalidExpression;
806 }
807
808 fn cmpOp(stack: *std.ArrayListUnmanaged(Value), op: std.math.CompareOperator) !void {
809 if (stack.items.len < 2) return error.InvalidExpression;
810 const a = stack.pop().?;
811 const b = stack.items[stack.items.len - 1];
812
813 const a_int = try a.asIntegral();
814 const b_int = try b.asIntegral();
815 stack.items[stack.items.len - 1] = .{ .generic = @intFromBool(std.math.compare(a_int, op, b_int)) };
747 }816 }
748 };817 };
749}818}
...@@ -758,7 +827,7 @@ pub fn Builder(comptime options: Options) type {...@@ -758,7 +827,7 @@ pub fn Builder(comptime options: Options) type {
758827
759 return struct {828 return struct {
760 /// Zero-operand instructions829 /// Zero-operand instructions
761 pub fn writeOpcode(writer: anytype, comptime opcode: u8) !void {830 pub fn writeOpcode(writer: *std.io.BufferedWriter, comptime opcode: u8) !void {
762 if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;831 if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
763 switch (opcode) {832 switch (opcode) {
764 OP.dup,833 OP.dup,
...@@ -799,14 +868,14 @@ pub fn Builder(comptime options: Options) type {...@@ -799,14 +868,14 @@ pub fn Builder(comptime options: Options) type {
799 }868 }
800869
801 // 2.5.1.1: Literal Encodings870 // 2.5.1.1: Literal Encodings
802 pub fn writeLiteral(writer: anytype, literal: u8) !void {871 pub fn writeLiteral(writer: *std.io.BufferedWriter, literal: u8) !void {
803 switch (literal) {872 switch (literal) {
804 0...31 => |n| try writer.writeByte(n + OP.lit0),873 0...31 => |n| try writer.writeByte(n + OP.lit0),
805 else => return error.InvalidLiteral,874 else => return error.InvalidLiteral,
806 }875 }
807 }876 }
808877
809 pub fn writeConst(writer: anytype, comptime T: type, value: T) !void {878 pub fn writeConst(writer: *std.io.BufferedWriter, comptime T: type, value: T) !void {
810 if (@typeInfo(T) != .int) @compileError("Constants must be integers");879 if (@typeInfo(T) != .int) @compileError("Constants must be integers");
811880
812 switch (T) {881 switch (T) {
...@@ -838,12 +907,12 @@ pub fn Builder(comptime options: Options) type {...@@ -838,12 +907,12 @@ pub fn Builder(comptime options: Options) type {
838 }907 }
839 }908 }
840909
841 pub fn writeConstx(writer: anytype, debug_addr_offset: anytype) !void {910 pub fn writeConstx(writer: *std.io.BufferedWriter, debug_addr_offset: anytype) !void {
842 try writer.writeByte(OP.constx);911 try writer.writeByte(OP.constx);
843 try leb.writeUleb128(writer, debug_addr_offset);912 try leb.writeUleb128(writer, debug_addr_offset);
844 }913 }
845914
846 pub fn writeConstType(writer: anytype, die_offset: anytype, value_bytes: []const u8) !void {915 pub fn writeConstType(writer: *std.io.BufferedWriter, die_offset: anytype, value_bytes: []const u8) !void {
847 if (options.call_frame_context) return error.InvalidCFAOpcode;916 if (options.call_frame_context) return error.InvalidCFAOpcode;
848 if (value_bytes.len > 0xff) return error.InvalidTypeLength;917 if (value_bytes.len > 0xff) return error.InvalidTypeLength;
849 try writer.writeByte(OP.const_type);918 try writer.writeByte(OP.const_type);
...@@ -852,36 +921,36 @@ pub fn Builder(comptime options: Options) type {...@@ -852,36 +921,36 @@ pub fn Builder(comptime options: Options) type {
852 try writer.writeAll(value_bytes);921 try writer.writeAll(value_bytes);
853 }922 }
854923
855 pub fn writeAddr(writer: anytype, value: Address) !void {924 pub fn writeAddr(writer: *std.io.BufferedWriter, value: Address) !void {
856 try writer.writeByte(OP.addr);925 try writer.writeByte(OP.addr);
857 try writer.writeInt(Address, value, options.endian);926 try writer.writeInt(Address, value, options.endian);
858 }927 }
859928
860 pub fn writeAddrx(writer: anytype, debug_addr_offset: anytype) !void {929 pub fn writeAddrx(writer: *std.io.BufferedWriter, debug_addr_offset: anytype) !void {
861 if (options.call_frame_context) return error.InvalidCFAOpcode;930 if (options.call_frame_context) return error.InvalidCFAOpcode;
862 try writer.writeByte(OP.addrx);931 try writer.writeByte(OP.addrx);
863 try leb.writeUleb128(writer, debug_addr_offset);932 try leb.writeUleb128(writer, debug_addr_offset);
864 }933 }
865934
866 // 2.5.1.2: Register Values935 // 2.5.1.2: Register Values
867 pub fn writeFbreg(writer: anytype, offset: anytype) !void {936 pub fn writeFbreg(writer: *std.io.BufferedWriter, offset: anytype) !void {
868 try writer.writeByte(OP.fbreg);937 try writer.writeByte(OP.fbreg);
869 try leb.writeIleb128(writer, offset);938 try leb.writeIleb128(writer, offset);
870 }939 }
871940
872 pub fn writeBreg(writer: anytype, register: u8, offset: anytype) !void {941 pub fn writeBreg(writer: *std.io.BufferedWriter, register: u8, offset: anytype) !void {
873 if (register > 31) return error.InvalidRegister;942 if (register > 31) return error.InvalidRegister;
874 try writer.writeByte(OP.breg0 + register);943 try writer.writeByte(OP.breg0 + register);
875 try leb.writeIleb128(writer, offset);944 try leb.writeIleb128(writer, offset);
876 }945 }
877946
878 pub fn writeBregx(writer: anytype, register: anytype, offset: anytype) !void {947 pub fn writeBregx(writer: *std.io.BufferedWriter, register: anytype, offset: anytype) !void {
879 try writer.writeByte(OP.bregx);948 try writer.writeByte(OP.bregx);
880 try leb.writeUleb128(writer, register);949 try leb.writeUleb128(writer, register);
881 try leb.writeIleb128(writer, offset);950 try leb.writeIleb128(writer, offset);
882 }951 }
883952
884 pub fn writeRegvalType(writer: anytype, register: anytype, offset: anytype) !void {953 pub fn writeRegvalType(writer: *std.io.BufferedWriter, register: anytype, offset: anytype) !void {
885 if (options.call_frame_context) return error.InvalidCFAOpcode;954 if (options.call_frame_context) return error.InvalidCFAOpcode;
886 try writer.writeByte(OP.regval_type);955 try writer.writeByte(OP.regval_type);
887 try leb.writeUleb128(writer, register);956 try leb.writeUleb128(writer, register);
...@@ -889,29 +958,29 @@ pub fn Builder(comptime options: Options) type {...@@ -889,29 +958,29 @@ pub fn Builder(comptime options: Options) type {
889 }958 }
890959
891 // 2.5.1.3: Stack Operations960 // 2.5.1.3: Stack Operations
892 pub fn writePick(writer: anytype, index: u8) !void {961 pub fn writePick(writer: *std.io.BufferedWriter, index: u8) !void {
893 try writer.writeByte(OP.pick);962 try writer.writeByte(OP.pick);
894 try writer.writeByte(index);963 try writer.writeByte(index);
895 }964 }
896965
897 pub fn writeDerefSize(writer: anytype, size: u8) !void {966 pub fn writeDerefSize(writer: *std.io.BufferedWriter, size: u8) !void {
898 try writer.writeByte(OP.deref_size);967 try writer.writeByte(OP.deref_size);
899 try writer.writeByte(size);968 try writer.writeByte(size);
900 }969 }
901970
902 pub fn writeXDerefSize(writer: anytype, size: u8) !void {971 pub fn writeXDerefSize(writer: *std.io.BufferedWriter, size: u8) !void {
903 try writer.writeByte(OP.xderef_size);972 try writer.writeByte(OP.xderef_size);
904 try writer.writeByte(size);973 try writer.writeByte(size);
905 }974 }
906975
907 pub fn writeDerefType(writer: anytype, size: u8, die_offset: anytype) !void {976 pub fn writeDerefType(writer: *std.io.BufferedWriter, size: u8, die_offset: anytype) !void {
908 if (options.call_frame_context) return error.InvalidCFAOpcode;977 if (options.call_frame_context) return error.InvalidCFAOpcode;
909 try writer.writeByte(OP.deref_type);978 try writer.writeByte(OP.deref_type);
910 try writer.writeByte(size);979 try writer.writeByte(size);
911 try leb.writeUleb128(writer, die_offset);980 try leb.writeUleb128(writer, die_offset);
912 }981 }
913982
914 pub fn writeXDerefType(writer: anytype, size: u8, die_offset: anytype) !void {983 pub fn writeXDerefType(writer: *std.io.BufferedWriter, size: u8, die_offset: anytype) !void {
915 try writer.writeByte(OP.xderef_type);984 try writer.writeByte(OP.xderef_type);
916 try writer.writeByte(size);985 try writer.writeByte(size);
917 try leb.writeUleb128(writer, die_offset);986 try leb.writeUleb128(writer, die_offset);
...@@ -919,24 +988,24 @@ pub fn Builder(comptime options: Options) type {...@@ -919,24 +988,24 @@ pub fn Builder(comptime options: Options) type {
919988
920 // 2.5.1.4: Arithmetic and Logical Operations989 // 2.5.1.4: Arithmetic and Logical Operations
921990
922 pub fn writePlusUconst(writer: anytype, uint_value: anytype) !void {991 pub fn writePlusUconst(writer: *std.io.BufferedWriter, uint_value: anytype) !void {
923 try writer.writeByte(OP.plus_uconst);992 try writer.writeByte(OP.plus_uconst);
924 try leb.writeUleb128(writer, uint_value);993 try leb.writeUleb128(writer, uint_value);
925 }994 }
926995
927 // 2.5.1.5: Control Flow Operations996 // 2.5.1.5: Control Flow Operations
928997
929 pub fn writeSkip(writer: anytype, offset: i16) !void {998 pub fn writeSkip(writer: *std.io.BufferedWriter, offset: i16) !void {
930 try writer.writeByte(OP.skip);999 try writer.writeByte(OP.skip);
931 try writer.writeInt(i16, offset, options.endian);1000 try writer.writeInt(i16, offset, options.endian);
932 }1001 }
9331002
934 pub fn writeBra(writer: anytype, offset: i16) !void {1003 pub fn writeBra(writer: *std.io.BufferedWriter, offset: i16) !void {
935 try writer.writeByte(OP.bra);1004 try writer.writeByte(OP.bra);
936 try writer.writeInt(i16, offset, options.endian);1005 try writer.writeInt(i16, offset, options.endian);
937 }1006 }
9381007
939 pub fn writeCall(writer: anytype, comptime T: type, offset: T) !void {1008 pub fn writeCall(writer: *std.io.BufferedWriter, comptime T: type, offset: T) !void {
940 if (options.call_frame_context) return error.InvalidCFAOpcode;1009 if (options.call_frame_context) return error.InvalidCFAOpcode;
941 switch (T) {1010 switch (T) {
942 u16 => try writer.writeByte(OP.call2),1011 u16 => try writer.writeByte(OP.call2),
...@@ -947,19 +1016,19 @@ pub fn Builder(comptime options: Options) type {...@@ -947,19 +1016,19 @@ pub fn Builder(comptime options: Options) type {
947 try writer.writeInt(T, offset, options.endian);1016 try writer.writeInt(T, offset, options.endian);
948 }1017 }
9491018
950 pub fn writeCallRef(writer: anytype, comptime is_64: bool, value: if (is_64) u64 else u32) !void {1019 pub fn writeCallRef(writer: *std.io.BufferedWriter, comptime is_64: bool, value: if (is_64) u64 else u32) !void {
951 if (options.call_frame_context) return error.InvalidCFAOpcode;1020 if (options.call_frame_context) return error.InvalidCFAOpcode;
952 try writer.writeByte(OP.call_ref);1021 try writer.writeByte(OP.call_ref);
953 try writer.writeInt(if (is_64) u64 else u32, value, options.endian);1022 try writer.writeInt(if (is_64) u64 else u32, value, options.endian);
954 }1023 }
9551024
956 pub fn writeConvert(writer: anytype, die_offset: anytype) !void {1025 pub fn writeConvert(writer: *std.io.BufferedWriter, die_offset: anytype) !void {
957 if (options.call_frame_context) return error.InvalidCFAOpcode;1026 if (options.call_frame_context) return error.InvalidCFAOpcode;
958 try writer.writeByte(OP.convert);1027 try writer.writeByte(OP.convert);
959 try leb.writeUleb128(writer, die_offset);1028 try leb.writeUleb128(writer, die_offset);
960 }1029 }
9611030
962 pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void {1031 pub fn writeReinterpret(writer: *std.io.BufferedWriter, die_offset: anytype) !void {
963 if (options.call_frame_context) return error.InvalidCFAOpcode;1032 if (options.call_frame_context) return error.InvalidCFAOpcode;
964 try writer.writeByte(OP.reinterpret);1033 try writer.writeByte(OP.reinterpret);
965 try leb.writeUleb128(writer, die_offset);1034 try leb.writeUleb128(writer, die_offset);
...@@ -967,23 +1036,23 @@ pub fn Builder(comptime options: Options) type {...@@ -967,23 +1036,23 @@ pub fn Builder(comptime options: Options) type {
9671036
968 // 2.5.1.7: Special Operations1037 // 2.5.1.7: Special Operations
9691038
970 pub fn writeEntryValue(writer: anytype, expression: []const u8) !void {1039 pub fn writeEntryValue(writer: *std.io.BufferedWriter, expression: []const u8) !void {
971 try writer.writeByte(OP.entry_value);1040 try writer.writeByte(OP.entry_value);
972 try leb.writeUleb128(writer, expression.len);1041 try leb.writeUleb128(writer, expression.len);
973 try writer.writeAll(expression);1042 try writer.writeAll(expression);
974 }1043 }
9751044
976 // 2.6: Location Descriptions1045 // 2.6: Location Descriptions
977 pub fn writeReg(writer: anytype, register: u8) !void {1046 pub fn writeReg(writer: *std.io.BufferedWriter, register: u8) !void {
978 try writer.writeByte(OP.reg0 + register);1047 try writer.writeByte(OP.reg0 + register);
979 }1048 }
9801049
981 pub fn writeRegx(writer: anytype, register: anytype) !void {1050 pub fn writeRegx(writer: *std.io.BufferedWriter, register: anytype) !void {
982 try writer.writeByte(OP.regx);1051 try writer.writeByte(OP.regx);
983 try leb.writeUleb128(writer, register);1052 try leb.writeUleb128(writer, register);
984 }1053 }
9851054
986 pub fn writeImplicitValue(writer: anytype, value_bytes: []const u8) !void {1055 pub fn writeImplicitValue(writer: *std.io.BufferedWriter, value_bytes: []const u8) !void {
987 try writer.writeByte(OP.implicit_value);1056 try writer.writeByte(OP.implicit_value);
988 try leb.writeUleb128(writer, value_bytes.len);1057 try leb.writeUleb128(writer, value_bytes.len);
989 try writer.writeAll(value_bytes);1058 try writer.writeAll(value_bytes);
...@@ -991,21 +1060,21 @@ pub fn Builder(comptime options: Options) type {...@@ -991,21 +1060,21 @@ pub fn Builder(comptime options: Options) type {
991 };1060 };
992}1061}
9931062
994// Certain opcodes are not allowed in a CFA context, see 6.4.21063/// Certain opcodes are not allowed in a CFA context, see 6.4.2
995fn isOpcodeValidInCFA(opcode: u8) bool {1064fn isOpcodeValidInCFA(opcode: OP) bool {
996 return switch (opcode) {1065 return switch (opcode) {
997 OP.addrx,1066 .addrx,
998 OP.call2,1067 .call2,
999 OP.call4,1068 .call4,
1000 OP.call_ref,1069 .call_ref,
1001 OP.const_type,1070 .const_type,
1002 OP.constx,1071 .constx,
1003 OP.convert,1072 .convert,
1004 OP.deref_type,1073 .deref_type,
1005 OP.regval_type,1074 .regval_type,
1006 OP.reinterpret,1075 .reinterpret,
1007 OP.push_object_address,1076 .push_object_address,
1008 OP.call_frame_cfa,1077 .call_frame_cfa,
1009 => false,1078 => false,
1010 else => true,1079 else => true,
1011 };1080 };
lib/std/dwarf.zig+220-1
...@@ -6,7 +6,226 @@...@@ -6,7 +6,226 @@
66
7pub const TAG = @import("dwarf/TAG.zig");7pub const TAG = @import("dwarf/TAG.zig");
8pub const AT = @import("dwarf/AT.zig");8pub const AT = @import("dwarf/AT.zig");
9pub const OP = @import("dwarf/OP.zig");9pub const OP = enum(u8) {
10 addr = 0x03,
11 deref = 0x06,
12 const1u = 0x08,
13 const1s = 0x09,
14 const2u = 0x0a,
15 const2s = 0x0b,
16 const4u = 0x0c,
17 const4s = 0x0d,
18 const8u = 0x0e,
19 const8s = 0x0f,
20 constu = 0x10,
21 consts = 0x11,
22 dup = 0x12,
23 drop = 0x13,
24 over = 0x14,
25 pick = 0x15,
26 swap = 0x16,
27 rot = 0x17,
28 xderef = 0x18,
29 abs = 0x19,
30 @"and" = 0x1a,
31 div = 0x1b,
32 minus = 0x1c,
33 mod = 0x1d,
34 mul = 0x1e,
35 neg = 0x1f,
36 not = 0x20,
37 @"or" = 0x21,
38 plus = 0x22,
39 plus_uconst = 0x23,
40 shl = 0x24,
41 shr = 0x25,
42 shra = 0x26,
43 xor = 0x27,
44 bra = 0x28,
45 eq = 0x29,
46 ge = 0x2a,
47 gt = 0x2b,
48 le = 0x2c,
49 lt = 0x2d,
50 ne = 0x2e,
51 skip = 0x2f,
52 lit0 = 0x30,
53 lit1 = 0x31,
54 lit2 = 0x32,
55 lit3 = 0x33,
56 lit4 = 0x34,
57 lit5 = 0x35,
58 lit6 = 0x36,
59 lit7 = 0x37,
60 lit8 = 0x38,
61 lit9 = 0x39,
62 lit10 = 0x3a,
63 lit11 = 0x3b,
64 lit12 = 0x3c,
65 lit13 = 0x3d,
66 lit14 = 0x3e,
67 lit15 = 0x3f,
68 lit16 = 0x40,
69 lit17 = 0x41,
70 lit18 = 0x42,
71 lit19 = 0x43,
72 lit20 = 0x44,
73 lit21 = 0x45,
74 lit22 = 0x46,
75 lit23 = 0x47,
76 lit24 = 0x48,
77 lit25 = 0x49,
78 lit26 = 0x4a,
79 lit27 = 0x4b,
80 lit28 = 0x4c,
81 lit29 = 0x4d,
82 lit30 = 0x4e,
83 lit31 = 0x4f,
84 reg0 = 0x50,
85 reg1 = 0x51,
86 reg2 = 0x52,
87 reg3 = 0x53,
88 reg4 = 0x54,
89 reg5 = 0x55,
90 reg6 = 0x56,
91 reg7 = 0x57,
92 reg8 = 0x58,
93 reg9 = 0x59,
94 reg10 = 0x5a,
95 reg11 = 0x5b,
96 reg12 = 0x5c,
97 reg13 = 0x5d,
98 reg14 = 0x5e,
99 reg15 = 0x5f,
100 reg16 = 0x60,
101 reg17 = 0x61,
102 reg18 = 0x62,
103 reg19 = 0x63,
104 reg20 = 0x64,
105 reg21 = 0x65,
106 reg22 = 0x66,
107 reg23 = 0x67,
108 reg24 = 0x68,
109 reg25 = 0x69,
110 reg26 = 0x6a,
111 reg27 = 0x6b,
112 reg28 = 0x6c,
113 reg29 = 0x6d,
114 reg30 = 0x6e,
115 reg31 = 0x6f,
116 breg0 = 0x70,
117 breg1 = 0x71,
118 breg2 = 0x72,
119 breg3 = 0x73,
120 breg4 = 0x74,
121 breg5 = 0x75,
122 breg6 = 0x76,
123 breg7 = 0x77,
124 breg8 = 0x78,
125 breg9 = 0x79,
126 breg10 = 0x7a,
127 breg11 = 0x7b,
128 breg12 = 0x7c,
129 breg13 = 0x7d,
130 breg14 = 0x7e,
131 breg15 = 0x7f,
132 breg16 = 0x80,
133 breg17 = 0x81,
134 breg18 = 0x82,
135 breg19 = 0x83,
136 breg20 = 0x84,
137 breg21 = 0x85,
138 breg22 = 0x86,
139 breg23 = 0x87,
140 breg24 = 0x88,
141 breg25 = 0x89,
142 breg26 = 0x8a,
143 breg27 = 0x8b,
144 breg28 = 0x8c,
145 breg29 = 0x8d,
146 breg30 = 0x8e,
147 breg31 = 0x8f,
148 regx = 0x90,
149 fbreg = 0x91,
150 bregx = 0x92,
151 piece = 0x93,
152 deref_size = 0x94,
153 xderef_size = 0x95,
154 nop = 0x96,
155
156 // DWARF 3 extensions.
157 push_object_address = 0x97,
158 call2 = 0x98,
159 call4 = 0x99,
160 call_ref = 0x9a,
161 form_tls_address = 0x9b,
162 call_frame_cfa = 0x9c,
163 bit_piece = 0x9d,
164
165 // DWARF 4 extensions.
166 implicit_value = 0x9e,
167 stack_value = 0x9f,
168
169 // DWARF 5 extensions.
170 implicit_pointer = 0xa0,
171 addrx = 0xa1,
172 constx = 0xa2,
173 entry_value = 0xa3,
174 const_type = 0xa4,
175 regval_type = 0xa5,
176 deref_type = 0xa6,
177 xderef_type = 0xa7,
178 convert = 0xa8,
179 reinterpret = 0xa9,
180
181 // GNU extensions.
182 GNU_push_tls_address = 0xe0,
183 /// The following is for marking variables that are uninitialized.
184 GNU_uninit = 0xf0,
185 GNU_encoded_addr = 0xf1,
186 /// The GNU implicit pointer extension.
187 /// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .
188 GNU_implicit_pointer = 0xf2,
189 /// The GNU entry value extension.
190 /// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .
191 GNU_entry_value = 0xf3,
192 /// The GNU typed stack extension.
193 /// See http://www.dwarfstd.org/doc/040408.1.html .
194 GNU_const_type = 0xf4,
195 GNU_regval_type = 0xf5,
196 GNU_deref_type = 0xf6,
197 GNU_convert = 0xf7,
198 GNU_reinterpret = 0xf9,
199 /// The GNU parameter ref extension.
200 GNU_parameter_ref = 0xfa,
201 /// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.
202 GNU_addr_index = 0xfb,
203 GNU_const_index = 0xfc,
204 // HP extensions.
205 HP_is_value = 0xe1,
206 HP_fltconst4 = 0xe2,
207 HP_fltconst8 = 0xe3,
208 HP_mod_range = 0xe4,
209 HP_unmod_range = 0xe5,
210 HP_tls = 0xe6,
211 // PGI (STMicroelectronics) extensions.
212 PGI_omp_thread_num = 0xf8,
213 // Wasm extensions.
214 WASM_location = 0xed,
215 WASM_local = 0x00,
216 WASM_global = 0x01,
217 WASM_operand_stack = 0x02,
218
219 _,
220
221 /// Implementation-defined range start.
222 pub const lo_user: OP = @enumFromInt(0xe0);
223 /// Implementation-defined range end.
224 pub const hi_user: OP = @enumFromInt(0xff);
225
226 pub const HP_unknown: OP = @enumFromInt(0xe0);
227 pub const WASM_global_u32: OP = @enumFromInt(0x03);
228};
10pub const LANG = @import("dwarf/LANG.zig");229pub const LANG = @import("dwarf/LANG.zig");
11pub const FORM = @import("dwarf/FORM.zig");230pub const FORM = @import("dwarf/FORM.zig");
12pub const ATE = @import("dwarf/ATE.zig");231pub const ATE = @import("dwarf/ATE.zig");
lib/std/dwarf/OP.zig deleted-213
...@@ -1,213 +0,0 @@
1pub const addr = 0x03;
2pub const deref = 0x06;
3pub const const1u = 0x08;
4pub const const1s = 0x09;
5pub const const2u = 0x0a;
6pub const const2s = 0x0b;
7pub const const4u = 0x0c;
8pub const const4s = 0x0d;
9pub const const8u = 0x0e;
10pub const const8s = 0x0f;
11pub const constu = 0x10;
12pub const consts = 0x11;
13pub const dup = 0x12;
14pub const drop = 0x13;
15pub const over = 0x14;
16pub const pick = 0x15;
17pub const swap = 0x16;
18pub const rot = 0x17;
19pub const xderef = 0x18;
20pub const abs = 0x19;
21pub const @"and" = 0x1a;
22pub const div = 0x1b;
23pub const minus = 0x1c;
24pub const mod = 0x1d;
25pub const mul = 0x1e;
26pub const neg = 0x1f;
27pub const not = 0x20;
28pub const @"or" = 0x21;
29pub const plus = 0x22;
30pub const plus_uconst = 0x23;
31pub const shl = 0x24;
32pub const shr = 0x25;
33pub const shra = 0x26;
34pub const xor = 0x27;
35pub const bra = 0x28;
36pub const eq = 0x29;
37pub const ge = 0x2a;
38pub const gt = 0x2b;
39pub const le = 0x2c;
40pub const lt = 0x2d;
41pub const ne = 0x2e;
42pub const skip = 0x2f;
43pub const lit0 = 0x30;
44pub const lit1 = 0x31;
45pub const lit2 = 0x32;
46pub const lit3 = 0x33;
47pub const lit4 = 0x34;
48pub const lit5 = 0x35;
49pub const lit6 = 0x36;
50pub const lit7 = 0x37;
51pub const lit8 = 0x38;
52pub const lit9 = 0x39;
53pub const lit10 = 0x3a;
54pub const lit11 = 0x3b;
55pub const lit12 = 0x3c;
56pub const lit13 = 0x3d;
57pub const lit14 = 0x3e;
58pub const lit15 = 0x3f;
59pub const lit16 = 0x40;
60pub const lit17 = 0x41;
61pub const lit18 = 0x42;
62pub const lit19 = 0x43;
63pub const lit20 = 0x44;
64pub const lit21 = 0x45;
65pub const lit22 = 0x46;
66pub const lit23 = 0x47;
67pub const lit24 = 0x48;
68pub const lit25 = 0x49;
69pub const lit26 = 0x4a;
70pub const lit27 = 0x4b;
71pub const lit28 = 0x4c;
72pub const lit29 = 0x4d;
73pub const lit30 = 0x4e;
74pub const lit31 = 0x4f;
75pub const reg0 = 0x50;
76pub const reg1 = 0x51;
77pub const reg2 = 0x52;
78pub const reg3 = 0x53;
79pub const reg4 = 0x54;
80pub const reg5 = 0x55;
81pub const reg6 = 0x56;
82pub const reg7 = 0x57;
83pub const reg8 = 0x58;
84pub const reg9 = 0x59;
85pub const reg10 = 0x5a;
86pub const reg11 = 0x5b;
87pub const reg12 = 0x5c;
88pub const reg13 = 0x5d;
89pub const reg14 = 0x5e;
90pub const reg15 = 0x5f;
91pub const reg16 = 0x60;
92pub const reg17 = 0x61;
93pub const reg18 = 0x62;
94pub const reg19 = 0x63;
95pub const reg20 = 0x64;
96pub const reg21 = 0x65;
97pub const reg22 = 0x66;
98pub const reg23 = 0x67;
99pub const reg24 = 0x68;
100pub const reg25 = 0x69;
101pub const reg26 = 0x6a;
102pub const reg27 = 0x6b;
103pub const reg28 = 0x6c;
104pub const reg29 = 0x6d;
105pub const reg30 = 0x6e;
106pub const reg31 = 0x6f;
107pub const breg0 = 0x70;
108pub const breg1 = 0x71;
109pub const breg2 = 0x72;
110pub const breg3 = 0x73;
111pub const breg4 = 0x74;
112pub const breg5 = 0x75;
113pub const breg6 = 0x76;
114pub const breg7 = 0x77;
115pub const breg8 = 0x78;
116pub const breg9 = 0x79;
117pub const breg10 = 0x7a;
118pub const breg11 = 0x7b;
119pub const breg12 = 0x7c;
120pub const breg13 = 0x7d;
121pub const breg14 = 0x7e;
122pub const breg15 = 0x7f;
123pub const breg16 = 0x80;
124pub const breg17 = 0x81;
125pub const breg18 = 0x82;
126pub const breg19 = 0x83;
127pub const breg20 = 0x84;
128pub const breg21 = 0x85;
129pub const breg22 = 0x86;
130pub const breg23 = 0x87;
131pub const breg24 = 0x88;
132pub const breg25 = 0x89;
133pub const breg26 = 0x8a;
134pub const breg27 = 0x8b;
135pub const breg28 = 0x8c;
136pub const breg29 = 0x8d;
137pub const breg30 = 0x8e;
138pub const breg31 = 0x8f;
139pub const regx = 0x90;
140pub const fbreg = 0x91;
141pub const bregx = 0x92;
142pub const piece = 0x93;
143pub const deref_size = 0x94;
144pub const xderef_size = 0x95;
145pub const nop = 0x96;
146
147// DWARF 3 extensions.
148pub const push_object_address = 0x97;
149pub const call2 = 0x98;
150pub const call4 = 0x99;
151pub const call_ref = 0x9a;
152pub const form_tls_address = 0x9b;
153pub const call_frame_cfa = 0x9c;
154pub const bit_piece = 0x9d;
155
156// DWARF 4 extensions.
157pub const implicit_value = 0x9e;
158pub const stack_value = 0x9f;
159
160// DWARF 5 extensions.
161pub const implicit_pointer = 0xa0;
162pub const addrx = 0xa1;
163pub const constx = 0xa2;
164pub const entry_value = 0xa3;
165pub const const_type = 0xa4;
166pub const regval_type = 0xa5;
167pub const deref_type = 0xa6;
168pub const xderef_type = 0xa7;
169pub const convert = 0xa8;
170pub const reinterpret = 0xa9;
171
172pub const lo_user = 0xe0; // Implementation-defined range start.
173pub const hi_user = 0xff; // Implementation-defined range end.
174
175// GNU extensions.
176pub const GNU_push_tls_address = 0xe0;
177// The following is for marking variables that are uninitialized.
178pub const GNU_uninit = 0xf0;
179pub const GNU_encoded_addr = 0xf1;
180// The GNU implicit pointer extension.
181// See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open .
182pub const GNU_implicit_pointer = 0xf2;
183// The GNU entry value extension.
184// See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open .
185pub const GNU_entry_value = 0xf3;
186// The GNU typed stack extension.
187// See http://www.dwarfstd.org/doc/040408.1.html .
188pub const GNU_const_type = 0xf4;
189pub const GNU_regval_type = 0xf5;
190pub const GNU_deref_type = 0xf6;
191pub const GNU_convert = 0xf7;
192pub const GNU_reinterpret = 0xf9;
193// The GNU parameter ref extension.
194pub const GNU_parameter_ref = 0xfa;
195// Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission.
196pub const GNU_addr_index = 0xfb;
197pub const GNU_const_index = 0xfc;
198// HP extensions.
199pub const HP_unknown = 0xe0; // Ouch, the same as GNU_push_tls_address.
200pub const HP_is_value = 0xe1;
201pub const HP_fltconst4 = 0xe2;
202pub const HP_fltconst8 = 0xe3;
203pub const HP_mod_range = 0xe4;
204pub const HP_unmod_range = 0xe5;
205pub const HP_tls = 0xe6;
206// PGI (STMicroelectronics) extensions.
207pub const PGI_omp_thread_num = 0xf8;
208// Wasm extensions.
209pub const WASM_location = 0xed;
210pub const WASM_local = 0x00;
211pub const WASM_global = 0x01;
212pub const WASM_global_u32 = 0x03;
213pub const WASM_operand_stack = 0x02;