Adjust MD_CONTEXT_CPU_MASK to reflect reality, fix some code so it can handle dumps using the old value for MD_CONTEXT_ARM

The value of MD_CONTEXT_CPU_MASK in use assumes that only the lower 6 bits are used for flags, and the upper 26 bits are for the CPU type. However, as of Windows 7 SP1, the 7th bit is being used as a flag (per http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx and the Windows SDK headers). Adjusting MD_CONTEXT_CPU_MASK works, but unfortunately that masks off the existing value of MD_CONTEXT_ARM. This patch also changes the value of MD_CONTEXT_ARM and adjusts the minidump context reading machinery to gracefully handle minidumps with the old value.
R=mark at http://breakpad.appspot.com/302001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@831 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek 2011-08-30 22:22:08 +00:00
parent 8ade75f955
commit 1a1890a52a
10 changed files with 658 additions and 42 deletions

View file

@ -201,8 +201,9 @@ typedef struct {
} MDRawContextAMD64; /* CONTEXT */
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
* context stored in the structure. The high 26 bits identify the CPU, the
* low 6 bits identify the type of context saved. */
* context stored in the structure. The high 24 bits identify the CPU, the
* low 8 bits identify the type of context saved. */
#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */
#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001)
/* CONTEXT_CONTROL */
#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002)
@ -213,6 +214,9 @@ typedef struct {
/* CONTEXT_FLOATING_POINT */
#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
/* CONTEXT_DEBUG_REGISTERS */
#define MD_CONTEXT_AMD64_XSTATE (MD_CONTEXT_AMD64 | 0x00000040)
/* CONTEXT_XSTATE */
/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
* I think it really means CONTEXT_FLOATING_POINT.
*/

View file

@ -128,6 +128,16 @@ enum MDARMRegisterNumbers {
/* For (MDRawContextARM).context_flags. These values indicate the type of
* context stored in the structure. */
/* CONTEXT_ARM from the Windows CE 5.0 SDK. This value isn't correct
* because this bit can be used for flags. Presumably this value was
* never actually used in minidumps, but only in "CEDumps" which
* are a whole parallel minidump file format for Windows CE.
* Therefore, Breakpad defines its own value for ARM CPUs.
*/
#define MD_CONTEXT_ARM_OLD 0x00000040
/* This value was chosen to avoid likely conflicts with MD_CONTEXT_*
* for other CPUs. */
#define MD_CONTEXT_ARM 0x40000000
#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002)
#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004)

View file

@ -141,8 +141,8 @@ typedef struct {
} MDRawContextX86; /* CONTEXT */
/* For (MDRawContextX86).context_flags. These values indicate the type of
* context stored in the structure. The high 26 bits identify the CPU, the
* low 6 bits identify the type of context saved. */
* context stored in the structure. The high 24 bits identify the CPU, the
* low 8 bits identify the type of context saved. */
#define MD_CONTEXT_X86 0x00010000
/* CONTEXT_i386, CONTEXT_i486: identifies CPU */
#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001)
@ -157,6 +157,8 @@ typedef struct {
/* CONTEXT_DEBUG_REGISTERS */
#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
/* CONTEXT_EXTENDED_REGISTERS */
#define MD_CONTEXT_X86_XSTATE (MD_CONTEXT_X86 | 0x00000040)
/* CONTEXT_XSTATE */
#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \
MD_CONTEXT_X86_INTEGER | \

View file

@ -90,19 +90,20 @@ typedef struct {
* WinNT.h
*/
/* Non-x86 CPU identifiers found in the high 26 bits of
/* Non-x86 CPU identifiers found in the high 24 bits of
* (MDRawContext*).context_flags. These aren't used by Breakpad, but are
* defined here for reference, to avoid assigning values that conflict
* (although some values already conflict). */
#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */
#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */
/* Additional values from winnt.h in the Windows CE 5.0 SDK: */
#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */
#define MD_CONTEXT_ARM 0x00000040 /* CONTEXT_ARM (0x40 bit set in SHx?) */
#define MD_CONTEXT_MIPS 0x00010000 /* CONTEXT_R4000 (same value as x86?) */
#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */
#define MD_CONTEXT_CPU_MASK 0xffffffc0
/* As of Windows 7 SP1, the number of flag bits has increased to
* include 0x40 (CONTEXT_XSTATE):
* http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx */
#define MD_CONTEXT_CPU_MASK 0xffffff00
/* This is a base type for MDRawContextX86 and MDRawContextPPC. This

View file

@ -410,6 +410,17 @@ bool MinidumpContext::Read(u_int32_t expected_size) {
Swap(&context_flags);
u_int32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
if (cpu_type == 0) {
// Unfortunately the flag for MD_CONTEXT_ARM that was taken
// from a Windows CE SDK header conflicts in practice with
// the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
// but handle dumps with the legacy value gracefully here.
if (context_flags & MD_CONTEXT_ARM_OLD) {
context_flags |= MD_CONTEXT_ARM;
context_flags &= ~MD_CONTEXT_ARM_OLD;
cpu_type = MD_CONTEXT_ARM;
}
}
// Allocate the context structure for the correct CPU and fill it. The
// casts are slightly unorthodox, but it seems better to do that than to

View file

@ -46,6 +46,7 @@ namespace {
using google_breakpad::Minidump;
using google_breakpad::MinidumpContext;
using google_breakpad::MinidumpException;
using google_breakpad::MinidumpMemoryInfo;
using google_breakpad::MinidumpMemoryInfoList;
using google_breakpad::MinidumpMemoryList;
@ -57,6 +58,7 @@ using google_breakpad::MinidumpThread;
using google_breakpad::MinidumpThreadList;
using google_breakpad::SynthMinidump::Context;
using google_breakpad::SynthMinidump::Dump;
using google_breakpad::SynthMinidump::Exception;
using google_breakpad::SynthMinidump::Memory;
using google_breakpad::SynthMinidump::Module;
using google_breakpad::SynthMinidump::Stream;
@ -588,4 +590,318 @@ TEST(Dump, OneMemoryInfo) {
ASSERT_EQ(kRegionSize, info2->GetSize());
}
TEST(Dump, OneExceptionX86) {
Dump dump(0, kLittleEndian);
MDRawContextX86 raw_context;
raw_context.context_flags = MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL;
raw_context.edi = 0x3ecba80d;
raw_context.esi = 0x382583b9;
raw_context.ebx = 0x7fccc03f;
raw_context.edx = 0xf62f8ec2;
raw_context.ecx = 0x46a6a6a8;
raw_context.eax = 0x6a5025e2;
raw_context.ebp = 0xd9fabb4a;
raw_context.eip = 0x6913f540;
raw_context.cs = 0xbffe6eda;
raw_context.eflags = 0xb2ce1e2d;
raw_context.esp = 0x659caaa4;
raw_context.ss = 0x2e951ef7;
Context context(dump, raw_context);
Exception exception(dump, context,
0x1234abcd, // thread id
0xdcba4321, // exception code
0xf0e0d0c0, // exception flags
0x0919a9b9c9d9e9f9ULL); // exception address
dump.Add(&context);
dump.Add(&exception);
dump.Finish();
string contents;
ASSERT_TRUE(dump.GetContents(&contents));
istringstream minidump_stream(contents);
Minidump minidump(minidump_stream);
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
MinidumpException *md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
u_int32_t thread_id;
ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
ASSERT_EQ(0x1234abcd, thread_id);
const MDRawExceptionStream* raw_exception = md_exception->exception();
ASSERT_TRUE(raw_exception != NULL);
EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
MinidumpContext *md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((u_int32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
(md_raw_context->context_flags
& (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
EXPECT_EQ(0x3ecba80dU, raw_context.edi);
EXPECT_EQ(0x382583b9U, raw_context.esi);
EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
EXPECT_EQ(0x6a5025e2U, raw_context.eax);
EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
EXPECT_EQ(0x6913f540U, raw_context.eip);
EXPECT_EQ(0xbffe6edaU, raw_context.cs);
EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
EXPECT_EQ(0x659caaa4U, raw_context.esp);
EXPECT_EQ(0x2e951ef7U, raw_context.ss);
}
TEST(Dump, OneExceptionX86XState) {
Dump dump(0, kLittleEndian);
MDRawContextX86 raw_context;
raw_context.context_flags = MD_CONTEXT_X86_INTEGER |
MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_XSTATE;
raw_context.edi = 0x3ecba80d;
raw_context.esi = 0x382583b9;
raw_context.ebx = 0x7fccc03f;
raw_context.edx = 0xf62f8ec2;
raw_context.ecx = 0x46a6a6a8;
raw_context.eax = 0x6a5025e2;
raw_context.ebp = 0xd9fabb4a;
raw_context.eip = 0x6913f540;
raw_context.cs = 0xbffe6eda;
raw_context.eflags = 0xb2ce1e2d;
raw_context.esp = 0x659caaa4;
raw_context.ss = 0x2e951ef7;
Context context(dump, raw_context);
Exception exception(dump, context,
0x1234abcd, // thread id
0xdcba4321, // exception code
0xf0e0d0c0, // exception flags
0x0919a9b9c9d9e9f9ULL); // exception address
dump.Add(&context);
dump.Add(&exception);
dump.Finish();
string contents;
ASSERT_TRUE(dump.GetContents(&contents));
istringstream minidump_stream(contents);
Minidump minidump(minidump_stream);
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
MinidumpException *md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
u_int32_t thread_id;
ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
ASSERT_EQ(0x1234abcd, thread_id);
const MDRawExceptionStream* raw_exception = md_exception->exception();
ASSERT_TRUE(raw_exception != NULL);
EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
MinidumpContext *md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_X86, md_context->GetContextCPU());
const MDRawContextX86 *md_raw_context = md_context->GetContextX86();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((u_int32_t) (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL),
(md_raw_context->context_flags
& (MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_CONTROL)));
EXPECT_EQ(0x3ecba80dU, raw_context.edi);
EXPECT_EQ(0x382583b9U, raw_context.esi);
EXPECT_EQ(0x7fccc03fU, raw_context.ebx);
EXPECT_EQ(0xf62f8ec2U, raw_context.edx);
EXPECT_EQ(0x46a6a6a8U, raw_context.ecx);
EXPECT_EQ(0x6a5025e2U, raw_context.eax);
EXPECT_EQ(0xd9fabb4aU, raw_context.ebp);
EXPECT_EQ(0x6913f540U, raw_context.eip);
EXPECT_EQ(0xbffe6edaU, raw_context.cs);
EXPECT_EQ(0xb2ce1e2dU, raw_context.eflags);
EXPECT_EQ(0x659caaa4U, raw_context.esp);
EXPECT_EQ(0x2e951ef7U, raw_context.ss);
}
TEST(Dump, OneExceptionARM) {
Dump dump(0, kLittleEndian);
MDRawContextARM raw_context;
raw_context.context_flags = MD_CONTEXT_ARM_INTEGER;
raw_context.iregs[0] = 0x3ecba80d;
raw_context.iregs[1] = 0x382583b9;
raw_context.iregs[2] = 0x7fccc03f;
raw_context.iregs[3] = 0xf62f8ec2;
raw_context.iregs[4] = 0x46a6a6a8;
raw_context.iregs[5] = 0x6a5025e2;
raw_context.iregs[6] = 0xd9fabb4a;
raw_context.iregs[7] = 0x6913f540;
raw_context.iregs[8] = 0xbffe6eda;
raw_context.iregs[9] = 0xb2ce1e2d;
raw_context.iregs[10] = 0x659caaa4;
raw_context.iregs[11] = 0xf0e0d0c0;
raw_context.iregs[12] = 0xa9b8c7d6;
raw_context.iregs[13] = 0x12345678;
raw_context.iregs[14] = 0xabcd1234;
raw_context.iregs[15] = 0x10203040;
raw_context.cpsr = 0x2e951ef7;
Context context(dump, raw_context);
Exception exception(dump, context,
0x1234abcd, // thread id
0xdcba4321, // exception code
0xf0e0d0c0, // exception flags
0x0919a9b9c9d9e9f9ULL); // exception address
dump.Add(&context);
dump.Add(&exception);
dump.Finish();
string contents;
ASSERT_TRUE(dump.GetContents(&contents));
istringstream minidump_stream(contents);
Minidump minidump(minidump_stream);
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
MinidumpException *md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
u_int32_t thread_id;
ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
ASSERT_EQ(0x1234abcd, thread_id);
const MDRawExceptionStream* raw_exception = md_exception->exception();
ASSERT_TRUE(raw_exception != NULL);
EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
MinidumpContext *md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
const MDRawContextARM *md_raw_context = md_context->GetContextARM();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_ARM_INTEGER,
(md_raw_context->context_flags
& MD_CONTEXT_ARM_INTEGER));
EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
}
TEST(Dump, OneExceptionARMOldFlags) {
Dump dump(0, kLittleEndian);
MDRawContextARM raw_context;
// MD_CONTEXT_ARM_INTEGER, but with _OLD
raw_context.context_flags = MD_CONTEXT_ARM_OLD | 0x00000002;
raw_context.iregs[0] = 0x3ecba80d;
raw_context.iregs[1] = 0x382583b9;
raw_context.iregs[2] = 0x7fccc03f;
raw_context.iregs[3] = 0xf62f8ec2;
raw_context.iregs[4] = 0x46a6a6a8;
raw_context.iregs[5] = 0x6a5025e2;
raw_context.iregs[6] = 0xd9fabb4a;
raw_context.iregs[7] = 0x6913f540;
raw_context.iregs[8] = 0xbffe6eda;
raw_context.iregs[9] = 0xb2ce1e2d;
raw_context.iregs[10] = 0x659caaa4;
raw_context.iregs[11] = 0xf0e0d0c0;
raw_context.iregs[12] = 0xa9b8c7d6;
raw_context.iregs[13] = 0x12345678;
raw_context.iregs[14] = 0xabcd1234;
raw_context.iregs[15] = 0x10203040;
raw_context.cpsr = 0x2e951ef7;
Context context(dump, raw_context);
Exception exception(dump, context,
0x1234abcd, // thread id
0xdcba4321, // exception code
0xf0e0d0c0, // exception flags
0x0919a9b9c9d9e9f9ULL); // exception address
dump.Add(&context);
dump.Add(&exception);
dump.Finish();
string contents;
ASSERT_TRUE(dump.GetContents(&contents));
istringstream minidump_stream(contents);
Minidump minidump(minidump_stream);
ASSERT_TRUE(minidump.Read());
ASSERT_EQ(1U, minidump.GetDirectoryEntryCount());
MinidumpException *md_exception = minidump.GetException();
ASSERT_TRUE(md_exception != NULL);
u_int32_t thread_id;
ASSERT_TRUE(md_exception->GetThreadID(&thread_id));
ASSERT_EQ(0x1234abcd, thread_id);
const MDRawExceptionStream* raw_exception = md_exception->exception();
ASSERT_TRUE(raw_exception != NULL);
EXPECT_EQ(0xdcba4321, raw_exception->exception_record.exception_code);
EXPECT_EQ(0xf0e0d0c0, raw_exception->exception_record.exception_flags);
EXPECT_EQ(0x0919a9b9c9d9e9f9ULL,
raw_exception->exception_record.exception_address);
MinidumpContext *md_context = md_exception->GetContext();
ASSERT_TRUE(md_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_ARM, md_context->GetContextCPU());
const MDRawContextARM *md_raw_context = md_context->GetContextARM();
ASSERT_TRUE(md_raw_context != NULL);
ASSERT_EQ((u_int32_t) MD_CONTEXT_ARM_INTEGER,
(md_raw_context->context_flags
& MD_CONTEXT_ARM_INTEGER));
EXPECT_EQ(0x3ecba80dU, raw_context.iregs[0]);
EXPECT_EQ(0x382583b9U, raw_context.iregs[1]);
EXPECT_EQ(0x7fccc03fU, raw_context.iregs[2]);
EXPECT_EQ(0xf62f8ec2U, raw_context.iregs[3]);
EXPECT_EQ(0x46a6a6a8U, raw_context.iregs[4]);
EXPECT_EQ(0x6a5025e2U, raw_context.iregs[5]);
EXPECT_EQ(0xd9fabb4aU, raw_context.iregs[6]);
EXPECT_EQ(0x6913f540U, raw_context.iregs[7]);
EXPECT_EQ(0xbffe6edaU, raw_context.iregs[8]);
EXPECT_EQ(0xb2ce1e2dU, raw_context.iregs[9]);
EXPECT_EQ(0x659caaa4U, raw_context.iregs[10]);
EXPECT_EQ(0xf0e0d0c0U, raw_context.iregs[11]);
EXPECT_EQ(0xa9b8c7d6U, raw_context.iregs[12]);
EXPECT_EQ(0x12345678U, raw_context.iregs[13]);
EXPECT_EQ(0xabcd1234U, raw_context.iregs[14]);
EXPECT_EQ(0x10203040U, raw_context.iregs[15]);
EXPECT_EQ(0x2e951ef7U, raw_context.cpsr);
}
} // namespace

View file

@ -170,6 +170,25 @@ Context::Context(const Dump &dump, const MDRawContextX86 &context)
assert(Size() == sizeof(MDRawContextX86));
}
Context::Context(const Dump &dump, const MDRawContextARM &context)
: Section(dump) {
// The caller should have properly set the CPU type flag.
assert((context.context_flags & MD_CONTEXT_ARM) ||
(context.context_flags & MD_CONTEXT_ARM_OLD));
// It doesn't make sense to store ARM registers in big-endian form.
assert(dump.endianness() == kLittleEndian);
D32(context.context_flags);
for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
D32(context.iregs[i]);
D32(context.cpsr);
D64(context.float_save.fpscr);
for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i)
D64(context.float_save.regs[i]);
for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i)
D32(context.float_save.extra[i]);
assert(Size() == sizeof(MDRawContextARM));
}
Thread::Thread(const Dump &dump,
u_int32_t thread_id, const Memory &stack, const Context &context,
u_int32_t suspend_count, u_int32_t priority_class,
@ -231,7 +250,28 @@ const MDVSFixedFileInfo Module::stock_version_info = {
MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype
0, // file_date_hi
0 // file_date_lo
};
};
Exception::Exception(const Dump &dump,
const Context &context,
u_int32_t thread_id,
u_int32_t exception_code,
u_int32_t exception_flags,
u_int64_t exception_address)
: Stream(dump, MD_EXCEPTION_STREAM) {
D32(thread_id);
D32(0); // __align
D32(exception_code);
D32(exception_flags);
D64(0); // exception_record
D64(exception_address);
D32(0); // number_parameters
D32(0); // __align
for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
D64(0); // exception_information
context.CiteLocationIn(this);
assert(Size() == sizeof(MDRawExceptionStream));
}
Dump::Dump(u_int64_t flags,
Endianness endianness,

View file

@ -196,7 +196,7 @@ class SystemInfo: public Stream {
static const string windows_x86_csd_version;
};
// An MDString: a string predeced by a 32-bit length.
// An MDString: a string preceded by a 32-bit length.
class String: public Section {
public:
String(const Dump &dump, const string &value);
@ -227,6 +227,7 @@ class Context: public Section {
public:
// Create a context belonging to DUMP whose contents are a copy of CONTEXT.
Context(const Dump &dump, const MDRawContextX86 &context);
Context(const Dump &dump, const MDRawContextARM &context);
// Add constructors for other architectures here. Remember to byteswap.
};
@ -266,6 +267,16 @@ class Module: public Section {
static const MDVSFixedFileInfo stock_version_info;
};
class Exception : public Stream {
public:
Exception(const Dump &dump,
const Context &context,
u_int32_t thread_id = 0,
u_int32_t exception_code = 0,
u_int32_t exception_flags = 0,
u_int64_t exception_address = 0);
};
// A list of entries starting with a 32-bit count, like a memory list
// or a thread list.
template<typename Element>

View file

@ -42,6 +42,7 @@
using google_breakpad::SynthMinidump::Context;
using google_breakpad::SynthMinidump::Dump;
using google_breakpad::SynthMinidump::Exception;
using google_breakpad::SynthMinidump::List;
using google_breakpad::SynthMinidump::Memory;
using google_breakpad::SynthMinidump::Module;
@ -133,6 +134,17 @@ TEST(Context, X86) {
== 0);
}
TEST(Context, ARM) {
Dump dump(0, kLittleEndian);
assert(arm_raw_context.context_flags & MD_CONTEXT_ARM);
Context context(dump, arm_raw_context);
string contents;
ASSERT_TRUE(context.GetContents(&contents));
EXPECT_EQ(sizeof(arm_expected_contents), contents.size());
EXPECT_TRUE(memcmp(contents.data(), arm_expected_contents, contents.size())
== 0);
}
TEST(ContextDeathTest, X86BadFlags) {
Dump dump(0, kLittleEndian);
MDRawContextX86 raw;
@ -179,6 +191,49 @@ TEST(Thread, Simple) {
EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
}
TEST(Exception, Simple) {
Dump dump(0, kLittleEndian);
Context context(dump, x86_raw_context);
context.Finish(0x8665da0c);
Exception exception(dump, context,
0x1234abcd, // thread id
0xdcba4321, // exception code
0xf0e0d0c0, // exception flags
0x0919a9b9c9d9e9f9ULL); // exception address
string contents;
ASSERT_TRUE(exception.GetContents(&contents));
static const u_int8_t expected_bytes[] = {
0xcd, 0xab, 0x34, 0x12, // thread id
0x00, 0x00, 0x00, 0x00, // __align
0x21, 0x43, 0xba, 0xdc, // exception code
0xc0, 0xd0, 0xe0, 0xf0, // exception flags
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception record
0xf9, 0xe9, 0xd9, 0xc9, 0xb9, 0xa9, 0x19, 0x09, // exception address
0x00, 0x00, 0x00, 0x00, // number parameters
0x00, 0x00, 0x00, 0x00, // __align
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exception_information
0xcc, 0x02, 0x00, 0x00, // context size
0x0c, 0xda, 0x65, 0x86 // context MDRVA
};
EXPECT_EQ(sizeof(expected_bytes), contents.size());
EXPECT_TRUE(memcmp(contents.data(), expected_bytes, contents.size()) == 0);
}
TEST(String, Simple) {
Dump dump(0, kBigEndian);
String s(dump, "All mimsy were the borogoves");

View file

@ -43,7 +43,7 @@ static const MDRawContextX86 x86_raw_context = {
0x84c53a90, // cr0_npx_state
},
0x79f71e76, // gs
0x8107bd25, // fs
0x452d2921, // es
@ -131,20 +131,20 @@ static const MDRawContextX86 x86_raw_context = {
};
static const u_int8_t x86_expected_contents[] = {
0x1b, 0xd7, 0xd5, 0xde,
0x2e, 0x43, 0xdb, 0x9f,
0x1a, 0xa8, 0xb7, 0x26,
0x48, 0xe3, 0xc7, 0xca,
0x09, 0xec, 0x99, 0xcf,
0xcd, 0xc2, 0xc8, 0x7d,
0x80, 0xb8, 0xde, 0x21,
0xb0, 0x2b, 0x5d, 0x8a,
0xc9, 0xc4, 0x86, 0x02,
0x21, 0xea, 0xfe, 0xf1,
0x76, 0x05, 0xd4, 0xb2,
0xde, 0x6c, 0x14, 0x48,
0x21, 0x9b, 0x3f, 0x98,
0x2c, 0xe1, 0x5b, 0x47,
0x1b, 0xd7, 0xd5, 0xde,
0x2e, 0x43, 0xdb, 0x9f,
0x1a, 0xa8, 0xb7, 0x26,
0x48, 0xe3, 0xc7, 0xca,
0x09, 0xec, 0x99, 0xcf,
0xcd, 0xc2, 0xc8, 0x7d,
0x80, 0xb8, 0xde, 0x21,
0xb0, 0x2b, 0x5d, 0x8a,
0xc9, 0xc4, 0x86, 0x02,
0x21, 0xea, 0xfe, 0xf1,
0x76, 0x05, 0xd4, 0xb2,
0xde, 0x6c, 0x14, 0x48,
0x21, 0x9b, 0x3f, 0x98,
0x2c, 0xe1, 0x5b, 0x47,
// float_save.register_area --- unswapped
0xd9, 0x04, 0x20, 0x6b, 0x88, 0x3a, 0x3f, 0xd5,
@ -158,23 +158,23 @@ static const u_int8_t x86_expected_contents[] = {
0xc7, 0x8d, 0x17, 0xb6, 0xe5, 0x0b, 0x94, 0xf7,
0x78, 0x9b, 0x63, 0x49, 0xba, 0xfc, 0x08, 0x4d,
0x90, 0x3a, 0xc5, 0x84,
0x76, 0x1e, 0xf7, 0x79,
0x25, 0xbd, 0x07, 0x81,
0x21, 0x29, 0x2d, 0x45,
0x75, 0x28, 0xec, 0x87,
0xf5, 0x73, 0xbb, 0xf8,
0x88, 0xbb, 0x3e, 0xa6,
0xbe, 0x5e, 0xd3, 0x95,
0x56, 0x24, 0xaa, 0x17,
0x08, 0xa2, 0x5f, 0x13,
0xe6, 0x15, 0x06, 0x50,
0x05, 0x42, 0xd1, 0x66,
0xa5, 0x19, 0x07, 0x00,
0x1b, 0x48, 0x7b, 0x47,
0xba, 0xdf, 0x84, 0x86,
0xdf, 0xcd, 0x3c, 0xe3,
0x33, 0x5d, 0xe6, 0xc0,
0x90, 0x3a, 0xc5, 0x84,
0x76, 0x1e, 0xf7, 0x79,
0x25, 0xbd, 0x07, 0x81,
0x21, 0x29, 0x2d, 0x45,
0x75, 0x28, 0xec, 0x87,
0xf5, 0x73, 0xbb, 0xf8,
0x88, 0xbb, 0x3e, 0xa6,
0xbe, 0x5e, 0xd3, 0x95,
0x56, 0x24, 0xaa, 0x17,
0x08, 0xa2, 0x5f, 0x13,
0xe6, 0x15, 0x06, 0x50,
0x05, 0x42, 0xd1, 0x66,
0xa5, 0x19, 0x07, 0x00,
0x1b, 0x48, 0x7b, 0x47,
0xba, 0xdf, 0x84, 0x86,
0xdf, 0xcd, 0x3c, 0xe3,
0x33, 0x5d, 0xe6, 0xc0,
// extended_registers --- unswapped
0x68, 0x63, 0xdf, 0x50, 0xf7, 0x3b, 0xe8, 0xe5,
@ -243,4 +243,170 @@ static const u_int8_t x86_expected_contents[] = {
0xb2, 0xc7, 0x3a, 0x6c, 0x8a, 0x35, 0xe1, 0xba
};
static const MDRawContextARM arm_raw_context = {
// context_flags
0x591b9e6a,
// iregs
0xa21594de,
0x820d8a25,
0xc4e133b2,
0x173a1c02,
0x105fb175,
0xe871793f,
0x5def70b3,
0xcee3a623,
0x7b3aa9b8,
0x52518537,
0x627012c5,
0x22723dcc,
0x16fcc971,
0x20988bcb,
0xf1ab806b,
0x99d5fc03,
// cpsr
0xb70df511,
// float_save
{
// fpscr
0xa1e1f7ce1077e6b5,
// regs
0xbcb8d002eed7fbde,
0x4dd26a43b96ae97f,
0x8eec22db8b31741c,
0xfd634bd7c5ad66a0,
0x1681da0daeb3debe,
0x474a32bdf72d0b71,
0xcaf464f8b1044834,
0xcaa6592ae5c7582a,
0x4ee46889d877c3db,
0xf8930cf301645cf5,
0x4da7e9ebba27f7c7,
0x69a7b02761944da3,
0x2cda2b2e78195c06,
0x66b227ab9b460a42,
0x7e77e49e52ee0849,
0xd62cd9663e76f255,
0xe9370f082451514b,
0x50a1c674dd1b6029,
0x405db4575829eac4,
0x67b948764649eee7,
0x93731885419229d4,
0xdb0338bad72a4ce7,
0xa0a451f996fca4c8,
0xb4508ea668400a45,
0xbff28c5c7a142423,
0x4f31b42b96f3a431,
0x2ce6789d4ea1ff37,
0xfa150b52e4f82a3c,
0xe9ec40449e6ed4f3,
0x5ceca87836fe2251,
0x66f50de463ee238c,
0x42823efcd59ab511,
// extra
0xe9e14cd2,
0x865bb640,
0x9f3f0b3e,
0x94a71c52,
0x3c012f19,
0x6436637c,
0x46ccedcb,
0x7b341be7
}
};
static const u_int8_t arm_expected_contents[] = {
0x6a, 0x9e, 0x1b, 0x59,
0xde, 0x94, 0x15, 0xa2,
0x25, 0x8a, 0x0d, 0x82,
0xb2, 0x33, 0xe1, 0xc4,
0x02, 0x1c, 0x3a, 0x17,
0x75, 0xb1, 0x5f, 0x10,
0x3f, 0x79, 0x71, 0xe8,
0xb3, 0x70, 0xef, 0x5d,
0x23, 0xa6, 0xe3, 0xce,
0xb8, 0xa9, 0x3a, 0x7b,
0x37, 0x85, 0x51, 0x52,
0xc5, 0x12, 0x70, 0x62,
0xcc, 0x3d, 0x72, 0x22,
0x71, 0xc9, 0xfc, 0x16,
0xcb, 0x8b, 0x98, 0x20,
0x6b, 0x80, 0xab, 0xf1,
0x03, 0xfc, 0xd5, 0x99,
0x11, 0xf5, 0x0d, 0xb7,
0xb5, 0xe6, 0x77, 0x10,
0xce, 0xf7, 0xe1, 0xa1,
0xde, 0xfb, 0xd7, 0xee,
0x02, 0xd0, 0xb8, 0xbc,
0x7f, 0xe9, 0x6a, 0xb9,
0x43, 0x6a, 0xd2, 0x4d,
0x1c, 0x74, 0x31, 0x8b,
0xdb, 0x22, 0xec, 0x8e,
0xa0, 0x66, 0xad, 0xc5,
0xd7, 0x4b, 0x63, 0xfd,
0xbe, 0xde, 0xb3, 0xae,
0x0d, 0xda, 0x81, 0x16,
0x71, 0x0b, 0x2d, 0xf7,
0xbd, 0x32, 0x4a, 0x47,
0x34, 0x48, 0x04, 0xb1,
0xf8, 0x64, 0xf4, 0xca,
0x2a, 0x58, 0xc7, 0xe5,
0x2a, 0x59, 0xa6, 0xca,
0xdb, 0xc3, 0x77, 0xd8,
0x89, 0x68, 0xe4, 0x4e,
0xf5, 0x5c, 0x64, 0x01,
0xf3, 0x0c, 0x93, 0xf8,
0xc7, 0xf7, 0x27, 0xba,
0xeb, 0xe9, 0xa7, 0x4d,
0xa3, 0x4d, 0x94, 0x61,
0x27, 0xb0, 0xa7, 0x69,
0x06, 0x5c, 0x19, 0x78,
0x2e, 0x2b, 0xda, 0x2c,
0x42, 0x0a, 0x46, 0x9b,
0xab, 0x27, 0xb2, 0x66,
0x49, 0x08, 0xee, 0x52,
0x9e, 0xe4, 0x77, 0x7e,
0x55, 0xf2, 0x76, 0x3e,
0x66, 0xd9, 0x2c, 0xd6,
0x4b, 0x51, 0x51, 0x24,
0x08, 0x0f, 0x37, 0xe9,
0x29, 0x60, 0x1b, 0xdd,
0x74, 0xc6, 0xa1, 0x50,
0xc4, 0xea, 0x29, 0x58,
0x57, 0xb4, 0x5d, 0x40,
0xe7, 0xee, 0x49, 0x46,
0x76, 0x48, 0xb9, 0x67,
0xd4, 0x29, 0x92, 0x41,
0x85, 0x18, 0x73, 0x93,
0xe7, 0x4c, 0x2a, 0xd7,
0xba, 0x38, 0x03, 0xdb,
0xc8, 0xa4, 0xfc, 0x96,
0xf9, 0x51, 0xa4, 0xa0,
0x45, 0x0a, 0x40, 0x68,
0xa6, 0x8e, 0x50, 0xb4,
0x23, 0x24, 0x14, 0x7a,
0x5c, 0x8c, 0xf2, 0xbf,
0x31, 0xa4, 0xf3, 0x96,
0x2b, 0xb4, 0x31, 0x4f,
0x37, 0xff, 0xa1, 0x4e,
0x9d, 0x78, 0xe6, 0x2c,
0x3c, 0x2a, 0xf8, 0xe4,
0x52, 0x0b, 0x15, 0xfa,
0xf3, 0xd4, 0x6e, 0x9e,
0x44, 0x40, 0xec, 0xe9,
0x51, 0x22, 0xfe, 0x36,
0x78, 0xa8, 0xec, 0x5c,
0x8c, 0x23, 0xee, 0x63,
0xe4, 0x0d, 0xf5, 0x66,
0x11, 0xb5, 0x9a, 0xd5,
0xfc, 0x3e, 0x82, 0x42,
0xd2, 0x4c, 0xe1, 0xe9,
0x40, 0xb6, 0x5b, 0x86,
0x3e, 0x0b, 0x3f, 0x9f,
0x52, 0x1c, 0xa7, 0x94,
0x19, 0x2f, 0x01, 0x3c,
0x7c, 0x63, 0x36, 0x64,
0xcb, 0xed, 0xcc, 0x46,
0xe7, 0x1b, 0x34, 0x7b
};
#endif // PROCESSOR_SYNTH_MINIDUMP_UNITTEST_DATA_H_