1 //===-- MinidumpTypes.h -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef liblldb_MinidumpTypes_h_
11 #define liblldb_MinidumpTypes_h_
12 
13 
14 #include "lldb/Utility/Status.h"
15 
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/BitmaskEnum.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/ConvertUTF.h"
22 #include "llvm/Support/Endian.h"
23 
24 // C includes
25 // C++ includes
26 
27 // Reference:
28 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms679293(v=vs.85).aspx
29 // https://chromium.googlesource.com/breakpad/breakpad/
30 
31 namespace lldb_private {
32 
33 namespace minidump {
34 
35 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
36 
37 enum class MinidumpHeaderConstants : uint32_t {
38   Signature = 0x504d444d, // 'PMDM'
39   Version = 0x0000a793,   // 42899
40   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Signature)
41 
42 };
43 
44 enum class CvSignature : uint32_t {
45   Pdb70 = 0x53445352, // RSDS
46   ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps)
47 };
48 
49 // Reference:
50 // https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html
51 struct CvRecordPdb70 {
52   uint8_t Uuid[16];
53   llvm::support::ulittle32_t Age;
54   // char PDBFileName[];
55 };
56 static_assert(sizeof(CvRecordPdb70) == 20,
57               "sizeof CvRecordPdb70 is not correct!");
58 
59 // Reference:
60 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680394.aspx
61 enum class MinidumpStreamType : uint32_t {
62   Unused = 0,
63   Reserved0 = 1,
64   Reserved1 = 2,
65   ThreadList = 3,
66   ModuleList = 4,
67   MemoryList = 5,
68   Exception = 6,
69   SystemInfo = 7,
70   ThreadExList = 8,
71   Memory64List = 9,
72   CommentA = 10,
73   CommentW = 11,
74   HandleData = 12,
75   FunctionTable = 13,
76   UnloadedModuleList = 14,
77   MiscInfo = 15,
78   MemoryInfoList = 16,
79   ThreadInfoList = 17,
80   HandleOperationList = 18,
81   Token = 19,
82   JavascriptData = 20,
83   SystemMemoryInfo = 21,
84   ProcessVMCounters = 22,
85   LastReserved = 0x0000ffff,
86 
87   /* Breakpad extension types.  0x4767 = "Gg" */
88   BreakpadInfo = 0x47670001,
89   AssertionInfo = 0x47670002,
90   /* These are additional minidump stream values which are specific to
91    * the linux breakpad implementation.   */
92   LinuxCPUInfo = 0x47670003,    /* /proc/cpuinfo      */
93   LinuxProcStatus = 0x47670004, /* /proc/$x/status    */
94   LinuxLSBRelease = 0x47670005, /* /etc/lsb-release   */
95   LinuxCMDLine = 0x47670006,    /* /proc/$x/cmdline   */
96   LinuxEnviron = 0x47670007,    /* /proc/$x/environ   */
97   LinuxAuxv = 0x47670008,       /* /proc/$x/auxv      */
98   LinuxMaps = 0x47670009,       /* /proc/$x/maps      */
99   LinuxDSODebug = 0x4767000A,
100   LinuxProcStat = 0x4767000B,   /* /proc/$x/stat      */
101   LinuxProcUptime = 0x4767000C, /* uptime             */
102   LinuxProcFD = 0x4767000D,     /* /proc/$x/fb        */
103 };
104 
105 // for MinidumpSystemInfo.processor_arch
106 enum class MinidumpCPUArchitecture : uint16_t {
107   X86 = 0,         /* PROCESSOR_ARCHITECTURE_INTEL */
108   MIPS = 1,        /* PROCESSOR_ARCHITECTURE_MIPS */
109   Alpha = 2,       /* PROCESSOR_ARCHITECTURE_ALPHA */
110   PPC = 3,         /* PROCESSOR_ARCHITECTURE_PPC */
111   SHX = 4,         /* PROCESSOR_ARCHITECTURE_SHX (Super-H) */
112   ARM = 5,         /* PROCESSOR_ARCHITECTURE_ARM */
113   IA64 = 6,        /* PROCESSOR_ARCHITECTURE_IA64 */
114   Alpha64 = 7,     /* PROCESSOR_ARCHITECTURE_ALPHA64 */
115   MSIL = 8,        /* PROCESSOR_ARCHITECTURE_MSIL
116                                               * (Microsoft Intermediate Language) */
117   AMD64 = 9,       /* PROCESSOR_ARCHITECTURE_AMD64 */
118   X86Win64 = 10,   /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
119   SPARC = 0x8001,  /* Breakpad-defined value for SPARC */
120   PPC64 = 0x8002,  /* Breakpad-defined value for PPC64 */
121   ARM64 = 0x8003,  /* Breakpad-defined value for ARM64 */
122   MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
123   Unknown = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
124 };
125 
126 // for MinidumpSystemInfo.platform_id
127 enum class MinidumpOSPlatform : uint32_t {
128   Win32S = 0,       /* VER_PLATFORM_WIN32s (Windows 3.1) */
129   Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
130   Win32NT = 2,      /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
131   Win32CE = 3,      /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
132                                   * (Windows CE, Windows Mobile, "Handheld") */
133 
134   /* The following values are Breakpad-defined. */
135   Unix = 0x8000,    /* Generic Unix-ish */
136   MacOSX = 0x8101,  /* Mac OS X/Darwin */
137   IOS = 0x8102,     /* iOS */
138   Linux = 0x8201,   /* Linux */
139   Solaris = 0x8202, /* Solaris */
140   Android = 0x8203, /* Android */
141   PS3 = 0x8204,     /* PS3 */
142   NaCl = 0x8205     /* Native Client (NaCl) */
143 };
144 
145 // For MinidumpCPUInfo.arm_cpu_info.elf_hwcaps.
146 // This matches the Linux kernel definitions from <asm/hwcaps.h>
147 enum class MinidumpPCPUInformationARMElfHwCaps : uint32_t {
148   SWP = (1 << 0),
149   Half = (1 << 1),
150   Thumb = (1 << 2),
151   _26BIT = (1 << 3),
152   FastMult = (1 << 4),
153   FPA = (1 << 5),
154   VFP = (1 << 6),
155   EDSP = (1 << 7),
156   Java = (1 << 8),
157   IWMMXT = (1 << 9),
158   Crunch = (1 << 10),
159   ThumbEE = (1 << 11),
160   Neon = (1 << 12),
161   VFPv3 = (1 << 13),
162   VFPv3D16 = (1 << 14),
163   TLS = (1 << 15),
164   VFPv4 = (1 << 16),
165   IDIVA = (1 << 17),
166   IDIVT = (1 << 18),
167   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IDIVT)
168 };
169 
170 enum class MinidumpMiscInfoFlags : uint32_t {
171   ProcessID = (1 << 0),
172   ProcessTimes = (1 << 1),
173   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ ProcessTimes)
174 };
175 
176 template <typename T>
consumeObject(llvm::ArrayRef<uint8_t> & Buffer,const T * & Object)177 Status consumeObject(llvm::ArrayRef<uint8_t> &Buffer, const T *&Object) {
178   Status error;
179   if (Buffer.size() < sizeof(T)) {
180     error.SetErrorString("Insufficient buffer!");
181     return error;
182   }
183 
184   Object = reinterpret_cast<const T *>(Buffer.data());
185   Buffer = Buffer.drop_front(sizeof(T));
186   return error;
187 }
188 
189 // parse a MinidumpString which is with UTF-16
190 // Reference:
191 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680395(v=vs.85).aspx
192 llvm::Optional<std::string> parseMinidumpString(llvm::ArrayRef<uint8_t> &data);
193 
194 // Reference:
195 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx
196 struct MinidumpHeader {
197   llvm::support::ulittle32_t signature;
198   llvm::support::ulittle32_t
199       version; // The high 16 bits of version field are implementation specific
200   llvm::support::ulittle32_t streams_count;
201   llvm::support::ulittle32_t
202       stream_directory_rva; // offset of the stream directory
203   llvm::support::ulittle32_t checksum;
204   llvm::support::ulittle32_t time_date_stamp; // time_t format
205   llvm::support::ulittle64_t flags;
206 
207   static const MinidumpHeader *Parse(llvm::ArrayRef<uint8_t> &data);
208 };
209 static_assert(sizeof(MinidumpHeader) == 32,
210               "sizeof MinidumpHeader is not correct!");
211 
212 // Reference:
213 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383.aspx
214 struct MinidumpLocationDescriptor {
215   llvm::support::ulittle32_t data_size;
216   llvm::support::ulittle32_t rva;
217 };
218 static_assert(sizeof(MinidumpLocationDescriptor) == 8,
219               "sizeof MinidumpLocationDescriptor is not correct!");
220 
221 // Reference:
222 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx
223 struct MinidumpMemoryDescriptor {
224   llvm::support::ulittle64_t start_of_memory_range;
225   MinidumpLocationDescriptor memory;
226 
227   static llvm::ArrayRef<MinidumpMemoryDescriptor>
228   ParseMemoryList(llvm::ArrayRef<uint8_t> &data);
229 };
230 static_assert(sizeof(MinidumpMemoryDescriptor) == 16,
231               "sizeof MinidumpMemoryDescriptor is not correct!");
232 
233 struct MinidumpMemoryDescriptor64 {
234   llvm::support::ulittle64_t start_of_memory_range;
235   llvm::support::ulittle64_t data_size;
236 
237   static std::pair<llvm::ArrayRef<MinidumpMemoryDescriptor64>, uint64_t>
238   ParseMemory64List(llvm::ArrayRef<uint8_t> &data);
239 };
240 static_assert(sizeof(MinidumpMemoryDescriptor64) == 16,
241               "sizeof MinidumpMemoryDescriptor64 is not correct!");
242 
243 // Reference:
244 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680365.aspx
245 struct MinidumpDirectory {
246   llvm::support::ulittle32_t stream_type;
247   MinidumpLocationDescriptor location;
248 };
249 static_assert(sizeof(MinidumpDirectory) == 12,
250               "sizeof MinidumpDirectory is not correct!");
251 
252 // Reference:
253 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx
254 struct MinidumpMemoryInfoListHeader {
255   llvm::support::ulittle32_t size_of_header;
256   llvm::support::ulittle32_t size_of_entry;
257   llvm::support::ulittle64_t num_of_entries;
258 };
259 static_assert(sizeof(MinidumpMemoryInfoListHeader) == 16,
260               "sizeof MinidumpMemoryInfoListHeader is not correct!");
261 
262 enum class MinidumpMemoryInfoState : uint32_t {
263   MemCommit = 0x1000,
264   MemFree = 0x10000,
265   MemReserve = 0x2000,
266   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemFree)
267 };
268 
269 enum class MinidumpMemoryInfoType : uint32_t {
270   MemImage = 0x1000000,
271   MemMapped = 0x40000,
272   MemPrivate = 0x20000,
273   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ MemImage)
274 };
275 
276 // Reference:
277 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx
278 enum class MinidumpMemoryProtectionContants : uint32_t {
279   PageExecute = 0x10,
280   PageExecuteRead = 0x20,
281   PageExecuteReadWrite = 0x40,
282   PageExecuteWriteCopy = 0x80,
283   PageNoAccess = 0x01,
284   PageReadOnly = 0x02,
285   PageReadWrite = 0x04,
286   PageWriteCopy = 0x08,
287   PageTargetsInvalid = 0x40000000,
288   PageTargetsNoUpdate = 0x40000000,
289 
290   PageWritable = PageExecuteReadWrite | PageExecuteWriteCopy | PageReadWrite |
291                  PageWriteCopy,
292   PageExecutable = PageExecute | PageExecuteRead | PageExecuteReadWrite |
293                    PageExecuteWriteCopy,
294   LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ PageTargetsInvalid)
295 };
296 
297 // Reference:
298 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx
299 struct MinidumpMemoryInfo {
300   llvm::support::ulittle64_t base_address;
301   llvm::support::ulittle64_t allocation_base;
302   llvm::support::ulittle32_t allocation_protect;
303   llvm::support::ulittle32_t alignment1;
304   llvm::support::ulittle64_t region_size;
305   llvm::support::ulittle32_t state;
306   llvm::support::ulittle32_t protect;
307   llvm::support::ulittle32_t type;
308   llvm::support::ulittle32_t alignment2;
309 
310   static std::vector<const MinidumpMemoryInfo *>
311   ParseMemoryInfoList(llvm::ArrayRef<uint8_t> &data);
312 
isReadableMinidumpMemoryInfo313   bool isReadable() const {
314     const auto mask = MinidumpMemoryProtectionContants::PageNoAccess;
315     return (static_cast<uint32_t>(mask) & protect) == 0;
316   }
317 
isWritableMinidumpMemoryInfo318   bool isWritable() const {
319     const auto mask = MinidumpMemoryProtectionContants::PageWritable;
320     return (static_cast<uint32_t>(mask) & protect) != 0;
321   }
322 
isExecutableMinidumpMemoryInfo323   bool isExecutable() const {
324     const auto mask = MinidumpMemoryProtectionContants::PageExecutable;
325     return (static_cast<uint32_t>(mask) & protect) != 0;
326   }
327 
isMappedMinidumpMemoryInfo328   bool isMapped() const {
329     return state != static_cast<uint32_t>(MinidumpMemoryInfoState::MemFree);
330   }
331 };
332 
333 static_assert(sizeof(MinidumpMemoryInfo) == 48,
334               "sizeof MinidumpMemoryInfo is not correct!");
335 
336 // Reference:
337 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx
338 struct MinidumpThread {
339   llvm::support::ulittle32_t thread_id;
340   llvm::support::ulittle32_t suspend_count;
341   llvm::support::ulittle32_t priority_class;
342   llvm::support::ulittle32_t priority;
343   llvm::support::ulittle64_t teb;
344   MinidumpMemoryDescriptor stack;
345   MinidumpLocationDescriptor thread_context;
346 
347   static const MinidumpThread *Parse(llvm::ArrayRef<uint8_t> &data);
348 
349   static llvm::ArrayRef<MinidumpThread>
350   ParseThreadList(llvm::ArrayRef<uint8_t> &data);
351 };
352 static_assert(sizeof(MinidumpThread) == 48,
353               "sizeof MinidumpThread is not correct!");
354 
355 // Reference:
356 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
357 union MinidumpCPUInfo {
358   struct {
359     llvm::support::ulittle32_t vendor_id[3];        /* cpuid 0: ebx, edx, ecx */
360     llvm::support::ulittle32_t version_information; /* cpuid 1: eax */
361     llvm::support::ulittle32_t feature_information; /* cpuid 1: edx */
362     llvm::support::ulittle32_t
363         amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
364   } x86_cpu_info;
365   struct {
366     llvm::support::ulittle32_t cpuid;
367     llvm::support::ulittle32_t elf_hwcaps; /* linux specific, 0 otherwise */
368   } arm_cpu_info;
369   struct {
370     llvm::support::ulittle64_t processor_features[2];
371   } other_cpu_info;
372 };
373 static_assert(sizeof(MinidumpCPUInfo) == 24,
374               "sizeof MinidumpCPUInfo is not correct!");
375 
376 // Reference:
377 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680396(v=vs.85).aspx
378 struct MinidumpSystemInfo {
379   llvm::support::ulittle16_t processor_arch;
380   llvm::support::ulittle16_t processor_level;
381   llvm::support::ulittle16_t processor_revision;
382 
383   uint8_t number_of_processors;
384   uint8_t product_type;
385 
386   llvm::support::ulittle32_t major_version;
387   llvm::support::ulittle32_t minor_version;
388   llvm::support::ulittle32_t build_number;
389   llvm::support::ulittle32_t platform_id;
390   llvm::support::ulittle32_t csd_version_rva;
391 
392   llvm::support::ulittle16_t suit_mask;
393   llvm::support::ulittle16_t reserved2;
394 
395   MinidumpCPUInfo cpu;
396 
397   static const MinidumpSystemInfo *Parse(llvm::ArrayRef<uint8_t> &data);
398 };
399 static_assert(sizeof(MinidumpSystemInfo) == 56,
400               "sizeof MinidumpSystemInfo is not correct!");
401 
402 // TODO misc2, misc3 ?
403 // Reference:
404 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680389(v=vs.85).aspx
405 struct MinidumpMiscInfo {
406   llvm::support::ulittle32_t size;
407   // flags1 represents what info in the struct is valid
408   llvm::support::ulittle32_t flags1;
409   llvm::support::ulittle32_t process_id;
410   llvm::support::ulittle32_t process_create_time;
411   llvm::support::ulittle32_t process_user_time;
412   llvm::support::ulittle32_t process_kernel_time;
413 
414   static const MinidumpMiscInfo *Parse(llvm::ArrayRef<uint8_t> &data);
415 
416   llvm::Optional<lldb::pid_t> GetPid() const;
417 };
418 static_assert(sizeof(MinidumpMiscInfo) == 24,
419               "sizeof MinidumpMiscInfo is not correct!");
420 
421 // The /proc/pid/status is saved as an ascii string in the file
422 class LinuxProcStatus {
423 public:
424   llvm::StringRef proc_status;
425   lldb::pid_t pid;
426 
427   static llvm::Optional<LinuxProcStatus> Parse(llvm::ArrayRef<uint8_t> &data);
428 
429   lldb::pid_t GetPid() const;
430 
431 private:
432   LinuxProcStatus() = default;
433 };
434 
435 // MinidumpModule stuff
436 struct MinidumpVSFixedFileInfo {
437   llvm::support::ulittle32_t signature;
438   llvm::support::ulittle32_t struct_version;
439   llvm::support::ulittle32_t file_version_hi;
440   llvm::support::ulittle32_t file_version_lo;
441   llvm::support::ulittle32_t product_version_hi;
442   llvm::support::ulittle32_t product_version_lo;
443   // file_flags_mask - identifies valid bits in fileFlags
444   llvm::support::ulittle32_t file_flags_mask;
445   llvm::support::ulittle32_t file_flags;
446   llvm::support::ulittle32_t file_os;
447   llvm::support::ulittle32_t file_type;
448   llvm::support::ulittle32_t file_subtype;
449   llvm::support::ulittle32_t file_date_hi;
450   llvm::support::ulittle32_t file_date_lo;
451 };
452 static_assert(sizeof(MinidumpVSFixedFileInfo) == 52,
453               "sizeof MinidumpVSFixedFileInfo is not correct!");
454 
455 struct MinidumpModule {
456   llvm::support::ulittle64_t base_of_image;
457   llvm::support::ulittle32_t size_of_image;
458   llvm::support::ulittle32_t checksum;
459   llvm::support::ulittle32_t time_date_stamp;
460   llvm::support::ulittle32_t module_name_rva;
461   MinidumpVSFixedFileInfo version_info;
462   MinidumpLocationDescriptor CV_record;
463   MinidumpLocationDescriptor misc_record;
464   llvm::support::ulittle32_t reserved0[2];
465   llvm::support::ulittle32_t reserved1[2];
466 
467   static const MinidumpModule *Parse(llvm::ArrayRef<uint8_t> &data);
468 
469   static llvm::ArrayRef<MinidumpModule>
470   ParseModuleList(llvm::ArrayRef<uint8_t> &data);
471 };
472 static_assert(sizeof(MinidumpModule) == 108,
473               "sizeof MinidumpVSFixedFileInfo is not correct!");
474 
475 // Exception stuff
476 struct MinidumpException {
477   enum : unsigned {
478     ExceptonInfoMaxParams = 15,
479     DumpRequested = 0xFFFFFFFF,
480   };
481 
482   llvm::support::ulittle32_t exception_code;
483   llvm::support::ulittle32_t exception_flags;
484   llvm::support::ulittle64_t exception_record;
485   llvm::support::ulittle64_t exception_address;
486   llvm::support::ulittle32_t number_parameters;
487   llvm::support::ulittle32_t unused_alignment;
488   llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams];
489 };
490 static_assert(sizeof(MinidumpException) == 152,
491               "sizeof MinidumpException is not correct!");
492 
493 struct MinidumpExceptionStream {
494   llvm::support::ulittle32_t thread_id;
495   llvm::support::ulittle32_t alignment;
496   MinidumpException exception_record;
497   MinidumpLocationDescriptor thread_context;
498 
499   static const MinidumpExceptionStream *Parse(llvm::ArrayRef<uint8_t> &data);
500 };
501 static_assert(sizeof(MinidumpExceptionStream) == 168,
502               "sizeof MinidumpExceptionStream is not correct!");
503 
504 } // namespace minidump
505 } // namespace lldb_private
506 #endif // liblldb_MinidumpTypes_h_
507