mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
crash/minidump: header parsing
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
const dir = @import("dir.zig");
|
||||
const sentry_envelope = @import("sentry_envelope.zig");
|
||||
|
||||
pub const minidump = @import("minidump.zig");
|
||||
pub const sentry = @import("sentry.zig");
|
||||
pub const Envelope = sentry_envelope.Envelope;
|
||||
pub const defaultDir = dir.defaultDir;
|
||||
|
75
src/crash/minidump.zig
Normal file
75
src/crash/minidump.zig
Normal file
@ -0,0 +1,75 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const log = std.log.scoped(.minidump);
|
||||
|
||||
/// Minidump parser.
|
||||
pub const Minidump = struct {
|
||||
header: Header,
|
||||
|
||||
/// Read the minidump file for the given source.
|
||||
///
|
||||
/// The source must have a reader() and seekableStream() method.
|
||||
/// For example, both File and std.io.FixedBufferStream implement these.
|
||||
pub fn read(alloc: Allocator, source: anytype) !Minidump {
|
||||
_ = alloc;
|
||||
|
||||
// Read the header which also determines the endianness of the file.
|
||||
const header, const endian = try readHeader(source);
|
||||
log.warn("header={} endian={}", .{ header, endian });
|
||||
|
||||
return .{
|
||||
.header = header,
|
||||
};
|
||||
}
|
||||
|
||||
/// Reads the header for the minidump file and returns endianness of
|
||||
/// the file.
|
||||
fn readHeader(source: anytype) !struct { Header, std.builtin.Endian } {
|
||||
// Start by trying LE.
|
||||
var endian: std.builtin.Endian = .little;
|
||||
var header = try source.reader().readStructEndian(Header, endian);
|
||||
|
||||
// If the signature doesn't match, we assume its BE.
|
||||
if (header.signature != signature) {
|
||||
// Seek back to the start of the file so we can reread.
|
||||
try source.seekableStream().seekTo(0);
|
||||
|
||||
// Try BE, if the signature doesn't match, return an error.
|
||||
endian = .big;
|
||||
header = try source.reader().readStructEndian(Header, endian);
|
||||
if (header.signature != signature) return error.InvalidHeader;
|
||||
}
|
||||
|
||||
// "The low-order word is MINIDUMP_VERSION. The high-order word is an
|
||||
// internal value that is implementation specific."
|
||||
if (header.version.low != version) return error.InvalidVersion;
|
||||
|
||||
return .{ header, endian };
|
||||
}
|
||||
};
|
||||
|
||||
/// "MDMP" in little-endian.
|
||||
pub const signature = 0x504D444D;
|
||||
|
||||
/// The version of the minidump format.
|
||||
pub const version = 0xA793;
|
||||
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
|
||||
pub const Header = extern struct {
|
||||
signature: u32,
|
||||
version: packed struct(u32) { low: u16, high: u16 },
|
||||
stream_count: u32,
|
||||
stream_directory_rva: u32,
|
||||
checksum: u32,
|
||||
time_date_stamp: u32,
|
||||
flags: u64,
|
||||
};
|
||||
|
||||
test "Minidump read" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
var fbs = std.io.fixedBufferStream(@embedFile("testdata/macos.dmp"));
|
||||
_ = try Minidump.read(alloc, &fbs);
|
||||
}
|
BIN
src/crash/testdata/macos.dmp
vendored
Normal file
BIN
src/crash/testdata/macos.dmp
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user