2018-10-16 10:48:59 +00:00
package minidump
// Package minidump provides a loader for Windows Minidump files.
// Minidump files are the Windows equivalent of unix core dumps.
// They can be created by the kernel when a program crashes (however this is
// disabled for Go programs) or programmatically using either WinDbg or the
// ProcDump utility.
//
// The file format is described on MSDN starting at:
2021-07-06 16:28:53 +00:00
// https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header
2018-10-16 10:48:59 +00:00
// which is the structure found at offset 0 on a minidump file.
//
// Further information on the format can be found reading
// chromium-breakpad's minidump loading code, specifically:
// https://chromium.googlesource.com/breakpad/breakpad/+/master/src/google_breakpad/common/minidump_cpu_amd64.h
// and:
// https://chromium.googlesource.com/breakpad/breakpad/+/master/src/google_breakpad/common/minidump_format.h
import (
"encoding/binary"
"fmt"
"io"
2023-09-25 18:41:59 +00:00
"os"
2018-10-16 10:48:59 +00:00
"unicode/utf16"
"unsafe"
2019-01-04 18:39:25 +00:00
"github.com/go-delve/delve/pkg/proc/winutil"
2018-10-16 10:48:59 +00:00
)
type minidumpBuf struct {
buf [ ] byte
kind string
off int
err error
ctx string
}
func ( buf * minidumpBuf ) u16 ( ) uint16 {
const stride = 2
if buf . err != nil {
return 0
}
if buf . off + stride >= len ( buf . buf ) {
buf . err = fmt . Errorf ( "minidump %s truncated at offset %#x while %s" , buf . kind , buf . off , buf . ctx )
}
r := binary . LittleEndian . Uint16 ( buf . buf [ buf . off : buf . off + stride ] )
buf . off += stride
return r
}
func ( buf * minidumpBuf ) u32 ( ) uint32 {
const stride = 4
if buf . err != nil {
return 0
}
if buf . off + stride >= len ( buf . buf ) {
buf . err = fmt . Errorf ( "minidump %s truncated at offset %#x while %s" , buf . kind , buf . off , buf . ctx )
}
r := binary . LittleEndian . Uint32 ( buf . buf [ buf . off : buf . off + stride ] )
buf . off += stride
return r
}
func ( buf * minidumpBuf ) u64 ( ) uint64 {
const stride = 8
if buf . err != nil {
return 0
}
if buf . off + stride >= len ( buf . buf ) {
buf . err = fmt . Errorf ( "minidump %s truncated at offset %#x while %s" , buf . kind , buf . off , buf . ctx )
}
r := binary . LittleEndian . Uint64 ( buf . buf [ buf . off : buf . off + stride ] )
buf . off += stride
return r
}
func streamBuf ( stream * Stream , buf * minidumpBuf , name string ) * minidumpBuf {
return & minidumpBuf {
buf : buf . buf ,
kind : "stream" ,
off : stream . Offset ,
err : nil ,
ctx : fmt . Sprintf ( "reading %s stream at %#x" , name , stream . Offset ) ,
}
}
// ErrNotAMinidump is the error returned when the file being loaded is not a
// minidump file.
type ErrNotAMinidump struct {
what string
got uint32
}
func ( err ErrNotAMinidump ) Error ( ) string {
return fmt . Sprintf ( "not a minidump, invalid %s %#x" , err . what , err . got )
}
const (
minidumpSignature = 0x504d444d // 'MDMP'
minidumpVersion = 0xa793
)
// Minidump represents a minidump file
type Minidump struct {
Timestamp uint32
Flags FileFlags
Streams [ ] Stream
Threads [ ] Thread
Modules [ ] Module
Pid uint32
MemoryRanges [ ] MemoryRange
MemoryInfo [ ] MemoryInfo
streamNum uint32
streamOff uint32
}
// Stream represents one (uninterpreted) stream in a minidump file.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory
2018-10-16 10:48:59 +00:00
type Stream struct {
Type StreamType
Offset int
RawData [ ] byte
}
// Thread represents an entry in the ThreadList stream.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread
2018-10-16 10:48:59 +00:00
type Thread struct {
ID uint32
SuspendCount uint32
PriorityClass uint32
Priority uint32
TEB uint64
2022-07-27 16:36:34 +00:00
Context winutil . AMD64CONTEXT
2018-10-16 10:48:59 +00:00
}
// Module represents an entry in the ModuleList stream.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module
2018-10-16 10:48:59 +00:00
type Module struct {
BaseOfImage uint64
SizeOfImage uint32
Checksum uint32
TimeDateStamp uint32
Name string
VersionInfo VSFixedFileInfo
// CVRecord stores a CodeView record and is populated when a module's debug information resides in a PDB file. It identifies the PDB file.
CVRecord [ ] byte
// MiscRecord is populated when a module's debug information resides in a DBG file. It identifies the DBG file. This field is effectively obsolete with modules built by recent toolchains.
MiscRecord [ ] byte
}
2021-09-28 19:07:42 +00:00
// VSFixedFileInfo Visual Studio Fixed File Info.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
2018-10-16 10:48:59 +00:00
type VSFixedFileInfo struct {
Signature uint32
StructVersion uint32
FileVersionHi uint32
FileVersionLo uint32
ProductVersionHi uint32
ProductVersionLo uint32
FileFlagsMask uint32
FileFlags uint32
FileOS uint32
FileType uint32
FileSubtype uint32
FileDateHi uint32
FileDateLo uint32
}
// MemoryRange represents a region of memory saved to the core file, it's constructed after either:
// 1. parsing an entry in the Memory64List stream.
// 2. parsing the stack field of an entry in the ThreadList stream.
type MemoryRange struct {
Addr uint64
Data [ ] byte
}
// ReadMemory reads len(buf) bytes of memory starting at addr into buf from this memory region.
2020-09-09 17:36:15 +00:00
func ( m * MemoryRange ) ReadMemory ( buf [ ] byte , addr uint64 ) ( int , error ) {
2018-10-16 10:48:59 +00:00
if len ( buf ) == 0 {
return 0 , nil
}
2023-11-14 15:36:55 +00:00
if ( addr < m . Addr ) || ( addr + uint64 ( len ( buf ) ) > m . Addr + uint64 ( len ( m . Data ) ) ) {
2018-10-16 10:48:59 +00:00
return 0 , io . EOF
}
2023-11-14 15:36:55 +00:00
copy ( buf , m . Data [ addr - m . Addr : ] )
2018-10-16 10:48:59 +00:00
return len ( buf ) , nil
}
2022-12-28 11:41:13 +00:00
// MemoryInfo represents an entry in the MemoryInfoList stream.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list
2018-10-16 10:48:59 +00:00
type MemoryInfo struct {
Addr uint64
Size uint64
State MemoryState
Protection MemoryProtection
Type MemoryType
}
//go:generate stringer -type FileFlags,StreamType,Arch,MemoryState,MemoryType,MemoryProtection
// MemoryState is the type of the State field of MINIDUMP_MEMORY_INFO
type MemoryState uint32
const (
MemoryStateCommit MemoryState = 0x1000
MemoryStateReserve MemoryState = 0x2000
MemoryStateFree MemoryState = 0x10000
)
// MemoryType is the type of the Type field of MINIDUMP_MEMORY_INFO
type MemoryType uint32
const (
MemoryTypePrivate MemoryType = 0x20000
MemoryTypeMapped MemoryType = 0x40000
MemoryTypeImage MemoryType = 0x1000000
)
// MemoryProtection is the type of the Protection field of MINIDUMP_MEMORY_INFO
type MemoryProtection uint32
const (
MemoryProtectNoAccess MemoryProtection = 0x01 // PAGE_NOACCESS
MemoryProtectReadOnly MemoryProtection = 0x02 // PAGE_READONLY
MemoryProtectReadWrite MemoryProtection = 0x04 // PAGE_READWRITE
MemoryProtectWriteCopy MemoryProtection = 0x08 // PAGE_WRITECOPY
MemoryProtectExecute MemoryProtection = 0x10 // PAGE_EXECUTE
MemoryProtectExecuteRead MemoryProtection = 0x20 // PAGE_EXECUTE_READ
MemoryProtectExecuteReadWrite MemoryProtection = 0x40 // PAGE_EXECUTE_READWRITE
MemoryProtectExecuteWriteCopy MemoryProtection = 0x80 // PAGE_EXECUTE_WRITECOPY
// These options can be combined with the previous flags
MemoryProtectPageGuard MemoryProtection = 0x100 // PAGE_GUARD
MemoryProtectNoCache MemoryProtection = 0x200 // PAGE_NOCACHE
MemoryProtectWriteCombine MemoryProtection = 0x400 // PAGE_WRITECOMBINE
)
// FileFlags is the type of the Flags field of MINIDUMP_HEADER
type FileFlags uint64
const (
FileNormal FileFlags = 0x00000000
FileWithDataSegs FileFlags = 0x00000001
FileWithFullMemory FileFlags = 0x00000002
FileWithHandleData FileFlags = 0x00000004
FileFilterMemory FileFlags = 0x00000008
FileScanMemory FileFlags = 0x00000010
FileWithUnloadedModules FileFlags = 0x00000020
FileWithIncorrectlyReferencedMemory FileFlags = 0x00000040
FileFilterModulePaths FileFlags = 0x00000080
FileWithProcessThreadData FileFlags = 0x00000100
FileWithPrivateReadWriteMemory FileFlags = 0x00000200
FileWithoutOptionalData FileFlags = 0x00000400
FileWithFullMemoryInfo FileFlags = 0x00000800
FileWithThreadInfo FileFlags = 0x00001000
FileWithCodeSegs FileFlags = 0x00002000
FileWithoutAuxilliarySegs FileFlags = 0x00004000
FileWithFullAuxilliaryState FileFlags = 0x00008000
FileWithPrivateCopyMemory FileFlags = 0x00010000
FileIgnoreInaccessibleMemory FileFlags = 0x00020000
FileWithTokenInformation FileFlags = 0x00040000
)
// StreamType is the type of the StreamType field of MINIDUMP_DIRECTORY
type StreamType uint32
const (
UnusedStream StreamType = 0
ReservedStream0 StreamType = 1
ReservedStream1 StreamType = 2
ThreadListStream StreamType = 3
ModuleListStream StreamType = 4
MemoryListStream StreamType = 5
ExceptionStream StreamType = 6
SystemInfoStream StreamType = 7
ThreadExListStream StreamType = 8
Memory64ListStream StreamType = 9
CommentStreamA StreamType = 10
CommentStreamW StreamType = 11
HandleDataStream StreamType = 12
FunctionTableStream StreamType = 13
UnloadedModuleStream StreamType = 14
MiscInfoStream StreamType = 15
MemoryInfoListStream StreamType = 16
ThreadInfoListStream StreamType = 17
HandleOperationListStream StreamType = 18
TokenStream StreamType = 19
JavascriptDataStream StreamType = 20
SystemMemoryInfoStream StreamType = 21
ProcessVMCounterStream StreamType = 22
)
// Arch is the type of the ProcessorArchitecture field of MINIDUMP_SYSTEM_INFO.
type Arch uint16
const (
CpuArchitectureX86 Arch = 0
CpuArchitectureMips Arch = 1
CpuArchitectureAlpha Arch = 2
CpuArchitecturePPC Arch = 3
CpuArchitectureSHX Arch = 4 // Super-H
CpuArchitectureARM Arch = 5
CpuArchitectureIA64 Arch = 6
CpuArchitectureAlpha64 Arch = 7
CpuArchitectureMSIL Arch = 8 // Microsoft Intermediate Language
CpuArchitectureAMD64 Arch = 9
CpuArchitectureWoW64 Arch = 10
CpuArchitectureARM64 Arch = 12
CpuArchitectureUnknown Arch = 0xffff
)
// Open reads the minidump file at path and returns it as a Minidump structure.
func Open ( path string , logfn func ( fmt string , args ... interface { } ) ) ( * Minidump , error ) {
2023-09-25 18:41:59 +00:00
rawbuf , err := os . ReadFile ( path ) //TODO(aarzilli): mmap?
2018-10-16 10:48:59 +00:00
if err != nil {
return nil , err
}
buf := & minidumpBuf { buf : rawbuf , kind : "file" }
var mdmp Minidump
readMinidumpHeader ( & mdmp , buf )
if buf . err != nil {
return nil , buf . err
}
if logfn != nil {
logfn ( "Minidump Header\n" )
logfn ( "Num Streams: %d\n" , mdmp . streamNum )
logfn ( "Streams offset: %#x\n" , mdmp . streamOff )
logfn ( "File flags: %s\n" , fileFlagsToString ( mdmp . Flags ) )
logfn ( "Offset after header %#x\n" , buf . off )
}
readDirectory ( & mdmp , buf )
if buf . err != nil {
return nil , buf . err
}
for i := range mdmp . Streams {
stream := & mdmp . Streams [ i ]
if stream . Type != SystemInfoStream {
continue
}
sb := streamBuf ( stream , buf , "system info" )
if buf . err != nil {
return nil , buf . err
}
arch := Arch ( sb . u16 ( ) )
if logfn != nil {
logfn ( "Found processor architecture %s\n" , arch . String ( ) )
}
if arch != CpuArchitectureAMD64 {
return nil , fmt . Errorf ( "unsupported architecture %s" , arch . String ( ) )
}
}
for i := range mdmp . Streams {
stream := & mdmp . Streams [ i ]
if logfn != nil {
logfn ( "Stream %d: type:%s off:%#x size:%#x\n" , i , stream . Type , stream . Offset , len ( stream . RawData ) )
}
switch stream . Type {
case ThreadListStream :
readThreadList ( & mdmp , streamBuf ( stream , buf , "thread list" ) )
if logfn != nil {
for i := range mdmp . Threads {
logfn ( "\tID:%#x TEB:%#x\n" , mdmp . Threads [ i ] . ID , mdmp . Threads [ i ] . TEB )
}
}
case ModuleListStream :
readModuleList ( & mdmp , streamBuf ( stream , buf , "module list" ) )
if logfn != nil {
for i := range mdmp . Modules {
logfn ( "\tName:%q BaseOfImage:%#x SizeOfImage:%#x\n" , mdmp . Modules [ i ] . Name , mdmp . Modules [ i ] . BaseOfImage , mdmp . Modules [ i ] . SizeOfImage )
}
}
case ExceptionStream :
//TODO(aarzilli): this stream contains the exception that made the
//process stop and caused the minidump to be taken. If we ever start
//caring about this we should parse this.
case Memory64ListStream :
readMemory64List ( & mdmp , streamBuf ( stream , buf , "memory64 list" ) , logfn )
case MemoryInfoListStream :
readMemoryInfoList ( & mdmp , streamBuf ( stream , buf , "memory info list" ) , logfn )
case MiscInfoStream :
readMiscInfo ( & mdmp , streamBuf ( stream , buf , "misc info" ) )
if logfn != nil {
logfn ( "\tPid: %#x\n" , mdmp . Pid )
}
case CommentStreamW :
if logfn != nil {
logfn ( "\t%q\n" , decodeUTF16 ( stream . RawData ) )
}
case CommentStreamA :
if logfn != nil {
logfn ( "\t%s\n" , string ( stream . RawData ) )
}
}
if buf . err != nil {
return nil , buf . err
}
}
return & mdmp , nil
}
// decodeUTF16 converts a NUL-terminated UTF16LE string to (non NUL-terminated) UTF8.
func decodeUTF16 ( in [ ] byte ) string {
utf16encoded := [ ] uint16 { }
for i := 0 ; i + 1 < len ( in ) ; i += 2 {
var ch uint16
ch = uint16 ( in [ i ] ) + uint16 ( in [ i + 1 ] ) << 8
utf16encoded = append ( utf16encoded , ch )
}
s := string ( utf16 . Decode ( utf16encoded ) )
if len ( s ) > 0 && s [ len ( s ) - 1 ] == 0 {
s = s [ : len ( s ) - 1 ]
}
return s
}
func fileFlagsToString ( flags FileFlags ) string {
out := [ ] byte { }
for i , name := range _FileFlags_map {
if i == 0 {
continue
}
if flags & i != 0 {
if len ( out ) > 0 {
out = append ( out , '|' )
}
out = append ( out , name ... )
}
}
if len ( out ) == 0 {
return flags . String ( )
}
return string ( out )
}
// readMinidumpHeader reads the minidump file header
func readMinidumpHeader ( mdmp * Minidump , buf * minidumpBuf ) {
buf . ctx = "reading minidump header"
if sig := buf . u32 ( ) ; sig != minidumpSignature {
buf . err = ErrNotAMinidump { "signature" , sig }
return
}
if ver := buf . u16 ( ) ; ver != minidumpVersion {
buf . err = ErrNotAMinidump { "version" , uint32 ( ver ) }
return
}
buf . u16 ( ) // implementation specific version
mdmp . streamNum = buf . u32 ( )
mdmp . streamOff = buf . u32 ( )
buf . u32 ( ) // checksum, but it's always 0
mdmp . Timestamp = buf . u32 ( )
mdmp . Flags = FileFlags ( buf . u64 ( ) )
}
2022-12-28 11:41:13 +00:00
// readDirectory reads the list of streams (i.e. the minidump "directory")
2018-10-16 10:48:59 +00:00
func readDirectory ( mdmp * Minidump , buf * minidumpBuf ) {
buf . off = int ( mdmp . streamOff )
mdmp . Streams = make ( [ ] Stream , mdmp . streamNum )
for i := range mdmp . Streams {
buf . ctx = fmt . Sprintf ( "reading stream directory entry %d" , i )
stream := & mdmp . Streams [ i ]
stream . Type = StreamType ( buf . u32 ( ) )
stream . Offset , stream . RawData = readLocationDescriptor ( buf )
if buf . err != nil {
return
}
}
}
// readLocationDescriptor reads a location descriptor structure (a structure
// which describes a subregion of the file), and returns the destination
// offset and a slice into the minidump file's buffer.
func readLocationDescriptor ( buf * minidumpBuf ) ( off int , rawData [ ] byte ) {
sz := buf . u32 ( )
off = int ( buf . u32 ( ) )
if buf . err != nil {
return off , nil
}
end := off + int ( sz )
if off >= len ( buf . buf ) || end > len ( buf . buf ) {
buf . err = fmt . Errorf ( "location starting at %#x of size %#x is past the end of file, while %s" , off , sz , buf . ctx )
return 0 , nil
}
rawData = buf . buf [ off : end ]
return
}
func readString ( buf * minidumpBuf ) string {
startOff := buf . off
sz := buf . u32 ( )
if buf . err != nil {
return ""
}
end := buf . off + int ( sz )
if buf . off >= len ( buf . buf ) || end > len ( buf . buf ) {
buf . err = fmt . Errorf ( "string starting at %#x of size %#x is past the end of file, while %s" , startOff , sz , buf . ctx )
return ""
}
return decodeUTF16 ( buf . buf [ buf . off : end ] )
}
// readThreadList reads a thread list stream and adds the threads to the minidump.
func readThreadList ( mdmp * Minidump , buf * minidumpBuf ) {
threadNum := buf . u32 ( )
if buf . err != nil {
return
}
mdmp . Threads = make ( [ ] Thread , threadNum )
for i := range mdmp . Threads {
buf . ctx = fmt . Sprintf ( "reading thread list entry %d" , i )
thread := & mdmp . Threads [ i ]
thread . ID = buf . u32 ( )
thread . SuspendCount = buf . u32 ( )
thread . PriorityClass = buf . u32 ( )
thread . Priority = buf . u32 ( )
thread . TEB = buf . u64 ( )
if buf . err != nil {
return
}
readMemoryDescriptor ( mdmp , buf ) // thread stack
_ , rawThreadContext := readLocationDescriptor ( buf ) // thread context
2022-07-27 16:36:34 +00:00
thread . Context = * ( ( * winutil . AMD64CONTEXT ) ( unsafe . Pointer ( & rawThreadContext [ 0 ] ) ) )
2018-10-16 10:48:59 +00:00
if buf . err != nil {
return
}
}
}
// readModuleList reads a module list stream and adds the modules to the minidump.
func readModuleList ( mdmp * Minidump , buf * minidumpBuf ) {
moduleNum := buf . u32 ( )
if buf . err != nil {
return
}
mdmp . Modules = make ( [ ] Module , moduleNum )
for i := range mdmp . Modules {
buf . ctx = fmt . Sprintf ( "reading module list entry %d" , i )
module := & mdmp . Modules [ i ]
module . BaseOfImage = buf . u64 ( )
module . SizeOfImage = buf . u32 ( )
module . Checksum = buf . u32 ( )
module . TimeDateStamp = buf . u32 ( )
nameOff := int ( buf . u32 ( ) )
versionInfoVec := make ( [ ] uint32 , unsafe . Sizeof ( VSFixedFileInfo { } ) / unsafe . Sizeof ( uint32 ( 0 ) ) )
for j := range versionInfoVec {
versionInfoVec [ j ] = buf . u32 ( )
}
module . VersionInfo = * ( * VSFixedFileInfo ) ( unsafe . Pointer ( & versionInfoVec [ 0 ] ) )
_ , module . CVRecord = readLocationDescriptor ( buf )
_ , module . MiscRecord = readLocationDescriptor ( buf )
if buf . err != nil {
return
}
nameBuf := minidumpBuf { buf : buf . buf , kind : "file" , off : nameOff , err : nil , ctx : buf . ctx }
module . Name = readString ( & nameBuf )
if nameBuf . err != nil {
buf . err = nameBuf . err
return
}
}
}
// readMemory64List reads a _MINIDUMP_MEMORY64_LIST structure, containing
// the description of the process memory.
2021-07-06 16:28:53 +00:00
// See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory64_list
// And: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor
2018-10-16 10:48:59 +00:00
func readMemory64List ( mdmp * Minidump , buf * minidumpBuf , logfn func ( fmt string , args ... interface { } ) ) {
rangesNum := buf . u64 ( )
baseOff := int ( buf . u64 ( ) )
if buf . err != nil {
return
}
for i := uint64 ( 0 ) ; i < rangesNum ; i ++ {
addr := buf . u64 ( )
sz := buf . u64 ( )
end := baseOff + int ( sz )
if baseOff >= len ( buf . buf ) || end > len ( buf . buf ) {
buf . err = fmt . Errorf ( "memory range at %#x of size %#x is past the end of file, while %s" , baseOff , sz , buf . ctx )
return
}
mdmp . addMemory ( addr , buf . buf [ baseOff : end ] )
if logfn != nil {
logfn ( "\tMemory %d addr:%#x size:%#x FileOffset:%#x\n" , i , addr , sz , baseOff )
}
baseOff = end
}
}
func readMemoryInfoList ( mdmp * Minidump , buf * minidumpBuf , logfn func ( fmt string , args ... interface { } ) ) {
startOff := buf . off
sizeOfHeader := int ( buf . u32 ( ) )
sizeOfEntry := int ( buf . u32 ( ) )
numEntries := buf . u64 ( )
buf . off = startOff + sizeOfHeader
mdmp . MemoryInfo = make ( [ ] MemoryInfo , numEntries )
for i := range mdmp . MemoryInfo {
memInfo := & mdmp . MemoryInfo [ i ]
startOff := buf . off
memInfo . Addr = buf . u64 ( )
buf . u64 ( ) // allocation_base
buf . u32 ( ) // allocation_protection
buf . u32 ( ) // alignment
memInfo . Size = buf . u64 ( )
memInfo . State = MemoryState ( buf . u32 ( ) )
memInfo . Protection = MemoryProtection ( buf . u32 ( ) )
memInfo . Type = MemoryType ( buf . u32 ( ) )
if logfn != nil {
logfn ( "\tMemoryInfo %d Addr:%#x Size:%#x %s %s %s\n" , i , memInfo . Addr , memInfo . Size , memInfo . State , memInfo . Protection , memInfo . Type )
}
buf . off = startOff + sizeOfEntry
}
}
// readMiscInfo reads the process_id from a MiscInfo stream.
func readMiscInfo ( mdmp * Minidump , buf * minidumpBuf ) {
buf . u32 ( ) // size of info
buf . u32 ( ) // flags1
mdmp . Pid = buf . u32 ( ) // process_id
// there are more fields here, but we don't care about them
}
// readMemoryDescriptor reads a memory descriptor struct and adds it to the memory map of the minidump.
func readMemoryDescriptor ( mdmp * Minidump , buf * minidumpBuf ) {
addr := buf . u64 ( )
if buf . err != nil {
return
}
_ , rawData := readLocationDescriptor ( buf )
if buf . err != nil {
return
}
mdmp . addMemory ( addr , rawData )
}
func ( mdmp * Minidump ) addMemory ( addr uint64 , data [ ] byte ) {
mdmp . MemoryRanges = append ( mdmp . MemoryRanges , MemoryRange { addr , data } )
}