std.debug: reorg and clarify API goals

After this commit:

`std.debug.SelfInfo` is a cross-platform abstraction for the current
executable's own debug information, with a goal of minimal code bloat
and compilation speed penalty.

`std.debug.Dwarf` does not assume the current executable is itself the
thing being debugged, however, it does assume the debug info has the
same CPU architecture and OS as the current executable. It is planned to
remove this limitation.
This commit is contained in:
Andrew Kelley
2024-08-01 22:04:40 -07:00
parent 290966c249
commit 48d584e3a3
8 changed files with 1434 additions and 1419 deletions

View File

@@ -1,11 +1,13 @@
const std = @import("std");
const builtin = @import("builtin");
const native_arch = builtin.cpu.arch;
const native_endian = native_arch.endian();
const std = @import("std");
const leb = std.leb;
const OP = std.dwarf.OP;
const abi = std.debug.Dwarf.abi;
const mem = std.mem;
const assert = std.debug.assert;
const native_endian = builtin.cpu.arch.endian();
/// Expressions can be evaluated in different contexts, each requiring its own set of inputs.
/// Callers should specify all the fields relevant to their context. If a field is required
@@ -14,7 +16,7 @@ pub const Context = struct {
/// The dwarf format of the section this expression is in
format: std.dwarf.Format = .@"32",
/// If specified, any addresses will pass through before being accessed
memory_accessor: ?*std.debug.StackIterator.MemoryAccessor = null,
memory_accessor: ?*std.debug.MemoryAccessor = null,
/// The compilation unit this expression relates to, if any
compile_unit: ?*const std.debug.Dwarf.CompileUnit = null,
/// When evaluating a user-presented expression, this is the address of the object being evaluated
@@ -34,7 +36,7 @@ pub const Options = struct {
/// The address size of the target architecture
addr_size: u8 = @sizeOf(usize),
/// Endianness of the target architecture
endian: std.builtin.Endian = builtin.target.cpu.arch.endian(),
endian: std.builtin.Endian = native_endian,
/// Restrict the stack machine to a subset of opcodes used in call frame instructions
call_frame_context: bool = false,
};
@@ -60,7 +62,7 @@ pub const Error = error{
InvalidTypeLength,
TruncatedIntegralType,
} || abi.AbiError || error{ EndOfStream, Overflow, OutOfMemory, DivisionByZero };
} || abi.RegBytesError || error{ EndOfStream, Overflow, OutOfMemory, DivisionByZero };
/// A stack machine that can decode and run DWARF expressions.
/// Expressions can be decoded for non-native address size and endianness,
@@ -304,7 +306,7 @@ pub fn StackMachine(comptime options: Options) type {
allocator: std.mem.Allocator,
context: Context,
) Error!bool {
if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())
if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != native_endian)
@compileError("Execution of non-native address sizes / endianness is not supported");
const opcode = try stream.reader().readByte();
@@ -1186,13 +1188,13 @@ test "DWARF expressions" {
// TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it
mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian);
(try abi.regValueNative(usize, &thread_context, abi.fpRegNum(reg_context), reg_context)).* = 1;
(try abi.regValueNative(usize, &thread_context, abi.spRegNum(reg_context), reg_context)).* = 2;
(try abi.regValueNative(usize, &thread_context, abi.ipRegNum(), reg_context)).* = 3;
(try abi.regValueNative(&thread_context, abi.fpRegNum(native_arch, reg_context), reg_context)).* = 1;
(try abi.regValueNative(&thread_context, abi.spRegNum(native_arch, reg_context), reg_context)).* = 2;
(try abi.regValueNative(&thread_context, abi.ipRegNum(native_arch), reg_context)).* = 3;
try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100));
try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200));
try b.writeBregx(writer, abi.ipRegNum(), @as(usize, 300));
try b.writeBreg(writer, abi.fpRegNum(native_arch, reg_context), @as(usize, 100));
try b.writeBreg(writer, abi.spRegNum(native_arch, reg_context), @as(usize, 200));
try b.writeBregx(writer, abi.ipRegNum(native_arch), @as(usize, 300));
try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400));
_ = try stack_machine.run(program.items, allocator, context, 0);