From c9f80bf1a8d8060c812e8cedbbd0129ec2d1fb21 Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Fri, 19 Aug 2016 13:29:36 -0400 Subject: [PATCH] Update MDRawMiscInfo to support version 5 of the MINIDUMP_MISC_INFO_N structure. The routines used to read from the structure were also modified to accomodate for unknown future versions by skipping over the unsupported part instead of failing. R=ted.mielczarek@gmail.com Review URL: https://codereview.chromium.org/2109063004/ . --- src/google_breakpad/common/minidump_format.h | 61 +++++++++++++- src/processor/minidump.cc | 87 ++++++++++++++++++-- 2 files changed, 139 insertions(+), 9 deletions(-) diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h index 645c56c5..251e503d 100644 --- a/src/google_breakpad/common/minidump_format.h +++ b/src/google_breakpad/common/minidump_format.h @@ -721,6 +721,41 @@ typedef struct { /* MAX_PATH from windef.h */ #define MD_MAX_PATH 260 +/* For MDXStateConfigFeatureMscInfo.features */ +typedef struct { + uint32_t offset; + uint32_t size; +} MDXStateFeature; + +/* For MDXStateConfigFeatureMscInfo.enabled_features from winnt.h */ +typedef enum { + MD_XSTATE_LEGACY_FLOATING_POINT = 0, /* XSTATE_LEGACY_FLOATING_POINT */ + MD_XSTATE_LEGACY_SSE = 1, /* XSTATE_LEGACY_SSE */ + MD_XSTATE_GSSE = 2, /* XSTATE_GSSE */ + MD_XSTATE_AVX = MD_XSTATE_GSSE, /* XSTATE_AVX */ + MD_XSTATE_MPX_BNDREGS = 3, /* XSTATE_MPX_BNDREGS */ + MD_XSTATE_MPX_BNDCSR = 4, /* XSTATE_MPX_BNDCSR */ + MD_XSTATE_AVX512_KMASK = 5, /* XSTATE_AVX512_KMASK */ + MD_XSTATE_AVX512_ZMM_H = 6, /* XSTATE_AVX512_ZMM_H */ + MD_XSTATE_AVX512_ZMM = 7, /* XSTATE_AVX512_ZMM */ + MD_XSTATE_IPT = 8, /* XSTATE_IPT */ + MD_XSTATE_LWP = 62 /* XSTATE_LWP */ +} MDXStateFeatureFlag; + +/* MAXIMUM_XSTATE_FEATURES from winnt.h */ +#define MD_MAXIMUM_XSTATE_FEATURES 64 + +/* For MDRawMiscInfo.xstate_data */ +typedef struct { + uint32_t size_of_info; + uint32_t context_size; + /* An entry in the features array is valid only if the corresponding bit in + * the enabled_features flag is set. */ + uint64_t enabled_features; + MDXStateFeature features[MD_MAXIMUM_XSTATE_FEATURES]; +} MDXStateConfigFeatureMscInfo; + + /* The miscellaneous information stream contains a variety * of small pieces of information. A member is valid if * it's within the available size and its corresponding @@ -781,9 +816,22 @@ typedef struct { * MD_MISCINFO_FLAGS1_BUILDSTRING. */ uint16_t build_string[MD_MAX_PATH]; /* UTF-16-encoded, 0-terminated */ uint16_t dbg_bld_str[40]; /* UTF-16-encoded, 0-terminated */ + + /* The following fields are not present in MINIDUMP_MISC_INFO_4 but are + * in MINIDUMP_MISC_INFO_5. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following field has its own flags for establishing the validity of + * the structure's contents.*/ + MDXStateConfigFeatureMscInfo xstate_data; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_COOKIE. */ + uint32_t process_cookie; } MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO_2, * MINIDUMP_MISC_INFO_3, MINIDUMP_MISC_INFO_4, - * MINIDUMP_MISC_INFO_N */ + * MINIDUMP_MISC_INFO_5, MINIDUMP_MISC_INFO_N */ static const size_t MD_MISCINFO_SIZE = offsetof(MDRawMiscInfo, processor_max_mhz); @@ -791,7 +839,14 @@ static const size_t MD_MISCINFO2_SIZE = offsetof(MDRawMiscInfo, process_integrity_level); static const size_t MD_MISCINFO3_SIZE = offsetof(MDRawMiscInfo, build_string[0]); -static const size_t MD_MISCINFO4_SIZE = sizeof(MDRawMiscInfo); +static const size_t MD_MISCINFO4_SIZE = + offsetof(MDRawMiscInfo, xstate_data); +/* Version 5 of the MDRawMiscInfo structure is not a multiple of 8 in size and + * yet it contains some 8-bytes sized fields. This causes many compilers to + * round the structure size up to a multiple of 8 by adding padding at the end. + * The following hack is thus required for matching the proper on-disk size. */ +static const size_t MD_MISCINFO5_SIZE = + offsetof(MDRawMiscInfo, process_cookie) + sizeof(uint32_t); /* For (MDRawMiscInfo).flags1. These values indicate which fields in the * MDRawMiscInfoStructure are valid. */ @@ -812,6 +867,8 @@ typedef enum { /* MINIDUMP_MISC3_PROTECTED_PROCESS */ MD_MISCINFO_FLAGS1_BUILDSTRING = 0x00000100, /* MINIDUMP_MISC4_BUILDSTRING */ + MD_MISCINFO_FLAGS1_PROCESS_COOKIE = 0x00000200, + /* MINIDUMP_MISC5_PROCESS_COOKIE */ } MDMiscInfoFlags1; /* diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index f94a409a..1e1d386d 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -197,6 +197,21 @@ static inline void Swap(MDSystemTime* system_time) { Swap(&system_time->milliseconds); } +static inline void Swap(MDXStateFeature* xstate_feature) { + Swap(&xstate_feature->offset); + Swap(&xstate_feature->size); +} + +static inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) { + Swap(&xstate_feature_info->size_of_info); + Swap(&xstate_feature_info->context_size); + Swap(&xstate_feature_info->enabled_features); + + for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) { + Swap(&xstate_feature_info->features[i]); + } +} + static inline void Swap(uint16_t* data, size_t size_in_bytes) { size_t data_length = size_in_bytes / sizeof(data[0]); for (size_t i = 0; i < data_length; i++) { @@ -3508,15 +3523,25 @@ MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump) bool MinidumpMiscInfo::Read(uint32_t expected_size) { valid_ = false; + size_t padding = 0; if (expected_size != MD_MISCINFO_SIZE && expected_size != MD_MISCINFO2_SIZE && expected_size != MD_MISCINFO3_SIZE && - expected_size != MD_MISCINFO4_SIZE) { - BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size - << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE - << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE - << ")"; - return false; + expected_size != MD_MISCINFO4_SIZE && + expected_size != MD_MISCINFO5_SIZE) { + if (expected_size > MD_MISCINFO5_SIZE) { + // Only read the part of the misc info structure we know how to handle + BPLOG(INFO) << "MinidumpMiscInfo size larger than expected " + << expected_size << ", skipping over the unknown part"; + padding = expected_size - MD_MISCINFO5_SIZE; + expected_size = MD_MISCINFO5_SIZE; + } else { + BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size + << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE + << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE + << ", " << MD_MISCINFO5_SIZE << ")"; + return false; + } } if (!minidump_->ReadBytes(&misc_info_, expected_size)) { @@ -3524,6 +3549,20 @@ bool MinidumpMiscInfo::Read(uint32_t expected_size) { return false; } + if (padding != 0) { + off_t saved_position = minidump_->Tell(); + if (saved_position == -1) { + BPLOG(ERROR) << "MinidumpMiscInfo could not tell the current position"; + return false; + } + + if (!minidump_->SeekSet(saved_position + padding)) { + BPLOG(ERROR) << "MinidumpMiscInfo could not seek past the miscellaneous " + << "info structure"; + return false; + } + } + if (minidump_->swap()) { // Swap version 1 fields Swap(&misc_info_.size_of_info); @@ -3553,9 +3592,14 @@ bool MinidumpMiscInfo::Read(uint32_t expected_size) { // Do not swap UTF-16 strings. The swap is done as part of the // conversion to UTF-8 (code follows below). } + if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) { + // Swap version 5 fields + Swap(&misc_info_.xstate_data); + Swap(&misc_info_.process_cookie); + } } - if (expected_size != misc_info_.size_of_info) { + if (expected_size + padding != misc_info_.size_of_info) { BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size << " != " << misc_info_.size_of_info; return false; @@ -3705,6 +3749,35 @@ void MinidumpMiscInfo::Print() { printf(" dbg_bld_str = (invalid)\n"); } } + if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) { + // Print version 5 fields + if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_COOKIE) { + printf(" xstate_data.size_of_info = %d\n", + misc_info_.xstate_data.size_of_info); + printf(" xstate_data.context_size = %d\n", + misc_info_.xstate_data.context_size); + printf(" xstate_data.enabled_features = 0x%" PRIx64 "\n", + misc_info_.xstate_data.enabled_features); + for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) { + if (misc_info_.xstate_data.enabled_features & (1 << i)) { + printf(" xstate_data.features[%02zu] = { %d, %d }\n", i, + misc_info_.xstate_data.features[i].offset, + misc_info_.xstate_data.features[i].size); + } + } + if (misc_info_.xstate_data.enabled_features == 0) { + printf(" xstate_data.features[] = (empty)\n"); + } + printf(" process_cookie = %d\n", + misc_info_.process_cookie); + } else { + printf(" xstate_data.size_of_info = (invalid)\n"); + printf(" xstate_data.context_size = (invalid)\n"); + printf(" xstate_data.enabled_features = (invalid)\n"); + printf(" xstate_data.features[] = (invalid)\n"); + printf(" process_cookie = (invalid)\n"); + } + } printf("\n"); }