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;
88const abi = std.debug.Dwarf.abi;
99const mem = std.mem;
1010const assert = std.debug.assert;
11const Allocator = std.mem.Allocator;
1112
1213/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.
1314/// Callers should specify all the fields relevant to their context. If a field is required
......@@ -41,8 +42,7 @@ pub const Options = struct {
4142 call_frame_context: bool = false,
4243};
4344
44// Explicitly defined to support executing sub-expressions
45pub const Error = error{
45pub const RunError = error{
4646 UnimplementedExpressionCall,
4747 UnimplementedOpcode,
4848 UnimplementedUserOpcode,
......@@ -62,7 +62,12 @@ pub const Error = error{
6262 InvalidTypeLength,
6363
6464 TruncatedIntegralType,
65} || abi.RegBytesError || error{ EndOfStream, Overflow, OutOfMemory, DivisionByZero, ReadFailed };
65
66 OutOfMemory,
67 EndOfStream,
68 Overflow,
69 DivisionByZero,
70} || abi.RegBytesError;
6671
6772/// A stack machine that can decode and run DWARF expressions.
6873/// Expressions can be decoded for non-native address size and endianness,
......@@ -74,44 +79,16 @@ pub fn StackMachine(comptime options: Options) type {
7479 8 => u64,
7580 else => @compileError("Unsupported address size of " ++ options.addr_size),
7681 };
77
7882 const SignedAddress = switch (options.addr_size) {
7983 2 => i16,
8084 4 => i32,
8185 8 => i64,
8286 else => @compileError("Unsupported address size of " ++ options.addr_size),
8387 };
84
8588 return struct {
86 const Self = @This();
89 stack: std.ArrayListUnmanaged(Value) = .empty,
8790
88 const Operand = union(enum) {
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 };
91 const Self = @This();
11592
11693 const Value = union(enum) {
11794 generic: Address,
......@@ -132,7 +109,7 @@ pub fn StackMachine(comptime options: Options) type {
132109 value_bytes: []const u8,
133110 },
134111
135 pub fn asIntegral(self: Value) !Address {
112 fn asIntegral(self: Value) !Address {
136113 return switch (self) {
137114 .generic => |v| v,
138115
......@@ -151,185 +128,131 @@ pub fn StackMachine(comptime options: Options) type {
151128 },
152129 };
153130 }
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
158148 pub fn reset(self: *Self) void {
159149 self.stack.clearRetainingCapacity();
160150 }
161151
162 pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
152 pub fn deinit(self: *Self, allocator: Allocator) void {
163153 self.stack.deinit(allocator);
164154 }
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
256156 pub fn run(
257157 self: *Self,
258158 expression: []const u8,
259 allocator: std.mem.Allocator,
159 gpa: Allocator,
260160 context: Context,
261161 initial_value: ?usize,
262 ) Error!?Value {
263 if (initial_value) |i| try self.stack.append(allocator, .{ .generic = i });
264 var reader: std.io.BufferedReader = undefined;
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)
162 ) RunError!?Value {
163 if (@sizeOf(usize) != @sizeOf(Address) or options.endian != native_endian) {
164 // This restriction can be removed when the `@ptrFromInt` calls are removed.
279165 @compileError("Execution of non-native address sizes / endianness is not supported");
166 }
280167
281 const opcode = reader.takeByte() catch |err| switch (err) {
282 error.EndOfStream => return false,
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) {
168 const stack = &self.stack;
169 if (initial_value) |i| try stack.append(gpa, .{ .generic = i });
288170
171 var i: usize = 0;
172 // TODO: https://github.com/ziglang/zig/issues/15556
173 op: switch (nextOpcode(expression, &i)) {
289174 // 2.5.1.1: Literal Encodings
290 OP.lit0...OP.lit31,
291 OP.addr,
292 OP.const1u,
293 OP.const2u,
294 OP.const4u,
295 OP.const8u,
296 OP.const1s,
297 OP.const2s,
298 OP.const4s,
299 OP.const8s,
300 OP.constu,
301 OP.consts,
302 => try self.stack.append(allocator, .{ .generic = operand.?.generic }),
303
304 OP.const_type => {
305 const const_type = operand.?.const_type;
306 try self.stack.append(allocator, .{ .const_type = .{
307 .type_offset = const_type.type_offset,
308 .value_bytes = const_type.value_bytes,
175 @intFromEnum(OP.lit0)...@intFromEnum(OP.lit31) => |n| {
176 try stack.append(gpa, .{ .generic = n - @intFromEnum(OP.lit0) });
177 continue :op nextOpcode(expression, &i);
178 },
179 @intFromEnum(OP.addr) => {
180 try stack.append(gpa, .fromInt(try nextInt(expression, &i, Address)));
181 continue :op nextOpcode(expression, &i);
182 },
183 @intFromEnum(OP.const1u) => {
184 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u8)));
185 continue :op nextOpcode(expression, &i);
186 },
187 @intFromEnum(OP.const2u) => {
188 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u16)));
189 continue :op nextOpcode(expression, &i);
190 },
191 @intFromEnum(OP.const4u) => {
192 try stack.append(gpa, .fromInt(try nextInt(expression, &i, u32)));
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)),
309229 } });
230 continue :op nextOpcode(expression, &i);
310231 },
311232
312 OP.addrx,
313 OP.constx,
233 @intFromEnum(OP.addrx),
234 @intFromEnum(OP.constx),
314235 => {
315 if (context.compile_unit == null) return error.IncompleteExpressionContext;
316 if (context.debug_addr == null) return error.IncompleteExpressionContext;
317 const debug_addr_index = operand.?.generic;
318 const offset = context.compile_unit.?.addr_base + debug_addr_index;
319 if (offset >= context.debug_addr.?.len) return error.InvalidExpression;
320 const value = mem.readInt(usize, context.debug_addr.?[offset..][0..@sizeOf(usize)], native_endian);
321 try self.stack.append(allocator, .{ .generic = value });
236 if (options.call_frame_context) return error.InvalidCFAOpcode;
237 const compile_unit = context.compile_unit orelse return error.IncompleteExpressionContext;
238 const debug_addr = context.debug_addr orelse return error.IncompleteExpressionContext;
239 const debug_addr_index = try nextLeb128(expression, &i, u64);
240 const offset = compile_unit.addr_base + debug_addr_index;
241 if (offset >= debug_addr.len) return error.InvalidExpression;
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);
322245 },
323246
324247 // 2.5.1.2: Register Values
325 OP.fbreg => {
326 if (context.compile_unit == null) return error.IncompleteExpressionContext;
327 if (context.compile_unit.?.frame_base == null) return error.IncompleteExpressionContext;
248 @intFromEnum(OP.fbreg) => {
249 const compile_unit = context.compile_unit orelse 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);
330253 _ = offset;
331254
332 switch (context.compile_unit.?.frame_base.?.*) {
255 switch (frame_base.*) {
333256 .exprloc => {
334257 // TODO: Run this expression in a nested stack machine
335258 return error.UnimplementedOpcode;
......@@ -345,344 +268,407 @@ pub fn StackMachine(comptime options: Options) type {
345268 else => return error.InvalidFrameBase,
346269 }
347270 },
348 OP.breg0...OP.breg31,
349 OP.bregx,
350 => {
351 if (context.thread_context == null) return error.IncompleteExpressionContext;
352
353 const base_register = operand.?.base_register;
354 var value: i64 = @intCast(mem.readInt(usize, (try abi.regBytes(
355 context.thread_context.?,
356 base_register.base_register,
357 context.reg_context,
358 ))[0..@sizeOf(usize)], native_endian));
359 value += base_register.offset;
360 try self.stack.append(allocator, .{ .generic = @intCast(value) });
361 },
362 OP.regval_type => {
363 const register_type = operand.?.register_type;
364 const value = mem.readInt(usize, (try abi.regBytes(
365 context.thread_context.?,
366 register_type.register,
367 context.reg_context,
368 ))[0..@sizeOf(usize)], native_endian);
369 try self.stack.append(allocator, .{
271 @intFromEnum(OP.breg0)...@intFromEnum(OP.breg31) => |n| {
272 const thread_context = context.thread_context orelse return error.IncompleteExpressionContext;
273 const base_register = n - @intFromEnum(OP.breg0);
274 const offset = try nextLeb128(expression, &i, i64);
275 const reg_bytes = try abi.regBytes(thread_context, base_register, context.reg_context);
276 const start_addr = mem.readInt(Address, reg_bytes[0..@sizeOf(Address)], options.endian);
277 try stack.append(gpa, .{
278 .generic = std.math.addAny(Address, start_addr, offset) orelse
279 return error.InvalidExpression,
280 });
281 continue :op nextOpcode(expression, &i);
282 },
283 @intFromEnum(OP.bregx) => {
284 const thread_context = context.thread_context orelse return error.IncompleteExpressionContext;
285 const base_register = try nextLeb128(expression, &i, u8);
286 const offset = try nextLeb128(expression, &i, i64);
287 const reg_bytes = try abi.regBytes(thread_context, base_register, context.reg_context);
288 const start_addr = mem.readInt(Address, reg_bytes[0..@sizeOf(Address)], options.endian);
289 try stack.append(gpa, .{
290 .generic = std.math.addAny(Address, start_addr, offset) orelse
291 return error.InvalidExpression,
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, .{
370303 .regval_type = .{
371 .type_offset = register_type.type_offset,
304 .type_offset = type_offset,
372305 .type_size = @sizeOf(Address),
373306 .value = value,
374307 },
375308 });
309 continue :op nextOpcode(expression, &i);
376310 },
377311
378312 // 2.5.1.3: Stack Operations
379 OP.dup => {
380 if (self.stack.items.len == 0) return error.InvalidExpression;
381 try self.stack.append(allocator, self.stack.items[self.stack.items.len - 1]);
313 @intFromEnum(OP.dup) => {
314 if (stack.items.len == 0) return error.InvalidExpression;
315 try stack.append(gpa, stack.items[stack.items.len - 1]);
316 continue :op nextOpcode(expression, &i);
382317 },
383 OP.drop => {
384 _ = self.stack.pop();
318 @intFromEnum(OP.drop) => {
319 _ = stack.pop();
320 continue :op nextOpcode(expression, &i);
385321 },
386 OP.pick, OP.over => {
387 const stack_index = if (opcode == OP.over) 1 else operand.?.generic;
388 if (stack_index >= self.stack.items.len) return error.InvalidExpression;
389 try self.stack.append(allocator, self.stack.items[self.stack.items.len - 1 - stack_index]);
322 @intFromEnum(OP.pick) => {
323 const stack_index = try nextInt(expression, &i, u8);
324 if (stack_index >= stack.items.len) return error.InvalidExpression;
325 try stack.append(gpa, stack.items[stack.items.len - 1 - stack_index]);
326 continue :op nextOpcode(expression, &i);
390327 },
391 OP.swap => {
392 if (self.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]);
328 @intFromEnum(OP.over) => {
329 if (stack.items.len < 2) return error.InvalidExpression;
330 try stack.append(gpa, stack.items[stack.items.len - 2]);
331 continue :op nextOpcode(expression, &i);
394332 },
395 OP.rot => {
396 if (self.stack.items.len < 3) return error.InvalidExpression;
397 const first = self.stack.items[self.stack.items.len - 1];
398 self.stack.items[self.stack.items.len - 1] = self.stack.items[self.stack.items.len - 2];
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;
333 @intFromEnum(OP.swap) => {
334 if (stack.items.len < 2) return error.InvalidExpression;
335 mem.swap(Value, &stack.items[stack.items.len - 1], &stack.items[stack.items.len - 2]);
336 continue :op nextOpcode(expression, &i);
401337 },
402 OP.deref,
403 OP.xderef,
404 OP.deref_size,
405 OP.xderef_size,
406 OP.deref_type,
407 OP.xderef_type,
408 => {
409 if (self.stack.items.len == 0) return error.InvalidExpression;
410 const addr = try self.stack.items[self.stack.items.len - 1].asIntegral();
411 const addr_space_identifier: ?usize = switch (opcode) {
412 OP.xderef,
413 OP.xderef_size,
414 OP.xderef_type,
415 => blk: {
416 _ = self.stack.pop();
417 if (self.stack.items.len == 0) return error.InvalidExpression;
418 break :blk try self.stack.items[self.stack.items.len - 1].asIntegral();
338 @intFromEnum(OP.rot) => {
339 if (stack.items.len < 3) return error.InvalidExpression;
340 const first = stack.items[stack.items.len - 1];
341 stack.items[stack.items.len - 1] = stack.items[stack.items.len - 2];
342 stack.items[stack.items.len - 2] = stack.items[stack.items.len - 3];
343 stack.items[stack.items.len - 3] = first;
344 continue :op nextOpcode(expression, &i);
345 },
346
347 @intFromEnum(OP.deref_type) => {
348 if (options.call_frame_context) return error.InvalidCFAOpcode;
349 if (stack.items.len == 0) return error.InvalidExpression;
350 const size = try nextInt(expression, &i, u8);
351 const type_offset = try nextLeb128(expression, &i, Address);
352 const addr = try stack.items[stack.items.len - 1].asIntegral();
353 const loaded = try accessAddress(size, addr, context.memory_accessor);
354 stack.items[stack.items.len - 1] = .{
355 .regval_type = .{
356 .type_offset = type_offset,
357 .type_size = size,
358 .value = loaded,
419359 },
420 else => null,
421360 };
422
361 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();
423376 // Usage of addr_space_identifier in the address calculation is implementation defined.
424377 // This code will need to be updated to handle any architectures that utilize this.
425378 _ = 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) {
428 OP.deref,
429 OP.xderef,
430 => @sizeOf(Address),
431 OP.deref_size,
432 OP.xderef_size,
433 => operand.?.type_size,
434 OP.deref_type,
435 OP.xderef_type,
436 => operand.?.deref_type.size,
437 else => unreachable,
438 };
439
440 if (context.memory_accessor) |memory_accessor| {
441 if (!switch (size) {
442 1 => memory_accessor.load(u8, addr) != null,
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 };
402 @intFromEnum(OP.xderef_type),
403 => {
404 if (stack.items.len < 2) return error.InvalidExpression;
405 const addr = try stack.pop().?.asIntegral();
406 const addr_space_identifier = try stack.items[stack.items.len - 1].asIntegral();
407 // Usage of addr_space_identifier in the address calculation is implementation defined.
408 // This code will need to be updated to handle any architectures that utilize this.
409 _ = addr_space_identifier;
410 const size = try nextInt(expression, &i, u8);
411 const type_offset = try nextLeb128(expression, &i, Address);
412 const loaded = try accessAddress(size, addr, context.memory_accessor);
413 stack.items[stack.items.len - 1] = .{
414 .regval_type = .{
415 .type_offset = type_offset,
416 .type_size = size,
417 .value = loaded,
472418 },
473 }
419 };
420 continue :op nextOpcode(expression, &i);
474421 },
475 OP.push_object_address => {
422 @intFromEnum(OP.push_object_address) => {
423 if (options.call_frame_context) return error.InvalidCFAOpcode;
476424 // In sub-expressions, `push_object_address` is not meaningful (as per the
477425 // spec), so treat it like a nop
478426 if (!context.entry_value_context) {
479427 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.?) });
481429 }
482430 },
483 OP.form_tls_address => {
431 @intFromEnum(OP.form_tls_address) => {
484432 return error.UnimplementedOpcode;
485433 },
486 OP.call_frame_cfa => {
434 @intFromEnum(OP.call_frame_cfa) => {
435 if (options.call_frame_context) return error.InvalidCFAOpcode;
487436 if (context.cfa) |cfa| {
488 try self.stack.append(allocator, .{ .generic = cfa });
437 try stack.append(gpa, .{ .generic = cfa });
489438 } else return error.IncompleteExpressionContext;
439 continue :op nextOpcode(expression, &i);
490440 },
491441
492442 // 2.5.1.4: Arithmetic and Logical Operations
493 OP.abs => {
494 if (self.stack.items.len == 0) return error.InvalidExpression;
495 const value: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
496 self.stack.items[self.stack.items.len - 1] = .{
443 @intFromEnum(OP.abs) => {
444 if (stack.items.len == 0) return error.InvalidExpression;
445 const value: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
446 stack.items[stack.items.len - 1] = .{
497447 .generic = @abs(value),
498448 };
449 continue :op nextOpcode(expression, &i);
499450 },
500 OP.@"and" => {
501 if (self.stack.items.len < 2) return error.InvalidExpression;
502 const a = try self.stack.pop().?.asIntegral();
503 self.stack.items[self.stack.items.len - 1] = .{
504 .generic = a & try self.stack.items[self.stack.items.len - 1].asIntegral(),
451 @intFromEnum(OP.@"and") => {
452 if (stack.items.len < 2) return error.InvalidExpression;
453 const a = try stack.pop().?.asIntegral();
454 stack.items[stack.items.len - 1] = .{
455 .generic = a & try stack.items[stack.items.len - 1].asIntegral(),
505456 };
457 continue :op nextOpcode(expression, &i);
506458 },
507 OP.div => {
508 if (self.stack.items.len < 2) return error.InvalidExpression;
509 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());
510 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
511 self.stack.items[self.stack.items.len - 1] = .{
459 @intFromEnum(OP.div) => {
460 if (stack.items.len < 2) return error.InvalidExpression;
461 const a: isize = @bitCast(try stack.pop().?.asIntegral());
462 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
463 stack.items[stack.items.len - 1] = .{
512464 .generic = @bitCast(try std.math.divTrunc(isize, b, a)),
513465 };
466 continue :op nextOpcode(expression, &i);
514467 },
515 OP.minus => {
516 if (self.stack.items.len < 2) return error.InvalidExpression;
517 const b = try self.stack.pop().?.asIntegral();
518 self.stack.items[self.stack.items.len - 1] = .{
519 .generic = try std.math.sub(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
468 @intFromEnum(OP.minus) => {
469 if (stack.items.len < 2) return error.InvalidExpression;
470 const b = try stack.pop().?.asIntegral();
471 stack.items[stack.items.len - 1] = .{
472 .generic = try std.math.sub(Address, try stack.items[stack.items.len - 1].asIntegral(), b),
520473 };
474 continue :op nextOpcode(expression, &i);
521475 },
522 OP.mod => {
523 if (self.stack.items.len < 2) return error.InvalidExpression;
524 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());
525 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
526 self.stack.items[self.stack.items.len - 1] = .{
476 @intFromEnum(OP.mod) => {
477 if (stack.items.len < 2) return error.InvalidExpression;
478 const a: isize = @bitCast(try stack.pop().?.asIntegral());
479 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
480 stack.items[stack.items.len - 1] = .{
527481 .generic = @bitCast(@mod(b, a)),
528482 };
483 continue :op nextOpcode(expression, &i);
529484 },
530 OP.mul => {
531 if (self.stack.items.len < 2) return error.InvalidExpression;
532 const a: isize = @bitCast(try self.stack.pop().?.asIntegral());
533 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
534 self.stack.items[self.stack.items.len - 1] = .{
485 @intFromEnum(OP.mul) => {
486 if (stack.items.len < 2) return error.InvalidExpression;
487 const a: isize = @bitCast(try stack.pop().?.asIntegral());
488 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
489 stack.items[stack.items.len - 1] = .{
535490 .generic = @bitCast(@mulWithOverflow(a, b)[0]),
536491 };
492 continue :op nextOpcode(expression, &i);
537493 },
538 OP.neg => {
539 if (self.stack.items.len == 0) return error.InvalidExpression;
540 self.stack.items[self.stack.items.len - 1] = .{
494 @intFromEnum(OP.neg) => {
495 if (stack.items.len == 0) return error.InvalidExpression;
496 stack.items[stack.items.len - 1] = .{
541497 .generic = @bitCast(
542498 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())),
544500 ),
545501 ),
546502 };
503 continue :op nextOpcode(expression, &i);
547504 },
548 OP.not => {
549 if (self.stack.items.len == 0) return error.InvalidExpression;
550 self.stack.items[self.stack.items.len - 1] = .{
551 .generic = ~try self.stack.items[self.stack.items.len - 1].asIntegral(),
505 @intFromEnum(OP.not) => {
506 if (stack.items.len == 0) return error.InvalidExpression;
507 stack.items[stack.items.len - 1] = .{
508 .generic = ~try stack.items[stack.items.len - 1].asIntegral(),
552509 };
510 continue :op nextOpcode(expression, &i);
553511 },
554 OP.@"or" => {
555 if (self.stack.items.len < 2) return error.InvalidExpression;
556 const a = try self.stack.pop().?.asIntegral();
557 self.stack.items[self.stack.items.len - 1] = .{
558 .generic = a | try self.stack.items[self.stack.items.len - 1].asIntegral(),
512 @intFromEnum(OP.@"or") => {
513 if (stack.items.len < 2) return error.InvalidExpression;
514 const a = try stack.pop().?.asIntegral();
515 stack.items[stack.items.len - 1] = .{
516 .generic = a | try stack.items[stack.items.len - 1].asIntegral(),
559517 };
518 continue :op nextOpcode(expression, &i);
560519 },
561 OP.plus => {
562 if (self.stack.items.len < 2) return error.InvalidExpression;
563 const b = try self.stack.pop().?.asIntegral();
564 self.stack.items[self.stack.items.len - 1] = .{
565 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), b),
520 @intFromEnum(OP.plus) => {
521 if (stack.items.len < 2) return error.InvalidExpression;
522 const b = try stack.pop().?.asIntegral();
523 stack.items[stack.items.len - 1] = .{
524 .generic = try std.math.add(Address, try stack.items[stack.items.len - 1].asIntegral(), b),
566525 };
526 continue :op nextOpcode(expression, &i);
567527 },
568 OP.plus_uconst => {
569 if (self.stack.items.len == 0) return error.InvalidExpression;
570 const constant = operand.?.generic;
571 self.stack.items[self.stack.items.len - 1] = .{
572 .generic = try std.math.add(Address, try self.stack.items[self.stack.items.len - 1].asIntegral(), constant),
573 };
528 @intFromEnum(OP.plus_uconst) => {
529 if (stack.items.len == 0) return error.InvalidExpression;
530 stack.items[stack.items.len - 1] = .{ .generic = std.math.addAny(
531 Address,
532 try nextLeb128(expression, &i, u64),
533 try stack.items[stack.items.len - 1].asIntegral(),
534 ) orelse return error.Overflow };
535 continue :op nextOpcode(expression, &i);
574536 },
575 OP.shl => {
576 if (self.stack.items.len < 2) return error.InvalidExpression;
577 const a = try self.stack.pop().?.asIntegral();
578 const b = try self.stack.items[self.stack.items.len - 1].asIntegral();
579 self.stack.items[self.stack.items.len - 1] = .{
537 @intFromEnum(OP.shl) => {
538 if (stack.items.len < 2) return error.InvalidExpression;
539 const a = try stack.pop().?.asIntegral();
540 const b = try stack.items[stack.items.len - 1].asIntegral();
541 stack.items[stack.items.len - 1] = .{
580542 .generic = std.math.shl(usize, b, a),
581543 };
544 continue :op nextOpcode(expression, &i);
582545 },
583 OP.shr => {
584 if (self.stack.items.len < 2) return error.InvalidExpression;
585 const a = try self.stack.pop().?.asIntegral();
586 const b = try self.stack.items[self.stack.items.len - 1].asIntegral();
587 self.stack.items[self.stack.items.len - 1] = .{
546 @intFromEnum(OP.shr) => {
547 if (stack.items.len < 2) return error.InvalidExpression;
548 const a = try stack.pop().?.asIntegral();
549 const b = try stack.items[stack.items.len - 1].asIntegral();
550 stack.items[stack.items.len - 1] = .{
588551 .generic = std.math.shr(usize, b, a),
589552 };
553 continue :op nextOpcode(expression, &i);
590554 },
591 OP.shra => {
592 if (self.stack.items.len < 2) return error.InvalidExpression;
593 const a = try self.stack.pop().?.asIntegral();
594 const b: isize = @bitCast(try self.stack.items[self.stack.items.len - 1].asIntegral());
595 self.stack.items[self.stack.items.len - 1] = .{
555 @intFromEnum(OP.shra) => {
556 if (stack.items.len < 2) return error.InvalidExpression;
557 const a = try stack.pop().?.asIntegral();
558 const b: isize = @bitCast(try stack.items[stack.items.len - 1].asIntegral());
559 stack.items[stack.items.len - 1] = .{
596560 .generic = @bitCast(std.math.shr(isize, b, a)),
597561 };
562 continue :op nextOpcode(expression, &i);
598563 },
599 OP.xor => {
600 if (self.stack.items.len < 2) return error.InvalidExpression;
601 const a = try self.stack.pop().?.asIntegral();
602 self.stack.items[self.stack.items.len - 1] = .{
603 .generic = a ^ try self.stack.items[self.stack.items.len - 1].asIntegral(),
564 @intFromEnum(OP.xor) => {
565 if (stack.items.len < 2) return error.InvalidExpression;
566 const a = try stack.pop().?.asIntegral();
567 stack.items[stack.items.len - 1] = .{
568 .generic = a ^ try stack.items[stack.items.len - 1].asIntegral(),
604569 };
570 continue :op nextOpcode(expression, &i);
605571 },
606572
607573 // 2.5.1.5: Control Flow Operations
608 OP.le,
609 OP.ge,
610 OP.eq,
611 OP.lt,
612 OP.gt,
613 OP.ne,
614 => {
615 if (self.stack.items.len < 2) return error.InvalidExpression;
616 const a = self.stack.pop().?;
617 const b = self.stack.items[self.stack.items.len - 1];
618
619 if (a == .generic and b == .generic) {
620 const a_int: isize = @bitCast(a.asIntegral() catch unreachable);
621 const b_int: isize = @bitCast(b.asIntegral() catch unreachable);
622 const result = @intFromBool(switch (opcode) {
623 OP.le => b_int <= a_int,
624 OP.ge => b_int >= a_int,
625 OP.eq => b_int == a_int,
626 OP.lt => b_int < a_int,
627 OP.gt => b_int > a_int,
628 OP.ne => b_int != a_int,
629 else => unreachable,
630 });
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 }
574 @intFromEnum(OP.le) => {
575 try cmpOp(stack, .lte);
576 continue :op nextOpcode(expression, &i);
577 },
578 @intFromEnum(OP.ge) => {
579 try cmpOp(stack, .gte);
580 continue :op nextOpcode(expression, &i);
581 },
582 @intFromEnum(OP.eq) => {
583 try cmpOp(stack, .eq);
584 continue :op nextOpcode(expression, &i);
585 },
586 @intFromEnum(OP.lt) => {
587 try cmpOp(stack, .lt);
588 continue :op nextOpcode(expression, &i);
589 },
590 @intFromEnum(OP.gt) => {
591 try cmpOp(stack, .gt);
592 continue :op nextOpcode(expression, &i);
593 },
594 @intFromEnum(OP.ne) => {
595 try cmpOp(stack, .neq);
596 continue :op nextOpcode(expression, &i);
637597 },
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);
646603 },
647 OP.call2,
648 OP.call4,
649 OP.call_ref,
650 => {
651 const debug_info_offset = operand.?.generic;
604 @intFromEnum(OP.bra) => {
605 const branch_offset = try nextInt(expression, &i, i16);
606 const condition = try (stack.pop() orelse return error.InvalidExpression).asIntegral();
607 if (condition != 0) {
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 };
652636 _ = debug_info_offset;
653
654637 // TODO: Load a DIE entry at debug_info_offset in a .debug_info section (the spec says that it
655638 // can be in a separate exe / shared object from the one containing this expression).
656639 // Transfer control to the DW_AT_location attribute, with the current stack as input.
657
658640 return error.UnimplementedExpressionCall;
659641 },
660642
661643 // 2.5.1.6: Type Conversions
662 OP.convert => {
663 if (self.stack.items.len == 0) return error.InvalidExpression;
664 const type_offset = operand.?.generic;
644 @intFromEnum(OP.convert) => {
645 if (options.call_frame_context) return error.InvalidCFAOpcode;
646
647 if (stack.items.len == 0) return error.InvalidExpression;
648 const type_offset = try nextLeb128(expression, &i, u64);
665649
666650 // 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];
668652 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() };
670654 } else {
671655 // TODO: Load the DW_TAG_base_type entry in context.compile_unit, find a conversion operator
672656 // from the old type to the new type, run it.
673657 return error.UnimplementedTypeConversion;
674658 }
659 continue :op nextOpcode(expression, &i);
675660 },
676 OP.reinterpret => {
677 if (self.stack.items.len == 0) return error.InvalidExpression;
678 const type_offset = operand.?.generic;
661 @intFromEnum(OP.reinterpret) => {
662 if (options.call_frame_context) return error.InvalidCFAOpcode;
663 if (stack.items.len == 0) return error.InvalidExpression;
664 const type_offset = try nextLeb128(expression, &i, u64);
679665
680666 // 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];
682668 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() };
684670 } else {
685 self.stack.items[self.stack.items.len - 1] = switch (value) {
671 stack.items[stack.items.len - 1] = switch (value) {
686672 .generic => |v| .{
687673 .regval_type = .{
688674 .type_offset = type_offset,
......@@ -705,45 +691,128 @@ pub fn StackMachine(comptime options: Options) type {
705691 },
706692 };
707693 }
694 continue :op nextOpcode(expression, &i);
708695 },
709696
710697 // 2.5.1.7: Special Operations
711 OP.nop => {},
712 OP.entry_value => {
713 const block = operand.?.block;
714 if (block.len == 0) return error.InvalidSubExpression;
698 @intFromEnum(OP.nop) => continue :op nextOpcode(expression, &i),
699 @intFromEnum(OP.entry_value) => {
700 const block_len = try nextLeb128(expression, &i, usize);
701 if (block_len == 0) return error.InvalidSubExpression;
702 const block = try nextSlice(expression, &i, block_len);
715703
716704 // TODO: The spec states that this sub-expression needs to observe the state (ie. registers)
717705 // as it was upon entering the current subprogram. If this isn't being called at the
718706 // end of a frame unwind operation, an additional ThreadContext with this state will be needed.
719707
720 if (isOpcodeRegisterLocation(block[0])) {
721 if (context.thread_context == null) return error.IncompleteExpressionContext;
708 switch (block[0]) {
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;
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);
740 @intFromEnum(OP.lo_user)...@intFromEnum(OP.hi_user) - 1 => return error.UnimplementedUserOpcode,
731741
732 var sub_context = context;
733 sub_context.entry_value_context = true;
734 const result = try stack_machine.run(block, allocator, sub_context, null);
735 try self.stack.append(allocator, result orelse return error.InvalidSubExpression);
736 }
742 // Repurposed for exiting the loop.
743 @intFromEnum(OP.hi_user) => {
744 if (stack.items.len == 0) return null;
745 return stack.items[stack.items.len - 1];
737746 },
738747
739 // These have already been handled by readOperand
740 OP.lo_user...OP.hi_user => unreachable,
741748 else => {
742749 //std.debug.print("Unknown DWARF expression opcode: {x}\n", .{opcode});
743750 return error.UnknownExpressionOpcode;
744751 },
745752 }
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)) };
747816 }
748817 };
749818}
......@@ -758,7 +827,7 @@ pub fn Builder(comptime options: Options) type {
758827
759828 return struct {
760829 /// 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 {
762831 if (options.call_frame_context and !comptime isOpcodeValidInCFA(opcode)) return error.InvalidCFAOpcode;
763832 switch (opcode) {
764833 OP.dup,
......@@ -799,14 +868,14 @@ pub fn Builder(comptime options: Options) type {
799868 }
800869
801870 // 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 {
803872 switch (literal) {
804873 0...31 => |n| try writer.writeByte(n + OP.lit0),
805874 else => return error.InvalidLiteral,
806875 }
807876 }
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 {
810879 if (@typeInfo(T) != .int) @compileError("Constants must be integers");
811880
812881 switch (T) {
......@@ -838,12 +907,12 @@ pub fn Builder(comptime options: Options) type {
838907 }
839908 }
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 {
842911 try writer.writeByte(OP.constx);
843912 try leb.writeUleb128(writer, debug_addr_offset);
844913 }
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 {
847916 if (options.call_frame_context) return error.InvalidCFAOpcode;
848917 if (value_bytes.len > 0xff) return error.InvalidTypeLength;
849918 try writer.writeByte(OP.const_type);
......@@ -852,36 +921,36 @@ pub fn Builder(comptime options: Options) type {
852921 try writer.writeAll(value_bytes);
853922 }
854923
855 pub fn writeAddr(writer: anytype, value: Address) !void {
924 pub fn writeAddr(writer: *std.io.BufferedWriter, value: Address) !void {
856925 try writer.writeByte(OP.addr);
857926 try writer.writeInt(Address, value, options.endian);
858927 }
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 {
861930 if (options.call_frame_context) return error.InvalidCFAOpcode;
862931 try writer.writeByte(OP.addrx);
863932 try leb.writeUleb128(writer, debug_addr_offset);
864933 }
865934
866935 // 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 {
868937 try writer.writeByte(OP.fbreg);
869938 try leb.writeIleb128(writer, offset);
870939 }
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 {
873942 if (register > 31) return error.InvalidRegister;
874943 try writer.writeByte(OP.breg0 + register);
875944 try leb.writeIleb128(writer, offset);
876945 }
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 {
879948 try writer.writeByte(OP.bregx);
880949 try leb.writeUleb128(writer, register);
881950 try leb.writeIleb128(writer, offset);
882951 }
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 {
885954 if (options.call_frame_context) return error.InvalidCFAOpcode;
886955 try writer.writeByte(OP.regval_type);
887956 try leb.writeUleb128(writer, register);
......@@ -889,29 +958,29 @@ pub fn Builder(comptime options: Options) type {
889958 }
890959
891960 // 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 {
893962 try writer.writeByte(OP.pick);
894963 try writer.writeByte(index);
895964 }
896965
897 pub fn writeDerefSize(writer: anytype, size: u8) !void {
966 pub fn writeDerefSize(writer: *std.io.BufferedWriter, size: u8) !void {
898967 try writer.writeByte(OP.deref_size);
899968 try writer.writeByte(size);
900969 }
901970
902 pub fn writeXDerefSize(writer: anytype, size: u8) !void {
971 pub fn writeXDerefSize(writer: *std.io.BufferedWriter, size: u8) !void {
903972 try writer.writeByte(OP.xderef_size);
904973 try writer.writeByte(size);
905974 }
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 {
908977 if (options.call_frame_context) return error.InvalidCFAOpcode;
909978 try writer.writeByte(OP.deref_type);
910979 try writer.writeByte(size);
911980 try leb.writeUleb128(writer, die_offset);
912981 }
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 {
915984 try writer.writeByte(OP.xderef_type);
916985 try writer.writeByte(size);
917986 try leb.writeUleb128(writer, die_offset);
......@@ -919,24 +988,24 @@ pub fn Builder(comptime options: Options) type {
919988
920989 // 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 {
923992 try writer.writeByte(OP.plus_uconst);
924993 try leb.writeUleb128(writer, uint_value);
925994 }
926995
927996 // 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 {
930999 try writer.writeByte(OP.skip);
9311000 try writer.writeInt(i16, offset, options.endian);
9321001 }
9331002
934 pub fn writeBra(writer: anytype, offset: i16) !void {
1003 pub fn writeBra(writer: *std.io.BufferedWriter, offset: i16) !void {
9351004 try writer.writeByte(OP.bra);
9361005 try writer.writeInt(i16, offset, options.endian);
9371006 }
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 {
9401009 if (options.call_frame_context) return error.InvalidCFAOpcode;
9411010 switch (T) {
9421011 u16 => try writer.writeByte(OP.call2),
......@@ -947,19 +1016,19 @@ pub fn Builder(comptime options: Options) type {
9471016 try writer.writeInt(T, offset, options.endian);
9481017 }
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 {
9511020 if (options.call_frame_context) return error.InvalidCFAOpcode;
9521021 try writer.writeByte(OP.call_ref);
9531022 try writer.writeInt(if (is_64) u64 else u32, value, options.endian);
9541023 }
9551024
956 pub fn writeConvert(writer: anytype, die_offset: anytype) !void {
1025 pub fn writeConvert(writer: *std.io.BufferedWriter, die_offset: anytype) !void {
9571026 if (options.call_frame_context) return error.InvalidCFAOpcode;
9581027 try writer.writeByte(OP.convert);
9591028 try leb.writeUleb128(writer, die_offset);
9601029 }
9611030
962 pub fn writeReinterpret(writer: anytype, die_offset: anytype) !void {
1031 pub fn writeReinterpret(writer: *std.io.BufferedWriter, die_offset: anytype) !void {
9631032 if (options.call_frame_context) return error.InvalidCFAOpcode;
9641033 try writer.writeByte(OP.reinterpret);
9651034 try leb.writeUleb128(writer, die_offset);
......@@ -967,23 +1036,23 @@ pub fn Builder(comptime options: Options) type {
9671036
9681037 // 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 {
9711040 try writer.writeByte(OP.entry_value);
9721041 try leb.writeUleb128(writer, expression.len);
9731042 try writer.writeAll(expression);
9741043 }
9751044
9761045 // 2.6: Location Descriptions
977 pub fn writeReg(writer: anytype, register: u8) !void {
1046 pub fn writeReg(writer: *std.io.BufferedWriter, register: u8) !void {
9781047 try writer.writeByte(OP.reg0 + register);
9791048 }
9801049
981 pub fn writeRegx(writer: anytype, register: anytype) !void {
1050 pub fn writeRegx(writer: *std.io.BufferedWriter, register: anytype) !void {
9821051 try writer.writeByte(OP.regx);
9831052 try leb.writeUleb128(writer, register);
9841053 }
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 {
9871056 try writer.writeByte(OP.implicit_value);
9881057 try leb.writeUleb128(writer, value_bytes.len);
9891058 try writer.writeAll(value_bytes);
......@@ -991,21 +1060,21 @@ pub fn Builder(comptime options: Options) type {
9911060 };
9921061}
9931062
994// Certain opcodes are not allowed in a CFA context, see 6.4.2
995fn isOpcodeValidInCFA(opcode: u8) bool {
1063/// Certain opcodes are not allowed in a CFA context, see 6.4.2
1064fn isOpcodeValidInCFA(opcode: OP) bool {
9961065 return switch (opcode) {
997 OP.addrx,
998 OP.call2,
999 OP.call4,
1000 OP.call_ref,
1001 OP.const_type,
1002 OP.constx,
1003 OP.convert,
1004 OP.deref_type,
1005 OP.regval_type,
1006 OP.reinterpret,
1007 OP.push_object_address,
1008 OP.call_frame_cfa,
1066 .addrx,
1067 .call2,
1068 .call4,
1069 .call_ref,
1070 .const_type,
1071 .constx,
1072 .convert,
1073 .deref_type,
1074 .regval_type,
1075 .reinterpret,
1076 .push_object_address,
1077 .call_frame_cfa,
10091078 => false,
10101079 else => true,
10111080 };
lib/std/dwarf.zig+220-1
......@@ -6,7 +6,226 @@
66
77pub const TAG = @import("dwarf/TAG.zig");
88pub 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};
10229pub const LANG = @import("dwarf/LANG.zig");
11230pub const FORM = @import("dwarf/FORM.zig");
12231pub 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;