github.com/undoio/delve@v1.9.0/pkg/proc/core/minidump/minidump.go (about) 1 package minidump 2 3 // Package minidump provides a loader for Windows Minidump files. 4 // Minidump files are the Windows equivalent of unix core dumps. 5 // They can be created by the kernel when a program crashes (however this is 6 // disabled for Go programs) or programmatically using either WinDbg or the 7 // ProcDump utility. 8 // 9 // The file format is described on MSDN starting at: 10 // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header 11 // which is the structure found at offset 0 on a minidump file. 12 // 13 // Further information on the format can be found reading 14 // chromium-breakpad's minidump loading code, specifically: 15 // https://chromium.googlesource.com/breakpad/breakpad/+/master/src/google_breakpad/common/minidump_cpu_amd64.h 16 // and: 17 // https://chromium.googlesource.com/breakpad/breakpad/+/master/src/google_breakpad/common/minidump_format.h 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "unicode/utf16" 25 "unsafe" 26 27 "github.com/undoio/delve/pkg/proc/winutil" 28 ) 29 30 type minidumpBuf struct { 31 buf []byte 32 kind string 33 off int 34 err error 35 ctx string 36 } 37 38 func (buf *minidumpBuf) u16() uint16 { 39 const stride = 2 40 if buf.err != nil { 41 return 0 42 } 43 if buf.off+stride >= len(buf.buf) { 44 buf.err = fmt.Errorf("minidump %s truncated at offset %#x while %s", buf.kind, buf.off, buf.ctx) 45 } 46 r := binary.LittleEndian.Uint16(buf.buf[buf.off : buf.off+stride]) 47 buf.off += stride 48 return r 49 } 50 51 func (buf *minidumpBuf) u32() uint32 { 52 const stride = 4 53 if buf.err != nil { 54 return 0 55 } 56 if buf.off+stride >= len(buf.buf) { 57 buf.err = fmt.Errorf("minidump %s truncated at offset %#x while %s", buf.kind, buf.off, buf.ctx) 58 } 59 r := binary.LittleEndian.Uint32(buf.buf[buf.off : buf.off+stride]) 60 buf.off += stride 61 return r 62 } 63 64 func (buf *minidumpBuf) u64() uint64 { 65 const stride = 8 66 if buf.err != nil { 67 return 0 68 } 69 if buf.off+stride >= len(buf.buf) { 70 buf.err = fmt.Errorf("minidump %s truncated at offset %#x while %s", buf.kind, buf.off, buf.ctx) 71 } 72 r := binary.LittleEndian.Uint64(buf.buf[buf.off : buf.off+stride]) 73 buf.off += stride 74 return r 75 } 76 77 func streamBuf(stream *Stream, buf *minidumpBuf, name string) *minidumpBuf { 78 return &minidumpBuf{ 79 buf: buf.buf, 80 kind: "stream", 81 off: stream.Offset, 82 err: nil, 83 ctx: fmt.Sprintf("reading %s stream at %#x", name, stream.Offset), 84 } 85 } 86 87 // ErrNotAMinidump is the error returned when the file being loaded is not a 88 // minidump file. 89 type ErrNotAMinidump struct { 90 what string 91 got uint32 92 } 93 94 func (err ErrNotAMinidump) Error() string { 95 return fmt.Sprintf("not a minidump, invalid %s %#x", err.what, err.got) 96 } 97 98 const ( 99 minidumpSignature = 0x504d444d // 'MDMP' 100 minidumpVersion = 0xa793 101 ) 102 103 // Minidump represents a minidump file 104 type Minidump struct { 105 Timestamp uint32 106 Flags FileFlags 107 108 Streams []Stream 109 110 Threads []Thread 111 Modules []Module 112 113 Pid uint32 114 115 MemoryRanges []MemoryRange 116 MemoryInfo []MemoryInfo 117 118 streamNum uint32 119 streamOff uint32 120 } 121 122 // Stream represents one (uninterpreted) stream in a minidump file. 123 // See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_directory 124 type Stream struct { 125 Type StreamType 126 Offset int 127 RawData []byte 128 } 129 130 // Thread represents an entry in the ThreadList stream. 131 // See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread 132 type Thread struct { 133 ID uint32 134 SuspendCount uint32 135 PriorityClass uint32 136 Priority uint32 137 TEB uint64 138 Context winutil.CONTEXT 139 } 140 141 // Module represents an entry in the ModuleList stream. 142 // See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_module 143 type Module struct { 144 BaseOfImage uint64 145 SizeOfImage uint32 146 Checksum uint32 147 TimeDateStamp uint32 148 Name string 149 VersionInfo VSFixedFileInfo 150 151 // CVRecord stores a CodeView record and is populated when a module's debug information resides in a PDB file. It identifies the PDB file. 152 CVRecord []byte 153 154 // 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. 155 MiscRecord []byte 156 } 157 158 // VSFixedFileInfo Visual Studio Fixed File Info. 159 // See: https://docs.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo 160 type VSFixedFileInfo struct { 161 Signature uint32 162 StructVersion uint32 163 FileVersionHi uint32 164 FileVersionLo uint32 165 ProductVersionHi uint32 166 ProductVersionLo uint32 167 FileFlagsMask uint32 168 FileFlags uint32 169 FileOS uint32 170 FileType uint32 171 FileSubtype uint32 172 FileDateHi uint32 173 FileDateLo uint32 174 } 175 176 // MemoryRange represents a region of memory saved to the core file, it's constructed after either: 177 // 1. parsing an entry in the Memory64List stream. 178 // 2. parsing the stack field of an entry in the ThreadList stream. 179 type MemoryRange struct { 180 Addr uint64 181 Data []byte 182 } 183 184 // ReadMemory reads len(buf) bytes of memory starting at addr into buf from this memory region. 185 func (m *MemoryRange) ReadMemory(buf []byte, addr uint64) (int, error) { 186 if len(buf) == 0 { 187 return 0, nil 188 } 189 if (uint64(addr) < m.Addr) || (uint64(addr)+uint64(len(buf)) > m.Addr+uint64(len(m.Data))) { 190 return 0, io.EOF 191 } 192 copy(buf, m.Data[uint64(addr)-m.Addr:]) 193 return len(buf), nil 194 } 195 196 // MemoryInfo reprents an entry in the MemoryInfoList stream. 197 // See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list 198 type MemoryInfo struct { 199 Addr uint64 200 Size uint64 201 State MemoryState 202 Protection MemoryProtection 203 Type MemoryType 204 } 205 206 //go:generate stringer -type FileFlags,StreamType,Arch,MemoryState,MemoryType,MemoryProtection 207 208 // MemoryState is the type of the State field of MINIDUMP_MEMORY_INFO 209 type MemoryState uint32 210 211 const ( 212 MemoryStateCommit MemoryState = 0x1000 213 MemoryStateReserve MemoryState = 0x2000 214 MemoryStateFree MemoryState = 0x10000 215 ) 216 217 // MemoryType is the type of the Type field of MINIDUMP_MEMORY_INFO 218 type MemoryType uint32 219 220 const ( 221 MemoryTypePrivate MemoryType = 0x20000 222 MemoryTypeMapped MemoryType = 0x40000 223 MemoryTypeImage MemoryType = 0x1000000 224 ) 225 226 // MemoryProtection is the type of the Protection field of MINIDUMP_MEMORY_INFO 227 type MemoryProtection uint32 228 229 const ( 230 MemoryProtectNoAccess MemoryProtection = 0x01 // PAGE_NOACCESS 231 MemoryProtectReadOnly MemoryProtection = 0x02 // PAGE_READONLY 232 MemoryProtectReadWrite MemoryProtection = 0x04 // PAGE_READWRITE 233 MemoryProtectWriteCopy MemoryProtection = 0x08 // PAGE_WRITECOPY 234 MemoryProtectExecute MemoryProtection = 0x10 // PAGE_EXECUTE 235 MemoryProtectExecuteRead MemoryProtection = 0x20 // PAGE_EXECUTE_READ 236 MemoryProtectExecuteReadWrite MemoryProtection = 0x40 // PAGE_EXECUTE_READWRITE 237 MemoryProtectExecuteWriteCopy MemoryProtection = 0x80 // PAGE_EXECUTE_WRITECOPY 238 // These options can be combined with the previous flags 239 MemoryProtectPageGuard MemoryProtection = 0x100 // PAGE_GUARD 240 MemoryProtectNoCache MemoryProtection = 0x200 // PAGE_NOCACHE 241 MemoryProtectWriteCombine MemoryProtection = 0x400 // PAGE_WRITECOMBINE 242 243 ) 244 245 // FileFlags is the type of the Flags field of MINIDUMP_HEADER 246 type FileFlags uint64 247 248 const ( 249 FileNormal FileFlags = 0x00000000 250 FileWithDataSegs FileFlags = 0x00000001 251 FileWithFullMemory FileFlags = 0x00000002 252 FileWithHandleData FileFlags = 0x00000004 253 FileFilterMemory FileFlags = 0x00000008 254 FileScanMemory FileFlags = 0x00000010 255 FileWithUnloadedModules FileFlags = 0x00000020 256 FileWithIncorrectlyReferencedMemory FileFlags = 0x00000040 257 FileFilterModulePaths FileFlags = 0x00000080 258 FileWithProcessThreadData FileFlags = 0x00000100 259 FileWithPrivateReadWriteMemory FileFlags = 0x00000200 260 FileWithoutOptionalData FileFlags = 0x00000400 261 FileWithFullMemoryInfo FileFlags = 0x00000800 262 FileWithThreadInfo FileFlags = 0x00001000 263 FileWithCodeSegs FileFlags = 0x00002000 264 FileWithoutAuxilliarySegs FileFlags = 0x00004000 265 FileWithFullAuxilliaryState FileFlags = 0x00008000 266 FileWithPrivateCopyMemory FileFlags = 0x00010000 267 FileIgnoreInaccessibleMemory FileFlags = 0x00020000 268 FileWithTokenInformation FileFlags = 0x00040000 269 ) 270 271 // StreamType is the type of the StreamType field of MINIDUMP_DIRECTORY 272 type StreamType uint32 273 274 const ( 275 UnusedStream StreamType = 0 276 ReservedStream0 StreamType = 1 277 ReservedStream1 StreamType = 2 278 ThreadListStream StreamType = 3 279 ModuleListStream StreamType = 4 280 MemoryListStream StreamType = 5 281 ExceptionStream StreamType = 6 282 SystemInfoStream StreamType = 7 283 ThreadExListStream StreamType = 8 284 Memory64ListStream StreamType = 9 285 CommentStreamA StreamType = 10 286 CommentStreamW StreamType = 11 287 HandleDataStream StreamType = 12 288 FunctionTableStream StreamType = 13 289 UnloadedModuleStream StreamType = 14 290 MiscInfoStream StreamType = 15 291 MemoryInfoListStream StreamType = 16 292 ThreadInfoListStream StreamType = 17 293 HandleOperationListStream StreamType = 18 294 TokenStream StreamType = 19 295 JavascriptDataStream StreamType = 20 296 SystemMemoryInfoStream StreamType = 21 297 ProcessVMCounterStream StreamType = 22 298 ) 299 300 // Arch is the type of the ProcessorArchitecture field of MINIDUMP_SYSTEM_INFO. 301 type Arch uint16 302 303 const ( 304 CpuArchitectureX86 Arch = 0 305 CpuArchitectureMips Arch = 1 306 CpuArchitectureAlpha Arch = 2 307 CpuArchitecturePPC Arch = 3 308 CpuArchitectureSHX Arch = 4 // Super-H 309 CpuArchitectureARM Arch = 5 310 CpuArchitectureIA64 Arch = 6 311 CpuArchitectureAlpha64 Arch = 7 312 CpuArchitectureMSIL Arch = 8 // Microsoft Intermediate Language 313 CpuArchitectureAMD64 Arch = 9 314 CpuArchitectureWoW64 Arch = 10 315 CpuArchitectureARM64 Arch = 12 316 CpuArchitectureUnknown Arch = 0xffff 317 ) 318 319 // Open reads the minidump file at path and returns it as a Minidump structure. 320 func Open(path string, logfn func(fmt string, args ...interface{})) (*Minidump, error) { 321 rawbuf, err := ioutil.ReadFile(path) //TODO(aarzilli): mmap? 322 if err != nil { 323 return nil, err 324 } 325 326 buf := &minidumpBuf{buf: rawbuf, kind: "file"} 327 328 var mdmp Minidump 329 330 readMinidumpHeader(&mdmp, buf) 331 if buf.err != nil { 332 return nil, buf.err 333 } 334 335 if logfn != nil { 336 logfn("Minidump Header\n") 337 logfn("Num Streams: %d\n", mdmp.streamNum) 338 logfn("Streams offset: %#x\n", mdmp.streamOff) 339 logfn("File flags: %s\n", fileFlagsToString(mdmp.Flags)) 340 logfn("Offset after header %#x\n", buf.off) 341 } 342 343 readDirectory(&mdmp, buf) 344 if buf.err != nil { 345 return nil, buf.err 346 } 347 348 for i := range mdmp.Streams { 349 stream := &mdmp.Streams[i] 350 if stream.Type != SystemInfoStream { 351 continue 352 } 353 354 sb := streamBuf(stream, buf, "system info") 355 if buf.err != nil { 356 return nil, buf.err 357 } 358 359 arch := Arch(sb.u16()) 360 361 if logfn != nil { 362 logfn("Found processor architecture %s\n", arch.String()) 363 } 364 365 if arch != CpuArchitectureAMD64 { 366 return nil, fmt.Errorf("unsupported architecture %s", arch.String()) 367 } 368 } 369 370 for i := range mdmp.Streams { 371 stream := &mdmp.Streams[i] 372 if logfn != nil { 373 logfn("Stream %d: type:%s off:%#x size:%#x\n", i, stream.Type, stream.Offset, len(stream.RawData)) 374 } 375 switch stream.Type { 376 case ThreadListStream: 377 readThreadList(&mdmp, streamBuf(stream, buf, "thread list")) 378 if logfn != nil { 379 for i := range mdmp.Threads { 380 logfn("\tID:%#x TEB:%#x\n", mdmp.Threads[i].ID, mdmp.Threads[i].TEB) 381 } 382 } 383 case ModuleListStream: 384 readModuleList(&mdmp, streamBuf(stream, buf, "module list")) 385 if logfn != nil { 386 for i := range mdmp.Modules { 387 logfn("\tName:%q BaseOfImage:%#x SizeOfImage:%#x\n", mdmp.Modules[i].Name, mdmp.Modules[i].BaseOfImage, mdmp.Modules[i].SizeOfImage) 388 } 389 } 390 case ExceptionStream: 391 //TODO(aarzilli): this stream contains the exception that made the 392 //process stop and caused the minidump to be taken. If we ever start 393 //caring about this we should parse this. 394 case Memory64ListStream: 395 readMemory64List(&mdmp, streamBuf(stream, buf, "memory64 list"), logfn) 396 case MemoryInfoListStream: 397 readMemoryInfoList(&mdmp, streamBuf(stream, buf, "memory info list"), logfn) 398 case MiscInfoStream: 399 readMiscInfo(&mdmp, streamBuf(stream, buf, "misc info")) 400 if logfn != nil { 401 logfn("\tPid: %#x\n", mdmp.Pid) 402 } 403 case CommentStreamW: 404 if logfn != nil { 405 logfn("\t%q\n", decodeUTF16(stream.RawData)) 406 } 407 case CommentStreamA: 408 if logfn != nil { 409 logfn("\t%s\n", string(stream.RawData)) 410 } 411 } 412 if buf.err != nil { 413 return nil, buf.err 414 } 415 } 416 417 return &mdmp, nil 418 } 419 420 // decodeUTF16 converts a NUL-terminated UTF16LE string to (non NUL-terminated) UTF8. 421 func decodeUTF16(in []byte) string { 422 utf16encoded := []uint16{} 423 for i := 0; i+1 < len(in); i += 2 { 424 var ch uint16 425 ch = uint16(in[i]) + uint16(in[i+1])<<8 426 utf16encoded = append(utf16encoded, ch) 427 } 428 s := string(utf16.Decode(utf16encoded)) 429 if len(s) > 0 && s[len(s)-1] == 0 { 430 s = s[:len(s)-1] 431 } 432 return s 433 } 434 435 func fileFlagsToString(flags FileFlags) string { 436 out := []byte{} 437 for i, name := range _FileFlags_map { 438 if i == 0 { 439 continue 440 } 441 if flags&i != 0 { 442 if len(out) > 0 { 443 out = append(out, '|') 444 } 445 out = append(out, name...) 446 } 447 } 448 if len(out) == 0 { 449 return flags.String() 450 } 451 return string(out) 452 } 453 454 // readMinidumpHeader reads the minidump file header 455 func readMinidumpHeader(mdmp *Minidump, buf *minidumpBuf) { 456 buf.ctx = "reading minidump header" 457 458 if sig := buf.u32(); sig != minidumpSignature { 459 buf.err = ErrNotAMinidump{"signature", sig} 460 return 461 } 462 463 if ver := buf.u16(); ver != minidumpVersion { 464 buf.err = ErrNotAMinidump{"version", uint32(ver)} 465 return 466 } 467 468 buf.u16() // implementation specific version 469 mdmp.streamNum = buf.u32() 470 mdmp.streamOff = buf.u32() 471 buf.u32() // checksum, but it's always 0 472 mdmp.Timestamp = buf.u32() 473 mdmp.Flags = FileFlags(buf.u64()) 474 } 475 476 // readDirectory reads the list of streams (i.e. the minidum "directory") 477 func readDirectory(mdmp *Minidump, buf *minidumpBuf) { 478 buf.off = int(mdmp.streamOff) 479 480 mdmp.Streams = make([]Stream, mdmp.streamNum) 481 for i := range mdmp.Streams { 482 buf.ctx = fmt.Sprintf("reading stream directory entry %d", i) 483 stream := &mdmp.Streams[i] 484 stream.Type = StreamType(buf.u32()) 485 stream.Offset, stream.RawData = readLocationDescriptor(buf) 486 if buf.err != nil { 487 return 488 } 489 } 490 } 491 492 // readLocationDescriptor reads a location descriptor structure (a structure 493 // which describes a subregion of the file), and returns the destination 494 // offset and a slice into the minidump file's buffer. 495 func readLocationDescriptor(buf *minidumpBuf) (off int, rawData []byte) { 496 sz := buf.u32() 497 off = int(buf.u32()) 498 if buf.err != nil { 499 return off, nil 500 } 501 end := off + int(sz) 502 if off >= len(buf.buf) || end > len(buf.buf) { 503 buf.err = fmt.Errorf("location starting at %#x of size %#x is past the end of file, while %s", off, sz, buf.ctx) 504 return 0, nil 505 } 506 rawData = buf.buf[off:end] 507 return 508 } 509 510 func readString(buf *minidumpBuf) string { 511 startOff := buf.off 512 sz := buf.u32() 513 if buf.err != nil { 514 return "" 515 } 516 end := buf.off + int(sz) 517 if buf.off >= len(buf.buf) || end > len(buf.buf) { 518 buf.err = fmt.Errorf("string starting at %#x of size %#x is past the end of file, while %s", startOff, sz, buf.ctx) 519 return "" 520 } 521 return decodeUTF16(buf.buf[buf.off:end]) 522 } 523 524 // readThreadList reads a thread list stream and adds the threads to the minidump. 525 func readThreadList(mdmp *Minidump, buf *minidumpBuf) { 526 threadNum := buf.u32() 527 if buf.err != nil { 528 return 529 } 530 531 mdmp.Threads = make([]Thread, threadNum) 532 533 for i := range mdmp.Threads { 534 buf.ctx = fmt.Sprintf("reading thread list entry %d", i) 535 thread := &mdmp.Threads[i] 536 537 thread.ID = buf.u32() 538 thread.SuspendCount = buf.u32() 539 thread.PriorityClass = buf.u32() 540 thread.Priority = buf.u32() 541 thread.TEB = buf.u64() 542 if buf.err != nil { 543 return 544 } 545 546 readMemoryDescriptor(mdmp, buf) // thread stack 547 _, rawThreadContext := readLocationDescriptor(buf) // thread context 548 thread.Context = *((*winutil.CONTEXT)(unsafe.Pointer(&rawThreadContext[0]))) 549 if buf.err != nil { 550 return 551 } 552 } 553 } 554 555 // readModuleList reads a module list stream and adds the modules to the minidump. 556 func readModuleList(mdmp *Minidump, buf *minidumpBuf) { 557 moduleNum := buf.u32() 558 if buf.err != nil { 559 return 560 } 561 562 mdmp.Modules = make([]Module, moduleNum) 563 564 for i := range mdmp.Modules { 565 buf.ctx = fmt.Sprintf("reading module list entry %d", i) 566 module := &mdmp.Modules[i] 567 568 module.BaseOfImage = buf.u64() 569 module.SizeOfImage = buf.u32() 570 module.Checksum = buf.u32() 571 module.TimeDateStamp = buf.u32() 572 nameOff := int(buf.u32()) 573 574 versionInfoVec := make([]uint32, unsafe.Sizeof(VSFixedFileInfo{})/unsafe.Sizeof(uint32(0))) 575 for j := range versionInfoVec { 576 versionInfoVec[j] = buf.u32() 577 } 578 579 module.VersionInfo = *(*VSFixedFileInfo)(unsafe.Pointer(&versionInfoVec[0])) 580 581 _, module.CVRecord = readLocationDescriptor(buf) 582 _, module.MiscRecord = readLocationDescriptor(buf) 583 584 if buf.err != nil { 585 return 586 } 587 588 nameBuf := minidumpBuf{buf: buf.buf, kind: "file", off: nameOff, err: nil, ctx: buf.ctx} 589 module.Name = readString(&nameBuf) 590 if nameBuf.err != nil { 591 buf.err = nameBuf.err 592 return 593 } 594 } 595 } 596 597 // readMemory64List reads a _MINIDUMP_MEMORY64_LIST structure, containing 598 // the description of the process memory. 599 // See: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory64_list 600 // And: https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_descriptor 601 func readMemory64List(mdmp *Minidump, buf *minidumpBuf, logfn func(fmt string, args ...interface{})) { 602 rangesNum := buf.u64() 603 baseOff := int(buf.u64()) 604 if buf.err != nil { 605 return 606 } 607 608 for i := uint64(0); i < rangesNum; i++ { 609 addr := buf.u64() 610 sz := buf.u64() 611 612 end := baseOff + int(sz) 613 if baseOff >= len(buf.buf) || end > len(buf.buf) { 614 buf.err = fmt.Errorf("memory range at %#x of size %#x is past the end of file, while %s", baseOff, sz, buf.ctx) 615 return 616 } 617 618 mdmp.addMemory(addr, buf.buf[baseOff:end]) 619 620 if logfn != nil { 621 logfn("\tMemory %d addr:%#x size:%#x FileOffset:%#x\n", i, addr, sz, baseOff) 622 } 623 624 baseOff = end 625 } 626 } 627 628 func readMemoryInfoList(mdmp *Minidump, buf *minidumpBuf, logfn func(fmt string, args ...interface{})) { 629 startOff := buf.off 630 sizeOfHeader := int(buf.u32()) 631 sizeOfEntry := int(buf.u32()) 632 numEntries := buf.u64() 633 634 buf.off = startOff + sizeOfHeader 635 636 mdmp.MemoryInfo = make([]MemoryInfo, numEntries) 637 638 for i := range mdmp.MemoryInfo { 639 memInfo := &mdmp.MemoryInfo[i] 640 startOff := buf.off 641 642 memInfo.Addr = buf.u64() 643 buf.u64() // allocation_base 644 645 buf.u32() // allocation_protection 646 buf.u32() // alignment 647 648 memInfo.Size = buf.u64() 649 650 memInfo.State = MemoryState(buf.u32()) 651 memInfo.Protection = MemoryProtection(buf.u32()) 652 memInfo.Type = MemoryType(buf.u32()) 653 654 if logfn != nil { 655 logfn("\tMemoryInfo %d Addr:%#x Size:%#x %s %s %s\n", i, memInfo.Addr, memInfo.Size, memInfo.State, memInfo.Protection, memInfo.Type) 656 } 657 658 buf.off = startOff + sizeOfEntry 659 } 660 } 661 662 // readMiscInfo reads the process_id from a MiscInfo stream. 663 func readMiscInfo(mdmp *Minidump, buf *minidumpBuf) { 664 buf.u32() // size of info 665 buf.u32() // flags1 666 667 mdmp.Pid = buf.u32() // process_id 668 // there are more fields here, but we don't care about them 669 } 670 671 // readMemoryDescriptor reads a memory descriptor struct and adds it to the memory map of the minidump. 672 func readMemoryDescriptor(mdmp *Minidump, buf *minidumpBuf) { 673 addr := buf.u64() 674 if buf.err != nil { 675 return 676 } 677 _, rawData := readLocationDescriptor(buf) 678 if buf.err != nil { 679 return 680 } 681 mdmp.addMemory(addr, rawData) 682 } 683 684 func (mdmp *Minidump) addMemory(addr uint64, data []byte) { 685 mdmp.MemoryRanges = append(mdmp.MemoryRanges, MemoryRange{addr, data}) 686 }