Flutter Engine
The Flutter Engine
minidump.py
Go to the documentation of this file.
1# Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2# for details. All rights reserved. Use of this source code is governed by a
3# BSD-style license that can be found in the LICENSE file.
4
5# This file contains a set of utilities for parsing minidumps.
6
7import ctypes
8import mmap
9import os
10import sys
11
12
13class Enum(object):
14
15 def __init__(self, type, name2value):
16 self.name2value = name2value
17 self.value2name = {v: k for k, v in name2value.items()}
18 self.type = type
19
20 def from_raw(self, v):
21 if v not in self.value2name:
22 return 'Unknown(' + str(v) + ')'
23 return self.value2name[v]
24
25 def to_raw(self, v):
26 return self.name2value[v]
27
28
29class Descriptor(object):
30 """A handy wrapper over ctypes.Structure"""
31
32 def __init__(self, fields):
33 self.fields = fields
34 self.ctype = Descriptor._GetCtype(fields)
35 self.size = ctypes.sizeof(self.ctype)
36
37 def Read(self, address):
38 return self.ctype.from_address(address)
39
40 @staticmethod
41 def _GetCtype(fields):
42 raw_fields = []
43 wrappers = {}
44 for field in fields:
45 (name, type) = field
46 if isinstance(type, Enum):
47 raw_fields.append(('_raw_' + name, type.type))
48 wrappers[name] = type
49 else:
50 raw_fields.append(field)
51
52 class Raw(ctypes.Structure):
53 _fields_ = raw_fields
54 _pack_ = 1
55
56 def __getattribute__(self, name):
57 if name in wrappers:
58 return wrappers[name].from_raw(
59 getattr(self, '_raw_' + name))
60 else:
61 return ctypes.Structure.__getattribute__(self, name)
62
63 def __repr__(self):
64 return '{' + ', '.join(
65 '%s: %s' % (field, self.__getattribute__(field))
66 for field, _ in fields) + '}'
67
68 return Raw
69
70
71# Structures below are based on the information in the MSDN pages and
72# Breakpad/Crashpad sources.
73
74MINIDUMP_HEADER = Descriptor([('signature', ctypes.c_uint32),
75 ('version', ctypes.c_uint32),
76 ('stream_count', ctypes.c_uint32),
77 ('stream_directories_rva', ctypes.c_uint32),
78 ('checksum', ctypes.c_uint32),
79 ('time_date_stampt', ctypes.c_uint32),
80 ('flags', ctypes.c_uint64)])
81
82MINIDUMP_LOCATION_DESCRIPTOR = Descriptor([('data_size', ctypes.c_uint32),
83 ('rva', ctypes.c_uint32)])
84
85MINIDUMP_STREAM_TYPE = {
86 'MD_UNUSED_STREAM': 0,
87 'MD_RESERVED_STREAM_0': 1,
88 'MD_RESERVED_STREAM_1': 2,
89 'MD_THREAD_LIST_STREAM': 3,
90 'MD_MODULE_LIST_STREAM': 4,
91 'MD_MEMORY_LIST_STREAM': 5,
92 'MD_EXCEPTION_STREAM': 6,
93 'MD_SYSTEM_INFO_STREAM': 7,
94 'MD_THREAD_EX_LIST_STREAM': 8,
95 'MD_MEMORY_64_LIST_STREAM': 9,
96 'MD_COMMENT_STREAM_A': 10,
97 'MD_COMMENT_STREAM_W': 11,
98 'MD_HANDLE_DATA_STREAM': 12,
99 'MD_FUNCTION_TABLE_STREAM': 13,
100 'MD_UNLOADED_MODULE_LIST_STREAM': 14,
101 'MD_MISC_INFO_STREAM': 15,
102 'MD_MEMORY_INFO_LIST_STREAM': 16,
103 'MD_THREAD_INFO_LIST_STREAM': 17,
104 'MD_HANDLE_OPERATION_LIST_STREAM': 18,
105}
106
107MINIDUMP_DIRECTORY = Descriptor([('stream_type',
108 Enum(ctypes.c_uint32, MINIDUMP_STREAM_TYPE)),
109 ('location',
110 MINIDUMP_LOCATION_DESCRIPTOR.ctype)])
111
112MINIDUMP_MISC_INFO_2 = Descriptor([
113 ('SizeOfInfo', ctypes.c_uint32),
114 ('Flags1', ctypes.c_uint32),
115 ('ProcessId', ctypes.c_uint32),
116 ('ProcessCreateTime', ctypes.c_uint32),
117 ('ProcessUserTime', ctypes.c_uint32),
118 ('ProcessKernelTime', ctypes.c_uint32),
119 ('ProcessorMaxMhz', ctypes.c_uint32),
120 ('ProcessorCurrentMhz', ctypes.c_uint32),
121 ('ProcessorMhzLimit', ctypes.c_uint32),
122 ('ProcessorMaxIdleState', ctypes.c_uint32),
123 ('ProcessorCurrentIdleState', ctypes.c_uint32),
124])
125
126MINIDUMP_MISC1_PROCESS_ID = 0x00000001
127
128
129# A helper to get a raw address of the memory mapped buffer returned by
130# mmap.
132 obj = ctypes.py_object(buf)
133 address = ctypes.c_void_p()
134 length = ctypes.c_ssize_t()
135 ctypes.pythonapi.PyObject_AsReadBuffer(obj, ctypes.byref(address),
136 ctypes.byref(length))
137 return address.value
138
139
140class MinidumpFile(object):
141 """Class for reading minidump files."""
142 _HEADER_MAGIC = 0x504d444d
143
144 def __init__(self, minidump_name):
145 self.minidump_name = minidump_name
146 self.minidump_file = open(minidump_name, 'r')
147 self.minidump = mmap.mmap(
148 self.minidump_file.fileno(), 0, access=mmap.ACCESS_READ)
150 self.header = self.Read(MINIDUMP_HEADER, 0)
151 if self.header.signature != MinidumpFile._HEADER_MAGIC:
152 raise Exception('Unsupported minidump header magic')
153 self.directories = []
154 offset = self.header.stream_directories_rva
155 for _ in range(self.header.stream_count):
156 self.directories.append(self.Read(MINIDUMP_DIRECTORY, offset))
157 offset += MINIDUMP_DIRECTORY.size
158
159 def GetProcessId(self):
160 for dir in self.directories:
161 if dir.stream_type == 'MD_MISC_INFO_STREAM':
162 info = self.Read(MINIDUMP_MISC_INFO_2, dir.location.rva)
163 if info.Flags1 & MINIDUMP_MISC1_PROCESS_ID != 0:
164 return info.ProcessId
165 return -1
166
167 def Read(self, what, offset):
168 return what.Read(self.minidump_address + offset)
169
170 def __enter__(self):
171 return self
172
173 def __exit__(self, type, value, traceback):
174 self.minidump.close()
175 self.minidump_file.close()
176
177
178# Returns process id of the crashed process recorded in the given minidump.
180 try:
181 with MinidumpFile(path) as f:
182 return int(f.GetProcessId())
183 except:
184 return -1
def Read(self, address)
Definition: minidump.py:37
def __init__(self, fields)
Definition: minidump.py:32
def from_raw(self, v)
Definition: minidump.py:20
def __init__(self, type, name2value)
Definition: minidump.py:15
def to_raw(self, v)
Definition: minidump.py:25
def GetProcessId(self)
Definition: minidump.py:159
def Read(self, what, offset)
Definition: minidump.py:167
def __enter__(self)
Definition: minidump.py:170
def __init__(self, minidump_name)
Definition: minidump.py:144
def __exit__(self, type, value, traceback)
Definition: minidump.py:173
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
def BufferToAddress(buf)
Definition: minidump.py:131
def GetProcessIdFromDump(path)
Definition: minidump.py:179
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741