summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2018-03-20 13:12:10 (GMT)
committerTobias Markmann <tm@ayena.de>2018-03-20 14:48:04 (GMT)
commitf2c2c7d035029fb9615b42c18ccea83e8e705b10 (patch)
tree2f56fb77de0f366528395f21732d418f016f63b5 /3rdParty/Breakpad/src
parent44581c5285d13c0ec715b35ddc79177e5ebeef39 (diff)
parent5ba3f18ad8efa040d49f36d83ec2e7891a9add9f (diff)
downloadswift-swift-5.0alpha2.zip
swift-swift-5.0alpha2.tar.bz2
Merge branch 'swift-4.x'swift-5.0alpha2
* swift-4.x: (44 commits) Test-Information: Builds on macOS 10.13.3 with clang trunk. Change-Id: If50381f103b0ad18d038b920d3d43537642141cb
Diffstat (limited to '3rdParty/Breakpad/src')
-rw-r--r--3rdParty/Breakpad/src/COPYING28
-rw-r--r--3rdParty/Breakpad/src/breakpad_googletest_includes.h57
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h83
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm167
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h162
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm362
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm65
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h47
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc166
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc17
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc19
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h2
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc170
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/exception_handler.h8
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h7
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc324
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h36
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc92
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h85
-rw-r--r--3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h47
-rw-r--r--3rdParty/Breakpad/src/client/minidump_file_writer.cc98
-rw-r--r--3rdParty/Breakpad/src/client/minidump_file_writer.h6
-rw-r--r--3rdParty/Breakpad/src/client/minidump_file_writer_unittest.cc179
-rw-r--r--3rdParty/Breakpad/src/client/windows/common/auto_critical_section.h81
-rw-r--r--3rdParty/Breakpad/src/client/windows/common/ipc_protocol.h4
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/ReadMe.txt58
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/client_info.cc223
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/client_info.h177
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.cc20
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.h2
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.cc943
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.h299
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.cc583
-rw-r--r--3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.h203
-rw-r--r--3rdParty/Breakpad/src/client/windows/handler/exception_handler.cc447
-rw-r--r--3rdParty/Breakpad/src/client/windows/handler/exception_handler.h107
-rw-r--r--3rdParty/Breakpad/src/common/basictypes.h58
-rw-r--r--3rdParty/Breakpad/src/common/byte_cursor_unittest.cc776
-rw-r--r--3rdParty/Breakpad/src/common/convert_UTF.c53
-rw-r--r--3rdParty/Breakpad/src/common/convert_UTF.h53
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/bytereader-inl.h29
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/bytereader.cc11
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/bytereader.h31
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/bytereader_unittest.cc707
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/cfi_assembler.cc204
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/cfi_assembler.h271
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.cc10
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.h18
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc527
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2enums.h37
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2reader.cc617
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2reader.h449
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc2555
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc487
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/dwarf2reader_test_common.h149
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/elf_reader.cc1273
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/elf_reader.h166
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/functioninfo.cc231
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/functioninfo.h188
-rw-r--r--3rdParty/Breakpad/src/common/dwarf/types.h8
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cfi_to_module.cc39
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cfi_to_module.h12
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cfi_to_module_unittest.cc306
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc336
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cu_to_module.h105
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_cu_to_module_unittest.cc1852
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_line_to_module.cc27
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_line_to_module.h8
-rw-r--r--3rdParty/Breakpad/src/common/dwarf_line_to_module_unittest.cc391
-rw-r--r--3rdParty/Breakpad/src/common/language.cc130
-rw-r--r--3rdParty/Breakpad/src/common/language.h17
-rw-r--r--3rdParty/Breakpad/src/common/linux/linux_libc_support.h17
-rw-r--r--3rdParty/Breakpad/src/common/mac/Breakpad.xcconfig52
-rw-r--r--3rdParty/Breakpad/src/common/mac/BreakpadDebug.xcconfig32
-rw-r--r--3rdParty/Breakpad/src/common/mac/BreakpadRelease.xcconfig34
-rw-r--r--3rdParty/Breakpad/src/common/mac/GTMDefines.h456
-rw-r--r--3rdParty/Breakpad/src/common/mac/GTMLogger.h504
-rw-r--r--3rdParty/Breakpad/src/common/mac/GTMLogger.m611
-rw-r--r--3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.h61
-rw-r--r--3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.m267
-rw-r--r--3rdParty/Breakpad/src/common/mac/MachIPC.h8
-rw-r--r--3rdParty/Breakpad/src/common/mac/arch_utilities.cc231
-rw-r--r--3rdParty/Breakpad/src/common/mac/arch_utilities.h47
-rw-r--r--3rdParty/Breakpad/src/common/mac/byteswap.h25
-rw-r--r--3rdParty/Breakpad/src/common/mac/dump_syms.cc (renamed from 3rdParty/Breakpad/src/common/mac/dump_syms.mm)476
-rw-r--r--3rdParty/Breakpad/src/common/mac/dump_syms.h76
-rw-r--r--3rdParty/Breakpad/src/common/mac/file_id.cc19
-rw-r--r--3rdParty/Breakpad/src/common/mac/file_id.h17
-rw-r--r--3rdParty/Breakpad/src/common/mac/launch_reporter.cc84
-rw-r--r--3rdParty/Breakpad/src/common/mac/launch_reporter.h43
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_id.cc65
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_id.h33
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_reader.cc47
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_reader.h21
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_reader_unittest.cc1902
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_utilities.cc89
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_utilities.h35
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_walker.cc69
-rw-r--r--3rdParty/Breakpad/src/common/mac/macho_walker.h26
-rw-r--r--3rdParty/Breakpad/src/common/mac/string_utilities.cc2
-rw-r--r--3rdParty/Breakpad/src/common/mac/super_fat_arch.h88
-rw-r--r--3rdParty/Breakpad/src/common/md5.cc8
-rw-r--r--3rdParty/Breakpad/src/common/md5.h2
-rw-r--r--3rdParty/Breakpad/src/common/memory.h193
-rw-r--r--3rdParty/Breakpad/src/common/memory_range.h145
-rw-r--r--3rdParty/Breakpad/src/common/memory_range_unittest.cc193
-rw-r--r--3rdParty/Breakpad/src/common/memory_unittest.cc124
-rw-r--r--3rdParty/Breakpad/src/common/minidump_type_helper.h56
-rw-r--r--3rdParty/Breakpad/src/common/module.cc125
-rw-r--r--3rdParty/Breakpad/src/common/module.h38
-rw-r--r--3rdParty/Breakpad/src/common/module_unittest.cc557
-rw-r--r--3rdParty/Breakpad/src/common/scoped_ptr.h404
-rw-r--r--3rdParty/Breakpad/src/common/simple_string_dictionary.cc45
-rw-r--r--3rdParty/Breakpad/src/common/simple_string_dictionary.h260
-rw-r--r--3rdParty/Breakpad/src/common/simple_string_dictionary_unittest.cc308
-rw-r--r--3rdParty/Breakpad/src/common/stabs_reader.h5
-rw-r--r--3rdParty/Breakpad/src/common/stabs_reader_unittest.cc611
-rw-r--r--3rdParty/Breakpad/src/common/stabs_to_module.cc7
-rw-r--r--3rdParty/Breakpad/src/common/stabs_to_module_unittest.cc258
-rw-r--r--3rdParty/Breakpad/src/common/stdio_wrapper.h43
-rw-r--r--3rdParty/Breakpad/src/common/string_conversion.cc42
-rw-r--r--3rdParty/Breakpad/src/common/string_conversion.h10
-rw-r--r--3rdParty/Breakpad/src/common/symbol_data.h42
-rw-r--r--3rdParty/Breakpad/src/common/test_assembler.cc359
-rw-r--r--3rdParty/Breakpad/src/common/test_assembler.h484
-rw-r--r--3rdParty/Breakpad/src/common/test_assembler_unittest.cc1662
-rw-r--r--3rdParty/Breakpad/src/common/unordered.h62
-rw-r--r--3rdParty/Breakpad/src/common/windows/dia_util.cc92
-rw-r--r--3rdParty/Breakpad/src/common/windows/dia_util.h64
-rw-r--r--3rdParty/Breakpad/src/common/windows/guid_string.h8
-rw-r--r--3rdParty/Breakpad/src/common/windows/http_upload.cc420
-rw-r--r--3rdParty/Breakpad/src/common/windows/http_upload.h129
-rw-r--r--3rdParty/Breakpad/src/common/windows/omap.cc716
-rw-r--r--3rdParty/Breakpad/src/common/windows/omap.h72
-rw-r--r--3rdParty/Breakpad/src/common/windows/omap_internal.h140
-rw-r--r--3rdParty/Breakpad/src/common/windows/omap_unittest.cc329
-rw-r--r--3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.cc1412
-rw-r--r--3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.h257
-rw-r--r--3rdParty/Breakpad/src/common/windows/string_utils-inl.h6
-rw-r--r--3rdParty/Breakpad/src/common/windows/string_utils.cc133
-rw-r--r--3rdParty/Breakpad/src/config.h.in91
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/breakpad_types.h35
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_amd64.h164
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm.h14
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm64.h140
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_mips.h176
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc.h43
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h39
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_sparc.h29
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_x86.h66
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_linux.h4
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_mac.h16
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_ps3.h67
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_win32.h2155
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_format.h569
-rw-r--r--3rdParty/Breakpad/src/google_breakpad/common/minidump_size.h6
-rw-r--r--3rdParty/Breakpad/src/processor/scoped_ptr.h335
157 files changed, 34652 insertions, 2060 deletions
diff --git a/3rdParty/Breakpad/src/COPYING b/3rdParty/Breakpad/src/COPYING
deleted file mode 100644
index d15b0c2..0000000
--- a/3rdParty/Breakpad/src/COPYING
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2006, Google Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/3rdParty/Breakpad/src/breakpad_googletest_includes.h b/3rdParty/Breakpad/src/breakpad_googletest_includes.h
new file mode 100644
index 0000000..19a3e98
--- /dev/null
+++ b/3rdParty/Breakpad/src/breakpad_googletest_includes.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BREAKPAD_GOOGLETEST_INCLUDES_H__
+#define BREAKPAD_GOOGLETEST_INCLUDES_H__
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
+// (illegal instruction) instead of SIGSEGV (segmentation fault). Also,
+// the number of memory regions differs, so there is no point in running
+// this test if AddressSanitizer is used.
+//
+// Ideally we'd use this attribute to disable ASAN on a per-func basis,
+// but this doesn't seem to actually work, and it's changed names over
+// time. So just stick with disabling the actual tests.
+// http://crbug.com/304575
+//#define NO_ASAN __attribute__((no_sanitize_address))
+#if defined(__clang__) && defined(__has_feature)
+// Have to keep this check sep from above as newer gcc will barf on it.
+# if __has_feature(address_sanitizer)
+# define ADDRESS_SANITIZER
+# endif
+#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)
+# define ADDRESS_SANITIZER
+#else
+# undef ADDRESS_SANITIZER
+#endif
+
+#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h
new file mode 100644
index 0000000..5662e8b
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility class that can persist a SimpleStringDictionary to disk.
+
+#import <Foundation/Foundation.h>
+
+#include "common/simple_string_dictionary.h"
+
+namespace google_breakpad {
+
+BOOL EnsureDirectoryPathExists(NSString *dirPath);
+
+//=============================================================================
+class ConfigFile {
+ public:
+ ConfigFile() {
+ config_file_ = -1;
+ config_file_path_[0] = 0;
+ has_created_file_ = false;
+ };
+
+ ~ConfigFile() {
+ };
+
+ void WriteFile(const char* directory,
+ const SimpleStringDictionary *configurationParameters,
+ const char *dump_dir,
+ const char *minidump_id);
+
+ const char *GetFilePath() { return config_file_path_; }
+
+ void Unlink() {
+ if (config_file_ != -1)
+ unlink(config_file_path_);
+
+ config_file_ = -1;
+ }
+
+ private:
+ BOOL WriteData(const void *data, size_t length);
+
+ BOOL AppendConfigData(const char *key,
+ const void *data,
+ size_t length);
+
+ BOOL AppendConfigString(const char *key,
+ const char *value);
+
+ BOOL AppendCrashTimeParameters(const char *processStartTimeString);
+
+ int config_file_; // descriptor for config file
+ char config_file_path_[PATH_MAX]; // Path to configuration file
+ bool has_created_file_;
+};
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm
new file mode 100644
index 0000000..acab7de
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm
@@ -0,0 +1,167 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility class that can persist a SimpleStringDictionary to disk.
+
+#import "client/mac/crash_generation/ConfigFile.h"
+
+#import <Foundation/Foundation.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#import "client/apple/Framework/BreakpadDefines.h"
+#import "common/mac/GTMDefines.h"
+
+
+namespace google_breakpad {
+
+//=============================================================================
+BOOL EnsureDirectoryPathExists(NSString *dirPath) {
+ NSFileManager *mgr = [NSFileManager defaultManager];
+
+ NSDictionary *attrs =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
+ forKey:NSFilePosixPermissions];
+
+ return [mgr createDirectoryAtPath:dirPath
+ withIntermediateDirectories:YES
+ attributes:attrs
+ error:nil];
+}
+
+//=============================================================================
+BOOL ConfigFile::WriteData(const void *data, size_t length) {
+ size_t result = write(config_file_, data, length);
+
+ return result == length;
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendConfigData(const char *key,
+ const void *data, size_t length) {
+ assert(config_file_ != -1);
+
+ if (!key) {
+ return NO;
+ }
+
+ if (!data) {
+ return NO;
+ }
+
+ // Write the key, \n, length of data (ascii integer), \n, data
+ char buffer[16];
+ char nl = '\n';
+ BOOL result = WriteData(key, strlen(key));
+
+ snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
+ result &= WriteData(buffer, strlen(buffer));
+ result &= WriteData(data, length);
+ result &= WriteData(&nl, 1);
+ return result;
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendConfigString(const char *key,
+ const char *value) {
+ return AppendConfigData(key, value, strlen(value));
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) {
+ // Set process uptime parameter
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ char processUptimeString[32], processCrashtimeString[32];
+ // Set up time if we've received the start time.
+ if (processStartTimeString) {
+ time_t processStartTime = strtol(processStartTimeString, NULL, 10);
+ time_t processUptime = tv.tv_sec - processStartTime;
+ // Store the uptime in milliseconds.
+ sprintf(processUptimeString, "%llu",
+ static_cast<unsigned long long int>(processUptime) * 1000);
+ if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString))
+ return false;
+ }
+
+ sprintf(processCrashtimeString, "%zd", tv.tv_sec);
+ return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME,
+ processCrashtimeString);
+}
+
+//=============================================================================
+void ConfigFile::WriteFile(const char* directory,
+ const SimpleStringDictionary *configurationParameters,
+ const char *dump_dir,
+ const char *minidump_id) {
+
+ assert(config_file_ == -1);
+
+ // Open and write out configuration file preamble
+ if (directory) {
+ snprintf(config_file_path_, sizeof(config_file_path_), "%s/Config-XXXXXX",
+ directory);
+ } else {
+ strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
+ sizeof(config_file_path_));
+ }
+ config_file_ = mkstemp(config_file_path_);
+
+ if (config_file_ == -1) {
+ return;
+ }
+
+ has_created_file_ = true;
+
+ // Add the minidump dir
+ AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
+ AppendConfigString(kReporterMinidumpIDKey, minidump_id);
+
+ // Write out the configuration parameters
+ BOOL result = YES;
+ const SimpleStringDictionary &dictionary = *configurationParameters;
+
+ const SimpleStringDictionary::Entry *entry = NULL;
+ SimpleStringDictionary::Iterator iter(dictionary);
+
+ while ((entry = iter.Next())) {
+ result = AppendConfigString(entry->key, entry->value);
+
+ if (!result)
+ break;
+ }
+ AppendCrashTimeParameters(
+ configurationParameters->GetValueForKey(BREAKPAD_PROCESS_START_TIME));
+
+ close(config_file_);
+ config_file_ = -1;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h
new file mode 100644
index 0000000..6712355
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Interface file between the Breakpad.framework and
+// the Inspector process.
+
+#include "common/simple_string_dictionary.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/mach.h>
+
+#import "client/mac/crash_generation/ConfigFile.h"
+#import "client/mac/handler/minidump_generator.h"
+
+
+// Types of mach messsages (message IDs)
+enum {
+ kMsgType_InspectorInitialInfo = 0, // data is InspectorInfo
+ kMsgType_InspectorKeyValuePair = 1, // data is KeyValueMessageData
+ kMsgType_InspectorAcknowledgement = 2 // no data sent
+};
+
+// Initial information sent from the crashed process by
+// Breakpad.framework to the Inspector process
+// The mach message with this struct as data will also include
+// several descriptors for sending mach port rights to the crashed
+// task, etc.
+struct InspectorInfo {
+ int exception_type;
+ int exception_code;
+ int exception_subcode;
+ unsigned int parameter_count; // key-value pairs
+};
+
+// Key/value message data to be sent to the Inspector
+struct KeyValueMessageData {
+ public:
+ KeyValueMessageData() {}
+ explicit KeyValueMessageData(
+ const google_breakpad::SimpleStringDictionary::Entry &inEntry) {
+ strlcpy(key, inEntry.key, sizeof(key) );
+ strlcpy(value, inEntry.value, sizeof(value) );
+ }
+
+ char key[google_breakpad::SimpleStringDictionary::key_size];
+ char value[google_breakpad::SimpleStringDictionary::value_size];
+};
+
+using std::string;
+using google_breakpad::MinidumpGenerator;
+
+namespace google_breakpad {
+
+//=============================================================================
+class MinidumpLocation {
+ public:
+ MinidumpLocation(NSString *minidumpDir) {
+ // Ensure that the path exists. Fallback to /tmp if unable to locate path.
+ assert(minidumpDir);
+ if (!EnsureDirectoryPathExists(minidumpDir)) {
+ minidumpDir = @"/tmp";
+ }
+
+ strlcpy(minidump_dir_path_, [minidumpDir fileSystemRepresentation],
+ sizeof(minidump_dir_path_));
+
+ // now generate a unique ID
+ string dump_path(minidump_dir_path_);
+ string next_minidump_id;
+
+ string next_minidump_path_ =
+ (MinidumpGenerator::UniqueNameInDirectory(dump_path, &next_minidump_id));
+
+ strlcpy(minidump_id_, next_minidump_id.c_str(), sizeof(minidump_id_));
+ };
+
+ const char *GetPath() { return minidump_dir_path_; }
+ const char *GetID() { return minidump_id_; }
+
+ private:
+ char minidump_dir_path_[PATH_MAX]; // Path to minidump directory
+ char minidump_id_[128];
+};
+
+//=============================================================================
+class Inspector {
+ public:
+ Inspector() {};
+
+ // given a bootstrap service name, receives mach messages
+ // from a crashed process, then inspects it, creates a minidump file
+ // and asks the user if he wants to upload it to a server.
+ void Inspect(const char *receive_port_name);
+
+ private:
+ // The Inspector is invoked with its bootstrap port set to the bootstrap
+ // subset established in OnDemandServer.mm OnDemandServer::Initialize.
+ // For proper communication with the system, the sender (which will inherit
+ // the Inspector's bootstrap port) needs the per-session bootstrap namespace
+ // available directly in its bootstrap port. OnDemandServer stashed this
+ // port into the subset namespace under a special name. ResetBootstrapPort
+ // recovers this port and switches this task to use it as its own bootstrap
+ // (ensuring that children like the sender will inherit it), and saves the
+ // subset in bootstrap_subset_port_ for use by ServiceCheckIn and
+ // ServiceCheckOut.
+ kern_return_t ResetBootstrapPort();
+
+ kern_return_t ServiceCheckIn(const char *receive_port_name);
+ kern_return_t ServiceCheckOut(const char *receive_port_name);
+
+ kern_return_t ReadMessages();
+
+ bool InspectTask();
+ kern_return_t SendAcknowledgement();
+
+ // The bootstrap port in which the inspector is registered and into which it
+ // must check in.
+ mach_port_t bootstrap_subset_port_;
+
+ mach_port_t service_rcv_port_;
+
+ int exception_type_;
+ int exception_code_;
+ int exception_subcode_;
+ mach_port_t remote_task_;
+ mach_port_t crashing_thread_;
+ mach_port_t handler_thread_;
+ mach_port_t ack_port_;
+
+ SimpleStringDictionary config_params_;
+
+ ConfigFile config_file_;
+};
+
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm
new file mode 100644
index 0000000..dc6f480
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm
@@ -0,0 +1,362 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility that can inspect another process and write a crash dump
+
+#include <cstdio>
+#include <iostream>
+#include <servers/bootstrap.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+#import "client/mac/crash_generation/Inspector.h"
+
+#import "client/mac/Framework/Breakpad.h"
+#import "client/mac/handler/minidump_generator.h"
+
+#import "common/mac/MachIPC.h"
+#include "common/mac/bootstrap_compat.h"
+#include "common/mac/launch_reporter.h"
+
+#import "GTMDefines.h"
+
+#import <Foundation/Foundation.h>
+
+namespace google_breakpad {
+
+//=============================================================================
+void Inspector::Inspect(const char *receive_port_name) {
+ kern_return_t result = ResetBootstrapPort();
+ if (result != KERN_SUCCESS) {
+ return;
+ }
+
+ result = ServiceCheckIn(receive_port_name);
+
+ if (result == KERN_SUCCESS) {
+ result = ReadMessages();
+
+ if (result == KERN_SUCCESS) {
+ // Inspect the task and write a minidump file.
+ bool wrote_minidump = InspectTask();
+
+ // Send acknowledgement to the crashed process that the inspection
+ // has finished. It will then be able to cleanly exit.
+ // The return value is ignored because failure isn't fatal. If the process
+ // didn't get the message there's nothing we can do, and we still want to
+ // send the report.
+ SendAcknowledgement();
+
+ if (wrote_minidump) {
+ // Ask the user if he wants to upload the crash report to a server,
+ // and do so if he agrees.
+ LaunchReporter(
+ config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
+ config_file_.GetFilePath());
+ } else {
+ fprintf(stderr, "Inspection of crashed process failed\n");
+ }
+
+ // Now that we're done reading messages, cleanup the service, but only
+ // if there was an actual exception
+ // Otherwise, it means the dump was generated on demand and the process
+ // lives on, and we might be needed again in the future.
+ if (exception_code_) {
+ ServiceCheckOut(receive_port_name);
+ }
+ } else {
+ PRINT_MACH_RESULT(result, "Inspector: WaitForMessage()");
+ }
+ }
+}
+
+//=============================================================================
+kern_return_t Inspector::ResetBootstrapPort() {
+ // A reasonable default, in case anything fails.
+ bootstrap_subset_port_ = bootstrap_port;
+
+ mach_port_t self_task = mach_task_self();
+
+ kern_return_t kr = task_get_bootstrap_port(self_task,
+ &bootstrap_subset_port_);
+ if (kr != KERN_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: task_get_bootstrap_port failed: %s (%d)",
+ mach_error_string(kr), kr);
+ return kr;
+ }
+
+ mach_port_t bootstrap_parent_port;
+ kr = bootstrap_look_up(bootstrap_subset_port_,
+ const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
+ &bootstrap_parent_port);
+ if (kr != BOOTSTRAP_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: bootstrap_look_up failed: %s (%d)",
+#if defined(MAC_OS_X_VERSION_10_5) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ bootstrap_strerror(kr),
+#else
+ mach_error_string(kr),
+#endif
+ kr);
+ return kr;
+ }
+
+ kr = task_set_bootstrap_port(self_task, bootstrap_parent_port);
+ if (kr != KERN_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: task_set_bootstrap_port failed: %s (%d)",
+ mach_error_string(kr), kr);
+ return kr;
+ }
+
+ // Some things access the bootstrap port through this global variable
+ // instead of calling task_get_bootstrap_port.
+ bootstrap_port = bootstrap_parent_port;
+
+ return KERN_SUCCESS;
+}
+
+//=============================================================================
+kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) {
+ // We need to get the mach port representing this service, so we can
+ // get information from the crashed process.
+ kern_return_t kr = bootstrap_check_in(bootstrap_subset_port_,
+ (char*)receive_port_name,
+ &service_rcv_port_);
+
+ if (kr != KERN_SUCCESS) {
+#if VERBOSE
+ PRINT_MACH_RESULT(kr, "Inspector: bootstrap_check_in()");
+#endif
+ }
+
+ return kr;
+}
+
+//=============================================================================
+kern_return_t Inspector::ServiceCheckOut(const char *receive_port_name) {
+ // We're done receiving mach messages from the crashed process,
+ // so clean up a bit.
+ kern_return_t kr;
+
+ // DO NOT use mach_port_deallocate() here -- it will fail and the
+ // following bootstrap_register() will also fail leaving our service
+ // name hanging around forever (until reboot)
+ kr = mach_port_destroy(mach_task_self(), service_rcv_port_);
+
+ if (kr != KERN_SUCCESS) {
+ PRINT_MACH_RESULT(kr,
+ "Inspector: UNREGISTERING: service_rcv_port mach_port_deallocate()");
+ return kr;
+ }
+
+ // Unregister the service associated with the receive port.
+ kr = breakpad::BootstrapRegister(bootstrap_subset_port_,
+ (char*)receive_port_name,
+ MACH_PORT_NULL);
+
+ if (kr != KERN_SUCCESS) {
+ PRINT_MACH_RESULT(kr, "Inspector: UNREGISTERING: bootstrap_register()");
+ }
+
+ return kr;
+}
+
+//=============================================================================
+kern_return_t Inspector::ReadMessages() {
+ // Wait for an initial message from the crashed process containing basic
+ // information about the crash.
+ ReceivePort receive_port(service_rcv_port_);
+
+ MachReceiveMessage message;
+ kern_return_t result = receive_port.WaitForMessage(&message, 1000);
+
+ if (result == KERN_SUCCESS) {
+ InspectorInfo &info = (InspectorInfo &)*message.GetData();
+ exception_type_ = info.exception_type;
+ exception_code_ = info.exception_code;
+ exception_subcode_ = info.exception_subcode;
+
+#if VERBOSE
+ printf("message ID = %d\n", message.GetMessageID());
+#endif
+
+ remote_task_ = message.GetTranslatedPort(0);
+ crashing_thread_ = message.GetTranslatedPort(1);
+ handler_thread_ = message.GetTranslatedPort(2);
+ ack_port_ = message.GetTranslatedPort(3);
+
+#if VERBOSE
+ printf("exception_type = %d\n", exception_type_);
+ printf("exception_code = %d\n", exception_code_);
+ printf("exception_subcode = %d\n", exception_subcode_);
+ printf("remote_task = %d\n", remote_task_);
+ printf("crashing_thread = %d\n", crashing_thread_);
+ printf("handler_thread = %d\n", handler_thread_);
+ printf("ack_port_ = %d\n", ack_port_);
+ printf("parameter count = %d\n", info.parameter_count);
+#endif
+
+ // In certain situations where multiple crash requests come
+ // through quickly, we can end up with the mach IPC messages not
+ // coming through correctly. Since we don't know what parameters
+ // we've missed, we can't do much besides abort the crash dump
+ // situation in this case.
+ unsigned int parameters_read = 0;
+ // The initial message contains the number of key value pairs that
+ // we are expected to read.
+ // Read each key/value pair, one mach message per key/value pair.
+ for (unsigned int i = 0; i < info.parameter_count; ++i) {
+ MachReceiveMessage parameter_message;
+ result = receive_port.WaitForMessage(&parameter_message, 1000);
+
+ if(result == KERN_SUCCESS) {
+ KeyValueMessageData &key_value_data =
+ (KeyValueMessageData&)*parameter_message.GetData();
+ // If we get a blank key, make sure we don't increment the
+ // parameter count; in some cases (notably on-demand generation
+ // many times in a short period of time) caused the Mach IPC
+ // messages to not come through correctly.
+ if (strlen(key_value_data.key) == 0) {
+ continue;
+ }
+ parameters_read++;
+
+ config_params_.SetKeyValue(key_value_data.key, key_value_data.value);
+ } else {
+ PRINT_MACH_RESULT(result, "Inspector: key/value message");
+ break;
+ }
+ }
+ if (parameters_read != info.parameter_count) {
+ return KERN_FAILURE;
+ }
+ }
+
+ return result;
+}
+
+//=============================================================================
+bool Inspector::InspectTask() {
+ // keep the task quiet while we're looking at it
+ task_suspend(remote_task_);
+
+ NSString *minidumpDir;
+
+ const char *minidumpDirectory =
+ config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
+
+ // If the client app has not specified a minidump directory,
+ // use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
+ if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
+ NSArray *libraryDirectories =
+ NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
+ NSUserDomainMask,
+ YES);
+
+ NSString *applicationSupportDirectory =
+ [libraryDirectories objectAtIndex:0];
+ NSString *library_subdirectory = [NSString
+ stringWithUTF8String:kDefaultLibrarySubdirectory];
+ NSString *breakpad_product = [NSString
+ stringWithUTF8String:config_params_.GetValueForKey(BREAKPAD_PRODUCT)];
+
+ NSArray *path_components = [NSArray
+ arrayWithObjects:applicationSupportDirectory,
+ library_subdirectory,
+ breakpad_product,
+ nil];
+
+ minidumpDir = [NSString pathWithComponents:path_components];
+ } else {
+ minidumpDir = [[NSString stringWithUTF8String:minidumpDirectory]
+ stringByExpandingTildeInPath];
+ }
+
+ MinidumpLocation minidumpLocation(minidumpDir);
+
+ // Obscure bug alert:
+ // Don't use [NSString stringWithFormat] to build up the path here since it
+ // assumes system encoding and in RTL locales will prepend an LTR override
+ // character for paths beginning with '/' which fileSystemRepresentation does
+ // not remove. Filed as rdar://6889706 .
+ NSString *path_ns = [NSString
+ stringWithUTF8String:minidumpLocation.GetPath()];
+ NSString *pathid_ns = [NSString
+ stringWithUTF8String:minidumpLocation.GetID()];
+ NSString *minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns];
+ minidumpPath = [minidumpPath
+ stringByAppendingPathExtension:@"dmp"];
+
+ config_file_.WriteFile( 0,
+ &config_params_,
+ minidumpLocation.GetPath(),
+ minidumpLocation.GetID());
+
+
+ MinidumpGenerator generator(remote_task_, handler_thread_);
+
+ if (exception_type_ && exception_code_) {
+ generator.SetExceptionInformation(exception_type_,
+ exception_code_,
+ exception_subcode_,
+ crashing_thread_);
+ }
+
+
+ bool result = generator.Write([minidumpPath fileSystemRepresentation]);
+
+ // let the task continue
+ task_resume(remote_task_);
+
+ return result;
+}
+
+//=============================================================================
+// The crashed task needs to be told that the inspection has finished.
+// It will wait on a mach port (with timeout) until we send acknowledgement.
+kern_return_t Inspector::SendAcknowledgement() {
+ if (ack_port_ != MACH_PORT_DEAD) {
+ MachPortSender sender(ack_port_);
+ MachSendMessage ack_message(kMsgType_InspectorAcknowledgement);
+
+ kern_return_t result = sender.SendMessage(ack_message, 2000);
+
+#if VERBOSE
+ PRINT_MACH_RESULT(result, "Inspector: sent acknowledgement");
+#endif
+
+ return result;
+ }
+
+ return KERN_INVALID_NAME;
+}
+
+} // namespace google_breakpad
+
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm
new file mode 100644
index 0000000..137c6a1
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm
@@ -0,0 +1,65 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Main driver for Inspector
+
+#import "client/mac/crash_generation/Inspector.h"
+#import <Cocoa/Cocoa.h>
+
+namespace google_breakpad {
+
+//=============================================================================
+extern "C" {
+
+int main(int argc, char *const argv[]) {
+#if DEBUG
+ // Since we're launched on-demand, this is necessary to see debugging
+ // output in the console window.
+ freopen("/dev/console", "w", stdout);
+ freopen("/dev/console", "w", stderr);
+#endif
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (argc != 2) {
+ exit(0);
+ }
+ // Our first command-line argument contains the name of the service
+ // that we're providing.
+ google_breakpad::Inspector inspector;
+ inspector.Inspect(argv[1]);
+
+ [pool release];
+
+ return 0;
+}
+
+} // extern "C"
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h b/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h
new file mode 100644
index 0000000..a3a95dc
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
+#define CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
+
+namespace google_breakpad {
+
+class ClientInfo {
+ public:
+ explicit ClientInfo(pid_t pid) : pid_(pid) {}
+
+ pid_t pid() const { return pid_; }
+
+ private:
+ pid_t pid_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc b/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc
new file mode 100644
index 0000000..451e8d9
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/mac/crash_generation/crash_generation_server.h"
+
+#include <pthread.h>
+
+#include "client/mac/crash_generation/client_info.h"
+#include "client/mac/handler/minidump_generator.h"
+#include "common/mac/scoped_task_suspend-inl.h"
+
+namespace google_breakpad {
+
+CrashGenerationServer::CrashGenerationServer(
+ const char *mach_port_name,
+ FilterCallback filter,
+ void *filter_context,
+ OnClientDumpRequestCallback dump_callback,
+ void *dump_context,
+ OnClientExitingCallback exit_callback,
+ void *exit_context,
+ bool generate_dumps,
+ const std::string &dump_path)
+ : filter_(filter),
+ filter_context_(filter_context),
+ dump_callback_(dump_callback),
+ dump_context_(dump_context),
+ exit_callback_(exit_callback),
+ exit_context_(exit_context),
+ generate_dumps_(generate_dumps),
+ dump_dir_(dump_path.empty() ? "/tmp" : dump_path),
+ started_(false),
+ receive_port_(mach_port_name),
+ mach_port_name_(mach_port_name) {
+}
+
+CrashGenerationServer::~CrashGenerationServer() {
+ if (started_)
+ Stop();
+}
+
+bool CrashGenerationServer::Start() {
+ int thread_create_result = pthread_create(&server_thread_, NULL,
+ &WaitForMessages, this);
+ started_ = thread_create_result == 0;
+ return started_;
+}
+
+bool CrashGenerationServer::Stop() {
+ if (!started_)
+ return false;
+
+ // Send a quit message to the background thread, and then join it.
+ MachPortSender sender(mach_port_name_.c_str());
+ MachSendMessage quit_message(kQuitMessage);
+ const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
+ kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs);
+ if (result == KERN_SUCCESS) {
+ int thread_join_result = pthread_join(server_thread_, NULL);
+ started_ = thread_join_result != 0;
+ }
+
+ return !started_;
+}
+
+// static
+void *CrashGenerationServer::WaitForMessages(void *server) {
+ CrashGenerationServer *self =
+ reinterpret_cast<CrashGenerationServer*>(server);
+ while (self->WaitForOneMessage()) {}
+ return NULL;
+}
+
+bool CrashGenerationServer::WaitForOneMessage() {
+ MachReceiveMessage message;
+ kern_return_t result = receive_port_.WaitForMessage(&message,
+ MACH_MSG_TIMEOUT_NONE);
+ if (result == KERN_SUCCESS) {
+ switch (message.GetMessageID()) {
+ case kDumpRequestMessage: {
+ ExceptionInfo &info = (ExceptionInfo &)*message.GetData();
+
+ mach_port_t remote_task = message.GetTranslatedPort(0);
+ mach_port_t crashing_thread = message.GetTranslatedPort(1);
+ mach_port_t handler_thread = message.GetTranslatedPort(2);
+ mach_port_t ack_port = message.GetTranslatedPort(3);
+ pid_t remote_pid = -1;
+ pid_for_task(remote_task, &remote_pid);
+ ClientInfo client(remote_pid);
+
+ bool result;
+ std::string dump_path;
+ if (generate_dumps_ && (!filter_ || filter_(filter_context_))) {
+ ScopedTaskSuspend suspend(remote_task);
+
+ MinidumpGenerator generator(remote_task, handler_thread);
+ dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL);
+
+ if (info.exception_type && info.exception_code) {
+ generator.SetExceptionInformation(info.exception_type,
+ info.exception_code,
+ info.exception_subcode,
+ crashing_thread);
+ }
+ result = generator.Write(dump_path.c_str());
+ } else {
+ result = true;
+ }
+
+ if (result && dump_callback_) {
+ dump_callback_(dump_context_, client, dump_path);
+ }
+
+ // TODO(ted): support a way for the client to send additional data,
+ // perhaps with a callback so users of the server can read the data
+ // themselves?
+
+ if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) {
+ MachPortSender sender(ack_port);
+ MachSendMessage ack_message(kAcknowledgementMessage);
+ const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
+
+ sender.SendMessage(ack_message, kSendTimeoutMs);
+ }
+
+ if (exit_callback_) {
+ exit_callback_(exit_context_, client);
+ }
+ break;
+ }
+ case kQuitMessage:
+ return false;
+ }
+ } else { // result != KERN_SUCCESS
+ return false;
+ }
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
index b50aa03..3492b82 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc
@@ -202,17 +202,6 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||
/* The following is the big-endian ppc64 check */
*((unsigned int *)&buf) == FAT_MAGIC) {
- /* Get host info */
- host_t host = mach_host_self();
- unsigned i = HOST_BASIC_INFO_COUNT;
- struct host_basic_info hbi;
- kern_return_t kr;
- if ((kr = host_info(host, HOST_BASIC_INFO,
- (host_info_t)(&hbi), &i)) != KERN_SUCCESS) {
- return -1;
- }
- mach_port_deallocate(mach_task_self(), host);
-
/* Read in the fat header */
struct fat_header fh;
if (lseek(fd, 0, SEEK_SET) == -1) {
@@ -281,7 +270,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
off_t sa; /* symbol address */
off_t ss; /* start of strings */
- register register_t n;
+ register_t n;
if (*((unsigned int *)&buf) == magic) {
if (lseek(fd, arch_offset, SEEK_SET) == -1) {
return -1;
@@ -354,14 +343,14 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,
// and look for a match
while (n) {
nlist_type space[BUFSIZ/sizeof (nlist_type)];
- register register_t m = sizeof (space);
+ register_t m = sizeof (space);
if (n < m)
m = n;
if (read(fd, (char *)space, m) != m)
break;
n -= m;
- long savpos = lseek(fd, 0, SEEK_CUR);
+ off_t savpos = lseek(fd, 0, SEEK_CUR);
if (savpos == -1) {
return -1;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
index ef5743c..cdba6df 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc
@@ -41,6 +41,7 @@ extern "C" { // needed to compile on Leopard
#include <mach/task_info.h>
#include <sys/sysctl.h>
#include <TargetConditionals.h>
+#include <unistd.h>
#include <algorithm>
#include <string>
@@ -261,8 +262,8 @@ bool FindTextSection(DynamicImage& image) {
reinterpret_cast<const mach_segment_command_type *>(cmd);
if (!strcmp(seg->segname, "__TEXT")) {
- image.vmaddr_ = seg->vmaddr;
- image.vmsize_ = seg->vmsize;
+ image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr);
+ image.vmsize_ = static_cast<mach_vm_size_t>(seg->vmsize);
image.slide_ = 0;
if (seg->fileoff == 0 && seg->filesize != 0) {
@@ -363,7 +364,7 @@ static uint64_t LookupSymbol(const char* symbol_name,
return list.n_value;
}
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
static bool HasTaskDyldInfo() {
return true;
}
@@ -380,13 +381,9 @@ static SInt32 GetOSVersion() {
}
static bool HasTaskDyldInfo() {
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
- return true;
-#else
return GetOSVersion() >= 0x1060;
-#endif
}
-#endif // TARGET_OS_IPHONE
+#endif // TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= 10_6
uint64_t DynamicImages::GetDyldAllImageInfosPointer() {
if (HasTaskDyldInfo()) {
@@ -475,8 +472,6 @@ void ReadImageInfo(DynamicImages& images,
mach_header_bytes) != KERN_SUCCESS)
continue;
- header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
-
// Read the file name from the task's memory space.
string file_path;
if (info.file_path_) {
@@ -492,7 +487,7 @@ void ReadImageInfo(DynamicImages& images,
header_size,
info.load_address_,
file_path,
- info.file_mod_date_,
+ static_cast<uintptr_t>(info.file_mod_date_),
images.task_,
images.cpu_type_);
@@ -568,7 +563,7 @@ cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) {
cpu_type_t cpu_type;
size_t cpuTypeSize = sizeof(cpu_type);
- sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0);
+ sysctl(mib, static_cast<u_int>(mibLen), &cpu_type, &cpuTypeSize, 0, 0);
return cpu_type;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
index d039eda..6514790 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h
@@ -285,6 +285,8 @@ class DynamicImages {
return CPU_TYPE_POWERPC64;
#elif defined(__arm__)
return CPU_TYPE_ARM;
+#elif defined(__aarch64__)
+ return CPU_TYPE_ARM64;
#else
#error "GetNativeCPUType not implemented for this architecture"
#endif
diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
index 4043019..2a19d46 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc
@@ -27,19 +27,32 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <map>
#include <mach/exc.h>
#include <mach/mig.h>
#include <pthread.h>
#include <signal.h>
#include <TargetConditionals.h>
+#include <map>
+
#include "client/mac/handler/exception_handler.h"
#include "client/mac/handler/minidump_generator.h"
#include "common/mac/macho_utilities.h"
#include "common/mac/scoped_task_suspend-inl.h"
#include "google_breakpad/common/minidump_exception_mac.h"
+#ifndef __EXCEPTIONS
+// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
+// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
+// exceptions disabled even when other C++ libraries are used. #undef the try
+// and catch macros first in case libstdc++ is in use and has already provided
+// its own definitions.
+#undef try
+#define try if (true)
+#undef catch
+#define catch(X) if (false)
+#endif // __EXCEPTIONS
+
#ifndef USE_PROTECTED_ALLOCATIONS
#if TARGET_OS_IPHONE
#define USE_PROTECTED_ALLOCATIONS 1
@@ -61,8 +74,12 @@ namespace google_breakpad {
static union {
#if USE_PROTECTED_ALLOCATIONS
+#if defined PAGE_MAX_SIZE
+ char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE)));
+#else
char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
-#endif
+#endif // defined PAGE_MAX_SIZE
+#endif // USE_PROTECTED_ALLOCATIONS
google_breakpad::ExceptionHandler *handler;
} gProtectedData;
@@ -103,14 +120,13 @@ exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
#if !TARGET_OS_IPHONE
-extern "C"
-{
+extern "C" {
// Forward declarations for functions that need "C" style compilation
- boolean_t exc_server(mach_msg_header_t *request,
- mach_msg_header_t *reply);
+ boolean_t exc_server(mach_msg_header_t* request,
+ mach_msg_header_t* reply);
// This symbol must be visible to dlsym() - see
- // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
+ // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=345 for details.
kern_return_t catch_exception_raise(mach_port_t target_port,
mach_port_t failed_thread,
mach_port_t task,
@@ -129,19 +145,19 @@ kern_return_t ForwardException(mach_port_t task,
#if TARGET_OS_IPHONE
// Implementation is based on the implementation generated by mig.
-boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
- mach_msg_header_t *OutHeadP) {
- OutHeadP->msgh_bits =
- MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
- OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
- /* Minimal size: routine() will update it if different */
- OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
- OutHeadP->msgh_local_port = MACH_PORT_NULL;
- OutHeadP->msgh_id = InHeadP->msgh_id + 100;
+boolean_t breakpad_exc_server(mach_msg_header_t* InHeadP,
+ mach_msg_header_t* OutHeadP) {
+ OutHeadP->msgh_bits =
+ MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
+ OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
+ /* Minimal size: routine() will update it if different */
+ OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
+ OutHeadP->msgh_local_port = MACH_PORT_NULL;
+ OutHeadP->msgh_id = InHeadP->msgh_id + 100;
if (InHeadP->msgh_id != 2401) {
- ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
- ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
+ ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record;
+ ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
@@ -171,8 +187,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
#pragma pack()
#endif
- Request *In0P = (Request *)InHeadP;
- Reply *OutP = (Reply *)OutHeadP;
+ Request* In0P = (Request*)InHeadP;
+ Reply* OutP = (Reply*)OutHeadP;
if (In0P->task.name != mach_task_self()) {
return FALSE;
@@ -186,8 +202,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
return TRUE;
}
#else
-boolean_t breakpad_exc_server(mach_msg_header_t *request,
- mach_msg_header_t *reply) {
+boolean_t breakpad_exc_server(mach_msg_header_t* request,
+ mach_msg_header_t* reply) {
return exc_server(request, reply);
}
@@ -207,9 +223,9 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler,
- const char *port_name)
+ const char* port_name)
: dump_path_(),
filter_(filter),
callback_(callback),
@@ -235,7 +251,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
// special constructor if we want to bypass minidump writing and
// simply get a callback with the exception information
ExceptionHandler::ExceptionHandler(DirectCallback callback,
- void *callback_context,
+ void* callback_context,
bool install_handler)
: dump_path_(),
filter_(NULL),
@@ -269,9 +285,13 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
// Send an empty message to the handle port so that a minidump will
// be written
- SendMessageToHandlerThread(write_exception_stream ?
- kWriteDumpWithExceptionMessage :
- kWriteDumpMessage);
+ bool result = SendMessageToHandlerThread(write_exception_stream ?
+ kWriteDumpWithExceptionMessage :
+ kWriteDumpMessage);
+ if (!result) {
+ pthread_mutex_unlock(&minidump_write_mutex_);
+ return false;
+ }
// Wait for the minidump writer to complete its writing. It will unlock
// the mutex when completed
@@ -287,18 +307,18 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
bool ExceptionHandler::WriteMinidump(const string &dump_path,
bool write_exception_stream,
MinidumpCallback callback,
- void *callback_context) {
+ void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
- NULL);
+ NULL);
return handler.WriteMinidump(write_exception_stream);
}
// static
bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
- mach_port_t child_blamed_thread,
- const string &dump_path,
- MinidumpCallback callback,
- void *callback_context) {
+ mach_port_t child_blamed_thread,
+ const string &dump_path,
+ MinidumpCallback callback,
+ void* callback_context) {
ScopedTaskSuspend suspend(child);
MinidumpGenerator generator(child, MACH_PORT_NULL);
@@ -306,34 +326,41 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id);
generator.SetExceptionInformation(EXC_BREAKPOINT,
-#if defined (__i386__) || defined(__x86_64__)
- EXC_I386_BPT,
-#elif defined (__ppc__) || defined (__ppc64__)
- EXC_PPC_BREAKPOINT,
-#elif defined (__arm__)
- EXC_ARM_BREAKPOINT,
+#if defined(__i386__) || defined(__x86_64__)
+ EXC_I386_BPT,
+#elif defined(__ppc__) || defined(__ppc64__)
+ EXC_PPC_BREAKPOINT,
+#elif defined(__arm__) || defined(__aarch64__)
+ EXC_ARM_BREAKPOINT,
#else
#error architecture not supported
#endif
- 0,
- child_blamed_thread);
+ 0,
+ child_blamed_thread);
bool result = generator.Write(dump_filename.c_str());
if (callback) {
return callback(dump_path.c_str(), dump_id.c_str(),
- callback_context, result);
+ callback_context, result);
}
return result;
}
-bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
- int exception_code,
- int exception_subcode,
- mach_port_t thread_name,
- bool exit_after_write,
- bool report_current_thread) {
+bool ExceptionHandler::WriteMinidumpWithException(
+ int exception_type,
+ int exception_code,
+ int exception_subcode,
+ breakpad_ucontext_t* task_context,
+ mach_port_t thread_name,
+ bool exit_after_write,
+ bool report_current_thread) {
bool result = false;
+#if TARGET_OS_IPHONE
+ // _exit() should never be called on iOS.
+ exit_after_write = false;
+#endif
+
if (directCallback_) {
if (directCallback_(callback_context_,
exception_type,
@@ -349,12 +376,15 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
if (filter_ && !filter_(callback_context_))
- return false;
- return crash_generation_client_->RequestDumpForException(
- exception_type,
- exception_code,
- exception_subcode,
- thread_name);
+ return false;
+ result = crash_generation_client_->RequestDumpForException(
+ exception_type,
+ exception_code,
+ exception_subcode,
+ thread_name);
+ if (result && exit_after_write) {
+ _exit(exception_type);
+ }
}
#endif
} else {
@@ -366,6 +396,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
MinidumpGenerator md(mach_task_self(),
report_current_thread ? MACH_PORT_NULL :
mach_thread_self());
+ md.SetTaskContext(task_context);
if (exception_type && exception_code) {
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
@@ -432,12 +463,13 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
exception_behavior_t target_behavior = current.behaviors[found];
kern_return_t result;
+ // TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES
+ // set. https://bugs.chromium.org/p/google-breakpad/issues/detail?id=551
switch (target_behavior) {
case EXCEPTION_DEFAULT:
result = exception_raise(target_port, failed_thread, task, exception,
code, code_count);
break;
-
default:
fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior);
result = KERN_FAILURE;
@@ -448,9 +480,9 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
}
// static
-void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
- ExceptionHandler *self =
- reinterpret_cast<ExceptionHandler *>(exception_handler_class);
+void* ExceptionHandler::WaitForMessage(void* exception_handler_class) {
+ ExceptionHandler* self =
+ reinterpret_cast<ExceptionHandler*>(exception_handler_class);
ExceptionMessage receive;
// Wait for the exception info
@@ -495,11 +527,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {
thread = receive.thread.name;
exception_type = EXC_BREAKPOINT;
-#if defined (__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__)
exception_code = EXC_I386_BPT;
-#elif defined (__ppc__) || defined (__ppc64__)
+#elif defined(__ppc__) || defined(__ppc64__)
exception_code = EXC_PPC_BREAKPOINT;
-#elif defined (__arm__)
+#elif defined(__arm__) || defined(__aarch64__)
exception_code = EXC_ARM_BREAKPOINT;
#else
#error architecture not supported
@@ -509,7 +541,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Write out the dump and save the result for later retrieval
self->last_minidump_write_result_ =
self->WriteMinidumpWithException(exception_type, exception_code,
- 0, thread,
+ 0, NULL, thread,
false, false);
#if USE_PROTECTED_ALLOCATIONS
@@ -544,8 +576,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
- subcode, receive.thread.name, true,
- false);
+ subcode, NULL, receive.thread.name,
+ true, false);
#if USE_PROTECTED_ALLOCATIONS
// This may have become protected again within
@@ -580,7 +612,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
return NULL;
}
-//static
+// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
#if USE_PROTECTED_ALLOCATIONS
if (gBreakpadAllocator)
@@ -590,6 +622,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
EXC_SOFTWARE,
MD_EXCEPTION_CODE_MAC_ABORT,
0,
+ static_cast<breakpad_ucontext_t*>(uc),
mach_thread_self(),
true,
true);
@@ -604,7 +637,6 @@ bool ExceptionHandler::InstallHandler() {
if (gProtectedData.handler != NULL) {
return false;
}
-#if TARGET_OS_IPHONE
if (!IsOutOfProcess()) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
@@ -624,7 +656,6 @@ bool ExceptionHandler::InstallHandler() {
mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ);
#endif
}
-#endif
try {
#if USE_PROTECTED_ALLOCATIONS
@@ -633,7 +664,6 @@ bool ExceptionHandler::InstallHandler() {
#else
previous_ = new ExceptionParameters();
#endif
-
}
catch (std::bad_alloc) {
return false;
@@ -732,7 +762,7 @@ bool ExceptionHandler::Setup(bool install_handler) {
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
}
- return result == KERN_SUCCESS ? true : false;
+ return result == KERN_SUCCESS;
}
bool ExceptionHandler::Teardown() {
diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
index ec09134..f1d9ae9 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h
@@ -41,7 +41,8 @@
#include <string>
-#include "processor/scoped_ptr.h"
+#include "client/mac/handler/ucontext_compat.h"
+#include "common/scoped_ptr.h"
#if !TARGET_OS_IPHONE
#include "client/mac/crash_generation/crash_generation_client.h"
@@ -182,10 +183,13 @@ class ExceptionHandler {
// success, false otherwise.
bool SendMessageToHandlerThread(HandlerThreadMessage message_id);
- // All minidump writing goes through this one routine
+ // All minidump writing goes through this one routine.
+ // |task_context| can be NULL. If not, it will be used to retrieve the
+ // context of the current thread, instead of using |thread_get_state|.
bool WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
+ breakpad_ucontext_t *task_context,
mach_port_t thread_name,
bool exit_after_write,
bool report_current_thread);
diff --git a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
index e0459be..9e9028b 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h
@@ -32,15 +32,14 @@
#include <TargetConditionals.h>
-// On iOS 5, mach/mach_vm.h is not supported anymore. As the architecture is 32
-// bits, we can use the simple vm_ functions instead of the mach_vm_ ones.
+// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding
+// vm_map functions instead.
#if TARGET_OS_IPHONE
#include <mach/vm_map.h>
#define mach_vm_address_t vm_address_t
#define mach_vm_deallocate vm_deallocate
#define mach_vm_read vm_read
-#define mach_vm_region vm_region
-#define mach_vm_region_recurse vm_region_recurse
+#define mach_vm_region_recurse vm_region_recurse_64
#define mach_vm_size_t vm_size_t
#else
#include <mach/mach_vm.h>
diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
index b1d429c..48cd2e9 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
+++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc
@@ -31,6 +31,7 @@
#include <cstdio>
#include <mach/host_info.h>
+#include <mach/machine.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
@@ -41,7 +42,7 @@
#include "client/mac/handler/minidump_generator.h"
-#ifdef HAS_ARM_SUPPORT
+#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
#include <mach/arm/thread_status.h>
#endif
#ifdef HAS_PPC_SUPPORT
@@ -61,7 +62,7 @@ using MacStringUtils::IntegerValueAtIndex;
namespace google_breakpad {
-#if __LP64__
+#if defined(__LP64__) && __LP64__
#define LC_SEGMENT_ARCH LC_SEGMENT_64
#else
#define LC_SEGMENT_ARCH LC_SEGMENT
@@ -77,6 +78,7 @@ MinidumpGenerator::MinidumpGenerator()
crashing_task_(mach_task_self()),
handler_thread_(mach_thread_self()),
cpu_type_(DynamicImages::GetNativeCPUType()),
+ task_context_(NULL),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
GatherSystemInformation();
@@ -94,6 +96,7 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
crashing_task_(crashing_task),
handler_thread_(handler_thread),
cpu_type_(DynamicImages::GetNativeCPUType()),
+ task_context_(NULL),
dynamic_images_(NULL),
memory_blocks_(&allocator_) {
if (crashing_task != mach_task_self()) {
@@ -130,25 +133,47 @@ void MinidumpGenerator::GatherSystemInformation() {
vers_path,
kCFURLPOSIXPathStyle,
false);
- CFDataRef data;
- SInt32 error;
- CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
- &error);
-
+ CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers);
+ CFRelease(sys_vers);
+ if (!read_stream) {
+ return;
+ }
+ if (!CFReadStreamOpen(read_stream)) {
+ CFRelease(read_stream);
+ return;
+ }
+ CFMutableDataRef data = NULL;
+ while (true) {
+ // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes.
+ const CFIndex kMaxBufferLength = 1024;
+ UInt8 data_bytes[kMaxBufferLength];
+ CFIndex num_bytes_read =
+ CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength);
+ if (num_bytes_read < 0) {
+ if (data) {
+ CFRelease(data);
+ data = NULL;
+ }
+ break;
+ } else if (num_bytes_read == 0) {
+ break;
+ } else if (!data) {
+ data = CFDataCreateMutable(NULL, 0);
+ }
+ CFDataAppendBytes(data, data_bytes, num_bytes_read);
+ }
+ CFReadStreamClose(read_stream);
+ CFRelease(read_stream);
if (!data) {
- CFRelease(sys_vers);
return;
}
-
- CFDictionaryRef list = static_cast<CFDictionaryRef>
- (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
- NULL));
+ CFDictionaryRef list =
+ static_cast<CFDictionaryRef>(CFPropertyListCreateWithData(
+ NULL, data, kCFPropertyListImmutable, NULL, NULL));
+ CFRelease(data);
if (!list) {
- CFRelease(sys_vers);
- CFRelease(data);
return;
}
-
CFStringRef build_version = static_cast<CFStringRef>
(CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
CFStringRef product_version = static_cast<CFStringRef>
@@ -157,8 +182,6 @@ void MinidumpGenerator::GatherSystemInformation() {
string product_str = ConvertToString(product_version);
CFRelease(list);
- CFRelease(sys_vers);
- CFRelease(data);
strlcpy(build_string_, build_str.c_str(), sizeof(build_string_));
@@ -168,6 +191,10 @@ void MinidumpGenerator::GatherSystemInformation() {
os_build_number_ = IntegerValueAtIndex(product_str, 2);
}
+void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) {
+ task_context_ = task_context;
+}
+
string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
string *unique_name) {
CFUUIDRef uuid = CFUUIDCreate(NULL);
@@ -288,7 +315,7 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
mach_vm_address_t proposed_next_region_base = next_region_base;
mach_vm_size_t next_region_size;
nesting_level = 0;
- mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
result = mach_vm_region_recurse(crashing_task_, &next_region_base,
&next_region_size, &nesting_level,
region_info, &info_count);
@@ -362,6 +389,10 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
case CPU_TYPE_ARM:
return WriteStackARM(state, stack_location);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return WriteStackARM64(state, stack_location);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return WriteStackPPC(state, stack_location);
@@ -386,6 +417,10 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
case CPU_TYPE_ARM:
return WriteContextARM(state, register_location);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return WriteContextARM64(state, register_location);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return WriteContextPPC(state, register_location);
@@ -403,13 +438,17 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
}
}
-u_int64_t MinidumpGenerator::CurrentPCForStack(
+uint64_t MinidumpGenerator::CurrentPCForStack(
breakpad_thread_state_data_t state) {
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
case CPU_TYPE_ARM:
return CurrentPCForStackARM(state);
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ return CurrentPCForStackARM64(state);
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
return CurrentPCForStackPPC(state);
@@ -423,7 +462,7 @@ u_int64_t MinidumpGenerator::CurrentPCForStack(
return CurrentPCForStackX86_64(state);
#endif
default:
- assert("Unknown CPU type!");
+ assert(0 && "Unknown CPU type!");
return 0;
}
}
@@ -437,7 +476,7 @@ bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
arm_thread_state_t *machine_state =
reinterpret_cast<arm_thread_state_t *>(state);
@@ -479,7 +518,82 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
AddGPR(10);
AddGPR(11);
AddGPR(12);
-#undef AddReg
+#undef AddGPR
+
+ return true;
+}
+#endif
+
+#ifdef HAS_ARM64_SUPPORT
+bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location) {
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+ mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
+ return WriteStackFromStartAddress(start_addr, stack_location);
+}
+
+uint64_t
+MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) {
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+
+ return REGISTER_FROM_THREADSTATE(machine_state, pc);
+}
+
+bool
+MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location)
+{
+ TypedMDRVA<MDRawContextARM64> context(&writer_);
+ arm_thread_state64_t *machine_state =
+ reinterpret_cast<arm_thread_state64_t *>(state);
+
+ if (!context.Allocate())
+ return false;
+
+ *register_location = context.location();
+ MDRawContextARM64 *context_ptr = context.get();
+ context_ptr->context_flags = MD_CONTEXT_ARM64_FULL;
+
+#define AddGPR(a) context_ptr->iregs[a] = \
+ REGISTER_FROM_THREADSTATE(machine_state, x[a])
+
+ context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp);
+ context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr);
+ context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp);
+ context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc);
+ context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr);
+
+ AddGPR(0);
+ AddGPR(1);
+ AddGPR(2);
+ AddGPR(3);
+ AddGPR(4);
+ AddGPR(5);
+ AddGPR(6);
+ AddGPR(7);
+ AddGPR(8);
+ AddGPR(9);
+ AddGPR(10);
+ AddGPR(11);
+ AddGPR(12);
+ AddGPR(13);
+ AddGPR(14);
+ AddGPR(15);
+ AddGPR(16);
+ AddGPR(17);
+ AddGPR(18);
+ AddGPR(19);
+ AddGPR(20);
+ AddGPR(21);
+ AddGPR(22);
+ AddGPR(23);
+ AddGPR(24);
+ AddGPR(25);
+ AddGPR(26);
+ AddGPR(27);
+ AddGPR(28);
#undef AddGPR
return true;
@@ -503,7 +617,7 @@ bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
ppc_thread_state_t *machine_state =
reinterpret_cast<ppc_thread_state_t *>(state);
@@ -511,7 +625,7 @@ MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
return REGISTER_FROM_THREADSTATE(machine_state, srr0);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
ppc_thread_state64_t *machine_state =
reinterpret_cast<ppc_thread_state64_t *>(state);
@@ -533,8 +647,11 @@ bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
MDRawContextPPC *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
-#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
+#define AddGPR(a) context_ptr->gpr[a] = \
+ static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, r ## a)
AddReg(srr0);
AddReg(cr);
@@ -596,8 +713,11 @@ bool MinidumpGenerator::WriteContextPPC64(
MDRawContextPPC64 *context_ptr = context.get();
context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
-#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
+#define AddGPR(a) context_ptr->gpr[a] = \
+ static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, r ## a)
AddReg(srr0);
AddReg(cr);
@@ -661,11 +781,12 @@ bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
x86_thread_state64_t *machine_state =
reinterpret_cast<x86_thread_state64_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp);
+ mach_vm_address_t start_addr = static_cast<mach_vm_address_t>(
+ REGISTER_FROM_THREADSTATE(machine_state, rsp));
return WriteStackFromStartAddress(start_addr, stack_location);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
i386_thread_state_t *machine_state =
reinterpret_cast<i386_thread_state_t *>(state);
@@ -673,7 +794,7 @@ MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
return REGISTER_FROM_THREADSTATE(machine_state, eip);
}
-u_int64_t
+uint64_t
MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
x86_thread_state64_t *machine_state =
reinterpret_cast<x86_thread_state64_t *>(state);
@@ -694,7 +815,8 @@ bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
*register_location = context.location();
MDRawContextX86 *context_ptr = context.get();
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
context_ptr->context_flags = MD_CONTEXT_X86;
AddReg(eax);
@@ -733,7 +855,8 @@ bool MinidumpGenerator::WriteContextX86_64(
*register_location = context.location();
MDRawContextAMD64 *context_ptr = context.get();
-#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
+#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
+ REGISTER_FROM_THREADSTATE(machine_state, a))
context_ptr->context_flags = MD_CONTEXT_AMD64;
AddReg(rax);
@@ -757,7 +880,7 @@ bool MinidumpGenerator::WriteContextX86_64(
// not used in the flags register. Since the minidump format
// specifies 32 bits for the flags register, we can truncate safely
// with no loss.
- context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
+ context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
AddReg(cs);
AddReg(fs);
AddReg(gs);
@@ -770,6 +893,40 @@ bool MinidumpGenerator::WriteContextX86_64(
bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
thread_state_t state,
mach_msg_type_number_t *count) {
+ if (task_context_ && target_thread == mach_thread_self()) {
+ switch (cpu_type_) {
+#ifdef HAS_ARM_SUPPORT
+ case CPU_TYPE_ARM:
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t));
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64: {
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t));
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+ }
+#endif
+#ifdef HAS_X86_SUPPORT
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64: {
+ size_t state_size = cpu_type_ == CPU_TYPE_I386 ?
+ sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t);
+ size_t final_size =
+ std::min(static_cast<size_t>(*count), state_size);
+ memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
+ *count = static_cast<mach_msg_type_number_t>(final_size);
+ return true;
+ }
+#endif
+ }
+ }
+
thread_state_flavor_t flavor;
switch (cpu_type_) {
#ifdef HAS_ARM_SUPPORT
@@ -777,6 +934,11 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
flavor = ARM_THREAD_STATE;
break;
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ flavor = ARM_THREAD_STATE64;
+ break;
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
flavor = PPC_THREAD_STATE;
@@ -878,26 +1040,25 @@ bool MinidumpGenerator::WriteMemoryListStream(
mach_msg_type_number_t stateCount
= static_cast<mach_msg_type_number_t>(sizeof(state));
- if (thread_get_state(exception_thread_,
- BREAKPAD_MACHINE_THREAD_STATE,
- state,
- &stateCount) == KERN_SUCCESS) {
- u_int64_t ip = CurrentPCForStack(state);
+ if (GetThreadState(exception_thread_, state, &stateCount)) {
+ uint64_t ip = CurrentPCForStack(state);
// Bound it to the upper and lower bounds of the region
// it's contained within. If it's not in a known memory region,
// don't bother trying to write it.
- mach_vm_address_t addr = ip;
+ mach_vm_address_t addr = static_cast<vm_address_t>(ip);
mach_vm_size_t size;
natural_t nesting_level = 0;
vm_region_submap_info_64 info;
mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ vm_region_recurse_info_t recurse_info;
+ recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info);
kern_return_t ret =
mach_vm_region_recurse(crashing_task_,
&addr,
&size,
&nesting_level,
- (vm_region_recurse_info_t)&info,
+ recurse_info,
&info_count);
if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
// Try to get 128 bytes before and after the IP, but
@@ -908,8 +1069,9 @@ bool MinidumpGenerator::WriteMemoryListStream(
uintptr_t end_of_range =
std::min(uintptr_t(ip + (kIPMemorySize / 2)),
uintptr_t(addr + size));
- ip_memory_d.memory.data_size =
- end_of_range - ip_memory_d.start_of_memory_range;
+ uintptr_t range_diff = end_of_range -
+ static_cast<uintptr_t>(ip_memory_d.start_of_memory_range);
+ ip_memory_d.memory.data_size = static_cast<uint32_t>(range_diff);
have_ip_memory = true;
// This needs to get appended to the list even though
// the memory bytes aren't filled in yet so the entire
@@ -921,7 +1083,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
}
// Now fill in the memory list and write it.
- unsigned memory_count = memory_blocks_.size();
+ size_t memory_count = memory_blocks_.size();
if (!list.AllocateObjectAndArray(memory_count,
sizeof(MDMemoryDescriptor)))
return false;
@@ -929,7 +1091,7 @@ bool MinidumpGenerator::WriteMemoryListStream(
memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
memory_list_stream->location = list.location();
- list.get()->number_of_memory_ranges = memory_count;
+ list.get()->number_of_memory_ranges = static_cast<uint32_t>(memory_count);
unsigned int i;
for (i = 0; i < memory_count; ++i) {
@@ -1027,6 +1189,11 @@ bool MinidumpGenerator::WriteSystemInfoStream(
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
break;
#endif
+#ifdef HAS_ARM64_SUPPORT
+ case CPU_TYPE_ARM64:
+ info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64;
+ break;
+#endif
#ifdef HAS_PPC_SUPPORT
case CPU_TYPE_POWERPC:
case CPU_TYPE_POWERPC64:
@@ -1078,9 +1245,9 @@ bool MinidumpGenerator::WriteSystemInfoStream(
info_ptr->processor_level =
(info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
// 0xMMSS (Model, Stepping)
- info_ptr->processor_revision =
- (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
- ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4);
+ info_ptr->processor_revision = static_cast<uint16_t>(
+ (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
+ ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4));
// decode extended model info
if (info_ptr->processor_level == 0xF ||
@@ -1103,7 +1270,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
break;
}
- info_ptr->number_of_processors = number_of_processors;
+ info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors);
#if TARGET_OS_IPHONE
info_ptr->platform_id = MD_OS_IOS;
#else
@@ -1142,13 +1309,13 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
return false;
module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
- module->size_of_image = static_cast<u_int32_t>(image->GetVMSize());
+ module->size_of_image = static_cast<uint32_t>(image->GetVMSize());
module->module_name_rva = string_location.rva;
// We'll skip the executable module, because they don't have
// LC_ID_DYLIB load commands, and the crash processing server gets
// version information from the Plist file, anyway.
- if (index != (uint32_t)FindExecutableModule()) {
+ if (index != static_cast<uint32_t>(FindExecutableModule())) {
module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
// Convert MAC dylib version format, which is a 32 bit number, to the
@@ -1208,7 +1375,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
return false;
module->base_of_image = seg->vmaddr + slide;
- module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
+ module->size_of_image = static_cast<uint32_t>(seg->vmsize);
module->module_name_rva = string_location.rva;
bool in_memory = false;
@@ -1267,7 +1434,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
size_t module_name_length = strlen(module_name);
- if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
+ if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t)))
return false;
if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
@@ -1285,22 +1452,27 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
MacFileUtilities::MachoID macho(module_path,
reinterpret_cast<void *>(module->base_of_image),
static_cast<size_t>(module->size_of_image));
- result = macho.UUIDCommand(cpu_type, identifier);
+ result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
if (!result)
- result = macho.MD5(cpu_type, identifier);
+ result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
}
if (!result) {
FileID file_id(module_path);
- result = file_id.MachoIdentifier(cpu_type, identifier);
+ result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE,
+ identifier);
}
if (result) {
- cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
- (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
- (uint32_t)identifier[3];
- cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
- cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7];
+ cv_ptr->signature.data1 =
+ static_cast<uint32_t>(identifier[0]) << 24 |
+ static_cast<uint32_t>(identifier[1]) << 16 |
+ static_cast<uint32_t>(identifier[2]) << 8 |
+ static_cast<uint32_t>(identifier[3]);
+ cv_ptr->signature.data2 =
+ static_cast<uint16_t>(identifier[4] << 8) | identifier[5];
+ cv_ptr->signature.data3 =
+ static_cast<uint16_t>(identifier[6] << 8) | identifier[7];
cv_ptr->signature.data4[0] = identifier[8];
cv_ptr->signature.data4[1] = identifier[9];
cv_ptr->signature.data4[2] = identifier[10];
@@ -1318,8 +1490,8 @@ bool MinidumpGenerator::WriteModuleListStream(
MDRawDirectory *module_list_stream) {
TypedMDRVA<MDRawModuleList> list(&writer_);
- size_t image_count = dynamic_images_ ?
- static_cast<size_t>(dynamic_images_->GetImageCount()) :
+ uint32_t image_count = dynamic_images_ ?
+ dynamic_images_->GetImageCount() :
_dyld_image_count();
if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
@@ -1327,22 +1499,22 @@ bool MinidumpGenerator::WriteModuleListStream(
module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
module_list_stream->location = list.location();
- list.get()->number_of_modules = image_count;
+ list.get()->number_of_modules = static_cast<uint32_t>(image_count);
// Write out the executable module as the first one
MDRawModule module;
- size_t executableIndex = FindExecutableModule();
+ uint32_t executableIndex = FindExecutableModule();
- if (!WriteModuleStream(executableIndex, &module)) {
+ if (!WriteModuleStream(static_cast<unsigned>(executableIndex), &module)) {
return false;
}
list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
int destinationIndex = 1; // Write all other modules after this one
- for (size_t i = 0; i < image_count; ++i) {
+ for (uint32_t i = 0; i < image_count; ++i) {
if (i != executableIndex) {
- if (!WriteModuleStream(i, &module)) {
+ if (!WriteModuleStream(static_cast<unsigned>(i), &module)) {
return false;
}
@@ -1363,7 +1535,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
misc_info_stream->location = info.location();
MDRawMiscInfo *info_ptr = info.get();
- info_ptr->size_of_info = static_cast<u_int32_t>(sizeof(MDRawMiscInfo));
+ info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo));
info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
MD_MISCINFO_FLAGS1_PROCESS_TIMES |
MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO;
@@ -1376,18 +1548,18 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
if (getrusage(RUSAGE_SELF, &usage) != -1) {
// Omit the fractional time since the MDRawMiscInfo only wants seconds
info_ptr->process_user_time =
- static_cast<u_int32_t>(usage.ru_utime.tv_sec);
+ static_cast<uint32_t>(usage.ru_utime.tv_sec);
info_ptr->process_kernel_time =
- static_cast<u_int32_t>(usage.ru_stime.tv_sec);
+ static_cast<uint32_t>(usage.ru_stime.tv_sec);
}
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
static_cast<int>(info_ptr->process_id) };
- u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
+ uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0]));
struct kinfo_proc proc;
size_t size = sizeof(proc);
if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {
info_ptr->process_create_time =
- static_cast<u_int32_t>(proc.kp_proc.p_starttime.tv_sec);
+ static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec);
}
// Speed
@@ -1395,11 +1567,11 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
const uint64_t kOneMillion = 1000 * 1000;
size = sizeof(speed);
sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0);
- info_ptr->processor_max_mhz = static_cast<u_int32_t>(speed / kOneMillion);
- info_ptr->processor_mhz_limit = static_cast<u_int32_t>(speed / kOneMillion);
+ info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion);
+ info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion);
size = sizeof(speed);
sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0);
- info_ptr->processor_current_mhz = static_cast<u_int32_t>(speed / kOneMillion);
+ info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion);
return true;
}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
index 8394ce6..4e4b4a6 100644
--- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
+++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h
@@ -37,6 +37,7 @@
#include <string>
+#include "client/mac/handler/ucontext_compat.h"
#include "client/minidump_file_writer.h"
#include "common/memory.h"
#include "common/mac/macho_utilities.h"
@@ -49,7 +50,9 @@
#define HAS_PPC_SUPPORT
#endif
#if defined(__arm__)
- #define HAS_ARM_SUPPORT
+#define HAS_ARM_SUPPORT
+#elif defined(__aarch64__)
+#define HAS_ARM64_SUPPORT
#elif defined(__i386__) || defined(__x86_64__)
#define HAS_X86_SUPPORT
#endif
@@ -102,6 +105,11 @@ class MinidumpGenerator {
exception_thread_ = thread_name;
}
+ // Specify the task context. If |task_context| is not NULL, it will be used
+ // to retrieve the context of the current thread, instead of using
+ // |thread_get_state|.
+ void SetTaskContext(breakpad_ucontext_t *task_context);
+
// Gather system information. This should be call at least once before using
// the MinidumpGenerator class.
static void GatherSystemInformation();
@@ -125,7 +133,7 @@ class MinidumpGenerator {
bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);
// Helpers
- u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);
bool GetThreadState(thread_act_t target_thread, thread_state_t state,
mach_msg_type_number_t *count);
bool WriteStackFromStartAddress(mach_vm_address_t start_addr,
@@ -146,31 +154,38 @@ class MinidumpGenerator {
MDMemoryDescriptor *stack_location);
bool WriteContextARM(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state);
+#endif
+#ifdef HAS_ARM64_SUPPORT
+ bool WriteStackARM64(breakpad_thread_state_data_t state,
+ MDMemoryDescriptor *stack_location);
+ bool WriteContextARM64(breakpad_thread_state_data_t state,
+ MDLocationDescriptor *register_location);
+ uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_PPC_SUPPORT
bool WriteStackPPC(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);
bool WriteStackPPC64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextPPC64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);
#endif
#ifdef HAS_X86_SUPPORT
bool WriteStackX86(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);
bool WriteStackX86_64(breakpad_thread_state_data_t state,
MDMemoryDescriptor *stack_location);
bool WriteContextX86_64(breakpad_thread_state_data_t state,
MDLocationDescriptor *register_location);
- u_int64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
+ uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);
#endif
// disallow copy ctor and operator=
@@ -192,13 +207,16 @@ class MinidumpGenerator {
// CPU type of the task being dumped.
cpu_type_t cpu_type_;
-
+
// System information
static char build_string_[16];
static int os_major_version_;
static int os_minor_version_;
static int os_build_number_;
-
+
+ // Context of the task to dump.
+ breakpad_ucontext_t *task_context_;
+
// Information about dynamically loaded code
DynamicImages *dynamic_images_;
diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc
new file mode 100644
index 0000000..6142ad1
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ProtectedMemoryAllocator
+//
+// See the header file for documentation
+
+#include "protected_memory_allocator.h"
+#include <assert.h>
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ProtectedMemoryAllocator::ProtectedMemoryAllocator(vm_size_t pool_size)
+ : pool_size_(pool_size),
+ next_alloc_offset_(0),
+ valid_(false) {
+
+ kern_return_t result = vm_allocate(mach_task_self(),
+ &base_address_,
+ pool_size,
+ TRUE
+ );
+
+ valid_ = (result == KERN_SUCCESS);
+ assert(valid_);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ProtectedMemoryAllocator::~ProtectedMemoryAllocator() {
+ vm_deallocate(mach_task_self(),
+ base_address_,
+ pool_size_
+ );
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) {
+ if (valid_ && next_alloc_offset_ + bytes <= pool_size_) {
+ char *p = (char*)base_address_ + next_alloc_offset_;
+ next_alloc_offset_ += bytes;
+ return p;
+ }
+
+ return NULL; // ran out of memory in our allocation block
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+kern_return_t ProtectedMemoryAllocator::Protect() {
+ kern_return_t result = vm_protect(mach_task_self(),
+ base_address_,
+ pool_size_,
+ FALSE,
+ VM_PROT_READ);
+
+ return result;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+kern_return_t ProtectedMemoryAllocator::Unprotect() {
+ kern_return_t result = vm_protect(mach_task_self(),
+ base_address_,
+ pool_size_,
+ FALSE,
+ VM_PROT_READ | VM_PROT_WRITE);
+
+ return result;
+}
diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h
new file mode 100644
index 0000000..7e188db
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ProtectedMemoryAllocator
+//
+// A very simple allocator class which allows allocation, but not deallocation.
+// The allocations can be made read-only with the Protect() method.
+// This class is NOT useful as a general-purpose memory allocation system,
+// since it does not allow deallocation. It is useful to use for a group
+// of allocations which are created in the same time-frame and destroyed
+// in the same time-frame. It is useful for making allocations of memory
+// which will not need to change often once initialized. This memory can then
+// be protected from memory smashers by calling the Protect() method.
+
+#ifndef PROTECTED_MEMORY_ALLOCATOR_H__
+#define PROTECTED_MEMORY_ALLOCATOR_H__
+
+#include <mach/mach.h>
+
+//
+class ProtectedMemoryAllocator {
+ public:
+ ProtectedMemoryAllocator(vm_size_t pool_size);
+ ~ProtectedMemoryAllocator();
+
+ // Returns a pointer to an allocation of size n within the pool.
+ // Fails by returning NULL is no more space is available.
+ // Please note that the pointers returned from this method should not
+ // be freed in any way (for example by calling free() on them ).
+ char * Allocate(vm_size_t n);
+
+ // Returns the base address of the allocation pool.
+ char * GetBaseAddress() { return (char*)base_address_; }
+
+ // Returns the size of the allocation pool, including allocated
+ // plus free space.
+ vm_size_t GetTotalSize() { return pool_size_; }
+
+ // Returns the number of bytes already allocated in the pool.
+ vm_size_t GetAllocatedSize() { return next_alloc_offset_; }
+
+ // Returns the number of bytes available for allocation.
+ vm_size_t GetFreeSize() { return pool_size_ - next_alloc_offset_; }
+
+ // Makes the entire allocation pool read-only including, of course,
+ // all allocations made from the pool.
+ kern_return_t Protect();
+
+ // Makes the entire allocation pool read/write.
+ kern_return_t Unprotect();
+
+ private:
+ vm_size_t pool_size_;
+ vm_address_t base_address_;
+ vm_size_t next_alloc_offset_;
+ bool valid_;
+};
+
+#endif // PROTECTED_MEMORY_ALLOCATOR_H__
diff --git a/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h
new file mode 100644
index 0000000..1e4b752
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h
@@ -0,0 +1,47 @@
+// Copyright 2013 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
+#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
+
+#include <sys/ucontext.h>
+
+// The purpose of this file is to work around the fact that ucontext_t's
+// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64.
+#if defined(__aarch64__)
+// <sys/ucontext.h> doesn't include the below file.
+#include <sys/_types/_ucontext64.h>
+typedef ucontext64_t breakpad_ucontext_t;
+#define breakpad_uc_mcontext uc_mcontext64
+#else
+typedef ucontext_t breakpad_ucontext_t;
+#define breakpad_uc_mcontext uc_mcontext
+#endif // defined(__aarch64__)
+
+#endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_
diff --git a/3rdParty/Breakpad/src/client/minidump_file_writer.cc b/3rdParty/Breakpad/src/client/minidump_file_writer.cc
index c267410..a1957f3 100644
--- a/3rdParty/Breakpad/src/client/minidump_file_writer.cc
+++ b/3rdParty/Breakpad/src/client/minidump_file_writer.cc
@@ -40,10 +40,51 @@
#include "client/minidump_file_writer-inl.h"
#include "common/linux/linux_libc_support.h"
#include "common/string_conversion.h"
-#if __linux__
+#if defined(__linux__) && __linux__
#include "third_party/lss/linux_syscall_support.h"
#endif
+#if defined(__ANDROID__)
+#include <errno.h>
+
+namespace {
+
+bool g_need_ftruncate_workaround = false;
+bool g_checked_need_ftruncate_workaround = false;
+
+void CheckNeedsFTruncateWorkAround(int file) {
+ if (g_checked_need_ftruncate_workaround) {
+ return;
+ }
+ g_checked_need_ftruncate_workaround = true;
+
+ // Attempt an idempotent truncate that chops off nothing and see if we
+ // run into any sort of errors.
+ off_t offset = sys_lseek(file, 0, SEEK_END);
+ if (offset == -1) {
+ // lseek failed. Don't apply work around. It's unlikely that we can write
+ // to a minidump with either method.
+ return;
+ }
+
+ int result = ftruncate(file, offset);
+ if (result == -1 && errno == EACCES) {
+ // It very likely that we are running into the kernel bug in M devices.
+ // We are going to deploy the workaround for writing minidump files
+ // without uses of ftruncate(). This workaround should be fine even
+ // for kernels without the bug.
+ // See http://crbug.com/542840 for more details.
+ g_need_ftruncate_workaround = true;
+ }
+}
+
+bool NeedsFTruncateWorkAround() {
+ return g_need_ftruncate_workaround;
+}
+
+} // namespace
+#endif // defined(__ANDROID__)
+
namespace google_breakpad {
const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast<MDRVA>(-1);
@@ -62,7 +103,7 @@ MinidumpFileWriter::~MinidumpFileWriter() {
bool MinidumpFileWriter::Open(const char *path) {
assert(file_ == -1);
-#if __linux__
+#if defined(__linux__) && __linux__
file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
#else
file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
@@ -75,16 +116,25 @@ void MinidumpFileWriter::SetFile(const int file) {
assert(file_ == -1);
file_ = file;
close_file_when_destroyed_ = false;
+#if defined(__ANDROID__)
+ CheckNeedsFTruncateWorkAround(file);
+#endif
}
bool MinidumpFileWriter::Close() {
bool result = true;
if (file_ != -1) {
- if (-1 == ftruncate(file_, position_)) {
+#if defined(__ANDROID__)
+ if (!NeedsFTruncateWorkAround() && ftruncate(file_, position_)) {
return false;
}
-#if __linux__
+#else
+ if (ftruncate(file_, position_)) {
+ return false;
+ }
+#endif
+#if defined(__linux__) && __linux__
result = (sys_close(file_) == 0);
#else
result = (close(file_) == 0);
@@ -99,11 +149,11 @@ bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
- if (sizeof(wchar_t) == sizeof(u_int16_t)) {
+ if (sizeof(wchar_t) == sizeof(uint16_t)) {
// Shortcut if wchar_t is the same size as MDString's buffer
result = mdstring->Copy(str, mdstring->get()->length);
} else {
- u_int16_t out[2];
+ uint16_t out[2];
int out_idx = 0;
// Copy the string character by character
@@ -120,7 +170,7 @@ bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str,
// zero, but the second one may be zero, depending on the conversion from
// UTF-32.
int out_count = out[1] ? 2 : 1;
- size_t out_size = sizeof(u_int16_t) * out_count;
+ size_t out_size = sizeof(uint16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
@@ -132,7 +182,7 @@ bool MinidumpFileWriter::CopyStringToMDString(const char *str,
unsigned int length,
TypedMDRVA<MDString> *mdstring) {
bool result = true;
- u_int16_t out[2];
+ uint16_t out[2];
int out_idx = 0;
// Copy the string character by character
@@ -147,7 +197,7 @@ bool MinidumpFileWriter::CopyStringToMDString(const char *str,
// Append the one or two UTF-16 characters
int out_count = out[1] ? 2 : 1;
- size_t out_size = sizeof(u_int16_t) * out_count;
+ size_t out_size = sizeof(uint16_t) * out_count;
result = mdstring->CopyIndexAfterObject(out_idx, out, out_size);
out_idx += out_count;
}
@@ -170,17 +220,17 @@ bool MinidumpFileWriter::WriteStringCore(const CharType *str,
// Allocate the string buffer
TypedMDRVA<MDString> mdstring(this);
- if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(u_int16_t)))
+ if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t)))
return false;
// Set length excluding the NULL and copy the string
mdstring.get()->length =
- static_cast<u_int32_t>(mdstring_length * sizeof(u_int16_t));
+ static_cast<uint32_t>(mdstring_length * sizeof(uint16_t));
bool result = CopyStringToMDString(str, mdstring_length, &mdstring);
// NULL terminate
if (result) {
- u_int16_t ch = 0;
+ uint16_t ch = 0;
result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch));
if (result)
@@ -211,7 +261,7 @@ bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
if (!mem.Copy(src, mem.size()))
return false;
- output->start_of_memory_range = reinterpret_cast<u_int64_t>(src);
+ output->start_of_memory_range = reinterpret_cast<uint64_t>(src);
output->memory = mem.location();
return true;
@@ -220,6 +270,20 @@ bool MinidumpFileWriter::WriteMemory(const void *src, size_t size,
MDRVA MinidumpFileWriter::Allocate(size_t size) {
assert(size);
assert(file_ != -1);
+#if defined(__ANDROID__)
+ if (NeedsFTruncateWorkAround()) {
+ // If ftruncate() is not available. We simply increase the size beyond the
+ // current file size. sys_write() will expand the file when data is written
+ // to it. Because we did not over allocate to fit memory pages, we also
+ // do not need to ftruncate() the file once we are done.
+ size_ += size;
+
+ // We don't need to seek since the file is unchanged.
+ MDRVA current_position = position_;
+ position_ += static_cast<MDRVA>(size);
+ return current_position;
+ }
+#endif
size_t aligned_size = (size + 7) & ~7; // 64-bit alignment
if (position_ + aligned_size > size_) {
@@ -253,17 +317,19 @@ bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) {
return false;
// Seek and write the data
-#if __linux__
+#if defined(__linux__) && __linux__
if (sys_lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (sys_write(file_, src, size) == size) {
+ return true;
+ }
+ }
#else
if (lseek(file_, position, SEEK_SET) == static_cast<off_t>(position)) {
if (write(file_, src, size) == size) {
-#endif
return true;
}
}
-
+#endif
return false;
}
diff --git a/3rdParty/Breakpad/src/client/minidump_file_writer.h b/3rdParty/Breakpad/src/client/minidump_file_writer.h
index 313b250..ce32b6d 100644
--- a/3rdParty/Breakpad/src/client/minidump_file_writer.h
+++ b/3rdParty/Breakpad/src/client/minidump_file_writer.h
@@ -74,8 +74,8 @@ public:
MinidumpFileWriter();
~MinidumpFileWriter();
- // Open |path| as the destination of the minidump data. Any existing file
- // will be overwritten.
+ // Open |path| as the destination of the minidump data. If |path| already
+ // exists, then Open() will fail.
// Return true on success, or false on failure.
bool Open(const char *path);
@@ -172,7 +172,7 @@ class UntypedMDRVA {
// Return size and position
inline MDLocationDescriptor location() const {
- MDLocationDescriptor location = { static_cast<u_int32_t>(size_),
+ MDLocationDescriptor location = { static_cast<uint32_t>(size_),
position_ };
return location;
}
diff --git a/3rdParty/Breakpad/src/client/minidump_file_writer_unittest.cc b/3rdParty/Breakpad/src/client/minidump_file_writer_unittest.cc
new file mode 100644
index 0000000..60c364e
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/minidump_file_writer_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: waylonis@google.com (Dan Waylonis)
+
+/*
+ g++ -I../ ../common/convert_UTF.c \
+ ../common/string_conversion.cc \
+ minidump_file_writer.cc \
+ minidump_file_writer_unittest.cc \
+ -o minidump_file_writer_unittest
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "minidump_file_writer-inl.h"
+
+using google_breakpad::MinidumpFileWriter;
+
+#define ASSERT_TRUE(cond) \
+if (!(cond)) { \
+ fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \
+ return false; \
+}
+
+#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
+#define ASSERT_NE(e1, e2) ASSERT_TRUE((e1) != (e2))
+
+struct StringStructure {
+ unsigned long integer_value;
+ MDLocationDescriptor first_string;
+ MDLocationDescriptor second_string;
+};
+
+struct ArrayStructure {
+ unsigned char char_value;
+ unsigned short short_value;
+ unsigned long long_value;
+};
+
+typedef struct {
+ unsigned long count;
+ ArrayStructure array[0];
+} ObjectAndArrayStructure;
+
+static bool WriteFile(const char *path) {
+ MinidumpFileWriter writer;
+ if (writer.Open(path)) {
+ // Test a single structure
+ google_breakpad::TypedMDRVA<StringStructure> strings(&writer);
+ ASSERT_TRUE(strings.Allocate());
+ strings.get()->integer_value = 0xBEEF;
+ const char *first = "First String";
+ ASSERT_TRUE(writer.WriteString(first, 0, &strings.get()->first_string));
+ const wchar_t *second = L"Second String";
+ ASSERT_TRUE(writer.WriteString(second, 0, &strings.get()->second_string));
+
+ // Test an array structure
+ google_breakpad::TypedMDRVA<ArrayStructure> array(&writer);
+ unsigned int count = 10;
+ ASSERT_TRUE(array.AllocateArray(count));
+ for (unsigned char i = 0; i < count; ++i) {
+ ArrayStructure local;
+ local.char_value = i;
+ local.short_value = i + 1;
+ local.long_value = i + 2;
+ ASSERT_TRUE(array.CopyIndex(i, &local));
+ }
+
+ // Test an object followed by an array
+ google_breakpad::TypedMDRVA<ObjectAndArrayStructure> obj_array(&writer);
+ ASSERT_TRUE(obj_array.AllocateObjectAndArray(count,
+ sizeof(ArrayStructure)));
+ obj_array.get()->count = count;
+ for (unsigned char i = 0; i < count; ++i) {
+ ArrayStructure local;
+ local.char_value = i;
+ local.short_value = i + 1;
+ local.long_value = i + 2;
+ ASSERT_TRUE(obj_array.CopyIndexAfterObject(i, &local, sizeof(local)));
+ }
+ }
+
+ return writer.Close();
+}
+
+static bool CompareFile(const char *path) {
+ unsigned long expected[] = {
+#if defined(__BIG_ENDIAN__)
+ 0x0000beef, 0x0000001e, 0x00000018, 0x00000020, 0x00000038, 0x00000000,
+ 0x00000018, 0x00460069, 0x00720073, 0x00740020, 0x00530074, 0x00720069,
+ 0x006e0067, 0x00000000, 0x0000001a, 0x00530065, 0x0063006f, 0x006e0064,
+ 0x00200053, 0x00740072, 0x0069006e, 0x00670000, 0x00000001, 0x00000002,
+ 0x01000002, 0x00000003, 0x02000003, 0x00000004, 0x03000004, 0x00000005,
+ 0x04000005, 0x00000006, 0x05000006, 0x00000007, 0x06000007, 0x00000008,
+ 0x07000008, 0x00000009, 0x08000009, 0x0000000a, 0x0900000a, 0x0000000b,
+ 0x0000000a, 0x00000001, 0x00000002, 0x01000002, 0x00000003, 0x02000003,
+ 0x00000004, 0x03000004, 0x00000005, 0x04000005, 0x00000006, 0x05000006,
+ 0x00000007, 0x06000007, 0x00000008, 0x07000008, 0x00000009, 0x08000009,
+ 0x0000000a, 0x0900000a, 0x0000000b, 0x00000000
+#else
+ 0x0000beef, 0x0000001e, 0x00000018, 0x00000020,
+ 0x00000038, 0x00000000, 0x00000018, 0x00690046,
+ 0x00730072, 0x00200074, 0x00740053, 0x00690072,
+ 0x0067006e, 0x00000000, 0x0000001a, 0x00650053,
+ 0x006f0063, 0x0064006e, 0x00530020, 0x00720074,
+ 0x006e0069, 0x00000067, 0x00011e00, 0x00000002,
+ 0x00021e01, 0x00000003, 0x00031e02, 0x00000004,
+ 0x00041e03, 0x00000005, 0x00051e04, 0x00000006,
+ 0x00061e05, 0x00000007, 0x00071e06, 0x00000008,
+ 0x00081e07, 0x00000009, 0x00091e08, 0x0000000a,
+ 0x000a1e09, 0x0000000b, 0x0000000a, 0x00011c00,
+ 0x00000002, 0x00021c01, 0x00000003, 0x00031c02,
+ 0x00000004, 0x00041c03, 0x00000005, 0x00051c04,
+ 0x00000006, 0x00061c05, 0x00000007, 0x00071c06,
+ 0x00000008, 0x00081c07, 0x00000009, 0x00091c08,
+ 0x0000000a, 0x000a1c09, 0x0000000b, 0x00000000,
+#endif
+ };
+ size_t expected_byte_count = sizeof(expected);
+ int fd = open(path, O_RDONLY, 0600);
+ void *buffer = malloc(expected_byte_count);
+ ASSERT_NE(fd, -1);
+ ASSERT_TRUE(buffer);
+ ASSERT_EQ(read(fd, buffer, expected_byte_count),
+ static_cast<ssize_t>(expected_byte_count));
+
+ char *b1, *b2;
+ b1 = reinterpret_cast<char*>(buffer);
+ b2 = reinterpret_cast<char*>(expected);
+ while (*b1 == *b2) {
+ b1++;
+ b2++;
+ }
+
+ printf("%p\n", reinterpret_cast<void*>(b1 - (char*)buffer));
+
+ ASSERT_EQ(memcmp(buffer, expected, expected_byte_count), 0);
+ return true;
+}
+
+static bool RunTests() {
+ const char *path = "/tmp/minidump_file_writer_unittest.dmp";
+ ASSERT_TRUE(WriteFile(path));
+ ASSERT_TRUE(CompareFile(path));
+ unlink(path);
+ return true;
+}
+
+extern "C" int main(int argc, const char *argv[]) {
+ return RunTests() ? 0 : 1;
+}
diff --git a/3rdParty/Breakpad/src/client/windows/common/auto_critical_section.h b/3rdParty/Breakpad/src/client/windows/common/auto_critical_section.h
new file mode 100644
index 0000000..3fd4b9b
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/common/auto_critical_section.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+
+#include <windows.h>
+
+namespace google_breakpad {
+
+// Automatically enters the critical section in the constructor and leaves
+// the critical section in the destructor.
+class AutoCriticalSection {
+ public:
+ // Creates a new instance with the given critical section object
+ // and enters the critical section immediately.
+ explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs), taken_(false) {
+ assert(cs_);
+ Acquire();
+ }
+
+ // Destructor: leaves the critical section.
+ ~AutoCriticalSection() {
+ if (taken_) {
+ Release();
+ }
+ }
+
+ // Enters the critical section. Recursive Acquire() calls are not allowed.
+ void Acquire() {
+ assert(!taken_);
+ EnterCriticalSection(cs_);
+ taken_ = true;
+ }
+
+ // Leaves the critical section. The caller should not call Release() unless
+ // the critical seciton has been entered already.
+ void Release() {
+ assert(taken_);
+ taken_ = false;
+ LeaveCriticalSection(cs_);
+ }
+
+ private:
+ // Disable copy ctor and operator=.
+ AutoCriticalSection(const AutoCriticalSection&);
+ AutoCriticalSection& operator=(const AutoCriticalSection&);
+
+ CRITICAL_SECTION* cs_;
+ bool taken_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
diff --git a/3rdParty/Breakpad/src/client/windows/common/ipc_protocol.h b/3rdParty/Breakpad/src/client/windows/common/ipc_protocol.h
index b03c032..c748681 100644
--- a/3rdParty/Breakpad/src/client/windows/common/ipc_protocol.h
+++ b/3rdParty/Breakpad/src/client/windows/common/ipc_protocol.h
@@ -30,8 +30,8 @@
#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
-#include <Windows.h>
-#include <DbgHelp.h>
+#include <windows.h>
+#include <dbghelp.h>
#include <string>
#include <utility>
#include "common/windows/string_utils-inl.h"
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/ReadMe.txt b/3rdParty/Breakpad/src/client/windows/crash_generation/ReadMe.txt
new file mode 100644
index 0000000..b54d0e1
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/ReadMe.txt
@@ -0,0 +1,58 @@
+=========================================================================
+ State machine transitions for the Crash Generation Server
+=========================================================================
+
+=========================================================================
+ |
+ STATE | ACTIONS
+ |
+=========================================================================
+ ERROR | Clean up resources used to serve clients.
+ | Always remain in ERROR state.
+-------------------------------------------------------------------------
+ INITIAL | Connect to the pipe asynchronously.
+ | If connection is successfully queued up asynchronously,
+ | go into CONNECTING state.
+ | If connection is done synchronously, go into CONNECTED
+ | state.
+ | For any unexpected problems, go into ERROR state.
+-------------------------------------------------------------------------
+ CONNECTING | Get the result of async connection request.
+ | If I/O is still incomplete, remain in the CONNECTING
+ | state.
+ | If connection is complete, go into CONNECTED state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ CONNECTED | Read from the pipe asynchronously.
+ | If read request is successfully queued up asynchronously,
+ | go into READING state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READING | Get the result of async read request.
+ | If read is done, go into READ_DONE state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READ_DONE | Register the client, prepare the reply and write the
+ | reply to the pipe asynchronously.
+ | If write request is successfully queued up asynchronously,
+ | go into WRITING state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ WRITING | Get the result of the async write request.
+ | If write is done, go into WRITE_DONE state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ WRITE_DONE | Read from the pipe asynchronously (for an ACK).
+ | If read request is successfully queued up asynchonously,
+ | go into READING_ACK state.
+ | For any unexpected problems, go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ READING_ACK | Get the result of the async read request.
+ | If read is done, perform action for successful client
+ | connection.
+ | Go into DISCONNECTING state.
+-------------------------------------------------------------------------
+ DISCONNECTING | Disconnect from the pipe, reset the event and go into
+ | INITIAL state and signal the event again. If anything
+ | fails, go into ERROR state.
+=========================================================================
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.cc b/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.cc
new file mode 100644
index 0000000..ed31263
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.cc
@@ -0,0 +1,223 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/client_info.h"
+#include "client/windows/common/ipc_protocol.h"
+
+static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
+static const size_t kMaxCustomInfoEntries = 4096;
+
+namespace google_breakpad {
+
+ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
+ DWORD pid,
+ MINIDUMP_TYPE dump_type,
+ DWORD* thread_id,
+ EXCEPTION_POINTERS** ex_info,
+ MDRawAssertionInfo* assert_info,
+ const CustomClientInfo& custom_client_info)
+ : crash_server_(crash_server),
+ pid_(pid),
+ dump_type_(dump_type),
+ ex_info_(ex_info),
+ assert_info_(assert_info),
+ custom_client_info_(custom_client_info),
+ thread_id_(thread_id),
+ process_handle_(NULL),
+ dump_requested_handle_(NULL),
+ dump_generated_handle_(NULL),
+ dump_request_wait_handle_(NULL),
+ process_exit_wait_handle_(NULL),
+ crash_id_(NULL) {
+ GetSystemTimeAsFileTime(&start_time_);
+}
+
+bool ClientInfo::Initialize() {
+ process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);
+ if (!process_handle_) {
+ return false;
+ }
+
+ // The crash_id will be the low order word of the process creation time.
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+ if (GetProcessTimes(process_handle_, &creation_time, &exit_time,
+ &kernel_time, &user_time)) {
+ start_time_ = creation_time;
+ }
+ crash_id_ = start_time_.dwLowDateTime;
+
+ dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
+ TRUE, // Manual reset.
+ FALSE, // Initial state.
+ NULL); // Name.
+ if (!dump_requested_handle_) {
+ return false;
+ }
+
+ dump_generated_handle_ = CreateEvent(NULL, // Security attributes.
+ TRUE, // Manual reset.
+ FALSE, // Initial state.
+ NULL); // Name.
+ return dump_generated_handle_ != NULL;
+}
+
+void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() {
+ if (dump_request_wait_handle_) {
+ // Wait for callbacks that might already be running to finish.
+ UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
+ dump_request_wait_handle_ = NULL;
+ }
+}
+
+void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) {
+ if (process_exit_wait_handle_) {
+ if (block_until_no_pending) {
+ // Wait for the callback that might already be running to finish.
+ UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
+ } else {
+ UnregisterWait(process_exit_wait_handle_);
+ }
+ process_exit_wait_handle_ = NULL;
+ }
+}
+
+ClientInfo::~ClientInfo() {
+ // Waiting for the callback to finish here is safe because ClientInfo's are
+ // never destroyed from the dump request handling callback.
+ UnregisterDumpRequestWaitAndBlockUntilNoPending();
+
+ // This is a little tricky because ClientInfo's may be destroyed by the same
+ // callback (OnClientEnd) and waiting for it to finish will cause a deadlock.
+ // Regardless of this complication, wait for any running callbacks to finish
+ // so that the common case is properly handled. In order to avoid deadlocks,
+ // the OnClientEnd callback must call UnregisterProcessExitWait(false)
+ // before deleting the ClientInfo.
+ UnregisterProcessExitWait(true);
+
+ if (process_handle_) {
+ CloseHandle(process_handle_);
+ }
+
+ if (dump_requested_handle_) {
+ CloseHandle(dump_requested_handle_);
+ }
+
+ if (dump_generated_handle_) {
+ CloseHandle(dump_generated_handle_);
+ }
+}
+
+bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
+ SIZE_T bytes_count = 0;
+ if (!ReadProcessMemory(process_handle_,
+ ex_info_,
+ ex_info,
+ sizeof(*ex_info),
+ &bytes_count)) {
+ return false;
+ }
+
+ return bytes_count == sizeof(*ex_info);
+}
+
+bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
+ SIZE_T bytes_count = 0;
+ if (!ReadProcessMemory(process_handle_,
+ thread_id_,
+ thread_id,
+ sizeof(*thread_id),
+ &bytes_count)) {
+ return false;
+ }
+
+ return bytes_count == sizeof(*thread_id);
+}
+
+void ClientInfo::SetProcessUptime() {
+ FILETIME now = {0};
+ GetSystemTimeAsFileTime(&now);
+
+ ULARGE_INTEGER time_start;
+ time_start.HighPart = start_time_.dwHighDateTime;
+ time_start.LowPart = start_time_.dwLowDateTime;
+
+ ULARGE_INTEGER time_now;
+ time_now.HighPart = now.dwHighDateTime;
+ time_now.LowPart = now.dwLowDateTime;
+
+ // Calculate the delay and convert it from 100-nanoseconds to milliseconds.
+ __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;
+
+ // Convert it to a string.
+ wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;
+ _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);
+}
+
+bool ClientInfo::PopulateCustomInfo() {
+ if (custom_client_info_.count > kMaxCustomInfoEntries)
+ return false;
+
+ SIZE_T bytes_count = 0;
+ SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
+
+ // If the scoped array for custom info already has an array, it will be
+ // the same size as what we need. This is because the number of custom info
+ // entries is always the same. So allocate memory only if scoped array has
+ // a NULL pointer.
+ if (!custom_info_entries_.get()) {
+ // Allocate an extra entry for reporting uptime for the client process.
+ custom_info_entries_.reset(
+ new CustomInfoEntry[custom_client_info_.count + 1]);
+ // Use the last element in the array for uptime.
+ custom_info_entries_.get()[custom_client_info_.count].set_name(
+ kCustomInfoProcessUptimeName);
+ }
+
+ if (!ReadProcessMemory(process_handle_,
+ custom_client_info_.entries,
+ custom_info_entries_.get(),
+ read_count,
+ &bytes_count)) {
+ return false;
+ }
+
+ SetProcessUptime();
+ return (bytes_count == read_count);
+}
+
+CustomClientInfo ClientInfo::GetCustomInfo() const {
+ CustomClientInfo custom_info;
+ custom_info.entries = custom_info_entries_.get();
+ // Add 1 to the count from the client process to account for extra entry for
+ // process uptime.
+ custom_info.count = custom_client_info_.count + 1;
+ return custom_info;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.h b/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.h
new file mode 100644
index 0000000..6a8fba3
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/client_info.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include "client/windows/common/ipc_protocol.h"
+#include "common/scoped_ptr.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+class CrashGenerationServer;
+
+// Abstraction for a crash client process.
+class ClientInfo {
+ public:
+ // Creates an instance with the given values. Gets the process
+ // handle for the given process id and creates necessary event
+ // objects.
+ ClientInfo(CrashGenerationServer* crash_server,
+ DWORD pid,
+ MINIDUMP_TYPE dump_type,
+ DWORD* thread_id,
+ EXCEPTION_POINTERS** ex_info,
+ MDRawAssertionInfo* assert_info,
+ const CustomClientInfo& custom_client_info);
+
+ ~ClientInfo();
+
+ CrashGenerationServer* crash_server() const { return crash_server_; }
+ DWORD pid() const { return pid_; }
+ MINIDUMP_TYPE dump_type() const { return dump_type_; }
+ EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
+ MDRawAssertionInfo* assert_info() const { return assert_info_; }
+ DWORD* thread_id() const { return thread_id_; }
+ HANDLE process_handle() const { return process_handle_; }
+ HANDLE dump_requested_handle() const { return dump_requested_handle_; }
+ HANDLE dump_generated_handle() const { return dump_generated_handle_; }
+ DWORD crash_id() const { return crash_id_; }
+ const CustomClientInfo& custom_client_info() const {
+ return custom_client_info_;
+ }
+
+ void set_dump_request_wait_handle(HANDLE value) {
+ dump_request_wait_handle_ = value;
+ }
+
+ void set_process_exit_wait_handle(HANDLE value) {
+ process_exit_wait_handle_ = value;
+ }
+
+ // Unregister the dump request wait operation and wait for all callbacks
+ // that might already be running to complete before returning.
+ void UnregisterDumpRequestWaitAndBlockUntilNoPending();
+
+ // Unregister the process exit wait operation. If block_until_no_pending is
+ // true, wait for all callbacks that might already be running to complete
+ // before returning.
+ void UnregisterProcessExitWait(bool block_until_no_pending);
+
+ bool Initialize();
+ bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
+ bool GetClientThreadId(DWORD* thread_id) const;
+
+ // Reads the custom information from the client process address space.
+ bool PopulateCustomInfo();
+
+ // Returns the client custom information.
+ CustomClientInfo GetCustomInfo() const;
+
+ private:
+ // Calcualtes the uptime for the client process, converts it to a string and
+ // stores it in the last entry of client custom info.
+ void SetProcessUptime();
+
+ // Crash generation server.
+ CrashGenerationServer* crash_server_;
+
+ // Client process ID.
+ DWORD pid_;
+
+ // Dump type requested by the client.
+ MINIDUMP_TYPE dump_type_;
+
+ // Address of an EXCEPTION_POINTERS* variable in the client
+ // process address space that will point to an instance of
+ // EXCEPTION_POINTERS containing information about crash.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ EXCEPTION_POINTERS** ex_info_;
+
+ // Address of an instance of MDRawAssertionInfo in the client
+ // process address space that will contain information about
+ // non-exception related crashes like invalid parameter assertion
+ // failures and pure calls.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ MDRawAssertionInfo* assert_info_;
+
+ // Custom information about the client.
+ CustomClientInfo custom_client_info_;
+
+ // Contains the custom client info entries read from the client process
+ // memory. This will be populated only if the method GetClientCustomInfo
+ // is called.
+ scoped_array<CustomInfoEntry> custom_info_entries_;
+
+ // Address of a variable in the client process address space that
+ // will contain the thread id of the crashing client thread.
+ //
+ // WARNING: Do not dereference these pointers as they are pointers
+ // in the address space of another process.
+ DWORD* thread_id_;
+
+ // Client process handle.
+ HANDLE process_handle_;
+
+ // Dump request event handle.
+ HANDLE dump_requested_handle_;
+
+ // Dump generated event handle.
+ HANDLE dump_generated_handle_;
+
+ // Wait handle for dump request event.
+ HANDLE dump_request_wait_handle_;
+
+ // Wait handle for process exit event.
+ HANDLE process_exit_wait_handle_;
+
+ // Time when the client process started. It is used to determine the uptime
+ // for the client process when it signals a crash.
+ FILETIME start_time_;
+
+ // The crash id which can be used to request an upload. This will be the
+ // value of the low order dword of the process creation time for the process
+ // being dumped.
+ DWORD crash_id_;
+
+ // Disallow copy ctor and operator=.
+ ClientInfo(const ClientInfo& client_info);
+ ClientInfo& operator=(const ClientInfo& client_info);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.cc b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.cc
index b0d3d04..3ba5d4e 100644
--- a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.cc
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.cc
@@ -96,14 +96,14 @@ CrashGenerationClient::CrashGenerationClient(
const CustomClientInfo* custom_info)
: pipe_name_(pipe_name),
pipe_handle_(NULL),
+ custom_info_(),
dump_type_(dump_type),
- thread_id_(0),
- server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
- exception_pointers_(NULL),
- custom_info_() {
+ server_process_id_(0),
+ thread_id_(0),
+ exception_pointers_(NULL) {
memset(&assert_info_, 0, sizeof(assert_info_));
if (custom_info) {
custom_info_ = *custom_info;
@@ -116,14 +116,14 @@ CrashGenerationClient::CrashGenerationClient(
const CustomClientInfo* custom_info)
: pipe_name_(),
pipe_handle_(pipe_handle),
+ custom_info_(),
dump_type_(dump_type),
- thread_id_(0),
- server_process_id_(0),
crash_event_(NULL),
crash_generated_(NULL),
server_alive_(NULL),
- exception_pointers_(NULL),
- custom_info_() {
+ server_process_id_(0),
+ thread_id_(0),
+ exception_pointers_(NULL) {
memset(&assert_info_, 0, sizeof(assert_info_));
if (custom_info) {
custom_info_ = *custom_info;
@@ -178,6 +178,10 @@ CrashGenerationClient::~CrashGenerationClient() {
//
// Returns true if the registration is successful; false otherwise.
bool CrashGenerationClient::Register() {
+ if (IsRegistered()) {
+ return true;
+ }
+
HANDLE pipe = ConnectToServer();
if (!pipe) {
return false;
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.h b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.h
index 2ce14dd..457f731 100644
--- a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.h
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_client.h
@@ -35,7 +35,7 @@
#include <string>
#include <utility>
#include "client/windows/common/ipc_protocol.h"
-#include "processor/scoped_ptr.h"
+#include "common/scoped_ptr.h"
namespace google_breakpad {
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.cc b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.cc
new file mode 100644
index 0000000..0af213b
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.cc
@@ -0,0 +1,943 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/crash_generation_server.h"
+#include <windows.h>
+#include <cassert>
+#include <list>
+#include "client/windows/common/auto_critical_section.h"
+#include "common/scoped_ptr.h"
+
+#include "client/windows/crash_generation/client_info.h"
+
+namespace google_breakpad {
+
+// Output buffer size.
+static const size_t kOutBufferSize = 64;
+
+// Input buffer size.
+static const size_t kInBufferSize = 64;
+
+// Access flags for the client on the dump request event.
+static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
+
+// Access flags for the client on the dump generated event.
+static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
+ SYNCHRONIZE;
+
+// Access flags for the client on the mutex.
+static const DWORD kMutexAccess = SYNCHRONIZE;
+
+// Attribute flags for the pipe.
+static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED;
+
+// Mode for the pipe.
+static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT;
+
+// For pipe I/O, execute the callback in the wait thread itself,
+// since the callback does very little work. The callback executes
+// the code for one of the states of the server state machine and
+// the code for all of the states perform async I/O and hence
+// finish very quickly.
+static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
+
+// Dump request threads will, most likely, generate dumps. That may
+// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
+static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
+ WT_EXECUTELONGFUNCTION;
+
+static bool IsClientRequestValid(const ProtocolMessage& msg) {
+ return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST ||
+ (msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
+ msg.id != 0 &&
+ msg.thread_id != NULL &&
+ msg.exception_pointers != NULL &&
+ msg.assert_info != NULL);
+}
+
+#ifndef NDEBUG
+static bool CheckForIOIncomplete(bool success) {
+ // We should never get an I/O incomplete since we should not execute this
+ // unless the operation has finished and the overlapped event is signaled. If
+ // we do get INCOMPLETE, we have a bug in our code.
+ return success ? false : (GetLastError() == ERROR_IO_INCOMPLETE);
+}
+#endif
+
+CrashGenerationServer::CrashGenerationServer(
+ const std::wstring& pipe_name,
+ SECURITY_ATTRIBUTES* pipe_sec_attrs,
+ OnClientConnectedCallback connect_callback,
+ void* connect_context,
+ OnClientDumpRequestCallback dump_callback,
+ void* dump_context,
+ OnClientExitedCallback exit_callback,
+ void* exit_context,
+ OnClientUploadRequestCallback upload_request_callback,
+ void* upload_context,
+ bool generate_dumps,
+ const std::wstring* dump_path)
+ : pipe_name_(pipe_name),
+ pipe_sec_attrs_(pipe_sec_attrs),
+ pipe_(NULL),
+ pipe_wait_handle_(NULL),
+ server_alive_handle_(NULL),
+ connect_callback_(connect_callback),
+ connect_context_(connect_context),
+ dump_callback_(dump_callback),
+ dump_context_(dump_context),
+ exit_callback_(exit_callback),
+ exit_context_(exit_context),
+ upload_request_callback_(upload_request_callback),
+ upload_context_(upload_context),
+ generate_dumps_(generate_dumps),
+ pre_fetch_custom_info_(true),
+ dump_path_(dump_path ? *dump_path : L""),
+ server_state_(IPC_SERVER_STATE_UNINITIALIZED),
+ shutting_down_(false),
+ overlapped_(),
+ client_info_(NULL) {
+ InitializeCriticalSection(&sync_);
+}
+
+// This should never be called from the OnPipeConnected callback.
+// Otherwise the UnregisterWaitEx call below will cause a deadlock.
+CrashGenerationServer::~CrashGenerationServer() {
+ // New scope to release the lock automatically.
+ {
+ // Make sure no clients are added or removed beyond this point.
+ // Before adding or removing any clients, the critical section
+ // must be entered and the shutting_down_ flag checked. The
+ // critical section is then exited only after the clients_ list
+ // modifications are done and the list is in a consistent state.
+ AutoCriticalSection lock(&sync_);
+
+ // Indicate to existing threads that server is shutting down.
+ shutting_down_ = true;
+ }
+ // No one will modify the clients_ list beyond this point -
+ // not even from another thread.
+
+ // Even if there are no current worker threads running, it is possible that
+ // an I/O request is pending on the pipe right now but not yet done.
+ // In fact, it's very likely this is the case unless we are in an ERROR
+ // state. If we don't wait for the pending I/O to be done, then when the I/O
+ // completes, it may write to invalid memory. AppVerifier will flag this
+ // problem too. So we disconnect from the pipe and then wait for the server
+ // to get into error state so that the pending I/O will fail and get
+ // cleared.
+ DisconnectNamedPipe(pipe_);
+ int num_tries = 100;
+ while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
+ Sleep(10);
+ }
+
+ // Unregister wait on the pipe.
+ if (pipe_wait_handle_) {
+ // Wait for already executing callbacks to finish.
+ UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
+ }
+
+ // Close the pipe to avoid further client connections.
+ if (pipe_) {
+ CloseHandle(pipe_);
+ }
+
+ // Request all ClientInfo objects to unregister all waits.
+ // No need to enter the critical section because no one is allowed to modify
+ // the clients_ list once the shutting_down_ flag is set.
+ std::list<ClientInfo*>::iterator iter;
+ for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+ ClientInfo* client_info = *iter;
+ // Unregister waits. Wait for already executing callbacks to finish.
+ // Unregister the client process exit wait first and only then unregister
+ // the dump request wait. The reason is that the OnClientExit callback
+ // also unregisters the dump request wait and such a race (doing the same
+ // unregistration from two threads) is undesirable.
+ client_info->UnregisterProcessExitWait(true);
+ client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
+
+ // Destroying the ClientInfo here is safe because all wait operations for
+ // this ClientInfo were unregistered and no pending or running callbacks
+ // for this ClientInfo can possible exist (block_until_no_pending option
+ // was used).
+ delete client_info;
+ }
+
+ if (server_alive_handle_) {
+ // Release the mutex before closing the handle so that clients requesting
+ // dumps wait for a long time for the server to generate a dump.
+ ReleaseMutex(server_alive_handle_);
+ CloseHandle(server_alive_handle_);
+ }
+
+ if (overlapped_.hEvent) {
+ CloseHandle(overlapped_.hEvent);
+ }
+
+ DeleteCriticalSection(&sync_);
+}
+
+bool CrashGenerationServer::Start() {
+ if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) {
+ return false;
+ }
+
+ server_state_ = IPC_SERVER_STATE_INITIAL;
+
+ server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
+ if (!server_alive_handle_) {
+ return false;
+ }
+
+ // Event to signal the client connection and pipe reads and writes.
+ overlapped_.hEvent = CreateEvent(NULL, // Security descriptor.
+ TRUE, // Manual reset.
+ FALSE, // Initially nonsignaled.
+ NULL); // Name.
+ if (!overlapped_.hEvent) {
+ return false;
+ }
+
+ // Register a callback with the thread pool for the client connection.
+ if (!RegisterWaitForSingleObject(&pipe_wait_handle_,
+ overlapped_.hEvent,
+ OnPipeConnected,
+ this,
+ INFINITE,
+ kPipeIOThreadFlags)) {
+ return false;
+ }
+
+ pipe_ = CreateNamedPipe(pipe_name_.c_str(),
+ kPipeAttr,
+ kPipeMode,
+ 1,
+ kOutBufferSize,
+ kInBufferSize,
+ 0,
+ pipe_sec_attrs_);
+ if (pipe_ == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ // Kick-start the state machine. This will initiate an asynchronous wait
+ // for client connections.
+ if (!SetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ return false;
+ }
+
+ // If we are in error state, it's because we failed to start listening.
+ return true;
+}
+
+// If the server thread serving clients ever gets into the
+// ERROR state, reset the event, close the pipe and remain
+// in the error state forever. Error state means something
+// that we didn't account for has happened, and it's dangerous
+// to do anything unknowingly.
+void CrashGenerationServer::HandleErrorState() {
+ assert(server_state_ == IPC_SERVER_STATE_ERROR);
+
+ // If the server is shutting down anyway, don't clean up
+ // here since shut down process will clean up.
+ if (shutting_down_) {
+ return;
+ }
+
+ if (pipe_wait_handle_) {
+ UnregisterWait(pipe_wait_handle_);
+ pipe_wait_handle_ = NULL;
+ }
+
+ if (pipe_) {
+ CloseHandle(pipe_);
+ pipe_ = NULL;
+ }
+
+ if (overlapped_.hEvent) {
+ CloseHandle(overlapped_.hEvent);
+ overlapped_.hEvent = NULL;
+ }
+}
+
+// When the server thread serving clients is in the INITIAL state,
+// try to connect to the pipe asynchronously. If the connection
+// finishes synchronously, directly go into the CONNECTED state;
+// otherwise go into the CONNECTING state. For any problems, go
+// into the ERROR state.
+void CrashGenerationServer::HandleInitialState() {
+ assert(server_state_ == IPC_SERVER_STATE_INITIAL);
+
+ if (!ResetEvent(overlapped_.hEvent)) {
+ EnterErrorState();
+ return;
+ }
+
+ bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
+ DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
+
+ // From MSDN, it is not clear that when ConnectNamedPipe is used
+ // in an overlapped mode, will it ever return non-zero value, and
+ // if so, in what cases.
+ assert(!success);
+
+ switch (error_code) {
+ case ERROR_IO_PENDING:
+ EnterStateWhenSignaled(IPC_SERVER_STATE_CONNECTING);
+ break;
+
+ case ERROR_PIPE_CONNECTED:
+ EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
+ break;
+
+ default:
+ EnterErrorState();
+ break;
+ }
+}
+
+// When the server thread serving the clients is in the CONNECTING state,
+// try to get the result of the asynchronous connection request using
+// the OVERLAPPED object. If the result indicates the connection is done,
+// go into the CONNECTED state. If the result indicates I/O is still
+// INCOMPLETE, remain in the CONNECTING state. For any problems,
+// go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectingState() {
+ assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+ DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
+
+ if (success) {
+ EnterStateImmediately(IPC_SERVER_STATE_CONNECTED);
+ } else if (error_code != ERROR_IO_INCOMPLETE) {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ } else {
+ // remain in CONNECTING state
+ }
+}
+
+// When the server thread serving the clients is in the CONNECTED state,
+// try to issue an asynchronous read from the pipe. If read completes
+// synchronously or if I/O is pending then go into the READING state.
+// For any problems, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectedState() {
+ assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
+
+ DWORD bytes_count = 0;
+ memset(&msg_, 0, sizeof(msg_));
+ bool success = ReadFile(pipe_,
+ &msg_,
+ sizeof(msg_),
+ &bytes_count,
+ &overlapped_) != FALSE;
+ DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
+
+ // Note that the asynchronous read issued above can finish before the
+ // code below executes. But, it is okay to change state after issuing
+ // the asynchronous read. This is because even if the asynchronous read
+ // is done, the callback for it would not be executed until the current
+ // thread finishes its execution.
+ if (success || error_code == ERROR_IO_PENDING) {
+ EnterStateWhenSignaled(IPC_SERVER_STATE_READING);
+ } else {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ }
+}
+
+// When the server thread serving the clients is in the READING state,
+// try to get the result of the async read. If async read is done,
+// go into the READ_DONE state. For any problems, go into the
+// DISCONNECTING state.
+void CrashGenerationServer::HandleReadingState() {
+ assert(server_state_ == IPC_SERVER_STATE_READING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+ if (success && bytes_count == sizeof(ProtocolMessage)) {
+ EnterStateImmediately(IPC_SERVER_STATE_READ_DONE);
+ return;
+ }
+
+ assert(!CheckForIOIncomplete(success));
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+}
+
+// When the server thread serving the client is in the READ_DONE state,
+// validate the client's request message, register the client by
+// creating appropriate objects and prepare the response. Then try to
+// write the response to the pipe asynchronously. If that succeeds,
+// go into the WRITING state. For any problems, go into the DISCONNECTING
+// state.
+void CrashGenerationServer::HandleReadDoneState() {
+ assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
+
+ if (!IsClientRequestValid(msg_)) {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ return;
+ }
+
+ if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) {
+ if (upload_request_callback_)
+ upload_request_callback_(upload_context_, msg_.id);
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ return;
+ }
+
+ scoped_ptr<ClientInfo> client_info(
+ new ClientInfo(this,
+ msg_.id,
+ msg_.dump_type,
+ msg_.thread_id,
+ msg_.exception_pointers,
+ msg_.assert_info,
+ msg_.custom_client_info));
+
+ if (!client_info->Initialize()) {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ return;
+ }
+
+ // Issues an asynchronous WriteFile call if successful.
+ // Iff successful, assigns ownership of the client_info pointer to the server
+ // instance, in which case we must be sure not to free it in this function.
+ if (!RespondToClient(client_info.get())) {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ return;
+ }
+
+ // This is only valid as long as it can be found in the clients_ list
+ client_info_ = client_info.release();
+
+ // Note that the asynchronous write issued by RespondToClient function
+ // can finish before the code below executes. But it is okay to change
+ // state after issuing the asynchronous write. This is because even if
+ // the asynchronous write is done, the callback for it would not be
+ // executed until the current thread finishes its execution.
+ EnterStateWhenSignaled(IPC_SERVER_STATE_WRITING);
+}
+
+// When the server thread serving the clients is in the WRITING state,
+// try to get the result of the async write. If the async write is done,
+// go into the WRITE_DONE state. For any problems, go into the
+// DISONNECTING state.
+void CrashGenerationServer::HandleWritingState() {
+ assert(server_state_ == IPC_SERVER_STATE_WRITING);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+ if (success) {
+ EnterStateImmediately(IPC_SERVER_STATE_WRITE_DONE);
+ return;
+ }
+
+ assert(!CheckForIOIncomplete(success));
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+}
+
+// When the server thread serving the clients is in the WRITE_DONE state,
+// try to issue an async read on the pipe. If the read completes synchronously
+// or if I/O is still pending then go into the READING_ACK state. For any
+// issues, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleWriteDoneState() {
+ assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
+
+ DWORD bytes_count = 0;
+ bool success = ReadFile(pipe_,
+ &msg_,
+ sizeof(msg_),
+ &bytes_count,
+ &overlapped_) != FALSE;
+ DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
+
+ if (success) {
+ EnterStateImmediately(IPC_SERVER_STATE_READING_ACK);
+ } else if (error_code == ERROR_IO_PENDING) {
+ EnterStateWhenSignaled(IPC_SERVER_STATE_READING_ACK);
+ } else {
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+ }
+}
+
+// When the server thread serving the clients is in the READING_ACK state,
+// try to get result of async read. Go into the DISCONNECTING state.
+void CrashGenerationServer::HandleReadingAckState() {
+ assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
+
+ DWORD bytes_count = 0;
+ bool success = GetOverlappedResult(pipe_,
+ &overlapped_,
+ &bytes_count,
+ FALSE) != FALSE;
+ if (success) {
+ // The connection handshake with the client is now complete; perform
+ // the callback.
+ if (connect_callback_) {
+ // Note that there is only a single copy of the ClientInfo of the
+ // currently connected client. However it is being referenced from
+ // two different places:
+ // - the client_info_ member
+ // - the clients_ list
+ // The lifetime of this ClientInfo depends on the lifetime of the
+ // client process - basically it can go away at any time.
+ // However, as long as it is referenced by the clients_ list it
+ // is guaranteed to be valid. Enter the critical section and check
+ // to see whether the client_info_ can be found in the list.
+ // If found, execute the callback and only then leave the critical
+ // section.
+ AutoCriticalSection lock(&sync_);
+
+ bool client_is_still_alive = false;
+ std::list<ClientInfo*>::iterator iter;
+ for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+ if (client_info_ == *iter) {
+ client_is_still_alive = true;
+ break;
+ }
+ }
+
+ if (client_is_still_alive) {
+ connect_callback_(connect_context_, client_info_);
+ }
+ }
+ } else {
+ assert(!CheckForIOIncomplete(success));
+ }
+
+ EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
+}
+
+// When the server thread serving the client is in the DISCONNECTING state,
+// disconnect from the pipe and reset the event. If anything fails, go into
+// the ERROR state. If it goes well, go into the INITIAL state and set the
+// event to start all over again.
+void CrashGenerationServer::HandleDisconnectingState() {
+ assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
+
+ // Done serving the client.
+ client_info_ = NULL;
+
+ overlapped_.Internal = NULL;
+ overlapped_.InternalHigh = NULL;
+ overlapped_.Offset = 0;
+ overlapped_.OffsetHigh = 0;
+ overlapped_.Pointer = NULL;
+
+ if (!ResetEvent(overlapped_.hEvent)) {
+ EnterErrorState();
+ return;
+ }
+
+ if (!DisconnectNamedPipe(pipe_)) {
+ EnterErrorState();
+ return;
+ }
+
+ // If the server is shutting down do not connect to the
+ // next client.
+ if (shutting_down_) {
+ return;
+ }
+
+ EnterStateImmediately(IPC_SERVER_STATE_INITIAL);
+}
+
+void CrashGenerationServer::EnterErrorState() {
+ SetEvent(overlapped_.hEvent);
+ server_state_ = IPC_SERVER_STATE_ERROR;
+}
+
+void CrashGenerationServer::EnterStateWhenSignaled(IPCServerState state) {
+ server_state_ = state;
+}
+
+void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
+ server_state_ = state;
+
+ if (!SetEvent(overlapped_.hEvent)) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ }
+}
+
+bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
+ ProtocolMessage* reply) const {
+ reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
+ reply->id = GetCurrentProcessId();
+
+ if (CreateClientHandles(client_info, reply)) {
+ return true;
+ }
+
+ // Closing of remote handles (belonging to a different process) can
+ // only be done through DuplicateHandle.
+ if (reply->dump_request_handle) {
+ DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
+ reply->dump_request_handle, // hSourceHandle
+ NULL, // hTargetProcessHandle
+ 0, // lpTargetHandle
+ 0, // dwDesiredAccess
+ FALSE, // bInheritHandle
+ DUPLICATE_CLOSE_SOURCE); // dwOptions
+ reply->dump_request_handle = NULL;
+ }
+
+ if (reply->dump_generated_handle) {
+ DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
+ reply->dump_generated_handle, // hSourceHandle
+ NULL, // hTargetProcessHandle
+ 0, // lpTargetHandle
+ 0, // dwDesiredAccess
+ FALSE, // bInheritHandle
+ DUPLICATE_CLOSE_SOURCE); // dwOptions
+ reply->dump_generated_handle = NULL;
+ }
+
+ if (reply->server_alive_handle) {
+ DuplicateHandle(client_info.process_handle(), // hSourceProcessHandle
+ reply->server_alive_handle, // hSourceHandle
+ NULL, // hTargetProcessHandle
+ 0, // lpTargetHandle
+ 0, // dwDesiredAccess
+ FALSE, // bInheritHandle
+ DUPLICATE_CLOSE_SOURCE); // dwOptions
+ reply->server_alive_handle = NULL;
+ }
+
+ return false;
+}
+
+bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
+ ProtocolMessage* reply) const {
+ HANDLE current_process = GetCurrentProcess();
+ if (!DuplicateHandle(current_process,
+ client_info.dump_requested_handle(),
+ client_info.process_handle(),
+ &reply->dump_request_handle,
+ kDumpRequestEventAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ if (!DuplicateHandle(current_process,
+ client_info.dump_generated_handle(),
+ client_info.process_handle(),
+ &reply->dump_generated_handle,
+ kDumpGeneratedEventAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ if (!DuplicateHandle(current_process,
+ server_alive_handle_,
+ client_info.process_handle(),
+ &reply->server_alive_handle,
+ kMutexAccess,
+ FALSE,
+ 0)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
+ ProtocolMessage reply;
+ if (!PrepareReply(*client_info, &reply)) {
+ return false;
+ }
+
+ DWORD bytes_count = 0;
+ bool success = WriteFile(pipe_,
+ &reply,
+ sizeof(reply),
+ &bytes_count,
+ &overlapped_) != FALSE;
+ DWORD error_code = success ? ERROR_SUCCESS : GetLastError();
+
+ if (!success && error_code != ERROR_IO_PENDING) {
+ return false;
+ }
+
+ // Takes over ownership of client_info. We MUST return true if AddClient
+ // succeeds.
+ return AddClient(client_info);
+}
+
+// The server thread servicing the clients runs this method. The method
+// implements the state machine described in ReadMe.txt along with the
+// helper methods HandleXXXState.
+void CrashGenerationServer::HandleConnectionRequest() {
+ // If the server is shutting down, get into ERROR state, reset the event so
+ // more workers don't run and return immediately.
+ if (shutting_down_) {
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ ResetEvent(overlapped_.hEvent);
+ return;
+ }
+
+ switch (server_state_) {
+ case IPC_SERVER_STATE_ERROR:
+ HandleErrorState();
+ break;
+
+ case IPC_SERVER_STATE_INITIAL:
+ HandleInitialState();
+ break;
+
+ case IPC_SERVER_STATE_CONNECTING:
+ HandleConnectingState();
+ break;
+
+ case IPC_SERVER_STATE_CONNECTED:
+ HandleConnectedState();
+ break;
+
+ case IPC_SERVER_STATE_READING:
+ HandleReadingState();
+ break;
+
+ case IPC_SERVER_STATE_READ_DONE:
+ HandleReadDoneState();
+ break;
+
+ case IPC_SERVER_STATE_WRITING:
+ HandleWritingState();
+ break;
+
+ case IPC_SERVER_STATE_WRITE_DONE:
+ HandleWriteDoneState();
+ break;
+
+ case IPC_SERVER_STATE_READING_ACK:
+ HandleReadingAckState();
+ break;
+
+ case IPC_SERVER_STATE_DISCONNECTING:
+ HandleDisconnectingState();
+ break;
+
+ default:
+ assert(false);
+ // This indicates that we added one more state without
+ // adding handling code.
+ server_state_ = IPC_SERVER_STATE_ERROR;
+ break;
+ }
+}
+
+bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
+ HANDLE request_wait_handle = NULL;
+ if (!RegisterWaitForSingleObject(&request_wait_handle,
+ client_info->dump_requested_handle(),
+ OnDumpRequest,
+ client_info,
+ INFINITE,
+ kDumpRequestThreadFlags)) {
+ return false;
+ }
+
+ client_info->set_dump_request_wait_handle(request_wait_handle);
+
+ // OnClientEnd will be called when the client process terminates.
+ HANDLE process_wait_handle = NULL;
+ if (!RegisterWaitForSingleObject(&process_wait_handle,
+ client_info->process_handle(),
+ OnClientEnd,
+ client_info,
+ INFINITE,
+ WT_EXECUTEONLYONCE)) {
+ return false;
+ }
+
+ client_info->set_process_exit_wait_handle(process_wait_handle);
+
+ // New scope to hold the lock for the shortest time.
+ {
+ AutoCriticalSection lock(&sync_);
+ if (shutting_down_) {
+ // If server is shutting down, don't add new clients
+ return false;
+ }
+ clients_.push_back(client_info);
+ }
+
+ return true;
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
+ assert(context);
+
+ CrashGenerationServer* obj =
+ reinterpret_cast<CrashGenerationServer*>(context);
+ obj->HandleConnectionRequest();
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
+ assert(context);
+ ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+ CrashGenerationServer* crash_server = client_info->crash_server();
+ assert(crash_server);
+ if (crash_server->pre_fetch_custom_info_) {
+ client_info->PopulateCustomInfo();
+ }
+ crash_server->HandleDumpRequest(*client_info);
+
+ ResetEvent(client_info->dump_requested_handle());
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
+ assert(context);
+ ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+ CrashGenerationServer* crash_server = client_info->crash_server();
+ assert(crash_server);
+
+ crash_server->HandleClientProcessExit(client_info);
+}
+
+void CrashGenerationServer::HandleClientProcessExit(ClientInfo* client_info) {
+ assert(client_info);
+
+ // Must unregister the dump request wait operation and wait for any
+ // dump requests that might be pending to finish before proceeding
+ // with the client_info cleanup.
+ client_info->UnregisterDumpRequestWaitAndBlockUntilNoPending();
+
+ if (exit_callback_) {
+ exit_callback_(exit_context_, client_info);
+ }
+
+ // Start a new scope to release lock automatically.
+ {
+ AutoCriticalSection lock(&sync_);
+ if (shutting_down_) {
+ // The crash generation server is shutting down and as part of the
+ // shutdown process it will delete all clients from the clients_ list.
+ return;
+ }
+ clients_.remove(client_info);
+ }
+
+ // Explicitly unregister the process exit wait using the non-blocking method.
+ // Otherwise, the destructor will attempt to unregister it using the blocking
+ // method which will lead to a deadlock because it is being called from the
+ // callback of the same wait operation
+ client_info->UnregisterProcessExitWait(false);
+
+ delete client_info;
+}
+
+void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
+ bool execute_callback = true;
+ // Generate the dump only if it's explicitly requested by the
+ // server application; otherwise the server might want to generate
+ // dump in the callback.
+ std::wstring dump_path;
+ if (generate_dumps_) {
+ if (!GenerateDump(client_info, &dump_path)) {
+ // client proccess terminated or some other error
+ execute_callback = false;
+ }
+ }
+
+ if (dump_callback_ && execute_callback) {
+ std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;
+ dump_callback_(dump_context_, &client_info, ptr_dump_path);
+ }
+
+ SetEvent(client_info.dump_generated_handle());
+}
+
+bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
+ std::wstring* dump_path) {
+ assert(client.pid() != 0);
+ assert(client.process_handle());
+
+ // We have to get the address of EXCEPTION_INFORMATION from
+ // the client process address space.
+ EXCEPTION_POINTERS* client_ex_info = NULL;
+ if (!client.GetClientExceptionInfo(&client_ex_info)) {
+ return false;
+ }
+
+ DWORD client_thread_id = 0;
+ if (!client.GetClientThreadId(&client_thread_id)) {
+ return false;
+ }
+
+ MinidumpGenerator dump_generator(dump_path_,
+ client.process_handle(),
+ client.pid(),
+ client_thread_id,
+ GetCurrentThreadId(),
+ client_ex_info,
+ client.assert_info(),
+ client.dump_type(),
+ true);
+
+ if (!dump_generator.GenerateDumpFile(dump_path)) {
+ return false;
+ }
+
+ // If the client requests a full memory dump, we will write a normal mini
+ // dump and a full memory dump. Both dump files use the same uuid as file
+ // name prefix.
+ if (client.dump_type() & MiniDumpWithFullMemory) {
+ std::wstring full_dump_path;
+ if (!dump_generator.GenerateFullDumpFile(&full_dump_path)) {
+ return false;
+ }
+ }
+
+ return dump_generator.WriteMinidump();
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.h b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.h
new file mode 100644
index 0000000..0ea90e5
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/crash_generation_server.h
@@ -0,0 +1,299 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+
+#include <list>
+#include <string>
+#include "client/windows/common/ipc_protocol.h"
+#include "client/windows/crash_generation/minidump_generator.h"
+#include "common/scoped_ptr.h"
+
+namespace google_breakpad {
+class ClientInfo;
+
+// Abstraction for server side implementation of out-of-process crash
+// generation protocol for Windows platform only. It generates Windows
+// minidump files for client processes that request dump generation. When
+// the server is requested to start listening for clients (by calling the
+// Start method), it creates a named pipe and waits for the clients to
+// register. In response, it hands them event handles that the client can
+// signal to request dump generation. When the clients request dump
+// generation in this way, the server generates Windows minidump files.
+class CrashGenerationServer {
+ public:
+ typedef void (*OnClientConnectedCallback)(void* context,
+ const ClientInfo* client_info);
+
+ typedef void (*OnClientDumpRequestCallback)(void* context,
+ const ClientInfo* client_info,
+ const std::wstring* file_path);
+
+ typedef void (*OnClientExitedCallback)(void* context,
+ const ClientInfo* client_info);
+
+ typedef void (*OnClientUploadRequestCallback)(void* context,
+ const DWORD crash_id);
+
+ // Creates an instance with the given parameters.
+ //
+ // Parameter pipe_name: Name of the Windows named pipe
+ // Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass
+ // NULL to use default security on the pipe. By default, the pipe created
+ // allows Local System, Administrators and the Creator full control and
+ // the Everyone group read access on the pipe.
+ // Parameter connect_callback: Callback for a new client connection.
+ // Parameter connect_context: Context for client connection callback.
+ // Parameter crash_callback: Callback for a client crash dump request.
+ // Parameter crash_context: Context for client crash dump request callback.
+ // Parameter exit_callback: Callback for client process exit.
+ // Parameter exit_context: Context for client exit callback.
+ // Parameter generate_dumps: Whether to automatically generate dumps.
+ // Client code of this class might want to generate dumps explicitly in the
+ // crash dump request callback. In that case, false can be passed for this
+ // parameter.
+ // Parameter dump_path: Path for generating dumps; required only if true is
+ // passed for generateDumps parameter; NULL can be passed otherwise.
+ CrashGenerationServer(const std::wstring& pipe_name,
+ SECURITY_ATTRIBUTES* pipe_sec_attrs,
+ OnClientConnectedCallback connect_callback,
+ void* connect_context,
+ OnClientDumpRequestCallback dump_callback,
+ void* dump_context,
+ OnClientExitedCallback exit_callback,
+ void* exit_context,
+ OnClientUploadRequestCallback upload_request_callback,
+ void* upload_context,
+ bool generate_dumps,
+ const std::wstring* dump_path);
+
+ ~CrashGenerationServer();
+
+ // Performs initialization steps needed to start listening to clients. Upon
+ // successful return clients may connect to this server's pipe.
+ //
+ // Returns true if initialization is successful; false otherwise.
+ bool Start();
+
+ void pre_fetch_custom_info(bool do_pre_fetch) {
+ pre_fetch_custom_info_ = do_pre_fetch;
+ }
+
+ private:
+ // Various states the client can be in during the handshake with
+ // the server.
+ enum IPCServerState {
+ // Server starts in this state.
+ IPC_SERVER_STATE_UNINITIALIZED,
+
+ // Server is in error state and it cannot serve any clients.
+ IPC_SERVER_STATE_ERROR,
+
+ // Server starts in this state.
+ IPC_SERVER_STATE_INITIAL,
+
+ // Server has issued an async connect to the pipe and it is waiting
+ // for the connection to be established.
+ IPC_SERVER_STATE_CONNECTING,
+
+ // Server is connected successfully.
+ IPC_SERVER_STATE_CONNECTED,
+
+ // Server has issued an async read from the pipe and it is waiting for
+ // the read to finish.
+ IPC_SERVER_STATE_READING,
+
+ // Server is done reading from the pipe.
+ IPC_SERVER_STATE_READ_DONE,
+
+ // Server has issued an async write to the pipe and it is waiting for
+ // the write to finish.
+ IPC_SERVER_STATE_WRITING,
+
+ // Server is done writing to the pipe.
+ IPC_SERVER_STATE_WRITE_DONE,
+
+ // Server has issued an async read from the pipe for an ack and it
+ // is waiting for the read to finish.
+ IPC_SERVER_STATE_READING_ACK,
+
+ // Server is done writing to the pipe and it is now ready to disconnect
+ // and reconnect.
+ IPC_SERVER_STATE_DISCONNECTING
+ };
+
+ //
+ // Helper methods to handle various server IPC states.
+ //
+ void HandleErrorState();
+ void HandleInitialState();
+ void HandleConnectingState();
+ void HandleConnectedState();
+ void HandleReadingState();
+ void HandleReadDoneState();
+ void HandleWritingState();
+ void HandleWriteDoneState();
+ void HandleReadingAckState();
+ void HandleDisconnectingState();
+
+ // Prepares reply for a client from the given parameters.
+ bool PrepareReply(const ClientInfo& client_info,
+ ProtocolMessage* reply) const;
+
+ // Duplicates various handles in the ClientInfo object for the client
+ // process and stores them in the given ProtocolMessage instance. If
+ // creating any handle fails, ProtocolMessage will contain the handles
+ // already created successfully, which should be closed by the caller.
+ bool CreateClientHandles(const ClientInfo& client_info,
+ ProtocolMessage* reply) const;
+
+ // Response to the given client. Return true if all steps of
+ // responding to the client succeed, false otherwise.
+ bool RespondToClient(ClientInfo* client_info);
+
+ // Handles a connection request from the client.
+ void HandleConnectionRequest();
+
+ // Handles a dump request from the client.
+ void HandleDumpRequest(const ClientInfo& client_info);
+
+ // Callback for pipe connected event.
+ static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
+
+ // Callback for a dump request.
+ static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
+
+ // Callback for client process exit event.
+ static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
+
+ // Handles client process exit.
+ void HandleClientProcessExit(ClientInfo* client_info);
+
+ // Adds the given client to the list of registered clients.
+ bool AddClient(ClientInfo* client_info);
+
+ // Generates dump for the given client.
+ bool GenerateDump(const ClientInfo& client, std::wstring* dump_path);
+
+ // Puts the server in a permanent error state and sets a signal such that
+ // the state will be immediately entered after the current state transition
+ // is complete.
+ void EnterErrorState();
+
+ // Puts the server in the specified state and sets a signal such that the
+ // state is immediately entered after the current state transition is
+ // complete.
+ void EnterStateImmediately(IPCServerState state);
+
+ // Puts the server in the specified state. No signal will be set, so the state
+ // transition will only occur when signaled manually or by completion of an
+ // asynchronous IO operation.
+ void EnterStateWhenSignaled(IPCServerState state);
+
+ // Sync object for thread-safe access to the shared list of clients.
+ CRITICAL_SECTION sync_;
+
+ // List of clients.
+ std::list<ClientInfo*> clients_;
+
+ // Pipe name.
+ std::wstring pipe_name_;
+
+ // Pipe security attributes
+ SECURITY_ATTRIBUTES* pipe_sec_attrs_;
+
+ // Handle to the pipe used for handshake with clients.
+ HANDLE pipe_;
+
+ // Pipe wait handle.
+ HANDLE pipe_wait_handle_;
+
+ // Handle to server-alive mutex.
+ HANDLE server_alive_handle_;
+
+ // Callback for a successful client connection.
+ OnClientConnectedCallback connect_callback_;
+
+ // Context for client connected callback.
+ void* connect_context_;
+
+ // Callback for a client dump request.
+ OnClientDumpRequestCallback dump_callback_;
+
+ // Context for client dump request callback.
+ void* dump_context_;
+
+ // Callback for client process exit.
+ OnClientExitedCallback exit_callback_;
+
+ // Context for client process exit callback.
+ void* exit_context_;
+
+ // Callback for upload request.
+ OnClientUploadRequestCallback upload_request_callback_;
+
+ // Context for upload request callback.
+ void* upload_context_;
+
+ // Whether to generate dumps.
+ bool generate_dumps_;
+
+ // Wether to populate custom information up-front.
+ bool pre_fetch_custom_info_;
+
+ // The dump path for the server.
+ const std::wstring dump_path_;
+
+ // State of the server in performing the IPC with the client.
+ // Note that since we restrict the pipe to one instance, we
+ // only need to keep one state of the server. Otherwise, server
+ // would have one state per client it is talking to.
+ IPCServerState server_state_;
+
+ // Whether the server is shutting down.
+ bool shutting_down_;
+
+ // Overlapped instance for async I/O on the pipe.
+ OVERLAPPED overlapped_;
+
+ // Message object used in IPC with the client.
+ ProtocolMessage msg_;
+
+ // Client Info for the client that's connecting to the server.
+ ClientInfo* client_info_;
+
+ // Disable copy ctor and operator=.
+ CrashGenerationServer(const CrashGenerationServer& crash_server);
+ CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.cc b/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.cc
new file mode 100644
index 0000000..100e365
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.cc
@@ -0,0 +1,583 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/minidump_generator.h"
+
+#include <assert.h>
+#include <avrfsdk.h>
+
+#include <algorithm>
+#include <iterator>
+#include <list>
+#include <vector>
+
+#include "client/windows/common/auto_critical_section.h"
+#include "common/scoped_ptr.h"
+#include "common/windows/guid_string.h"
+
+using std::wstring;
+
+namespace {
+
+// A helper class used to collect handle operations data. Unlike
+// |MiniDumpWithHandleData| it records the operations for a single handle value
+// only, making it possible to include this information to a minidump.
+class HandleTraceData {
+ public:
+ HandleTraceData();
+ ~HandleTraceData();
+
+ // Collects the handle operations data and formats a user stream to be added
+ // to the minidump.
+ bool CollectHandleData(HANDLE process_handle,
+ EXCEPTION_POINTERS* exception_pointers);
+
+ // Fills the user dump entry with a pointer to the collected handle operations
+ // data. Returns |true| if the entry was initialized successfully, or |false|
+ // if no trace data is available.
+ bool GetUserStream(MINIDUMP_USER_STREAM* user_stream);
+
+ private:
+ // Reads the exception code from the client process's address space.
+ // This routine assumes that the client process's pointer width matches ours.
+ static bool ReadExceptionCode(HANDLE process_handle,
+ EXCEPTION_POINTERS* exception_pointers,
+ DWORD* exception_code);
+
+ // Stores handle operations retrieved by VerifierEnumerateResource().
+ static ULONG CALLBACK RecordHandleOperations(void* resource_description,
+ void* enumeration_context,
+ ULONG* enumeration_level);
+
+ // Function pointer type for VerifierEnumerateResource, which is looked up
+ // dynamically.
+ typedef BOOL (WINAPI* VerifierEnumerateResourceType)(
+ HANDLE Process,
+ ULONG Flags,
+ ULONG ResourceType,
+ AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback,
+ PVOID EnumerationContext);
+
+ // Handle to dynamically loaded verifier.dll.
+ HMODULE verifier_module_;
+
+ // Pointer to the VerifierEnumerateResource function.
+ VerifierEnumerateResourceType enumerate_resource_;
+
+ // Handle value to look for.
+ ULONG64 handle_;
+
+ // List of handle operations for |handle_|.
+ std::list<AVRF_HANDLE_OPERATION> operations_;
+
+ // Minidump stream data.
+ std::vector<char> stream_;
+};
+
+HandleTraceData::HandleTraceData()
+ : verifier_module_(NULL),
+ enumerate_resource_(NULL),
+ handle_(NULL) {
+}
+
+HandleTraceData::~HandleTraceData() {
+ if (verifier_module_) {
+ FreeLibrary(verifier_module_);
+ }
+}
+
+bool HandleTraceData::CollectHandleData(
+ HANDLE process_handle,
+ EXCEPTION_POINTERS* exception_pointers) {
+ DWORD exception_code;
+ if (!ReadExceptionCode(process_handle, exception_pointers, &exception_code)) {
+ return false;
+ }
+
+ // Verify whether the execption is STATUS_INVALID_HANDLE. Do not record any
+ // handle information if it is a different exception to keep the minidump
+ // small.
+ if (exception_code != STATUS_INVALID_HANDLE) {
+ return true;
+ }
+
+ // Load verifier!VerifierEnumerateResource() dynamically.
+ verifier_module_ = LoadLibrary(TEXT("verifier.dll"));
+ if (!verifier_module_) {
+ return false;
+ }
+
+ enumerate_resource_ = reinterpret_cast<VerifierEnumerateResourceType>(
+ GetProcAddress(verifier_module_, "VerifierEnumerateResource"));
+ if (!enumerate_resource_) {
+ return false;
+ }
+
+ // STATUS_INVALID_HANDLE does not provide the offending handle value in
+ // the exception parameters so we have to guess. At the moment we scan
+ // the handle operations trace looking for the last invalid handle operation
+ // and record only the operations for that handle value.
+ if (enumerate_resource_(process_handle,
+ 0,
+ AvrfResourceHandleTrace,
+ &RecordHandleOperations,
+ this) != ERROR_SUCCESS) {
+ // The handle tracing must have not been enabled.
+ return true;
+ }
+
+ // Now that |handle_| is initialized, purge all irrelevant operations.
+ std::list<AVRF_HANDLE_OPERATION>::iterator i = operations_.begin();
+ std::list<AVRF_HANDLE_OPERATION>::iterator i_end = operations_.end();
+ while (i != i_end) {
+ if (i->Handle == handle_) {
+ ++i;
+ } else {
+ i = operations_.erase(i);
+ }
+ }
+
+ // Convert the list of recorded operations to a minidump stream.
+ stream_.resize(sizeof(MINIDUMP_HANDLE_OPERATION_LIST) +
+ sizeof(AVRF_HANDLE_OPERATION) * operations_.size());
+
+ MINIDUMP_HANDLE_OPERATION_LIST* stream_data =
+ reinterpret_cast<MINIDUMP_HANDLE_OPERATION_LIST*>(
+ &stream_.front());
+ stream_data->SizeOfHeader = sizeof(MINIDUMP_HANDLE_OPERATION_LIST);
+ stream_data->SizeOfEntry = sizeof(AVRF_HANDLE_OPERATION);
+ stream_data->NumberOfEntries = static_cast<ULONG32>(operations_.size());
+ stream_data->Reserved = 0;
+ std::copy(operations_.begin(),
+ operations_.end(),
+#ifdef _MSC_VER
+ stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>(
+ reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1),
+ operations_.size())
+#else
+ reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1)
+#endif
+ );
+
+ return true;
+}
+
+bool HandleTraceData::GetUserStream(MINIDUMP_USER_STREAM* user_stream) {
+ if (stream_.empty()) {
+ return false;
+ } else {
+ user_stream->Type = HandleOperationListStream;
+ user_stream->BufferSize = static_cast<ULONG>(stream_.size());
+ user_stream->Buffer = &stream_.front();
+ return true;
+ }
+}
+
+bool HandleTraceData::ReadExceptionCode(
+ HANDLE process_handle,
+ EXCEPTION_POINTERS* exception_pointers,
+ DWORD* exception_code) {
+ EXCEPTION_POINTERS pointers;
+ if (!ReadProcessMemory(process_handle,
+ exception_pointers,
+ &pointers,
+ sizeof(pointers),
+ NULL)) {
+ return false;
+ }
+
+ if (!ReadProcessMemory(process_handle,
+ pointers.ExceptionRecord,
+ exception_code,
+ sizeof(*exception_code),
+ NULL)) {
+ return false;
+ }
+
+ return true;
+}
+
+ULONG CALLBACK HandleTraceData::RecordHandleOperations(
+ void* resource_description,
+ void* enumeration_context,
+ ULONG* enumeration_level) {
+ AVRF_HANDLE_OPERATION* description =
+ reinterpret_cast<AVRF_HANDLE_OPERATION*>(resource_description);
+ HandleTraceData* self =
+ reinterpret_cast<HandleTraceData*>(enumeration_context);
+
+ // Remember the last invalid handle operation.
+ if (description->OperationType == OperationDbBADREF) {
+ self->handle_ = description->Handle;
+ }
+
+ // Record all handle operations.
+ self->operations_.push_back(*description);
+
+ *enumeration_level = HeapEnumerationEverything;
+ return ERROR_SUCCESS;
+}
+
+} // namespace
+
+namespace google_breakpad {
+
+MinidumpGenerator::MinidumpGenerator(
+ const std::wstring& dump_path,
+ const HANDLE process_handle,
+ const DWORD process_id,
+ const DWORD thread_id,
+ const DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exception_pointers,
+ MDRawAssertionInfo* assert_info,
+ const MINIDUMP_TYPE dump_type,
+ const bool is_client_pointers)
+ : dbghelp_module_(NULL),
+ write_dump_(NULL),
+ rpcrt4_module_(NULL),
+ create_uuid_(NULL),
+ process_handle_(process_handle),
+ process_id_(process_id),
+ thread_id_(thread_id),
+ requesting_thread_id_(requesting_thread_id),
+ exception_pointers_(exception_pointers),
+ assert_info_(assert_info),
+ dump_type_(dump_type),
+ is_client_pointers_(is_client_pointers),
+ dump_path_(dump_path),
+ uuid_generated_(false),
+ dump_file_(INVALID_HANDLE_VALUE),
+ full_dump_file_(INVALID_HANDLE_VALUE),
+ dump_file_is_internal_(false),
+ full_dump_file_is_internal_(false),
+ additional_streams_(NULL),
+ callback_info_(NULL) {
+ uuid_ = {0};
+ InitializeCriticalSection(&module_load_sync_);
+ InitializeCriticalSection(&get_proc_address_sync_);
+}
+
+MinidumpGenerator::~MinidumpGenerator() {
+ if (dump_file_is_internal_ && dump_file_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(dump_file_);
+ }
+
+ if (full_dump_file_is_internal_ && full_dump_file_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(full_dump_file_);
+ }
+
+ if (dbghelp_module_) {
+ FreeLibrary(dbghelp_module_);
+ }
+
+ if (rpcrt4_module_) {
+ FreeLibrary(rpcrt4_module_);
+ }
+
+ DeleteCriticalSection(&get_proc_address_sync_);
+ DeleteCriticalSection(&module_load_sync_);
+}
+
+bool MinidumpGenerator::WriteMinidump() {
+ bool full_memory_dump = (dump_type_ & MiniDumpWithFullMemory) != 0;
+ if (dump_file_ == INVALID_HANDLE_VALUE ||
+ (full_memory_dump && full_dump_file_ == INVALID_HANDLE_VALUE)) {
+ return false;
+ }
+
+ MiniDumpWriteDumpType write_dump = GetWriteDump();
+ if (!write_dump) {
+ return false;
+ }
+
+ MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
+ MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
+
+ // Setup the exception information object only if it's a dump
+ // due to an exception.
+ if (exception_pointers_) {
+ dump_exception_pointers = &dump_exception_info;
+ dump_exception_info.ThreadId = thread_id_;
+ dump_exception_info.ExceptionPointers = exception_pointers_;
+ dump_exception_info.ClientPointers = is_client_pointers_;
+ }
+
+ // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
+ // information about the exception handler to the Breakpad processor.
+ // The information will help the processor determine which threads are
+ // relevant. The Breakpad processor does not require this information but
+ // can function better with Breakpad-generated dumps when it is present.
+ // The native debugger is not harmed by the presence of this information.
+ MDRawBreakpadInfo breakpad_info = {0};
+ if (!is_client_pointers_) {
+ // Set the dump thread id and requesting thread id only in case of
+ // in-process dump generation.
+ breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+ MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+ breakpad_info.dump_thread_id = thread_id_;
+ breakpad_info.requesting_thread_id = requesting_thread_id_;
+ }
+
+ int additional_streams_count = additional_streams_ ?
+ additional_streams_->UserStreamCount : 0;
+ scoped_array<MINIDUMP_USER_STREAM> user_stream_array(
+ new MINIDUMP_USER_STREAM[3 + additional_streams_count]);
+ user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
+ user_stream_array[0].BufferSize = sizeof(breakpad_info);
+ user_stream_array[0].Buffer = &breakpad_info;
+
+ MINIDUMP_USER_STREAM_INFORMATION user_streams;
+ user_streams.UserStreamCount = 1;
+ user_streams.UserStreamArray = user_stream_array.get();
+
+ MDRawAssertionInfo* actual_assert_info = assert_info_;
+ MDRawAssertionInfo client_assert_info = {{0}};
+
+ if (assert_info_) {
+ // If the assertion info object lives in the client process,
+ // read the memory of the client process.
+ if (is_client_pointers_) {
+ SIZE_T bytes_read = 0;
+ if (!ReadProcessMemory(process_handle_,
+ assert_info_,
+ &client_assert_info,
+ sizeof(client_assert_info),
+ &bytes_read)) {
+ if (dump_file_is_internal_)
+ CloseHandle(dump_file_);
+ if (full_dump_file_is_internal_ &&
+ full_dump_file_ != INVALID_HANDLE_VALUE)
+ CloseHandle(full_dump_file_);
+ return false;
+ }
+
+ if (bytes_read != sizeof(client_assert_info)) {
+ if (dump_file_is_internal_)
+ CloseHandle(dump_file_);
+ if (full_dump_file_is_internal_ &&
+ full_dump_file_ != INVALID_HANDLE_VALUE)
+ CloseHandle(full_dump_file_);
+ return false;
+ }
+
+ actual_assert_info = &client_assert_info;
+ }
+
+ user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
+ user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
+ user_stream_array[1].Buffer = actual_assert_info;
+ ++user_streams.UserStreamCount;
+ }
+
+ if (additional_streams_) {
+ for (size_t i = 0;
+ i < additional_streams_->UserStreamCount;
+ i++, user_streams.UserStreamCount++) {
+ user_stream_array[user_streams.UserStreamCount].Type =
+ additional_streams_->UserStreamArray[i].Type;
+ user_stream_array[user_streams.UserStreamCount].BufferSize =
+ additional_streams_->UserStreamArray[i].BufferSize;
+ user_stream_array[user_streams.UserStreamCount].Buffer =
+ additional_streams_->UserStreamArray[i].Buffer;
+ }
+ }
+
+ // If the process is terminated by STATUS_INVALID_HANDLE exception store
+ // the trace of operations for the offending handle value. Do nothing special
+ // if the client already requested the handle trace to be stored in the dump.
+ HandleTraceData handle_trace_data;
+ if (exception_pointers_ && (dump_type_ & MiniDumpWithHandleData) == 0) {
+ if (!handle_trace_data.CollectHandleData(process_handle_,
+ exception_pointers_)) {
+ if (dump_file_is_internal_)
+ CloseHandle(dump_file_);
+ if (full_dump_file_is_internal_ &&
+ full_dump_file_ != INVALID_HANDLE_VALUE)
+ CloseHandle(full_dump_file_);
+ return false;
+ }
+ }
+
+ bool result_full_memory = true;
+ if (full_memory_dump) {
+ result_full_memory = write_dump(
+ process_handle_,
+ process_id_,
+ full_dump_file_,
+ static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal))
+ | MiniDumpWithHandleData),
+ exception_pointers_ ? &dump_exception_info : NULL,
+ &user_streams,
+ NULL) != FALSE;
+ }
+
+ // Add handle operations trace stream to the minidump if it was collected.
+ if (handle_trace_data.GetUserStream(
+ &user_stream_array[user_streams.UserStreamCount])) {
+ ++user_streams.UserStreamCount;
+ }
+
+ bool result_minidump = write_dump(
+ process_handle_,
+ process_id_,
+ dump_file_,
+ static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory))
+ | MiniDumpNormal),
+ exception_pointers_ ? &dump_exception_info : NULL,
+ &user_streams,
+ callback_info_) != FALSE;
+
+ return result_minidump && result_full_memory;
+}
+
+bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) {
+ // The dump file was already set by handle or this function was previously
+ // called.
+ if (dump_file_ != INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ wstring dump_file_path;
+ if (!GenerateDumpFilePath(&dump_file_path)) {
+ return false;
+ }
+
+ dump_file_ = CreateFile(dump_file_path.c_str(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (dump_file_ == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ dump_file_is_internal_ = true;
+ *dump_path = dump_file_path;
+ return true;
+}
+
+bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) {
+ // A full minidump was not requested.
+ if ((dump_type_ & MiniDumpWithFullMemory) == 0) {
+ return false;
+ }
+
+ // The dump file was already set by handle or this function was previously
+ // called.
+ if (full_dump_file_ != INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ wstring full_dump_file_path;
+ if (!GenerateDumpFilePath(&full_dump_file_path)) {
+ return false;
+ }
+ full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp
+ full_dump_file_path.append(TEXT("-full.dmp"));
+
+ full_dump_file_ = CreateFile(full_dump_file_path.c_str(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (full_dump_file_ == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ full_dump_file_is_internal_ = true;
+ *full_dump_path = full_dump_file_path;
+ return true;
+}
+
+HMODULE MinidumpGenerator::GetDbghelpModule() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!dbghelp_module_) {
+ dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
+ }
+
+ return dbghelp_module_;
+}
+
+MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
+ AutoCriticalSection lock(&get_proc_address_sync_);
+ if (!write_dump_) {
+ HMODULE module = GetDbghelpModule();
+ if (module) {
+ FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
+ write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
+ }
+ }
+
+ return write_dump_;
+}
+
+HMODULE MinidumpGenerator::GetRpcrt4Module() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!rpcrt4_module_) {
+ rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
+ }
+
+ return rpcrt4_module_;
+}
+
+MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
+ AutoCriticalSection lock(&module_load_sync_);
+ if (!create_uuid_) {
+ HMODULE module = GetRpcrt4Module();
+ if (module) {
+ FARPROC proc = GetProcAddress(module, "UuidCreate");
+ create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
+ }
+ }
+
+ return create_uuid_;
+}
+
+bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
+ if (!uuid_generated_) {
+ UuidCreateType create_uuid = GetCreateUuid();
+ if (!create_uuid) {
+ return false;
+ }
+
+ create_uuid(&uuid_);
+ uuid_generated_ = true;
+ }
+
+ wstring id_str = GUIDString::GUIDToWString(&uuid_);
+
+ *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.h b/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.h
new file mode 100644
index 0000000..a707c0b
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/windows/crash_generation/minidump_generator.h
@@ -0,0 +1,203 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
+#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <rpc.h>
+#include <list>
+#include <string>
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Abstraction for various objects and operations needed to generate
+// minidump on Windows. This abstraction is useful to hide all the gory
+// details for minidump generation and provide a clean interface to
+// the clients to generate minidumps.
+class MinidumpGenerator {
+ public:
+ // Creates an instance with the given parameters.
+ // is_client_pointers specifies whether the exception_pointers and
+ // assert_info point into the process that is being dumped.
+ // Before calling WriteMinidump on the returned instance a dump file muct be
+ // specified by a call to either SetDumpFile() or GenerateDumpFile().
+ // If a full dump file will be requested via a subsequent call to either
+ // SetFullDumpFile or GenerateFullDumpFile() dump_type must include
+ // MiniDumpWithFullMemory.
+ MinidumpGenerator(const std::wstring& dump_path,
+ const HANDLE process_handle,
+ const DWORD process_id,
+ const DWORD thread_id,
+ const DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exception_pointers,
+ MDRawAssertionInfo* assert_info,
+ const MINIDUMP_TYPE dump_type,
+ const bool is_client_pointers);
+
+ ~MinidumpGenerator();
+
+ void SetDumpFile(const HANDLE dump_file) { dump_file_ = dump_file; }
+ void SetFullDumpFile(const HANDLE full_dump_file) {
+ full_dump_file_ = full_dump_file;
+ }
+
+ // Generate the name for the dump file that will be written to once
+ // WriteMinidump() is called. Can only be called once and cannot be called
+ // if the dump file is set via SetDumpFile().
+ bool GenerateDumpFile(std::wstring* dump_path);
+
+ // Generate the name for the full dump file that will be written to once
+ // WriteMinidump() is called. Cannot be called unless the minidump type
+ // includes MiniDumpWithFullMemory. Can only be called once and cannot be
+ // called if the dump file is set via SetFullDumpFile().
+ bool GenerateFullDumpFile(std::wstring* full_dump_path);
+
+ void SetAdditionalStreams(
+ MINIDUMP_USER_STREAM_INFORMATION* additional_streams) {
+ additional_streams_ = additional_streams;
+ }
+
+ void SetCallback(MINIDUMP_CALLBACK_INFORMATION* callback_info) {
+ callback_info_ = callback_info;
+ }
+
+ // Writes the minidump with the given parameters. Stores the
+ // dump file path in the dump_path parameter if dump generation
+ // succeeds.
+ bool WriteMinidump();
+
+ private:
+ // Function pointer type for MiniDumpWriteDump, which is looked up
+ // dynamically.
+ typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
+ HANDLE hProcess,
+ DWORD ProcessId,
+ HANDLE hFile,
+ MINIDUMP_TYPE DumpType,
+ CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+ // Function pointer type for UuidCreate, which is looked up dynamically.
+ typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
+
+ // Loads the appropriate DLL lazily in a thread safe way.
+ HMODULE GetDbghelpModule();
+
+ // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
+ // function lazily and in a thread-safe manner.
+ MiniDumpWriteDumpType GetWriteDump();
+
+ // Loads the appropriate DLL lazily in a thread safe way.
+ HMODULE GetRpcrt4Module();
+
+ // Loads the appropriate DLL and gets a pointer to the UuidCreate
+ // function lazily and in a thread-safe manner.
+ UuidCreateType GetCreateUuid();
+
+ // Returns the path for the file to write dump to.
+ bool GenerateDumpFilePath(std::wstring* file_path);
+
+ // Handle to dynamically loaded DbgHelp.dll.
+ HMODULE dbghelp_module_;
+
+ // Pointer to the MiniDumpWriteDump function.
+ MiniDumpWriteDumpType write_dump_;
+
+ // Handle to dynamically loaded rpcrt4.dll.
+ HMODULE rpcrt4_module_;
+
+ // Pointer to the UuidCreate function.
+ UuidCreateType create_uuid_;
+
+ // Handle for the process to dump.
+ HANDLE process_handle_;
+
+ // Process ID for the process to dump.
+ DWORD process_id_;
+
+ // The crashing thread ID.
+ DWORD thread_id_;
+
+ // The thread ID which is requesting the dump.
+ DWORD requesting_thread_id_;
+
+ // Pointer to the exception information for the crash. This may point to an
+ // address in the crashing process so it should not be dereferenced.
+ EXCEPTION_POINTERS* exception_pointers_;
+
+ // Assertion info for the report.
+ MDRawAssertionInfo* assert_info_;
+
+ // Type of minidump to generate.
+ MINIDUMP_TYPE dump_type_;
+
+ // Specifies whether the exception_pointers_ reference memory in the crashing
+ // process.
+ bool is_client_pointers_;
+
+ // Folder path to store dump files.
+ std::wstring dump_path_;
+
+ // UUID used to make dump file names.
+ UUID uuid_;
+ bool uuid_generated_;
+
+ // The file where the dump will be written.
+ HANDLE dump_file_;
+
+ // The file where the full dump will be written.
+ HANDLE full_dump_file_;
+
+ // Tracks whether the dump file handle is managed externally.
+ bool dump_file_is_internal_;
+
+ // Tracks whether the full dump file handle is managed externally.
+ bool full_dump_file_is_internal_;
+
+ // Additional streams to be written to the dump.
+ MINIDUMP_USER_STREAM_INFORMATION* additional_streams_;
+
+ // The user defined callback for the various stages of the dump process.
+ MINIDUMP_CALLBACK_INFORMATION* callback_info_;
+
+ // Critical section to sychronize action of loading modules dynamically.
+ CRITICAL_SECTION module_load_sync_;
+
+ // Critical section to synchronize action of dynamically getting function
+ // addresses from modules.
+ CRITICAL_SECTION get_proc_address_sync_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
diff --git a/3rdParty/Breakpad/src/client/windows/handler/exception_handler.cc b/3rdParty/Breakpad/src/client/windows/handler/exception_handler.cc
index 272ca5f..b3daa0c 100644
--- a/3rdParty/Breakpad/src/client/windows/handler/exception_handler.cc
+++ b/3rdParty/Breakpad/src/client/windows/handler/exception_handler.cc
@@ -27,7 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <ObjBase.h>
+#include <objbase.h>
#include <algorithm>
#include <cassert>
@@ -41,16 +41,17 @@
namespace google_breakpad {
-static const int kWaitForHandlerThreadMs = 60000;
-static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
-
// This is passed as the context to the MinidumpWriteDump callback.
typedef struct {
- ULONG64 memory_base;
- ULONG memory_size;
- bool finished;
+ AppMemoryList::const_iterator iter;
+ AppMemoryList::const_iterator end;
} MinidumpCallbackContext;
+// This define is new to Windows 10.
+#ifndef DBG_PRINTEXCEPTION_WIDE_C
+#define DBG_PRINTEXCEPTION_WIDE_C ((DWORD)0x4001000A)
+#endif
+
vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
LONG ExceptionHandler::handler_stack_index_ = 0;
CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
@@ -71,7 +72,8 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path,
handler_types,
dump_type,
pipe_name,
- NULL,
+ NULL, // pipe_handle
+ NULL, // crash_generation_client
custom_info);
}
@@ -89,10 +91,32 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path,
callback_context,
handler_types,
dump_type,
- NULL,
+ NULL, // pipe_name
pipe_handle,
+ NULL, // crash_generation_client
custom_info);
-}
+}
+
+ExceptionHandler::ExceptionHandler(
+ const wstring& dump_path,
+ FilterCallback filter,
+ MinidumpCallback callback,
+ void* callback_context,
+ int handler_types,
+ CrashGenerationClient* crash_generation_client) {
+ // The dump_type, pipe_name and custom_info that are passed in to Initialize()
+ // are not used. The ones set in crash_generation_client are used instead.
+ Initialize(dump_path,
+ filter,
+ callback,
+ callback_context,
+ handler_types,
+ MiniDumpNormal, // dump_type - not used
+ NULL, // pipe_name - not used
+ NULL, // pipe_handle
+ crash_generation_client,
+ NULL); // custom_info - not used
+}
ExceptionHandler::ExceptionHandler(const wstring &dump_path,
FilterCallback filter,
@@ -105,20 +129,23 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
callback_context,
handler_types,
MiniDumpNormal,
- NULL,
- NULL,
- NULL);
+ NULL, // pipe_name
+ NULL, // pipe_handle
+ NULL, // crash_generation_client
+ NULL); // custom_info
}
-void ExceptionHandler::Initialize(const wstring& dump_path,
- FilterCallback filter,
- MinidumpCallback callback,
- void* callback_context,
- int handler_types,
- MINIDUMP_TYPE dump_type,
- const wchar_t* pipe_name,
- HANDLE pipe_handle,
- const CustomClientInfo* custom_info) {
+void ExceptionHandler::Initialize(
+ const wstring& dump_path,
+ FilterCallback filter,
+ MinidumpCallback callback,
+ void* callback_context,
+ int handler_types,
+ MINIDUMP_TYPE dump_type,
+ const wchar_t* pipe_name,
+ HANDLE pipe_handle,
+ CrashGenerationClient* crash_generation_client,
+ const CustomClientInfo* custom_info) {
LONG instance_count = InterlockedIncrement(&instance_count_);
filter_ = filter;
callback_ = callback;
@@ -147,24 +174,22 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
assertion_ = NULL;
handler_return_value_ = false;
handle_debug_exceptions_ = false;
+ consume_invalid_handle_exceptions_ = false;
+
+ // Attempt to use out-of-process if user has specified a pipe or a
+ // crash generation client.
+ scoped_ptr<CrashGenerationClient> client;
+ if (crash_generation_client) {
+ client.reset(crash_generation_client);
+ } else if (pipe_name) {
+ client.reset(
+ new CrashGenerationClient(pipe_name, dump_type_, custom_info));
+ } else if (pipe_handle) {
+ client.reset(
+ new CrashGenerationClient(pipe_handle, dump_type_, custom_info));
+ }
- // Attempt to use out-of-process if user has specified a pipe.
- if (pipe_name != NULL || pipe_handle != NULL) {
- assert(!(pipe_name && pipe_handle));
-
- scoped_ptr<CrashGenerationClient> client;
- if (pipe_name) {
- client.reset(
- new CrashGenerationClient(pipe_name,
- dump_type_,
- custom_info));
- } else {
- client.reset(
- new CrashGenerationClient(pipe_handle,
- dump_type_,
- custom_info));
- }
-
+ if (client.get() != NULL) {
// If successful in registering with the monitoring process,
// there is no need to setup in-process crash generation.
if (client->Register()) {
@@ -192,6 +217,7 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
// Don't attempt to create the thread if we could not create the semaphores.
if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
DWORD thread_id;
+ const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
handler_thread_ = CreateThread(NULL, // lpThreadAttributes
kExceptionHandlerThreadInitialStackSize,
ExceptionHandlerThreadMain,
@@ -222,6 +248,12 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
set_dump_path(dump_path);
}
+ // Reserve one element for the instruction memory
+ AppMemory instruction_memory;
+ instruction_memory.ptr = NULL;
+ instruction_memory.length = 0;
+ app_memory_info_.push_back(instruction_memory);
+
// There is a race condition here. If the first instance has not yet
// initialized the critical section, the second (and later) instances may
// try to use uninitialized critical section object. The feature of multiple
@@ -323,6 +355,7 @@ ExceptionHandler::~ExceptionHandler() {
// inside DllMain.
is_shutdown_ = true;
ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
+ const int kWaitForHandlerThreadMs = 60000;
WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
#else
TerminateThread(handler_thread_, 1);
@@ -450,7 +483,14 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
DWORD code = exinfo->ExceptionRecord->ExceptionCode;
LONG action;
bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
- (code == EXCEPTION_SINGLE_STEP);
+ (code == EXCEPTION_SINGLE_STEP) ||
+ (code == DBG_PRINTEXCEPTION_C) ||
+ (code == DBG_PRINTEXCEPTION_WIDE_C);
+
+ if (code == EXCEPTION_INVALID_HANDLE &&
+ current_handler->consume_invalid_handle_exceptions_) {
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
bool success = false;
@@ -729,12 +769,72 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
// static
bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
MinidumpCallback callback,
- void* callback_context) {
+ void* callback_context,
+ MINIDUMP_TYPE dump_type) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context,
- HANDLER_NONE);
+ HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
return handler.WriteMinidump();
}
+// static
+bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
+ DWORD child_blamed_thread,
+ const wstring& dump_path,
+ MinidumpCallback callback,
+ void* callback_context,
+ MINIDUMP_TYPE dump_type) {
+ EXCEPTION_RECORD ex;
+ CONTEXT ctx;
+ EXCEPTION_POINTERS exinfo = { NULL, NULL };
+ // As documented on MSDN, on failure SuspendThread returns (DWORD) -1
+ const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
+ DWORD last_suspend_count = kFailedToSuspendThread;
+ HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT |
+ THREAD_QUERY_INFORMATION |
+ THREAD_SUSPEND_RESUME,
+ FALSE,
+ child_blamed_thread);
+ // This thread may have died already, so not opening the handle is a
+ // non-fatal error.
+ if (child_thread_handle != NULL) {
+ last_suspend_count = SuspendThread(child_thread_handle);
+ if (last_suspend_count != kFailedToSuspendThread) {
+ ctx.ContextFlags = CONTEXT_ALL;
+ if (GetThreadContext(child_thread_handle, &ctx)) {
+ memset(&ex, 0, sizeof(ex));
+ ex.ExceptionCode = EXCEPTION_BREAKPOINT;
+#if defined(_M_IX86)
+ ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Eip);
+#elif defined(_M_X64)
+ ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Rip);
+#endif
+ exinfo.ExceptionRecord = &ex;
+ exinfo.ContextRecord = &ctx;
+ }
+ }
+ }
+
+ ExceptionHandler handler(dump_path, NULL, callback, callback_context,
+ HANDLER_NONE, dump_type, (HANDLE)NULL, NULL);
+ bool success = handler.WriteMinidumpWithExceptionForProcess(
+ child_blamed_thread,
+ exinfo.ExceptionRecord ? &exinfo : NULL,
+ NULL, child, false);
+
+ if (last_suspend_count != kFailedToSuspendThread) {
+ ResumeThread(child_thread_handle);
+ }
+
+ CloseHandle(child_thread_handle);
+
+ if (callback) {
+ success = callback(handler.dump_path_c_, handler.next_minidump_id_c_,
+ callback_context, NULL, NULL, success);
+ }
+
+ return success;
+}
+
bool ExceptionHandler::WriteMinidumpWithException(
DWORD requesting_thread_id,
EXCEPTION_POINTERS* exinfo,
@@ -753,106 +853,11 @@ bool ExceptionHandler::WriteMinidumpWithException(
if (IsOutOfProcess()) {
success = crash_generation_client_->RequestDump(exinfo, assertion);
} else {
- if (minidump_write_dump_) {
- HANDLE dump_file = CreateFile(next_minidump_path_c_,
- GENERIC_WRITE,
- 0, // no sharing
- NULL,
- CREATE_NEW, // fail if exists
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (dump_file != INVALID_HANDLE_VALUE) {
- MINIDUMP_EXCEPTION_INFORMATION except_info;
- except_info.ThreadId = requesting_thread_id;
- except_info.ExceptionPointers = exinfo;
- except_info.ClientPointers = FALSE;
-
- // Add an MDRawBreakpadInfo stream to the minidump, to provide
- // additional information about the exception handler to the Breakpad
- // processor. The information will help the processor determine which
- // threads are relevant. The Breakpad processor does not require this
- // information but can function better with Breakpad-generated dumps
- // when it is present. The native debugger is not harmed by the
- // presence of this information.
- MDRawBreakpadInfo breakpad_info;
- breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
- MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
- breakpad_info.dump_thread_id = GetCurrentThreadId();
- breakpad_info.requesting_thread_id = requesting_thread_id;
-
- // Leave room in user_stream_array for a possible assertion info stream.
- MINIDUMP_USER_STREAM user_stream_array[2];
- user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
- user_stream_array[0].BufferSize = sizeof(breakpad_info);
- user_stream_array[0].Buffer = &breakpad_info;
-
- MINIDUMP_USER_STREAM_INFORMATION user_streams;
- user_streams.UserStreamCount = 1;
- user_streams.UserStreamArray = user_stream_array;
-
- if (assertion) {
- user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
- user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
- user_stream_array[1].Buffer = assertion;
- ++user_streams.UserStreamCount;
- }
-
- MINIDUMP_CALLBACK_INFORMATION callback;
- MinidumpCallbackContext context;
- MINIDUMP_CALLBACK_INFORMATION* callback_pointer = NULL;
- // Older versions of DbgHelp.dll don't correctly put the memory around
- // the faulting instruction pointer into the minidump. This
- // callback will ensure that it gets included.
- if (exinfo) {
- // Find a memory region of 256 bytes centered on the
- // faulting instruction pointer.
- const ULONG64 instruction_pointer =
-#if defined(_M_IX86)
- exinfo->ContextRecord->Eip;
-#elif defined(_M_AMD64)
- exinfo->ContextRecord->Rip;
-#else
-#error Unsupported platform
-#endif
-
- MEMORY_BASIC_INFORMATION info;
- if (VirtualQuery(reinterpret_cast<LPCVOID>(instruction_pointer),
- &info,
- sizeof(MEMORY_BASIC_INFORMATION)) != 0 &&
- info.State == MEM_COMMIT) {
- // Attempt to get 128 bytes before and after the instruction
- // pointer, but settle for whatever's available up to the
- // boundaries of the memory region.
- const ULONG64 kIPMemorySize = 256;
- context.memory_base =
- (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress),
- instruction_pointer - (kIPMemorySize / 2));
- ULONG64 end_of_range =
- (std::min)(instruction_pointer + (kIPMemorySize / 2),
- reinterpret_cast<ULONG64>(info.BaseAddress)
- + info.RegionSize);
- context.memory_size =
- static_cast<ULONG>(end_of_range - context.memory_base);
-
- context.finished = false;
- callback.CallbackRoutine = MinidumpWriteDumpCallback;
- callback.CallbackParam = reinterpret_cast<void*>(&context);
- callback_pointer = &callback;
- }
- }
-
- // The explicit comparison to TRUE avoids a warning (C4800).
- success = (minidump_write_dump_(GetCurrentProcess(),
- GetCurrentProcessId(),
- dump_file,
- dump_type_,
- exinfo ? &except_info : NULL,
- &user_streams,
- callback_pointer) == TRUE);
-
- CloseHandle(dump_file);
- }
- }
+ success = WriteMinidumpWithExceptionForProcess(requesting_thread_id,
+ exinfo,
+ assertion,
+ GetCurrentProcess(),
+ true);
}
if (callback_) {
@@ -876,16 +881,16 @@ BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback(
case MemoryCallback: {
MinidumpCallbackContext* callback_context =
reinterpret_cast<MinidumpCallbackContext*>(context);
- if (callback_context->finished)
+ if (callback_context->iter == callback_context->end)
return FALSE;
// Include the specified memory region.
- callback_output->MemoryBase = callback_context->memory_base;
- callback_output->MemorySize = callback_context->memory_size;
- callback_context->finished = true;
+ callback_output->MemoryBase = callback_context->iter->ptr;
+ callback_output->MemorySize = callback_context->iter->length;
+ callback_context->iter++;
return TRUE;
}
-
+
// Include all modules.
case IncludeModuleCallback:
case ModuleCallback:
@@ -906,6 +911,132 @@ BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback(
return FALSE;
}
+bool ExceptionHandler::WriteMinidumpWithExceptionForProcess(
+ DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ HANDLE process,
+ bool write_requester_stream) {
+ bool success = false;
+ if (minidump_write_dump_) {
+ HANDLE dump_file = CreateFile(next_minidump_path_c_,
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL,
+ CREATE_NEW, // fail if exists
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (dump_file != INVALID_HANDLE_VALUE) {
+ MINIDUMP_EXCEPTION_INFORMATION except_info;
+ except_info.ThreadId = requesting_thread_id;
+ except_info.ExceptionPointers = exinfo;
+ except_info.ClientPointers = FALSE;
+
+ // Leave room in user_stream_array for possible breakpad and
+ // assertion info streams.
+ MINIDUMP_USER_STREAM user_stream_array[2];
+ MINIDUMP_USER_STREAM_INFORMATION user_streams;
+ user_streams.UserStreamCount = 0;
+ user_streams.UserStreamArray = user_stream_array;
+
+ if (write_requester_stream) {
+ // Add an MDRawBreakpadInfo stream to the minidump, to provide
+ // additional information about the exception handler to the Breakpad
+ // processor. The information will help the processor determine which
+ // threads are relevant. The Breakpad processor does not require this
+ // information but can function better with Breakpad-generated dumps
+ // when it is present. The native debugger is not harmed by the
+ // presence of this information.
+ MDRawBreakpadInfo breakpad_info;
+ breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+ MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+ breakpad_info.dump_thread_id = GetCurrentThreadId();
+ breakpad_info.requesting_thread_id = requesting_thread_id;
+
+ int index = user_streams.UserStreamCount;
+ user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM;
+ user_stream_array[index].BufferSize = sizeof(breakpad_info);
+ user_stream_array[index].Buffer = &breakpad_info;
+ ++user_streams.UserStreamCount;
+ }
+
+ if (assertion) {
+ int index = user_streams.UserStreamCount;
+ user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM;
+ user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo);
+ user_stream_array[index].Buffer = assertion;
+ ++user_streams.UserStreamCount;
+ }
+
+ // Older versions of DbgHelp.dll don't correctly put the memory around
+ // the faulting instruction pointer into the minidump. This
+ // callback will ensure that it gets included.
+ if (exinfo) {
+ // Find a memory region of 256 bytes centered on the
+ // faulting instruction pointer.
+ const ULONG64 instruction_pointer =
+#if defined(_M_IX86)
+ exinfo->ContextRecord->Eip;
+#elif defined(_M_AMD64)
+ exinfo->ContextRecord->Rip;
+#else
+#error Unsupported platform
+#endif
+
+ MEMORY_BASIC_INFORMATION info;
+ if (VirtualQueryEx(process,
+ reinterpret_cast<LPCVOID>(instruction_pointer),
+ &info,
+ sizeof(MEMORY_BASIC_INFORMATION)) != 0 &&
+ info.State == MEM_COMMIT) {
+ // Attempt to get 128 bytes before and after the instruction
+ // pointer, but settle for whatever's available up to the
+ // boundaries of the memory region.
+ const ULONG64 kIPMemorySize = 256;
+ ULONG64 base =
+ (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress),
+ instruction_pointer - (kIPMemorySize / 2));
+ ULONG64 end_of_range =
+ (std::min)(instruction_pointer + (kIPMemorySize / 2),
+ reinterpret_cast<ULONG64>(info.BaseAddress)
+ + info.RegionSize);
+ ULONG size = static_cast<ULONG>(end_of_range - base);
+
+ AppMemory& elt = app_memory_info_.front();
+ elt.ptr = base;
+ elt.length = size;
+ }
+ }
+
+ MinidumpCallbackContext context;
+ context.iter = app_memory_info_.begin();
+ context.end = app_memory_info_.end();
+
+ // Skip the reserved element if there was no instruction memory
+ if (context.iter->ptr == 0) {
+ context.iter++;
+ }
+
+ MINIDUMP_CALLBACK_INFORMATION callback;
+ callback.CallbackRoutine = MinidumpWriteDumpCallback;
+ callback.CallbackParam = reinterpret_cast<void*>(&context);
+
+ // The explicit comparison to TRUE avoids a warning (C4800).
+ success = (minidump_write_dump_(process,
+ GetProcessId(process),
+ dump_file,
+ dump_type_,
+ exinfo ? &except_info : NULL,
+ &user_streams,
+ &callback) == TRUE);
+
+ CloseHandle(dump_file);
+ }
+ }
+
+ return success;
+}
+
void ExceptionHandler::UpdateNextID() {
assert(uuid_create_);
UUID id = {0};
@@ -926,4 +1057,26 @@ void ExceptionHandler::UpdateNextID() {
next_minidump_path_c_ = next_minidump_path_.c_str();
}
+void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
+ AppMemoryList::iterator iter =
+ std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
+ if (iter != app_memory_info_.end()) {
+ // Don't allow registering the same pointer twice.
+ return;
+ }
+
+ AppMemory app_memory;
+ app_memory.ptr = reinterpret_cast<ULONG64>(ptr);
+ app_memory.length = static_cast<ULONG>(length);
+ app_memory_info_.push_back(app_memory);
+}
+
+void ExceptionHandler::UnregisterAppMemory(void* ptr) {
+ AppMemoryList::iterator iter =
+ std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
+ if (iter != app_memory_info_.end()) {
+ app_memory_info_.erase(iter);
+ }
+}
+
} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/windows/handler/exception_handler.h b/3rdParty/Breakpad/src/client/windows/handler/exception_handler.h
index 6f59348..2939a68 100644
--- a/3rdParty/Breakpad/src/client/windows/handler/exception_handler.h
+++ b/3rdParty/Breakpad/src/client/windows/handler/exception_handler.h
@@ -57,27 +57,44 @@
#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
#include <stdlib.h>
-#include <Windows.h>
-#include <DbgHelp.h>
+#include <windows.h>
+#include <dbghelp.h>
#include <rpc.h>
-#pragma warning( push )
+#pragma warning(push)
// Disable exception handler warnings.
-#pragma warning( disable : 4530 )
+#pragma warning(disable:4530)
+#include <list>
#include <string>
#include <vector>
#include "client/windows/common/ipc_protocol.h"
#include "client/windows/crash_generation/crash_generation_client.h"
+#include "common/scoped_ptr.h"
#include "google_breakpad/common/minidump_format.h"
-#include "processor/scoped_ptr.h"
namespace google_breakpad {
using std::vector;
using std::wstring;
+// These entries store a list of memory regions that the client wants included
+// in the minidump.
+struct AppMemory {
+ ULONG64 ptr;
+ ULONG length;
+
+ bool operator==(const struct AppMemory& other) const {
+ return ptr == other.ptr;
+ }
+
+ bool operator==(const void* other) const {
+ return ptr == reinterpret_cast<ULONG64>(other);
+ }
+};
+typedef std::list<AppMemory> AppMemoryList;
+
class ExceptionHandler {
public:
// A callback function to run before Breakpad performs any substantial
@@ -178,6 +195,25 @@ class ExceptionHandler {
HANDLE pipe_handle,
const CustomClientInfo* custom_info);
+ // ExceptionHandler that ENSURES out-of-process dump generation. Expects a
+ // crash generation client that is already registered with a crash generation
+ // server. Takes ownership of the passed-in crash_generation_client.
+ //
+ // Usage example:
+ // crash_generation_client = new CrashGenerationClient(..);
+ // if (crash_generation_client->Register()) {
+ // // Registration with the crash generation server succeeded.
+ // // Out-of-process dump generation is guaranteed.
+ // g_handler = new ExceptionHandler(.., crash_generation_client, ..);
+ // return true;
+ // }
+ ExceptionHandler(const wstring& dump_path,
+ FilterCallback filter,
+ MinidumpCallback callback,
+ void* callback_context,
+ int handler_types,
+ CrashGenerationClient* crash_generation_client);
+
~ExceptionHandler();
// Get and set the minidump path.
@@ -208,7 +244,20 @@ class ExceptionHandler {
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const wstring &dump_path,
- MinidumpCallback callback, void* callback_context);
+ MinidumpCallback callback, void* callback_context,
+ MINIDUMP_TYPE dump_type = MiniDumpNormal);
+
+ // Write a minidump of |child| immediately. This can be used to
+ // capture the execution state of |child| independently of a crash.
+ // Pass a meaningful |child_blamed_thread| to make that thread in
+ // the child process the one from which a crash signature is
+ // extracted.
+ static bool WriteMinidumpForChild(HANDLE child,
+ DWORD child_blamed_thread,
+ const wstring& dump_path,
+ MinidumpCallback callback,
+ void* callback_context,
+ MINIDUMP_TYPE dump_type = MiniDumpNormal);
// Get the thread ID of the thread requesting the dump (either the exception
// thread or any other thread that called WriteMinidump directly). This
@@ -222,9 +271,23 @@ class ExceptionHandler {
handle_debug_exceptions_ = handle_debug_exceptions;
}
+ // Controls behavior of EXCEPTION_INVALID_HANDLE.
+ bool get_consume_invalid_handle_exceptions() const {
+ return consume_invalid_handle_exceptions_;
+ }
+ void set_consume_invalid_handle_exceptions(
+ bool consume_invalid_handle_exceptions) {
+ consume_invalid_handle_exceptions_ = consume_invalid_handle_exceptions;
+ }
+
// Returns whether out-of-process dump generation is used or not.
bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
+ // Calling RegisterAppMemory(p, len) causes len bytes starting
+ // at address p to be copied to the minidump when a crash happens.
+ void RegisterAppMemory(void* ptr, size_t length);
+ void UnregisterAppMemory(void* ptr);
+
private:
friend class AutoExceptionHandler;
@@ -237,6 +300,7 @@ class ExceptionHandler {
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
HANDLE pipe_handle,
+ CrashGenerationClient* crash_generation_client,
const CustomClientInfo* custom_info);
// Function pointer type for MiniDumpWriteDump, which is looked up
@@ -289,8 +353,9 @@ class ExceptionHandler {
bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion);
- // This function does the actual writing of a minidump. It is called
- // on the handler thread. requesting_thread_id is the ID of the thread
+ // This function is called on the handler thread. It calls into
+ // WriteMinidumpWithExceptionForProcess() with a handle to the
+ // current process. requesting_thread_id is the ID of the thread
// that requested the dump. If the dump is requested as a result of
// an exception, exinfo contains exception information, otherwise,
// it is NULL.
@@ -305,6 +370,20 @@ class ExceptionHandler {
const PMINIDUMP_CALLBACK_INPUT callback_input,
PMINIDUMP_CALLBACK_OUTPUT callback_output);
+ // This function does the actual writing of a minidump. It is
+ // called on the handler thread. requesting_thread_id is the ID of
+ // the thread that requested the dump, if that information is
+ // meaningful. If the dump is requested as a result of an
+ // exception, exinfo contains exception information, otherwise, it
+ // is NULL. process is the one that will be dumped. If
+ // requesting_thread_id is meaningful and should be added to the
+ // minidump, write_requester_stream is |true|.
+ bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ HANDLE process,
+ bool write_requester_stream);
+
// Generates a new ID and stores it in next_minidump_id_, and stores the
// path of the next minidump to be written in next_minidump_path_.
void UpdateNextID();
@@ -414,6 +493,14 @@ class ExceptionHandler {
// to not interfere with debuggers.
bool handle_debug_exceptions_;
+ // If true, the handler will consume any EXCEPTION_INVALID_HANDLE exceptions.
+ // Leave this false (the default) to handle these exceptions as normal.
+ bool consume_invalid_handle_exceptions_;
+
+ // Callers can request additional memory regions to be included in
+ // the dump.
+ AppMemoryList app_memory_info_;
+
// A stack of ExceptionHandler objects that have installed unhandled
// exception filters. This vector is used by HandleException to determine
// which ExceptionHandler object to route an exception to. When an
@@ -433,7 +520,7 @@ class ExceptionHandler {
static CRITICAL_SECTION handler_stack_critical_section_;
// The number of instances of this class.
- volatile static LONG instance_count_;
+ static volatile LONG instance_count_;
// disallow copy ctor and operator=
explicit ExceptionHandler(const ExceptionHandler &);
@@ -442,6 +529,6 @@ class ExceptionHandler {
} // namespace google_breakpad
-#pragma warning( pop )
+#pragma warning(pop)
#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
diff --git a/3rdParty/Breakpad/src/common/basictypes.h b/3rdParty/Breakpad/src/common/basictypes.h
new file mode 100644
index 0000000..9426c1f
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/basictypes.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_BASICTYPES_H_
+#define COMMON_BASICTYPES_H_
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#ifndef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+#endif // DISALLOW_COPY_AND_ASSIGN
+
+namespace google_breakpad {
+
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked with __attribute__((warn_unused_result)), wrap it with
+// this. Example:
+//
+// scoped_ptr<MyType> my_var = ...;
+// if (TakeOwnership(my_var.get()) == SUCCESS)
+// ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T&) {
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_BASICTYPES_H_
diff --git a/3rdParty/Breakpad/src/common/byte_cursor_unittest.cc b/3rdParty/Breakpad/src/common/byte_cursor_unittest.cc
new file mode 100644
index 0000000..06bfd89
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/byte_cursor_unittest.cc
@@ -0,0 +1,776 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer
+// and google_breakpad::ByteCursor.
+
+#include <string>
+
+#include <string.h>
+
+#include "breakpad_googletest_includes.h"
+#include "common/byte_cursor.h"
+#include "common/using_std_string.h"
+
+using google_breakpad::ByteBuffer;
+using google_breakpad::ByteCursor;
+
+TEST(Buffer, SizeOfNothing) {
+ uint8_t data[1];
+ ByteBuffer buffer(data, 0);
+ EXPECT_EQ(0U, buffer.Size());
+}
+
+TEST(Buffer, SizeOfSomething) {
+ uint8_t data[10];
+ ByteBuffer buffer(data, sizeof(data));
+ EXPECT_EQ(10U, buffer.Size());
+}
+
+TEST(Extent, AvailableEmpty) {
+ uint8_t data[1];
+ ByteBuffer buffer(data, 0);
+ ByteCursor cursor(&buffer);
+ EXPECT_EQ(0U, cursor.Available());
+}
+
+TEST(Extent, AtEndEmpty) {
+ uint8_t data[1];
+ ByteBuffer buffer(data, 0);
+ ByteCursor cursor(&buffer);
+ EXPECT_TRUE(cursor.AtEnd());
+}
+
+TEST(Extent, AsBoolEmpty) {
+ uint8_t data[1];
+ ByteBuffer buffer(data, 0);
+ ByteCursor cursor(&buffer);
+ EXPECT_TRUE(cursor);
+}
+
+TEST(Extent, AvailableSome) {
+ uint8_t data[10];
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ EXPECT_EQ(10U, cursor.Available());
+}
+
+TEST(Extent, AtEndSome) {
+ uint8_t data[10];
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ EXPECT_FALSE(cursor.AtEnd());
+ EXPECT_TRUE(cursor.Skip(sizeof(data)).AtEnd());
+}
+
+TEST(Extent, AsBoolSome) {
+ uint8_t data[10];
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ EXPECT_TRUE(cursor);
+ EXPECT_TRUE(cursor.Skip(sizeof(data)));
+ EXPECT_FALSE(cursor.Skip(1));
+}
+
+TEST(Extent, Cursor) {
+ uint8_t data[] = { 0xf7,
+ 0x9f, 0xbe,
+ 0x67, 0xfb, 0xd3, 0x58,
+ 0x6f, 0x36, 0xde, 0xd1,
+ 0x2a, 0x2a, 0x2a };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+
+ uint8_t a;
+ uint16_t b;
+ uint32_t c;
+ uint32_t d;
+ uint8_t stars[3];
+
+ EXPECT_EQ(data + 0U, cursor.here());
+
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(data + 1U, cursor.here());
+
+ EXPECT_TRUE(cursor >> b);
+ EXPECT_EQ(data + 3U, cursor.here());
+
+ EXPECT_TRUE(cursor >> c);
+ EXPECT_EQ(data + 7U, cursor.here());
+
+ EXPECT_TRUE(cursor.Skip(4));
+ EXPECT_EQ(data + 11U, cursor.here());
+
+ EXPECT_TRUE(cursor.Read(stars, 3));
+ EXPECT_EQ(data + 14U, cursor.here());
+
+ EXPECT_FALSE(cursor >> d);
+ EXPECT_EQ(data + 14U, cursor.here());
+}
+
+TEST(Extent, SetOffset) {
+ uint8_t data[] = { 0x5c, 0x79, 0x8c, 0xd5 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+
+ uint8_t a, b, c, d, e;
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(0x5cU, a);
+ EXPECT_EQ(data + 1U, cursor.here());
+ EXPECT_TRUE(((cursor >> b).set_here(data + 3) >> c).set_here(data + 1)
+ >> d >> e);
+ EXPECT_EQ(0x79U, b);
+ EXPECT_EQ(0xd5U, c);
+ EXPECT_EQ(0x79U, d);
+ EXPECT_EQ(0x8cU, e);
+ EXPECT_EQ(data + 3U, cursor.here());
+}
+
+TEST(BigEndian, Signed1) {
+ uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ cursor.set_big_endian(true);
+ int a, b, c, d, e;
+ ASSERT_TRUE(cursor
+ .Read(1, true, &a)
+ .Read(1, true, &b)
+ .Read(1, true, &c)
+ .Read(1, true, &d));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7f, b);
+ EXPECT_EQ(-0x80, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(1, true, &e));
+}
+
+TEST(BigEndian, Signed2) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff,
+ 0x80, 0x00, 0x80, 0x80, 0xff, 0xff,
+ 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, true);
+ int a, b, c, d, e, f, g, h, i, j;
+ ASSERT_TRUE(cursor
+ .Read(2, true, &a)
+ .Read(2, true, &b)
+ .Read(2, true, &c)
+ .Read(2, true, &d)
+ .Read(2, true, &e)
+ .Read(2, true, &f)
+ .Read(2, true, &g)
+ .Read(2, true, &h)
+ .Read(2, true, &i));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x80, b);
+ EXPECT_EQ(0x7fff, c);
+ EXPECT_EQ(-0x8000, d);
+ EXPECT_EQ(-0x7f80, e);
+ EXPECT_EQ(-1, f);
+ EXPECT_EQ(0x39f1, g);
+ EXPECT_EQ(-0x7544, h);
+ EXPECT_EQ(0x5aec, i);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(2, true, &j));
+}
+
+TEST(BigEndian, Signed4) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xb6, 0xb1, 0xff, 0xef,
+ 0x19, 0x6a, 0xca, 0x46 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ cursor.set_big_endian(true);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(4, true, &a)
+ .Read(4, true, &b)
+ .Read(4, true, &c)
+ .Read(4, true, &d)
+ .Read(4, true, &e)
+ .Read(4, true, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffff, b);
+ EXPECT_EQ(-0x80000000LL, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_EQ((int32_t) 0xb6b1ffef, e);
+ EXPECT_EQ(0x196aca46, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(4, true, &g));
+}
+
+TEST(BigEndian, Signed8) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c,
+ 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, true);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(8, true, &a)
+ .Read(8, true, &b)
+ .Read(8, true, &c)
+ .Read(8, true, &d)
+ .Read(8, true, &e)
+ .Read(8, true, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffffffffffffLL, b);
+ EXPECT_EQ(-0x7fffffffffffffffLL - 1, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e);
+ EXPECT_EQ(0x4e4249d27f8414a4LL, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(8, true, &g));
+}
+
+TEST(BigEndian, Unsigned1) {
+ uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ cursor.set_big_endian(true);
+ int32_t a, b, c, d, e;
+ ASSERT_TRUE(cursor
+ .Read(1, false, &a)
+ .Read(1, false, &b)
+ .Read(1, false, &c)
+ .Read(1, false, &d));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7f, b);
+ EXPECT_EQ(0x80, c);
+ EXPECT_EQ(0xff, d);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(1, false, &e));
+}
+
+TEST(BigEndian, Unsigned2) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff,
+ 0x80, 0x00, 0x80, 0x80, 0xff, 0xff,
+ 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, true);
+ int64_t a, b, c, d, e, f, g, h, i, j;
+ ASSERT_TRUE(cursor
+ .Read(2, false, &a)
+ .Read(2, false, &b)
+ .Read(2, false, &c)
+ .Read(2, false, &d)
+ .Read(2, false, &e)
+ .Read(2, false, &f)
+ .Read(2, false, &g)
+ .Read(2, false, &h)
+ .Read(2, false, &i));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x80, b);
+ EXPECT_EQ(0x7fff, c);
+ EXPECT_EQ(0x8000, d);
+ EXPECT_EQ(0x8080, e);
+ EXPECT_EQ(0xffff, f);
+ EXPECT_EQ(0x39f1, g);
+ EXPECT_EQ(0x8abc, h);
+ EXPECT_EQ(0x5aec, i);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(2, false, &j));
+}
+
+TEST(BigEndian, Unsigned4) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0xff, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xb6, 0xb1, 0xff, 0xef,
+ 0x19, 0x6a, 0xca, 0x46 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ cursor.set_big_endian(true);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(4, false, &a)
+ .Read(4, false, &b)
+ .Read(4, false, &c)
+ .Read(4, false, &d)
+ .Read(4, false, &e)
+ .Read(4, false, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffff, b);
+ EXPECT_EQ(0x80000000, c);
+ EXPECT_EQ(0xffffffff, d);
+ EXPECT_EQ(0xb6b1ffef, e);
+ EXPECT_EQ(0x196aca46, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(4, false, &g));
+}
+
+TEST(BigEndian, Unsigned8) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c,
+ 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, true);
+ uint64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(8, false, &a)
+ .Read(8, false, &b)
+ .Read(8, false, &c)
+ .Read(8, false, &d)
+ .Read(8, false, &e)
+ .Read(8, false, &f));
+ EXPECT_EQ(0U, a);
+ EXPECT_EQ(0x7fffffffffffffffULL, b);
+ EXPECT_EQ(0x8000000000000000ULL, c);
+ EXPECT_EQ(0xffffffffffffffffULL, d);
+ EXPECT_EQ(0x9320d5e9d2d5879cULL, e);
+ EXPECT_EQ(0x4e4249d27f8414a4ULL, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(8, false, &g));
+}
+
+TEST(LittleEndian, Signed1) {
+ uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int32_t a, b, c, d, e;
+ ASSERT_TRUE(cursor
+ .Read(1, true, &a)
+ .Read(1, true, &b)
+ .Read(1, true, &c)
+ .Read(1, true, &d));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7f, b);
+ EXPECT_EQ(-0x80, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(1, true, &e));
+}
+
+TEST(LittleEndian, Signed2) {
+ uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f,
+ 0x00, 0x80, 0x80, 0x80, 0xff, 0xff,
+ 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, false);
+ int32_t a, b, c, d, e, f, g, h, i, j;
+ ASSERT_TRUE(cursor
+ .Read(2, true, &a)
+ .Read(2, true, &b)
+ .Read(2, true, &c)
+ .Read(2, true, &d)
+ .Read(2, true, &e)
+ .Read(2, true, &f)
+ .Read(2, true, &g)
+ .Read(2, true, &h)
+ .Read(2, true, &i));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x80, b);
+ EXPECT_EQ(0x7fff, c);
+ EXPECT_EQ(-0x8000, d);
+ EXPECT_EQ(-0x7f80, e);
+ EXPECT_EQ(-1, f);
+ EXPECT_EQ(0x39f1, g);
+ EXPECT_EQ(-0x7544, h);
+ EXPECT_EQ(0x5aec, i);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(2, true, &j));
+}
+
+TEST(LittleEndian, Signed4) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xff, 0xb1, 0xb6,
+ 0x46, 0xca, 0x6a, 0x19 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(4, true, &a)
+ .Read(4, true, &b)
+ .Read(4, true, &c)
+ .Read(4, true, &d)
+ .Read(4, true, &e)
+ .Read(4, true, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffff, b);
+ EXPECT_EQ(-0x80000000LL, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_EQ((int32_t) 0xb6b1ffef, e);
+ EXPECT_EQ(0x196aca46, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(4, true, &g));
+}
+
+TEST(LittleEndian, Signed8) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93,
+ 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer, false);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(8, true, &a)
+ .Read(8, true, &b)
+ .Read(8, true, &c)
+ .Read(8, true, &d)
+ .Read(8, true, &e)
+ .Read(8, true, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffffffffffffLL, b);
+ EXPECT_EQ(-0x7fffffffffffffffLL - 1, c);
+ EXPECT_EQ(-1, d);
+ EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e);
+ EXPECT_EQ(0x4e4249d27f8414a4LL, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(8, true, &g));
+}
+
+TEST(LittleEndian, Unsigned1) {
+ uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int32_t a, b, c, d, e;
+ ASSERT_TRUE(cursor
+ .Read(1, false, &a)
+ .Read(1, false, &b)
+ .Read(1, false, &c)
+ .Read(1, false, &d));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7f, b);
+ EXPECT_EQ(0x80, c);
+ EXPECT_EQ(0xff, d);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(1, false, &e));
+}
+
+TEST(LittleEndian, Unsigned2) {
+ uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f,
+ 0x00, 0x80, 0x80, 0x80, 0xff, 0xff,
+ 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int32_t a, b, c, d, e, f, g, h, i, j;
+ ASSERT_TRUE(cursor
+ .Read(2, false, &a)
+ .Read(2, false, &b)
+ .Read(2, false, &c)
+ .Read(2, false, &d)
+ .Read(2, false, &e)
+ .Read(2, false, &f)
+ .Read(2, false, &g)
+ .Read(2, false, &h)
+ .Read(2, false, &i));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x80, b);
+ EXPECT_EQ(0x7fff, c);
+ EXPECT_EQ(0x8000, d);
+ EXPECT_EQ(0x8080, e);
+ EXPECT_EQ(0xffff, f);
+ EXPECT_EQ(0x39f1, g);
+ EXPECT_EQ(0x8abc, h);
+ EXPECT_EQ(0x5aec, i);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(2, false, &j));
+}
+
+TEST(LittleEndian, Unsigned4) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xef, 0xff, 0xb1, 0xb6,
+ 0x46, 0xca, 0x6a, 0x19 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(4, false, &a)
+ .Read(4, false, &b)
+ .Read(4, false, &c)
+ .Read(4, false, &d)
+ .Read(4, false, &e)
+ .Read(4, false, &f));
+ EXPECT_EQ(0, a);
+ EXPECT_EQ(0x7fffffff, b);
+ EXPECT_EQ(0x80000000, c);
+ EXPECT_EQ(0xffffffff, d);
+ EXPECT_EQ(0xb6b1ffef, e);
+ EXPECT_EQ(0x196aca46, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(4, false, &g));
+}
+
+TEST(LittleEndian, Unsigned8) {
+ uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93,
+ 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ uint64_t a, b, c, d, e, f, g;
+ ASSERT_TRUE(cursor
+ .Read(8, false, &a)
+ .Read(8, false, &b)
+ .Read(8, false, &c)
+ .Read(8, false, &d)
+ .Read(8, false, &e)
+ .Read(8, false, &f));
+ EXPECT_EQ(0U, a);
+ EXPECT_EQ(0x7fffffffffffffffULL, b);
+ EXPECT_EQ(0x8000000000000000ULL, c);
+ EXPECT_EQ(0xffffffffffffffffULL, d);
+ EXPECT_EQ(0x9320d5e9d2d5879cULL, e);
+ EXPECT_EQ(0x4e4249d27f8414a4ULL, f);
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor.Read(8, false, &g));
+}
+
+TEST(Extractor, Signed1) {
+ uint8_t data[] = { 0xfd };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int8_t a;
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(-3, a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Signed2) {
+ uint8_t data[] = { 0x13, 0xcd };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int16_t a;
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(-13037, a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Signed4) {
+ uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ int32_t a;
+ // For some reason, G++ 4.4.1 complains:
+ // warning: array subscript is above array bounds
+ // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but
+ // I'm not able to see how such a reference would occur.
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(-380377902, a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Unsigned1) {
+ uint8_t data[] = { 0xfd };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ uint8_t a;
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(0xfd, a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Unsigned2) {
+ uint8_t data[] = { 0x13, 0xcd };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ uint16_t a;
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(0xcd13, a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Unsigned4) {
+ uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ uint32_t a;
+ // For some reason, G++ 4.4.1 complains:
+ // warning: array subscript is above array bounds
+ // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but
+ // I'm not able to see how such a reference would occur.
+ EXPECT_TRUE(cursor >> a);
+ EXPECT_EQ(0xe953e4d2, a);
+ EXPECT_FALSE(cursor >> a);
+ EXPECT_FALSE(cursor >> a);
+}
+
+TEST(Extractor, Mixed) {
+ uint8_t data[] = { 0x42,
+ 0x25, 0x0b,
+ 0x3d, 0x25, 0xed, 0x2a,
+ 0xec, 0x16, 0x9e, 0x14, 0x61, 0x5b, 0x2c, 0xcf,
+ 0xd8,
+ 0x22, 0xa5,
+ 0x3a, 0x02, 0x6a, 0xd7,
+ 0x93, 0x2a, 0x2d, 0x8d, 0xb4, 0x95, 0xe0, 0xc6 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+ cursor.set_big_endian(true);
+
+ uint8_t a;
+ uint16_t b;
+ uint32_t c;
+ uint64_t d;
+ int8_t e;
+ int16_t f;
+ int32_t g;
+ int64_t h;
+ int z;
+ EXPECT_FALSE(cursor.AtEnd());
+ EXPECT_TRUE(cursor >> a >> b >> c >> d >> e >> f >> g >> h);
+ EXPECT_EQ(0x42U, a);
+ EXPECT_EQ(0x250bU, b);
+ EXPECT_EQ(0x3d25ed2aU, c);
+ EXPECT_EQ(0xec169e14615b2ccfULL, d);
+ EXPECT_EQ(-40, e);
+ EXPECT_EQ(0x22a5, f);
+ EXPECT_EQ(0x3a026ad7, g);
+ EXPECT_EQ(-7842405714468937530LL, h);
+
+ EXPECT_TRUE(cursor.AtEnd());
+ EXPECT_FALSE(cursor >> z);
+}
+
+TEST(Strings, Zero) {
+ uint8_t data[] = { 0xa6 };
+ ByteBuffer buffer(data, 0);
+ ByteCursor cursor(&buffer);
+
+ uint8_t received[1];
+ received[0] = 0xc2;
+ EXPECT_TRUE(cursor.Read(received, 0));
+ EXPECT_EQ(0xc2U, received[0]);
+}
+
+TEST(Strings, Some) {
+ uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+
+ uint8_t received[7] = { 0xa7, 0xf7, 0x43, 0x0c, 0x27, 0xea, 0xed };
+ EXPECT_TRUE(cursor.Skip(2).Read(received, 5));
+ uint8_t expected[7] = { 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xea, 0xed };
+ EXPECT_TRUE(memcmp(received, expected, 7) == 0);
+}
+
+TEST(Strings, TooMuch) {
+ uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+
+ uint8_t received1[3];
+ uint8_t received2[3];
+ uint8_t received3[3];
+ EXPECT_FALSE(cursor
+ .Read(received1, 3)
+ .Read(received2, 3)
+ .Read(received3, 3));
+ uint8_t expected1[3] = { 0x5d, 0x31, 0x09 };
+ uint8_t expected2[3] = { 0xa6, 0x2e, 0x2c };
+
+ EXPECT_TRUE(memcmp(received1, expected1, 3) == 0);
+ EXPECT_TRUE(memcmp(received2, expected2, 3) == 0);
+}
+
+TEST(Strings, PointTo) {
+ uint8_t data[] = { 0x83, 0x80, 0xb4, 0x38, 0x00, 0x2c, 0x0a, 0x27 };
+ ByteBuffer buffer(data, sizeof(data));
+ ByteCursor cursor(&buffer);
+
+ const uint8_t *received1;
+ const uint8_t *received2;
+ const uint8_t *received3;
+ const uint8_t *received4;
+ EXPECT_FALSE(cursor
+ .PointTo(&received1, 3)
+ .PointTo(&received2, 3)
+ .PointTo(&received3)
+ .PointTo(&received4, 3));
+ EXPECT_EQ(data + 0, received1);
+ EXPECT_EQ(data + 3, received2);
+ EXPECT_EQ(data + 6, received3);
+ EXPECT_EQ(NULL, received4);
+}
+
+TEST(Strings, CString) {
+ uint8_t data[] = "abc\0\0foo";
+ ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0'
+ ByteCursor cursor(&buffer);
+
+ string a, b, c;
+ EXPECT_TRUE(cursor.CString(&a).CString(&b));
+ EXPECT_EQ("abc", a);
+ EXPECT_EQ("", b);
+ EXPECT_FALSE(cursor.CString(&c));
+ EXPECT_EQ("", c);
+ EXPECT_TRUE(cursor.AtEnd());
+}
+
+TEST(Strings, CStringLimit) {
+ uint8_t data[] = "abcdef\0\0foobar";
+ ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0'
+ ByteCursor cursor(&buffer);
+
+ string a, b, c, d, e;
+
+ EXPECT_TRUE(cursor.CString(&a, 3));
+ EXPECT_EQ("abc", a);
+
+ EXPECT_TRUE(cursor.CString(&b, 0));
+ EXPECT_EQ("", b);
+
+ EXPECT_TRUE(cursor.CString(&c, 6));
+ EXPECT_EQ("def", c);
+
+ EXPECT_TRUE(cursor.CString(&d, 4));
+ EXPECT_EQ("ooba", d);
+
+ EXPECT_FALSE(cursor.CString(&e, 4));
+ EXPECT_EQ("", e);
+
+ EXPECT_TRUE(cursor.AtEnd());
+}
+
+// uint8_t data[] = { 0xa6, 0x54, 0xdf, 0x67, 0x51, 0x43, 0xac, 0xf1 };
+// ByteBuffer buffer(data, sizeof(data));
diff --git a/3rdParty/Breakpad/src/common/convert_UTF.c b/3rdParty/Breakpad/src/common/convert_UTF.c
index 80178d3..12a3c89 100644
--- a/3rdParty/Breakpad/src/common/convert_UTF.c
+++ b/3rdParty/Breakpad/src/common/convert_UTF.c
@@ -1,23 +1,39 @@
/*
- * Copyright 2001-2004 Unicode, Inc.
+ * Copyright © 1991-2015 Unicode, Inc. All rights reserved.
+ * Distributed under the Terms of Use in
+ * http://www.unicode.org/copyright.html.
*
- * Disclaimer
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation
+ * (the "Data Files") or Unicode software and any associated documentation
+ * (the "Software") to deal in the Data Files or Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of
+ * the Data Files or Software, and to permit persons to whom the Data Files
+ * or Software are furnished to do so, provided that
+ * (a) this copyright and permission notice appear with all copies
+ * of the Data Files or Software,
+ * (b) this copyright and permission notice appear in associated
+ * documentation, and
+ * (c) there is clear notice in each modified Data File or in the Software
+ * as well as in the documentation associated with the Data File(s) or
+ * Software that the data or software has been modified.
*
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in these Data Files or Software without prior
+ * written authorization of the copyright holder.
*/
/* ---------------------------------------------------------------------
@@ -53,8 +69,13 @@ static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
+
+#ifndef false
#define false 0
+#endif
+#ifndef true
#define true 1
+#endif
/* --------------------------------------------------------------------- */
diff --git a/3rdParty/Breakpad/src/common/convert_UTF.h b/3rdParty/Breakpad/src/common/convert_UTF.h
index b1556de..644d099 100644
--- a/3rdParty/Breakpad/src/common/convert_UTF.h
+++ b/3rdParty/Breakpad/src/common/convert_UTF.h
@@ -1,25 +1,44 @@
/*
- * Copyright 2001-2004 Unicode, Inc.
+ * Copyright © 1991-2015 Unicode, Inc. All rights reserved.
+ * Distributed under the Terms of Use in
+ * http://www.unicode.org/copyright.html.
*
- * Disclaimer
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation
+ * (the "Data Files") or Unicode software and any associated documentation
+ * (the "Software") to deal in the Data Files or Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of
+ * the Data Files or Software, and to permit persons to whom the Data Files
+ * or Software are furnished to do so, provided that
+ * (a) this copyright and permission notice appear with all copies
+ * of the Data Files or Software,
+ * (b) this copyright and permission notice appear in associated
+ * documentation, and
+ * (c) there is clear notice in each modified Data File or in the Software
+ * as well as in the documentation associated with the Data File(s) or
+ * Software that the data or software has been modified.
*
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
*
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in these Data Files or Software without prior
+ * written authorization of the copyright holder.
*/
+#ifndef COMMON_CONVERT_UTF_H_
+#define COMMON_CONVERT_UTF_H_
+
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
@@ -141,3 +160,5 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#endif
/* --------------------------------------------------------------------- */
+
+#endif // COMMON_CONVERT_UTF_H_
diff --git a/3rdParty/Breakpad/src/common/dwarf/bytereader-inl.h b/3rdParty/Breakpad/src/common/dwarf/bytereader-inl.h
index 3c16708..42c92f9 100644
--- a/3rdParty/Breakpad/src/common/dwarf/bytereader-inl.h
+++ b/3rdParty/Breakpad/src/common/dwarf/bytereader-inl.h
@@ -32,16 +32,15 @@
#include "common/dwarf/bytereader.h"
#include <assert.h>
+#include <stdint.h>
namespace dwarf2reader {
-inline uint8 ByteReader::ReadOneByte(const char* buffer) const {
+inline uint8 ByteReader::ReadOneByte(const uint8_t *buffer) const {
return buffer[0];
}
-inline uint16 ByteReader::ReadTwoBytes(const char* signed_buffer) const {
- const unsigned char *buffer
- = reinterpret_cast<const unsigned char *>(signed_buffer);
+inline uint16 ByteReader::ReadTwoBytes(const uint8_t *buffer) const {
const uint16 buffer0 = buffer[0];
const uint16 buffer1 = buffer[1];
if (endian_ == ENDIANNESS_LITTLE) {
@@ -51,9 +50,7 @@ inline uint16 ByteReader::ReadTwoBytes(const char* signed_buffer) const {
}
}
-inline uint64 ByteReader::ReadFourBytes(const char* signed_buffer) const {
- const unsigned char *buffer
- = reinterpret_cast<const unsigned char *>(signed_buffer);
+inline uint64 ByteReader::ReadFourBytes(const uint8_t *buffer) const {
const uint32 buffer0 = buffer[0];
const uint32 buffer1 = buffer[1];
const uint32 buffer2 = buffer[2];
@@ -65,9 +62,7 @@ inline uint64 ByteReader::ReadFourBytes(const char* signed_buffer) const {
}
}
-inline uint64 ByteReader::ReadEightBytes(const char* signed_buffer) const {
- const unsigned char *buffer
- = reinterpret_cast<const unsigned char *>(signed_buffer);
+inline uint64 ByteReader::ReadEightBytes(const uint8_t *buffer) const {
const uint64 buffer0 = buffer[0];
const uint64 buffer1 = buffer[1];
const uint64 buffer2 = buffer[2];
@@ -89,12 +84,12 @@ inline uint64 ByteReader::ReadEightBytes(const char* signed_buffer) const {
// information, plus one bit saying whether the number continues or
// not.
-inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer,
+inline uint64 ByteReader::ReadUnsignedLEB128(const uint8_t *buffer,
size_t* len) const {
uint64 result = 0;
size_t num_read = 0;
unsigned int shift = 0;
- unsigned char byte;
+ uint8_t byte;
do {
byte = *buffer++;
@@ -114,12 +109,12 @@ inline uint64 ByteReader::ReadUnsignedLEB128(const char* buffer,
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
-inline int64 ByteReader::ReadSignedLEB128(const char* buffer,
+inline int64 ByteReader::ReadSignedLEB128(const uint8_t *buffer,
size_t* len) const {
int64 result = 0;
unsigned int shift = 0;
size_t num_read = 0;
- unsigned char byte;
+ uint8_t byte;
do {
byte = *buffer++;
@@ -134,18 +129,18 @@ inline int64 ByteReader::ReadSignedLEB128(const char* buffer,
return result;
}
-inline uint64 ByteReader::ReadOffset(const char* buffer) const {
+inline uint64 ByteReader::ReadOffset(const uint8_t *buffer) const {
assert(this->offset_reader_);
return (this->*offset_reader_)(buffer);
}
-inline uint64 ByteReader::ReadAddress(const char* buffer) const {
+inline uint64 ByteReader::ReadAddress(const uint8_t *buffer) const {
assert(this->address_reader_);
return (this->*address_reader_)(buffer);
}
inline void ByteReader::SetCFIDataBase(uint64 section_base,
- const char *buffer_base) {
+ const uint8_t *buffer_base) {
section_base_ = section_base;
buffer_base_ = buffer_base;
have_section_base_ = true;
diff --git a/3rdParty/Breakpad/src/common/dwarf/bytereader.cc b/3rdParty/Breakpad/src/common/dwarf/bytereader.cc
index 6802026..14b43ad 100644
--- a/3rdParty/Breakpad/src/common/dwarf/bytereader.cc
+++ b/3rdParty/Breakpad/src/common/dwarf/bytereader.cc
@@ -27,6 +27,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
+#include <stdint.h>
#include <stdlib.h>
#include "common/dwarf/bytereader-inl.h"
@@ -62,7 +63,7 @@ void ByteReader::SetAddressSize(uint8 size) {
}
}
-uint64 ByteReader::ReadInitialLength(const char* start, size_t* len) {
+uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) {
const uint64 initial_length = ReadFourBytes(start);
start += 4;
@@ -100,7 +101,7 @@ bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
}
}
-uint64 ByteReader::ReadEncodedPointer(const char *buffer,
+uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer,
DwarfPointerEncoding encoding,
size_t *len) const {
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
@@ -129,7 +130,7 @@ uint64 ByteReader::ReadEncodedPointer(const char *buffer,
// Round up to the next boundary.
uint64 aligned = (offset + AddressSize() - 1) & -AddressSize();
// Convert back to a pointer.
- const char *aligned_buffer = buffer_base_ + (aligned - skew);
+ const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew);
// Finally, store the length and actually fetch the pointer.
*len = aligned_buffer - buffer + AddressSize();
return ReadAddress(aligned_buffer);
@@ -242,4 +243,8 @@ uint64 ByteReader::ReadEncodedPointer(const char *buffer,
return pointer;
}
+Endianness ByteReader::GetEndianness() const {
+ return endian_;
+}
+
} // namespace dwarf2reader
diff --git a/3rdParty/Breakpad/src/common/dwarf/bytereader.h b/3rdParty/Breakpad/src/common/dwarf/bytereader.h
index e389427..59d4303 100644
--- a/3rdParty/Breakpad/src/common/dwarf/bytereader.h
+++ b/3rdParty/Breakpad/src/common/dwarf/bytereader.h
@@ -31,7 +31,10 @@
#ifndef COMMON_DWARF_BYTEREADER_H__
#define COMMON_DWARF_BYTEREADER_H__
+#include <stdint.h>
+
#include <string>
+
#include "common/dwarf/types.h"
#include "common/dwarf/dwarf2enums.h"
@@ -59,22 +62,22 @@ class ByteReader {
// Read a single byte from BUFFER and return it as an unsigned 8 bit
// number.
- uint8 ReadOneByte(const char* buffer) const;
+ uint8 ReadOneByte(const uint8_t *buffer) const;
// Read two bytes from BUFFER and return them as an unsigned 16 bit
// number, using this ByteReader's endianness.
- uint16 ReadTwoBytes(const char* buffer) const;
+ uint16 ReadTwoBytes(const uint8_t *buffer) const;
// Read four bytes from BUFFER and return them as an unsigned 32 bit
// number, using this ByteReader's endianness. This function returns
// a uint64 so that it is compatible with ReadAddress and
// ReadOffset. The number it returns will never be outside the range
// of an unsigned 32 bit integer.
- uint64 ReadFourBytes(const char* buffer) const;
+ uint64 ReadFourBytes(const uint8_t *buffer) const;
// Read eight bytes from BUFFER and return them as an unsigned 64
// bit number, using this ByteReader's endianness.
- uint64 ReadEightBytes(const char* buffer) const;
+ uint64 ReadEightBytes(const uint8_t *buffer) const;
// Read an unsigned LEB128 (Little Endian Base 128) number from
// BUFFER and return it as an unsigned 64 bit integer. Set LEN to
@@ -93,7 +96,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
- uint64 ReadUnsignedLEB128(const char* buffer, size_t* len) const;
+ uint64 ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const;
// Read a signed LEB128 number from BUFFER and return it as an
// signed 64 bit integer. Set LEN to the number of bytes read.
@@ -112,7 +115,7 @@ class ByteReader {
// In other words, we break VALUE into groups of seven bits, put
// them in little-endian order, and then write them as eight-bit
// bytes with the high bit on all but the last.
- int64 ReadSignedLEB128(const char* buffer, size_t* len) const;
+ int64 ReadSignedLEB128(const uint8_t *buffer, size_t *len) const;
// Indicate that addresses on this architecture are SIZE bytes long. SIZE
// must be either 4 or 8. (DWARF allows addresses to be any number of
@@ -135,7 +138,7 @@ class ByteReader {
// Read an address from BUFFER and return it as an unsigned 64 bit
// integer, respecting this ByteReader's endianness and address size. You
// must call SetAddressSize before calling this function.
- uint64 ReadAddress(const char* buffer) const;
+ uint64 ReadAddress(const uint8_t *buffer) const;
// DWARF actually defines two slightly different formats: 32-bit DWARF
// and 64-bit DWARF. This is *not* related to the size of registers or
@@ -172,14 +175,14 @@ class ByteReader {
// - The 32-bit value 0xffffffff, followed by a 64-bit byte count,
// indicating that the data whose length is being measured uses
// the 64-bit DWARF format.
- uint64 ReadInitialLength(const char* start, size_t* len);
+ uint64 ReadInitialLength(const uint8_t *start, size_t *len);
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer, respecting the ByteReader's endianness. In 32-bit DWARF, the
// offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes
// long. You must call ReadInitialLength or SetOffsetSize before calling
// this function; see the comments above for details.
- uint64 ReadOffset(const char* buffer) const;
+ uint64 ReadOffset(const uint8_t *buffer) const;
// Return the current offset size, in bytes.
// A return value of 4 indicates that we are reading 32-bit DWARF.
@@ -234,7 +237,7 @@ class ByteReader {
// is BUFFER_BASE. This allows us to find the address that a given
// byte in our buffer would have when loaded into the program the
// data describes. We need this to resolve DW_EH_PE_pcrel pointers.
- void SetCFIDataBase(uint64 section_base, const char *buffer_base);
+ void SetCFIDataBase(uint64 section_base, const uint8_t *buffer_base);
// Indicate that the base address of the program's ".text" section
// is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers.
@@ -273,13 +276,15 @@ class ByteReader {
// base address this reader hasn't been given, so you should check
// with ValidEncoding and UsableEncoding first if you would rather
// die in a more helpful way.
- uint64 ReadEncodedPointer(const char *buffer, DwarfPointerEncoding encoding,
+ uint64 ReadEncodedPointer(const uint8_t *buffer,
+ DwarfPointerEncoding encoding,
size_t *len) const;
+ Endianness GetEndianness() const;
private:
// Function pointer type for our address and offset readers.
- typedef uint64 (ByteReader::*AddressReader)(const char*) const;
+ typedef uint64 (ByteReader::*AddressReader)(const uint8_t *) const;
// Read an offset from BUFFER and return it as an unsigned 64 bit
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
@@ -302,7 +307,7 @@ class ByteReader {
bool have_section_base_, have_text_base_, have_data_base_;
bool have_function_base_;
uint64 section_base_, text_base_, data_base_, function_base_;
- const char *buffer_base_;
+ const uint8_t *buffer_base_;
};
} // namespace dwarf2reader
diff --git a/3rdParty/Breakpad/src/common/dwarf/bytereader_unittest.cc b/3rdParty/Breakpad/src/common/dwarf/bytereader_unittest.cc
new file mode 100644
index 0000000..e66062d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/bytereader_unittest.cc
@@ -0,0 +1,707 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader
+
+#include <stdint.h>
+
+#include <string>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf/bytereader.h"
+#include "common/dwarf/bytereader-inl.h"
+#include "common/dwarf/cfi_assembler.h"
+#include "common/using_std_string.h"
+
+using dwarf2reader::ByteReader;
+using dwarf2reader::DwarfPointerEncoding;
+using dwarf2reader::ENDIANNESS_BIG;
+using dwarf2reader::ENDIANNESS_LITTLE;
+using google_breakpad::CFISection;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+using google_breakpad::test_assembler::Section;
+using testing::Test;
+
+struct ReaderFixture {
+ string contents;
+ size_t pointer_size;
+};
+
+class Reader: public ReaderFixture, public Test { };
+class ReaderDeathTest: public ReaderFixture, public Test { };
+
+TEST_F(Reader, SimpleConstructor) {
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ CFISection section(kBigEndian, 4);
+ section
+ .D8(0xc0)
+ .D16(0xcf0d)
+ .D32(0x96fdd219)
+ .D64(0xbbf55fef0825f117ULL)
+ .ULEB128(0xa0927048ba8121afULL)
+ .LEB128(-0x4f337badf4483f83LL)
+ .D32(0xfec319c9);
+ ASSERT_TRUE(section.GetContents(&contents));
+ const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data());
+ EXPECT_EQ(0xc0U, reader.ReadOneByte(data));
+ EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1));
+ EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3));
+ EXPECT_EQ(0xbbf55fef0825f117ULL, reader.ReadEightBytes(data + 7));
+ size_t leb128_size;
+ EXPECT_EQ(0xa0927048ba8121afULL,
+ reader.ReadUnsignedLEB128(data + 15, &leb128_size));
+ EXPECT_EQ(10U, leb128_size);
+ EXPECT_EQ(-0x4f337badf4483f83LL,
+ reader.ReadSignedLEB128(data + 25, &leb128_size));
+ EXPECT_EQ(10U, leb128_size);
+ EXPECT_EQ(0xfec319c9, reader.ReadAddress(data + 35));
+}
+
+TEST_F(Reader, ValidEncodings) {
+ ByteReader reader(ENDIANNESS_LITTLE);
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_pcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_textrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_datarel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_absptr |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_uleb128 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata2 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata4 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_udata8 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sleb128 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata2 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata4 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+ EXPECT_TRUE(reader.ValidEncoding(
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect |
+ dwarf2reader::DW_EH_PE_sdata8 |
+ dwarf2reader::DW_EH_PE_funcrel)));
+
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0d)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0f)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x51)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x60)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x70)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xf0)));
+ EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xd0)));
+}
+
+TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
+ static const uint8_t data[] = { 42 };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit,
+ &pointer_size),
+ "encoding != DW_EH_PE_omit");
+}
+
+TEST_F(Reader, DW_EH_PE_absptr4) {
+ static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(4);
+ EXPECT_EQ(0x40ea5727U,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr,
+ &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_absptr8) {
+ static const uint8_t data[] = {
+ 0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50
+ };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0x010598c240ea5727ULL,
+ reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr,
+ &pointer_size));
+ EXPECT_EQ(8U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_uleb128) {
+ static const uint8_t data[] = { 0x81, 0x84, 0x4c };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(4);
+ EXPECT_EQ(0x130201U,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128,
+ &pointer_size));
+ EXPECT_EQ(3U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_udata2) {
+ static const uint8_t data[] = { 0xf4, 0x8d };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ EXPECT_EQ(0xf48dU,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2,
+ &pointer_size));
+ EXPECT_EQ(2U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_udata4) {
+ static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0xa5628f8b,
+ reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4,
+ &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_udata8Addr8) {
+ static const uint8_t data[] = {
+ 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
+ };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0x8fed199f69047304ULL,
+ reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8,
+ &pointer_size));
+ EXPECT_EQ(8U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_udata8Addr4) {
+ static const uint8_t data[] = {
+ 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
+ };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(4);
+ EXPECT_EQ(0x69047304ULL,
+ reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8,
+ &pointer_size));
+ EXPECT_EQ(8U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_sleb128) {
+ static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ EXPECT_EQ(-0x030201U & 0xffffffff,
+ reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128,
+ &pointer_size));
+ EXPECT_EQ(3U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_sdata2) {
+ static const uint8_t data[] = { 0xb9, 0xbf };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0xffffffffffffbfb9ULL,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2,
+ &pointer_size));
+ EXPECT_EQ(2U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_sdata4) {
+ static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0xffffffffadc2b8f2ULL,
+ reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4,
+ &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_sdata8) {
+ static const uint8_t data[] = {
+ 0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87
+ };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(8);
+ EXPECT_EQ(0x87269b0ce0795766ULL,
+ reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8,
+ &pointer_size));
+ EXPECT_EQ(8U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_pcrel) {
+ static const uint8_t data[] = {
+ 0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce
+ };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ DwarfPointerEncoding encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel
+ | dwarf2reader::DW_EH_PE_absptr);
+ reader.SetCFIDataBase(0x89951377, data);
+ EXPECT_EQ(0x89951377 + 3 + 0x14c8c402,
+ reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_textrel) {
+ static const uint8_t data[] = {
+ 0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e
+ };
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(4);
+ reader.SetTextBase(0xb91beaf0);
+ DwarfPointerEncoding encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
+ | dwarf2reader::DW_EH_PE_sdata2);
+ EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff,
+ reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
+ EXPECT_EQ(2U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_datarel) {
+ static const uint8_t data[] = {
+ 0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39
+ };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(8);
+ reader.SetDataBase(0xbef308bd25ce74f0ULL);
+ DwarfPointerEncoding encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
+ | dwarf2reader::DW_EH_PE_sleb128);
+ EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL,
+ reader.ReadEncodedPointer(data + 2, encoding, &pointer_size));
+ EXPECT_EQ(3U, pointer_size);
+}
+
+TEST_F(Reader, DW_EH_PE_funcrel) {
+ static const uint8_t data[] = {
+ 0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9
+ };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetAddressSize(4);
+ reader.SetFunctionBase(0x823c3520);
+ DwarfPointerEncoding encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
+ | dwarf2reader::DW_EH_PE_udata2);
+ EXPECT_EQ(0x823c3520 + 0xd148,
+ reader.ReadEncodedPointer(data + 5, encoding, &pointer_size));
+ EXPECT_EQ(2U, pointer_size);
+}
+
+TEST(UsableBase, CFI) {
+ static const uint8_t data[] = { 0x42 };
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetCFIDataBase(0xb31cbd20, data);
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
+}
+
+TEST(UsableBase, Text) {
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetTextBase(0xa899ccb9);
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
+}
+
+TEST(UsableBase, Data) {
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetDataBase(0xf7b10bcd);
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
+}
+
+TEST(UsableBase, Function) {
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetFunctionBase(0xc2c0ed81);
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
+}
+
+TEST(UsableBase, ClearFunction) {
+ ByteReader reader(ENDIANNESS_BIG);
+ reader.SetFunctionBase(0xc2c0ed81);
+ reader.ClearFunctionBase();
+ EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel));
+ EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit));
+ EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
+}
+
+struct AlignedFixture {
+ AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); }
+ static const uint8_t data[10];
+ ByteReader reader;
+ size_t pointer_size;
+};
+
+const uint8_t AlignedFixture::data[10] = {
+ 0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b
+};
+
+class Aligned: public AlignedFixture, public Test { };
+
+TEST_F(Aligned, DW_EH_PE_aligned0) {
+ reader.SetCFIDataBase(0xb440305c, data);
+ EXPECT_EQ(0xfe6e93d8U,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned1) {
+ reader.SetCFIDataBase(0xb440305d, data);
+ EXPECT_EQ(0xd834d51cU,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(7U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned2) {
+ reader.SetCFIDataBase(0xb440305e, data);
+ EXPECT_EQ(0x93d834d5U,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(6U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned3) {
+ reader.SetCFIDataBase(0xb440305f, data);
+ EXPECT_EQ(0x6e93d834U,
+ reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(5U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned11) {
+ reader.SetCFIDataBase(0xb4403061, data);
+ EXPECT_EQ(0xd834d51cU,
+ reader.ReadEncodedPointer(data + 1,
+ dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(6U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned30) {
+ reader.SetCFIDataBase(0xb4403063, data);
+ EXPECT_EQ(0x6e93d834U,
+ reader.ReadEncodedPointer(data + 1,
+ dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(4U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned23) {
+ reader.SetCFIDataBase(0xb4403062, data);
+ EXPECT_EQ(0x1cd3ac2bU,
+ reader.ReadEncodedPointer(data + 3,
+ dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(7U, pointer_size);
+}
+
+TEST_F(Aligned, DW_EH_PE_aligned03) {
+ reader.SetCFIDataBase(0xb4403064, data);
+ EXPECT_EQ(0x34d51cd3U,
+ reader.ReadEncodedPointer(data + 3,
+ dwarf2reader::DW_EH_PE_aligned,
+ &pointer_size));
+ EXPECT_EQ(5U, pointer_size);
+}
diff --git a/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.cc b/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.cc
new file mode 100644
index 0000000..2dc2208
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// cfi_assembler.cc: Implementation of google_breakpad::CFISection class.
+// See cfi_assembler.h for details.
+
+#include "common/dwarf/cfi_assembler.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+namespace google_breakpad {
+
+using dwarf2reader::DwarfPointerEncoding;
+
+CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
+ int data_alignment_factor,
+ unsigned return_address_register,
+ uint8_t version,
+ const string &augmentation,
+ bool dwarf64,
+ uint8_t address_size,
+ uint8_t segment_size) {
+ assert(!entry_length_);
+ entry_length_ = new PendingLength();
+ in_fde_ = false;
+
+ if (dwarf64) {
+ D32(kDwarf64InitialLengthMarker);
+ D64(entry_length_->length);
+ entry_length_->start = Here();
+ D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier);
+ } else {
+ D32(entry_length_->length);
+ entry_length_->start = Here();
+ D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier);
+ }
+ D8(version);
+ AppendCString(augmentation);
+ if (version >= 4) {
+ D8(address_size);
+ D8(segment_size);
+ }
+ ULEB128(code_alignment_factor);
+ LEB128(data_alignment_factor);
+ if (version == 1)
+ D8(return_address_register);
+ else
+ ULEB128(return_address_register);
+ return *this;
+}
+
+CFISection &CFISection::FDEHeader(Label cie_pointer,
+ uint64_t initial_location,
+ uint64_t address_range,
+ bool dwarf64) {
+ assert(!entry_length_);
+ entry_length_ = new PendingLength();
+ in_fde_ = true;
+ fde_start_address_ = initial_location;
+
+ if (dwarf64) {
+ D32(0xffffffff);
+ D64(entry_length_->length);
+ entry_length_->start = Here();
+ if (eh_frame_)
+ D64(Here() - cie_pointer);
+ else
+ D64(cie_pointer);
+ } else {
+ D32(entry_length_->length);
+ entry_length_->start = Here();
+ if (eh_frame_)
+ D32(Here() - cie_pointer);
+ else
+ D32(cie_pointer);
+ }
+ EncodedPointer(initial_location);
+ // The FDE length in an .eh_frame section uses the same encoding as the
+ // initial location, but ignores the base address (selected by the upper
+ // nybble of the encoding), as it's a length, not an address that can be
+ // made relative.
+ EncodedPointer(address_range,
+ DwarfPointerEncoding(pointer_encoding_ & 0x0f));
+ return *this;
+}
+
+CFISection &CFISection::FinishEntry() {
+ assert(entry_length_);
+ Align(address_size_, dwarf2reader::DW_CFA_nop);
+ entry_length_->length = Here() - entry_length_->start;
+ delete entry_length_;
+ entry_length_ = NULL;
+ in_fde_ = false;
+ return *this;
+}
+
+CFISection &CFISection::EncodedPointer(uint64_t address,
+ DwarfPointerEncoding encoding,
+ const EncodedPointerBases &bases) {
+ // Omitted data is extremely easy to emit.
+ if (encoding == dwarf2reader::DW_EH_PE_omit)
+ return *this;
+
+ // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume
+ // that ADDRESS is the address at which the pointer is stored --- in
+ // other words, that bit has no effect on how we write the pointer.
+ encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect);
+
+ // Find the base address to which this pointer is relative. The upper
+ // nybble of the encoding specifies this.
+ uint64_t base;
+ switch (encoding & 0xf0) {
+ case dwarf2reader::DW_EH_PE_absptr: base = 0; break;
+ case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break;
+ case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break;
+ case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break;
+ case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break;
+ case dwarf2reader::DW_EH_PE_aligned: base = 0; break;
+ default: abort();
+ };
+
+ // Make ADDRESS relative. Yes, this is appropriate even for "absptr"
+ // values; see gcc/unwind-pe.h.
+ address -= base;
+
+ // Align the pointer, if required.
+ if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned)
+ Align(AddressSize());
+
+ // Append ADDRESS to this section in the appropriate form. For the
+ // fixed-width forms, we don't need to differentiate between signed and
+ // unsigned encodings, because ADDRESS has already been extended to 64
+ // bits before it was passed to us.
+ switch (encoding & 0x0f) {
+ case dwarf2reader::DW_EH_PE_absptr:
+ Address(address);
+ break;
+
+ case dwarf2reader::DW_EH_PE_uleb128:
+ ULEB128(address);
+ break;
+
+ case dwarf2reader::DW_EH_PE_sleb128:
+ LEB128(address);
+ break;
+
+ case dwarf2reader::DW_EH_PE_udata2:
+ case dwarf2reader::DW_EH_PE_sdata2:
+ D16(address);
+ break;
+
+ case dwarf2reader::DW_EH_PE_udata4:
+ case dwarf2reader::DW_EH_PE_sdata4:
+ D32(address);
+ break;
+
+ case dwarf2reader::DW_EH_PE_udata8:
+ case dwarf2reader::DW_EH_PE_sdata8:
+ D64(address);
+ break;
+
+ default:
+ abort();
+ }
+
+ return *this;
+};
+
+const uint32_t CFISection::kDwarf64InitialLengthMarker;
+const uint32_t CFISection::kDwarf32CIEIdentifier;
+const uint64_t CFISection::kDwarf64CIEIdentifier;
+const uint32_t CFISection::kEHFrame32CIEIdentifier;
+const uint64_t CFISection::kEHFrame64CIEIdentifier;
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.h b/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.h
new file mode 100644
index 0000000..bd7354d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/cfi_assembler.h
@@ -0,0 +1,271 @@
+// -*- mode: C++ -*-
+
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// cfi_assembler.h: Define CFISection, a class for creating properly
+// (and improperly) formatted DWARF CFI data for unit tests.
+
+#ifndef PROCESSOR_CFI_ASSEMBLER_H_
+#define PROCESSOR_CFI_ASSEMBLER_H_
+
+#include <string>
+
+#include "common/dwarf/dwarf2enums.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+namespace google_breakpad {
+
+using dwarf2reader::DwarfPointerEncoding;
+using google_breakpad::test_assembler::Endianness;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+
+class CFISection: public Section {
+ public:
+
+ // CFI augmentation strings beginning with 'z', defined by the
+ // Linux/IA-64 C++ ABI, can specify interesting encodings for
+ // addresses appearing in FDE headers and call frame instructions (and
+ // for additional fields whose presence the augmentation string
+ // specifies). In particular, pointers can be specified to be relative
+ // to various base address: the start of the .text section, the
+ // location holding the address itself, and so on. These allow the
+ // frame data to be position-independent even when they live in
+ // write-protected pages. These variants are specified at the
+ // following two URLs:
+ //
+ // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
+ // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+ //
+ // CFISection leaves the production of well-formed 'z'-augmented CIEs and
+ // FDEs to the user, but does provide EncodedPointer, to emit
+ // properly-encoded addresses for a given pointer encoding.
+ // EncodedPointer uses an instance of this structure to find the base
+ // addresses it should use; you can establish a default for all encoded
+ // pointers appended to this section with SetEncodedPointerBases.
+ struct EncodedPointerBases {
+ EncodedPointerBases() : cfi(), text(), data() { }
+
+ // The starting address of this CFI section in memory, for
+ // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data
+ // that has is loaded into the program's address space.
+ uint64_t cfi;
+
+ // The starting address of this file's .text section, for DW_EH_PE_textrel.
+ uint64_t text;
+
+ // The starting address of this file's .got or .eh_frame_hdr section,
+ // for DW_EH_PE_datarel.
+ uint64_t data;
+ };
+
+ // Create a CFISection whose endianness is ENDIANNESS, and where
+ // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is
+ // true, use the .eh_frame format, as described by the Linux
+ // Standards Base Core Specification, instead of the DWARF CFI
+ // format.
+ CFISection(Endianness endianness, size_t address_size,
+ bool eh_frame = false)
+ : Section(endianness), address_size_(address_size), eh_frame_(eh_frame),
+ pointer_encoding_(dwarf2reader::DW_EH_PE_absptr),
+ encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) {
+ // The 'start', 'Here', and 'Mark' members of a CFISection all refer
+ // to section offsets.
+ start() = 0;
+ }
+
+ // Return this CFISection's address size.
+ size_t AddressSize() const { return address_size_; }
+
+ // Return true if this CFISection uses the .eh_frame format, or
+ // false if it contains ordinary DWARF CFI data.
+ bool ContainsEHFrame() const { return eh_frame_; }
+
+ // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer.
+ void SetPointerEncoding(DwarfPointerEncoding encoding) {
+ pointer_encoding_ = encoding;
+ }
+
+ // Use the addresses in BASES as the base addresses for encoded
+ // pointers in subsequent calls to FDEHeader or EncodedPointer.
+ // This function makes a copy of BASES.
+ void SetEncodedPointerBases(const EncodedPointerBases &bases) {
+ encoded_pointer_bases_ = bases;
+ }
+
+ // Append a Common Information Entry header to this section with the
+ // given values. If dwarf64 is true, use the 64-bit DWARF initial
+ // length format for the CIE's initial length. Return a reference to
+ // this section. You should call FinishEntry after writing the last
+ // instruction for the CIE.
+ //
+ // Before calling this function, you will typically want to use Mark
+ // or Here to make a label to pass to FDEHeader that refers to this
+ // CIE's position in the section.
+ CFISection &CIEHeader(uint64_t code_alignment_factor,
+ int data_alignment_factor,
+ unsigned return_address_register,
+ uint8_t version = 3,
+ const string &augmentation = "",
+ bool dwarf64 = false,
+ uint8_t address_size = 8,
+ uint8_t segment_size = 0);
+
+ // Append a Frame Description Entry header to this section with the
+ // given values. If dwarf64 is true, use the 64-bit DWARF initial
+ // length format for the CIE's initial length. Return a reference to
+ // this section. You should call FinishEntry after writing the last
+ // instruction for the CIE.
+ //
+ // This function doesn't support entries that are longer than
+ // 0xffffff00 bytes. (The "initial length" is always a 32-bit
+ // value.) Nor does it support .debug_frame sections longer than
+ // 0xffffff00 bytes.
+ CFISection &FDEHeader(Label cie_pointer,
+ uint64_t initial_location,
+ uint64_t address_range,
+ bool dwarf64 = false);
+
+ // Note the current position as the end of the last CIE or FDE we
+ // started, after padding with DW_CFA_nops for alignment. This
+ // defines the label representing the entry's length, cited in the
+ // entry's header. Return a reference to this section.
+ CFISection &FinishEntry();
+
+ // Append the contents of BLOCK as a DW_FORM_block value: an
+ // unsigned LEB128 length, followed by that many bytes of data.
+ CFISection &Block(const string &block) {
+ ULEB128(block.size());
+ Append(block);
+ return *this;
+ }
+
+ // Append ADDRESS to this section, in the appropriate size and
+ // endianness. Return a reference to this section.
+ CFISection &Address(uint64_t address) {
+ Section::Append(endianness(), address_size_, address);
+ return *this;
+ }
+ CFISection &Address(Label address) {
+ Section::Append(endianness(), address_size_, address);
+ return *this;
+ }
+
+ // Append ADDRESS to this section, using ENCODING and BASES. ENCODING
+ // defaults to this section's default encoding, established by
+ // SetPointerEncoding. BASES defaults to this section's bases, set by
+ // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the
+ // encoding, assume that ADDRESS is where the true address is stored.
+ // Return a reference to this section.
+ //
+ // (C++ doesn't let me use default arguments here, because I want to
+ // refer to members of *this in the default argument expression.)
+ CFISection &EncodedPointer(uint64_t address) {
+ return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
+ }
+ CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
+ return EncodedPointer(address, encoding, encoded_pointer_bases_);
+ }
+ CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding,
+ const EncodedPointerBases &bases);
+
+ // Restate some member functions, to keep chaining working nicely.
+ CFISection &Mark(Label *label) { Section::Mark(label); return *this; }
+ CFISection &D8(uint8_t v) { Section::D8(v); return *this; }
+ CFISection &D16(uint16_t v) { Section::D16(v); return *this; }
+ CFISection &D16(Label v) { Section::D16(v); return *this; }
+ CFISection &D32(uint32_t v) { Section::D32(v); return *this; }
+ CFISection &D32(const Label &v) { Section::D32(v); return *this; }
+ CFISection &D64(uint64_t v) { Section::D64(v); return *this; }
+ CFISection &D64(const Label &v) { Section::D64(v); return *this; }
+ CFISection &LEB128(long long v) { Section::LEB128(v); return *this; }
+ CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; }
+
+ private:
+ // A length value that we've appended to the section, but is not yet
+ // known. LENGTH is the appended value; START is a label referring
+ // to the start of the data whose length was cited.
+ struct PendingLength {
+ Label length;
+ Label start;
+ };
+
+ // Constants used in CFI/.eh_frame data:
+
+ // If the first four bytes of an "initial length" are this constant, then
+ // the data uses the 64-bit DWARF format, and the length itself is the
+ // subsequent eight bytes.
+ static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU;
+
+ // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
+ static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0;
+ static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0;
+ static const uint32_t kEHFrame32CIEIdentifier = 0;
+ static const uint64_t kEHFrame64CIEIdentifier = 0;
+
+ // The size of a machine address for the data in this section.
+ size_t address_size_;
+
+ // If true, we are generating a Linux .eh_frame section, instead of
+ // a standard DWARF .debug_frame section.
+ bool eh_frame_;
+
+ // The encoding to use for FDE pointers.
+ DwarfPointerEncoding pointer_encoding_;
+
+ // The base addresses to use when emitting encoded pointers.
+ EncodedPointerBases encoded_pointer_bases_;
+
+ // The length value for the current entry.
+ //
+ // Oddly, this must be dynamically allocated. Labels never get new
+ // values; they only acquire constraints on the value they already
+ // have, or assert if you assign them something incompatible. So
+ // each header needs truly fresh Label objects to cite in their
+ // headers and track their positions. The alternative is explicit
+ // destructor invocation and a placement new. Ick.
+ PendingLength *entry_length_;
+
+ // True if we are currently emitting an FDE --- that is, we have
+ // called FDEHeader but have not yet called FinishEntry.
+ bool in_fde_;
+
+ // If in_fde_ is true, this is its starting address. We use this for
+ // emitting DW_EH_PE_funcrel pointers.
+ uint64_t fde_start_address_;
+};
+
+} // namespace google_breakpad
+
+#endif // PROCESSOR_CFI_ASSEMBLER_H_
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.cc b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.cc
index c741d69..94542b5 100644
--- a/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.cc
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.cc
@@ -32,6 +32,7 @@
// See dwarf2diehandler.h for details.
#include <assert.h>
+#include <stdint.h>
#include <string>
@@ -57,8 +58,7 @@ bool DIEDispatcher::StartCompilationUnit(uint64 offset, uint8 address_size,
dwarf_version);
}
-bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs) {
+bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag) {
// The stack entry for the parent of this DIE, if there is one.
HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
@@ -82,7 +82,7 @@ bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
if (parent) {
if (parent->handler_)
// Ask the parent to find a handler.
- handler = parent->handler_->FindChildHandler(offset, tag, attrs);
+ handler = parent->handler_->FindChildHandler(offset, tag);
else
// No parent handler means we're not interested in any of our
// children.
@@ -92,7 +92,7 @@ bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
// decides whether to visit it, but the root DIE has no parent
// handler, so we have a special method on the root DIE handler
// itself to decide.
- if (root_handler_->StartRootDIE(offset, tag, attrs))
+ if (root_handler_->StartRootDIE(offset, tag))
handler = root_handler_;
else
handler = NULL;
@@ -168,7 +168,7 @@ void DIEDispatcher::ProcessAttributeReference(uint64 offset,
void DIEDispatcher::ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const char* data,
+ const uint8_t *data,
uint64 len) {
HandlerStack &current = die_handlers_.top();
// This had better be an attribute of the DIE we were meant to handle.
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.h b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.h
index 12b8d3a..a1e589a 100644
--- a/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.h
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler.h
@@ -156,6 +156,8 @@
#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
#define COMMON_DWARF_DWARF2DIEHANDLER_H__
+#include <stdint.h>
+
#include <stack>
#include <string>
@@ -206,7 +208,7 @@ class DIEHandler {
uint64 data) { }
virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
enum DwarfForm form,
- const char* data,
+ const uint8_t *data,
uint64 len) { }
virtual void ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
@@ -239,12 +241,10 @@ class DIEHandler {
// that child DIE (and all its descendants).
//
// OFFSET is the offset of the child; TAG indicates what kind of DIE
- // it is; and ATTRS is the list of attributes the DIE will have, and
- // their forms (their values are not provided).
+ // it is.
//
// The default definition skips all children.
- virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
- const AttributeList &attrs) {
+ virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag) {
return NULL;
}
@@ -280,8 +280,7 @@ class RootDIEHandler: public DIEHandler {
// unit.
//
// The default definition elects to visit the root DIE.
- virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs) { return true; }
+ virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag) { return true; }
};
class DIEDispatcher: public Dwarf2Handler {
@@ -296,8 +295,7 @@ class DIEDispatcher: public Dwarf2Handler {
bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version);
- bool StartDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList &attrs);
+ bool StartDIE(uint64 offset, enum DwarfTag tag);
void ProcessAttributeUnsigned(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
@@ -313,7 +311,7 @@ class DIEDispatcher: public Dwarf2Handler {
void ProcessAttributeBuffer(uint64 offset,
enum DwarfAttribute attr,
enum DwarfForm form,
- const char* data,
+ const uint8_t *data,
uint64 len);
void ProcessAttributeString(uint64 offset,
enum DwarfAttribute attr,
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
new file mode 100644
index 0000000..db70eb3
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
@@ -0,0 +1,527 @@
+// -*- mode: c++ -*-
+
+// Copyright (c) 2010 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "breakpad_googletest_includes.h"
+
+#include "common/dwarf/dwarf2diehandler.h"
+#include "common/using_std_string.h"
+
+using std::make_pair;
+
+using ::testing::_;
+using ::testing::ContainerEq;
+using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::Sequence;
+using ::testing::StrEq;
+
+using dwarf2reader::DIEDispatcher;
+using dwarf2reader::DIEHandler;
+using dwarf2reader::DwarfAttribute;
+using dwarf2reader::DwarfForm;
+using dwarf2reader::DwarfTag;
+using dwarf2reader::RootDIEHandler;
+
+class MockDIEHandler: public DIEHandler {
+ public:
+ MOCK_METHOD3(ProcessAttributeUnsigned,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD3(ProcessAttributeSigned,
+ void(DwarfAttribute, DwarfForm, int64));
+ MOCK_METHOD3(ProcessAttributeReference,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD4(ProcessAttributeBuffer,
+ void(DwarfAttribute, DwarfForm, const uint8_t *, uint64));
+ MOCK_METHOD3(ProcessAttributeString,
+ void(DwarfAttribute, DwarfForm, const string &));
+ MOCK_METHOD3(ProcessAttributeSignature,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD0(EndAttributes, bool());
+ MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
+ MOCK_METHOD0(Finish, void());
+};
+
+class MockRootDIEHandler: public RootDIEHandler {
+ public:
+ MOCK_METHOD3(ProcessAttributeUnsigned,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD3(ProcessAttributeSigned,
+ void(DwarfAttribute, DwarfForm, int64));
+ MOCK_METHOD3(ProcessAttributeReference,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD4(ProcessAttributeBuffer,
+ void(DwarfAttribute, DwarfForm, const uint8_t *, uint64));
+ MOCK_METHOD3(ProcessAttributeString,
+ void(DwarfAttribute, DwarfForm, const string &));
+ MOCK_METHOD3(ProcessAttributeSignature,
+ void(DwarfAttribute, DwarfForm, uint64));
+ MOCK_METHOD0(EndAttributes, bool());
+ MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
+ MOCK_METHOD0(Finish, void());
+ MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8));
+ MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag));
+};
+
+// If the handler elects to skip the compilation unit, the dispatcher
+// should tell the reader so.
+TEST(Dwarf2DIEHandler, SkipCompilationUnit) {
+ Sequence s;
+ MockRootDIEHandler mock_root_handler;
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0x8d42aed77cfccf3eLL,
+ 0x89, 0xdc,
+ 0x2ecb4dc778a80f21LL,
+ 0x66))
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
+ 0x89, 0xdc,
+ 0x2ecb4dc778a80f21LL,
+ 0x66));
+}
+
+// If the handler elects to skip the root DIE, the dispatcher should
+// tell the reader so.
+TEST(Dwarf2DIEHandler, SkipRootDIE) {
+ Sequence s;
+ MockRootDIEHandler mock_root_handler;
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02,
+ 0xb00febffa76e2b2bLL, 0x5c))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_root_handler,
+ StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL,
+ 0xf4, 0x02,
+ 0xb00febffa76e2b2bLL, 0x5c));
+ EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
+ (DwarfTag) 0xb4f98da6));
+ die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
+}
+
+// If the handler elects to skip the root DIE's children, the
+// dispatcher should tell the reader so --- and avoid deleting the
+// root handler.
+TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
+ MockRootDIEHandler mock_root_handler;
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0,
+ 0x09f8bf0767f91675LL, 0xdb))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_root_handler,
+ StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
+ .WillOnce(Return(true));
+ // Please don't tell me about my children.
+ EXPECT_CALL(mock_root_handler, EndAttributes())
+ .WillOnce(Return(false));
+ EXPECT_CALL(mock_root_handler, Finish())
+ .WillOnce(Return());
+ }
+
+ EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL,
+ 0x26, 0xa0,
+ 0x09f8bf0767f91675LL, 0xdb));
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
+ (DwarfTag) 0xb4f98da6));
+ EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL,
+ (DwarfTag) 0xc3a17bba));
+ die_dispatcher.EndDIE(0x435150ceedccda18LL);
+ die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
+}
+
+// The dispatcher should pass attribute values through to the die
+// handler accurately.
+TEST(Dwarf2DIEHandler, PassAttributeValues) {
+ MockRootDIEHandler mock_root_handler;
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ const uint8_t buffer[10] = {
+ 0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18
+ };
+ string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
+
+ // Set expectations.
+ {
+ InSequence s;
+
+ // We'll like the compilation unit header.
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc,
+ 0x2ecb4dc778a80f21LL, 0x66))
+ .WillOnce(Return(true));
+
+ // We'll like the root DIE.
+ EXPECT_CALL(mock_root_handler,
+ StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c))
+ .WillOnce(Return(true));
+
+ // Expect some attribute values.
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed,
+ (DwarfForm) 0x424f1468,
+ 0xa592571997facda1ULL))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeSigned((DwarfAttribute) 0x43694dc9,
+ (DwarfForm) 0xf6f78901L,
+ 0x92602a4e3bf1f446LL))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeReference((DwarfAttribute) 0x4033e8cL,
+ (DwarfForm) 0xf66fbe0bL,
+ 0x50fddef44734fdecULL))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af,
+ (DwarfForm) 0xe99a539a,
+ buffer, sizeof(buffer)))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeString((DwarfAttribute) 0x310ed065,
+ (DwarfForm) 0x15762fec,
+ StrEq(str)))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
+ (DwarfForm) 0x4159f138,
+ 0x94682463613e6a5fULL))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler, EndAttributes())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_root_handler, FindChildHandler(_, _))
+ .Times(0);
+ EXPECT_CALL(mock_root_handler, Finish())
+ .WillOnce(Return());
+ }
+
+ // Drive the dispatcher.
+
+ // Report the CU header.
+ EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
+ 0x89, 0xdc,
+ 0x2ecb4dc778a80f21LL,
+ 0x66));
+ // Report the root DIE.
+ EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL,
+ (DwarfTag) 0x9829445c));
+
+ // Report some attribute values.
+ die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x1cc0bfed,
+ (DwarfForm) 0x424f1468,
+ 0xa592571997facda1ULL);
+ die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x43694dc9,
+ (DwarfForm) 0xf6f78901,
+ 0x92602a4e3bf1f446LL);
+ die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x4033e8c,
+ (DwarfForm) 0xf66fbe0b,
+ 0x50fddef44734fdecULL);
+ die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x25d7e0af,
+ (DwarfForm) 0xe99a539a,
+ buffer, sizeof(buffer));
+ die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x310ed065,
+ (DwarfForm) 0x15762fec,
+ str);
+ die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
+ (DwarfAttribute) 0x58790d72,
+ (DwarfForm) 0x4159f138,
+ 0x94682463613e6a5fULL);
+
+ // Finish the root DIE (and thus the CU).
+ die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);
+}
+
+TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
+ MockRootDIEHandler mock_root_handler;
+ MockDIEHandler *mock_child1_handler = new(MockDIEHandler);
+ MockDIEHandler *mock_child3_handler = new(MockDIEHandler);
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ {
+ InSequence s;
+
+ // We'll like the compilation unit header.
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
+ 0x47dd3c764275a216LL, 0xa5))
+ .WillOnce(Return(true));
+
+ // Root DIE.
+ {
+ EXPECT_CALL(mock_root_handler,
+ StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_root_handler,
+ ProcessAttributeSigned((DwarfAttribute) 0xf779a642,
+ (DwarfForm) 0x2cb63027,
+ 0x18e744661769d08fLL))
+ .WillOnce(Return());
+ EXPECT_CALL(mock_root_handler, EndAttributes())
+ .WillOnce(Return(true));
+
+ // First child DIE.
+ EXPECT_CALL(mock_root_handler,
+ FindChildHandler(0x149f644f8116fe8cLL,
+ (DwarfTag) 0xac2cbd8c))
+ .WillOnce(Return(mock_child1_handler));
+ {
+ EXPECT_CALL(*mock_child1_handler,
+ ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65,
+ (DwarfForm) 0xe4f64c41,
+ 0x1b04e5444a55fe67LL))
+ .WillOnce(Return());
+ EXPECT_CALL(*mock_child1_handler, EndAttributes())
+ .WillOnce(Return(false));
+ // Skip first grandchild DIE and first great-grandchild DIE.
+ EXPECT_CALL(*mock_child1_handler, Finish())
+ .WillOnce(Return());
+ }
+
+ // Second child DIE. Root handler will decline to return a handler
+ // for this child.
+ EXPECT_CALL(mock_root_handler,
+ FindChildHandler(0x97412be24875de9dLL,
+ (DwarfTag) 0x505a068b))
+ .WillOnce(Return((DIEHandler *) NULL));
+
+ // Third child DIE.
+ EXPECT_CALL(mock_root_handler,
+ FindChildHandler(0x753c964c8ab538aeLL,
+ (DwarfTag) 0x8c22970e))
+ .WillOnce(Return(mock_child3_handler));
+ {
+ EXPECT_CALL(*mock_child3_handler,
+ ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
+ (DwarfForm) 0x610b7ae1,
+ 0x3ea5c609d7d7560fLL))
+ .WillOnce(Return());
+ EXPECT_CALL(*mock_child3_handler, EndAttributes())
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_child3_handler, Finish())
+ .WillOnce(Return());
+ }
+
+ EXPECT_CALL(mock_root_handler, Finish())
+ .WillOnce(Return());
+ }
+ }
+
+
+ // Drive the dispatcher.
+
+ // Report the CU header.
+ EXPECT_TRUE(die_dispatcher
+ .StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
+ 0x47dd3c764275a216LL, 0xa5));
+ // Report the root DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL,
+ (DwarfTag) 0xf5d60c59));
+ die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL,
+ (DwarfAttribute) 0xf779a642,
+ (DwarfForm) 0x2cb63027,
+ 0x18e744661769d08fLL);
+
+ // First child DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL,
+ (DwarfTag) 0xac2cbd8c));
+ die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL,
+ (DwarfAttribute) 0xa6fd6f65,
+ (DwarfForm) 0xe4f64c41,
+ 0x1b04e5444a55fe67LL);
+
+ // First grandchild DIE. Will be skipped.
+ {
+ EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL,
+ (DwarfTag) 0x22f05a15));
+ // First great-grandchild DIE. Will be skipped without being
+ // mentioned to any handler.
+ {
+ EXPECT_FALSE(die_dispatcher
+ .StartDIE(0xb3076285d25cac25LL,
+ (DwarfTag) 0xcff4061b));
+ die_dispatcher.EndDIE(0xb3076285d25cac25LL);
+ }
+ die_dispatcher.EndDIE(0xd68de1ee0bd29419LL);
+ }
+ die_dispatcher.EndDIE(0x149f644f8116fe8cLL);
+ }
+
+ // Second child DIE. Root handler will decline to find a handler for it.
+ {
+ EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL,
+ (DwarfTag) 0x505a068b));
+ die_dispatcher.EndDIE(0x97412be24875de9dLL);
+ }
+
+ // Third child DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL,
+ (DwarfTag) 0x8c22970e));
+ die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL,
+ (DwarfAttribute) 0x4e2b7cfb,
+ (DwarfForm) 0x610b7ae1,
+ 0x3ea5c609d7d7560fLL);
+ die_dispatcher.EndDIE(0x753c964c8ab538aeLL);
+ }
+
+ // Finish the root DIE (and thus the CU).
+ die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL);
+ }
+}
+
+// The DIEDispatcher destructor is supposed to delete all handlers on
+// the stack, except for the root.
+TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
+ MockRootDIEHandler mock_root_handler;
+ MockDIEHandler *mock_child_handler = new(MockDIEHandler);
+ MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler);
+
+ {
+ InSequence s;
+
+ // We'll like the compilation unit header.
+ EXPECT_CALL(mock_root_handler,
+ StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
+ 0x76d392ff393ddda2LL, 0xbf))
+ .WillOnce(Return(true));
+
+ // Root DIE.
+ {
+ EXPECT_CALL(mock_root_handler,
+ StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_root_handler, EndAttributes())
+ .WillOnce(Return(true));
+
+ // Child DIE.
+ EXPECT_CALL(mock_root_handler,
+ FindChildHandler(0x058f09240c5fc8c9LL,
+ (DwarfTag) 0x898bf0d0))
+ .WillOnce(Return(mock_child_handler));
+ {
+ EXPECT_CALL(*mock_child_handler, EndAttributes())
+ .WillOnce(Return(true));
+
+ // Grandchild DIE.
+ EXPECT_CALL(*mock_child_handler,
+ FindChildHandler(0x32dc00c9945dc0c8LL,
+ (DwarfTag) 0x2802d007))
+ .WillOnce(Return(mock_grandchild_handler));
+ {
+ EXPECT_CALL(*mock_grandchild_handler,
+ ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
+ (DwarfForm) 0x610b7ae1,
+ 0x3ea5c609d7d7560fLL))
+ .WillOnce(Return());
+
+ // At this point, we abandon the traversal, so none of the
+ // usual stuff should get called.
+ EXPECT_CALL(*mock_grandchild_handler, EndAttributes())
+ .Times(0);
+ EXPECT_CALL(*mock_grandchild_handler, Finish())
+ .Times(0);
+ }
+
+ EXPECT_CALL(*mock_child_handler, Finish())
+ .Times(0);
+ }
+
+ EXPECT_CALL(mock_root_handler, Finish())
+ .Times(0);
+ }
+ }
+
+ // The dispatcher.
+ DIEDispatcher die_dispatcher(&mock_root_handler);
+
+ // Report the CU header.
+ EXPECT_TRUE(die_dispatcher
+ .StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
+ 0x76d392ff393ddda2LL, 0xbf));
+ // Report the root DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL,
+ (DwarfTag) 0x98980361));
+
+ // Child DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL,
+ (DwarfTag) 0x898bf0d0));
+
+ // Grandchild DIE.
+ {
+ EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL,
+ (DwarfTag) 0x2802d007));
+ die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL,
+ (DwarfAttribute) 0x4e2b7cfb,
+ (DwarfForm) 0x610b7ae1,
+ 0x3ea5c609d7d7560fLL);
+
+ // Stop the traversal abruptly, so that there will still be
+ // handlers on the stack when the dispatcher is destructed.
+
+ // No EndDIE call...
+ }
+ // No EndDIE call...
+ }
+ // No EndDIE call...
+ }
+}
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2enums.h b/3rdParty/Breakpad/src/common/dwarf/dwarf2enums.h
index 5565d66..4316a89 100644
--- a/3rdParty/Breakpad/src/common/dwarf/dwarf2enums.h
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2enums.h
@@ -149,7 +149,10 @@ enum DwarfForm {
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
- DW_FORM_ref_sig8 = 0x20
+ DW_FORM_ref_sig8 = 0x20,
+ // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
+ DW_FORM_GNU_addr_index = 0x1f01,
+ DW_FORM_GNU_str_index = 0x1f02
};
// Attribute names and codes
@@ -229,6 +232,8 @@ enum DwarfAttribute {
DW_AT_call_column = 0x57,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
+ // DWARF 4
+ DW_AT_linkage_name = 0x6e,
// SGI/MIPS extensions.
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
@@ -264,6 +269,13 @@ enum DwarfAttribute {
DW_AT_body_begin = 0x2105,
DW_AT_body_end = 0x2106,
DW_AT_GNU_vector = 0x2107,
+ // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
+ DW_AT_GNU_dwo_name = 0x2130,
+ DW_AT_GNU_dwo_id = 0x2131,
+ DW_AT_GNU_ranges_base = 0x2132,
+ DW_AT_GNU_addr_base = 0x2133,
+ DW_AT_GNU_pubnames = 0x2134,
+ DW_AT_GNU_pubtypes = 0x2135,
// VMS extensions.
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
// UPC extension.
@@ -489,9 +501,24 @@ enum DwarfOpcode {
DW_OP_call_frame_cfa =0x9c,
DW_OP_bit_piece =0x9d,
DW_OP_lo_user =0xe0,
- DW_OP_hi_user =0xff,
+ DW_OP_hi_user =0xff,
// GNU extensions
- DW_OP_GNU_push_tls_address =0xe0
+ DW_OP_GNU_push_tls_address =0xe0,
+ // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
+ DW_OP_GNU_addr_index =0xfb,
+ DW_OP_GNU_const_index =0xfc
+};
+
+// Section identifiers for DWP files
+enum DwarfSectionId {
+ DW_SECT_INFO = 1,
+ DW_SECT_TYPES = 2,
+ DW_SECT_ABBREV = 3,
+ DW_SECT_LINE = 4,
+ DW_SECT_LOC = 5,
+ DW_SECT_STR_OFFSETS = 6,
+ DW_SECT_MACINFO = 7,
+ DW_SECT_MACRO = 8
};
// Source languages. These are values for DW_AT_language.
@@ -517,6 +544,8 @@ enum DwarfLanguage
DW_LANG_ObjC_plus_plus =0x0011,
DW_LANG_UPC =0x0012,
DW_LANG_D =0x0013,
+ DW_LANG_Rust =0x001c,
+ DW_LANG_Swift =0x001e,
// Implementation-defined language code range.
DW_LANG_lo_user = 0x8000,
DW_LANG_hi_user = 0xffff,
@@ -643,7 +672,7 @@ enum DwarfPointerEncoding
// encoding (except DW_EH_PE_aligned), and indicates that the
// encoded value represents the address at which the true address
// is stored, not the true address itself.
- DW_EH_PE_indirect = 0x80
+ DW_EH_PE_indirect = 0x80
};
} // namespace dwarf2reader
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.cc b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.cc
index 7c1a29d..8774122 100644
--- a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.cc
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.cc
@@ -44,6 +44,8 @@
#include <string>
#include <utility>
+#include <sys/stat.h>
+
#include "common/dwarf/bytereader-inl.h"
#include "common/dwarf/bytereader.h"
#include "common/dwarf/line_state_machine.h"
@@ -51,11 +53,38 @@
namespace dwarf2reader {
-CompilationUnit::CompilationUnit(const SectionMap& sections, uint64 offset,
+CompilationUnit::CompilationUnit(const string& path,
+ const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler)
- : offset_from_section_start_(offset), reader_(reader),
- sections_(sections), handler_(handler), abbrevs_(NULL),
- string_buffer_(NULL), string_buffer_length_(0) {}
+ : path_(path), offset_from_section_start_(offset), reader_(reader),
+ sections_(sections), handler_(handler), abbrevs_(),
+ string_buffer_(NULL), string_buffer_length_(0),
+ str_offsets_buffer_(NULL), str_offsets_buffer_length_(0),
+ addr_buffer_(NULL), addr_buffer_length_(0),
+ is_split_dwarf_(false), dwo_id_(0), dwo_name_(),
+ skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0),
+ have_checked_for_dwp_(false), dwp_path_(),
+ dwp_byte_reader_(), dwp_reader_() {}
+
+// Initialize a compilation unit from a .dwo or .dwp file.
+// In this case, we need the .debug_addr section from the
+// executable file that contains the corresponding skeleton
+// compilation unit. We also inherit the Dwarf2Handler from
+// the executable file, and call it as if we were still
+// processing the original compilation unit.
+
+void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer,
+ uint64 addr_buffer_length,
+ uint64 addr_base,
+ uint64 ranges_base,
+ uint64 dwo_id) {
+ is_split_dwarf_ = true;
+ addr_buffer_ = addr_buffer;
+ addr_buffer_length_ = addr_buffer_length;
+ addr_base_ = addr_base;
+ ranges_base_ = ranges_base;
+ skeleton_dwo_id_ = dwo_id;
+}
// Read a DWARF2/3 abbreviation section.
// Each abbrev consists of a abbreviation number, a tag, a byte
@@ -83,9 +112,9 @@ void CompilationUnit::ReadAbbrevs() {
// The only way to check whether we are reading over the end of the
// buffer would be to first compute the size of the leb128 data by
// reading it, then go back and read it again.
- const char* abbrev_start = iter->second.first +
+ const uint8_t *abbrev_start = iter->second.first +
header_.abbrev_offset;
- const char* abbrevptr = abbrev_start;
+ const uint8_t *abbrevptr = abbrev_start;
#ifndef NDEBUG
const uint64 abbrev_length = iter->second.second - header_.abbrev_offset;
#endif
@@ -132,8 +161,8 @@ void CompilationUnit::ReadAbbrevs() {
}
// Skips a single DIE's attributes.
-const char* CompilationUnit::SkipDIE(const char* start,
- const Abbrev& abbrev) {
+const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start,
+ const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
@@ -143,8 +172,8 @@ const char* CompilationUnit::SkipDIE(const char* start,
}
// Skips a single attribute form's data.
-const char* CompilationUnit::SkipAttribute(const char* start,
- enum DwarfForm form) {
+const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start,
+ enum DwarfForm form) {
size_t len;
switch (form) {
@@ -171,9 +200,11 @@ const char* CompilationUnit::SkipAttribute(const char* start,
case DW_FORM_ref_sig8:
return start + 8;
case DW_FORM_string:
- return start + strlen(start) + 1;
+ return start + strlen(reinterpret_cast<const char *>(start)) + 1;
case DW_FORM_udata:
case DW_FORM_ref_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
reader_->ReadUnsignedLEB128(start, &len);
return start + len;
@@ -183,14 +214,15 @@ const char* CompilationUnit::SkipAttribute(const char* start,
case DW_FORM_addr:
return start + reader_->AddressSize();
case DW_FORM_ref_addr:
- // DWARF2 and 3 differ on whether ref_addr is address size or
+ // DWARF2 and 3/4 differ on whether ref_addr is address size or
// offset size.
- assert(header_.version == 2 || header_.version == 3);
+ assert(header_.version >= 2);
if (header_.version == 2) {
return start + reader_->AddressSize();
- } else if (header_.version == 3) {
+ } else if (header_.version >= 3) {
return start + reader_->OffsetSize();
}
+ break;
case DW_FORM_block1:
return start + 1 + reader_->ReadOneByte(start);
@@ -217,7 +249,7 @@ const char* CompilationUnit::SkipAttribute(const char* start,
// the offset in the .debug_abbrev section for our abbrevs, and an
// address size.
void CompilationUnit::ReadHeader() {
- const char* headerptr = buffer_;
+ const uint8_t *headerptr = buffer_;
size_t initial_length_size;
assert(headerptr + 4 < buffer_ + buffer_length_);
@@ -234,7 +266,9 @@ void CompilationUnit::ReadHeader() {
header_.abbrev_offset = reader_->ReadOffset(headerptr);
headerptr += reader_->OffsetSize();
- assert(headerptr + 1 < buffer_ + buffer_length_);
+ // Compare against less than or equal because this may be the last
+ // section in the file.
+ assert(headerptr + 1 <= buffer_ + buffer_length_);
header_.address_size = reader_->ReadOneByte(headerptr);
reader_->SetAddressSize(header_.address_size);
headerptr += 1;
@@ -295,17 +329,39 @@ uint64 CompilationUnit::Start() {
string_buffer_length_ = iter->second.second;
}
+ // Set the string offsets section if we have one.
+ iter = sections_.find(".debug_str_offsets");
+ if (iter != sections_.end()) {
+ str_offsets_buffer_ = iter->second.first;
+ str_offsets_buffer_length_ = iter->second.second;
+ }
+
+ // Set the address section if we have one.
+ iter = sections_.find(".debug_addr");
+ if (iter != sections_.end()) {
+ addr_buffer_ = iter->second.first;
+ addr_buffer_length_ = iter->second.second;
+ }
+
// Now that we have our abbreviations, start processing DIE's.
ProcessDIEs();
+ // If this is a skeleton compilation unit generated with split DWARF,
+ // and the client needs the full debug info, we need to find the full
+ // compilation unit in a .dwo or .dwp file.
+ if (!is_split_dwarf_
+ && dwo_name_ != NULL
+ && handler_->NeedSplitDebugInfo())
+ ProcessSplitDwarf();
+
return ourlength;
}
// If one really wanted, you could merge SkipAttribute and
// ProcessAttribute
// This is all boring data manipulation and calling of the handler.
-const char* CompilationUnit::ProcessAttribute(
- uint64 dieoffset, const char* start, enum DwarfAttribute attr,
+const uint8_t *CompilationUnit::ProcessAttribute(
+ uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr,
enum DwarfForm form) {
size_t len;
@@ -319,48 +375,46 @@ const char* CompilationUnit::ProcessAttribute(
return ProcessAttribute(dieoffset, start, attr, form);
case DW_FORM_flag_present:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form, 1);
+ ProcessAttributeUnsigned(dieoffset, attr, form, 1);
return start;
case DW_FORM_data1:
case DW_FORM_flag:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadOneByte(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadOneByte(start));
return start + 1;
case DW_FORM_data2:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadTwoBytes(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadTwoBytes(start));
return start + 2;
case DW_FORM_data4:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadFourBytes(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadFourBytes(start));
return start + 4;
case DW_FORM_data8:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadEightBytes(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadEightBytes(start));
return start + 8;
case DW_FORM_string: {
- const char* str = start;
- handler_->ProcessAttributeString(dieoffset, attr, form,
- str);
+ const char *str = reinterpret_cast<const char *>(start);
+ ProcessAttributeString(dieoffset, attr, form, str);
return start + strlen(str) + 1;
}
case DW_FORM_udata:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadUnsignedLEB128(start,
- &len));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadUnsignedLEB128(start, &len));
return start + len;
case DW_FORM_sdata:
- handler_->ProcessAttributeSigned(dieoffset, attr, form,
- reader_->ReadSignedLEB128(start, &len));
+ ProcessAttributeSigned(dieoffset, attr, form,
+ reader_->ReadSignedLEB128(start, &len));
return start + len;
case DW_FORM_addr:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadAddress(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadAddress(start));
return start + reader_->AddressSize();
case DW_FORM_sec_offset:
- handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
- reader_->ReadOffset(start));
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadOffset(start));
return start + reader_->OffsetSize();
case DW_FORM_ref1:
@@ -390,14 +444,14 @@ const char* CompilationUnit::ProcessAttribute(
+ offset_from_section_start_);
return start + len;
case DW_FORM_ref_addr:
- // DWARF2 and 3 differ on whether ref_addr is address size or
+ // DWARF2 and 3/4 differ on whether ref_addr is address size or
// offset size.
- assert(header_.version == 2 || header_.version == 3);
+ assert(header_.version >= 2);
if (header_.version == 2) {
handler_->ProcessAttributeReference(dieoffset, attr, form,
reader_->ReadAddress(start));
return start + reader_->AddressSize();
- } else if (header_.version == 3) {
+ } else if (header_.version >= 3) {
handler_->ProcessAttributeReference(dieoffset, attr, form,
reader_->ReadOffset(start));
return start + reader_->OffsetSize();
@@ -439,34 +493,66 @@ const char* CompilationUnit::ProcessAttribute(
const uint64 offset = reader_->ReadOffset(start);
assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_);
- const char* str = string_buffer_ + offset;
- handler_->ProcessAttributeString(dieoffset, attr, form,
- str);
+ const char *str = reinterpret_cast<const char *>(string_buffer_ + offset);
+ ProcessAttributeString(dieoffset, attr, form, str);
return start + reader_->OffsetSize();
}
+
+ case DW_FORM_GNU_str_index: {
+ uint64 str_index = reader_->ReadUnsignedLEB128(start, &len);
+ const uint8_t* offset_ptr =
+ str_offsets_buffer_ + str_index * reader_->OffsetSize();
+ const uint64 offset = reader_->ReadOffset(offset_ptr);
+ if (offset >= string_buffer_length_) {
+ return NULL;
+ }
+
+ const char* str = reinterpret_cast<const char *>(string_buffer_) + offset;
+ ProcessAttributeString(dieoffset, attr, form, str);
+ return start + len;
+ break;
+ }
+ case DW_FORM_GNU_addr_index: {
+ uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len);
+ const uint8_t* addr_ptr =
+ addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize();
+ ProcessAttributeUnsigned(dieoffset, attr, form,
+ reader_->ReadAddress(addr_ptr));
+ return start + len;
+ }
}
fprintf(stderr, "Unhandled form type\n");
return NULL;
}
-const char* CompilationUnit::ProcessDIE(uint64 dieoffset,
- const char* start,
- const Abbrev& abbrev) {
+const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset,
+ const uint8_t *start,
+ const Abbrev& abbrev) {
for (AttributeList::const_iterator i = abbrev.attributes.begin();
i != abbrev.attributes.end();
i++) {
start = ProcessAttribute(dieoffset, start, i->first, i->second);
}
+
+ // If this is a compilation unit in a split DWARF object, verify that
+ // the dwo_id matches. If it does not match, we will ignore this
+ // compilation unit.
+ if (abbrev.tag == DW_TAG_compile_unit
+ && is_split_dwarf_
+ && dwo_id_ != skeleton_dwo_id_) {
+ return NULL;
+ }
+
return start;
}
void CompilationUnit::ProcessDIEs() {
- const char* dieptr = after_header_;
+ const uint8_t *dieptr = after_header_;
size_t len;
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
- const char* lengthstart = buffer_;
+ const uint8_t *lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@@ -500,7 +586,7 @@ void CompilationUnit::ProcessDIEs() {
const Abbrev& abbrev = abbrevs_->at(static_cast<size_t>(abbrev_num));
const enum DwarfTag tag = abbrev.tag;
- if (!handler_->StartDIE(absolute_offset, tag, abbrev.attributes)) {
+ if (!handler_->StartDIE(absolute_offset, tag)) {
dieptr = SkipDIE(dieptr, abbrev);
} else {
dieptr = ProcessDIE(absolute_offset, dieptr, abbrev);
@@ -514,10 +600,313 @@ void CompilationUnit::ProcessDIEs() {
}
}
-LineInfo::LineInfo(const char* buffer, uint64 buffer_length,
+// Check for a valid ELF file and return the Address size.
+// Returns 0 if not a valid ELF file.
+inline int GetElfWidth(const ElfReader& elf) {
+ if (elf.IsElf32File())
+ return 4;
+ if (elf.IsElf64File())
+ return 8;
+ return 0;
+}
+
+void CompilationUnit::ProcessSplitDwarf() {
+ struct stat statbuf;
+ if (!have_checked_for_dwp_) {
+ // Look for a .dwp file in the same directory as the executable.
+ have_checked_for_dwp_ = true;
+ string dwp_suffix(".dwp");
+ dwp_path_ = path_ + dwp_suffix;
+ if (stat(dwp_path_.c_str(), &statbuf) != 0) {
+ // Fall back to a split .debug file in the same directory.
+ string debug_suffix(".debug");
+ dwp_path_ = path_;
+ size_t found = path_.rfind(debug_suffix);
+ if (found + debug_suffix.length() == path_.length())
+ dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix);
+ }
+ if (stat(dwp_path_.c_str(), &statbuf) == 0) {
+ ElfReader* elf = new ElfReader(dwp_path_);
+ int width = GetElfWidth(*elf);
+ if (width != 0) {
+ dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness()));
+ dwp_byte_reader_->SetAddressSize(width);
+ dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf));
+ dwp_reader_->Initialize();
+ } else {
+ delete elf;
+ }
+ }
+ }
+ bool found_in_dwp = false;
+ if (dwp_reader_) {
+ // If we have a .dwp file, read the debug sections for the requested CU.
+ SectionMap sections;
+ dwp_reader_->ReadDebugSectionsForCU(dwo_id_, &sections);
+ if (!sections.empty()) {
+ found_in_dwp = true;
+ CompilationUnit dwp_comp_unit(dwp_path_, sections, 0,
+ dwp_byte_reader_.get(), handler_);
+ dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_,
+ ranges_base_, dwo_id_);
+ dwp_comp_unit.Start();
+ }
+ }
+ if (!found_in_dwp) {
+ // If no .dwp file, try to open the .dwo file.
+ if (stat(dwo_name_, &statbuf) == 0) {
+ ElfReader elf(dwo_name_);
+ int width = GetElfWidth(elf);
+ if (width != 0) {
+ ByteReader reader(ENDIANNESS_LITTLE);
+ reader.SetAddressSize(width);
+ SectionMap sections;
+ ReadDebugSectionsFromDwo(&elf, &sections);
+ CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader,
+ handler_);
+ dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_,
+ addr_base_, ranges_base_, dwo_id_);
+ dwo_comp_unit.Start();
+ }
+ }
+ }
+}
+
+void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader,
+ SectionMap* sections) {
+ static const char* const section_names[] = {
+ ".debug_abbrev",
+ ".debug_info",
+ ".debug_str_offsets",
+ ".debug_str"
+ };
+ for (unsigned int i = 0u;
+ i < sizeof(section_names)/sizeof(*(section_names)); ++i) {
+ string base_name = section_names[i];
+ string dwo_name = base_name + ".dwo";
+ size_t section_size;
+ const char* section_data = elf_reader->GetSectionByName(dwo_name,
+ &section_size);
+ if (section_data != NULL)
+ sections->insert(std::make_pair(
+ base_name, std::make_pair(
+ reinterpret_cast<const uint8_t *>(section_data),
+ section_size)));
+ }
+}
+
+DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader)
+ : elf_reader_(elf_reader), byte_reader_(byte_reader),
+ cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL),
+ string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0),
+ nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL),
+ offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL),
+ abbrev_size_(0), info_data_(NULL), info_size_(0),
+ str_offsets_data_(NULL), str_offsets_size_(0) {}
+
+DwpReader::~DwpReader() {
+ if (elf_reader_) delete elf_reader_;
+}
+
+void DwpReader::Initialize() {
+ cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index",
+ &cu_index_size_);
+ if (cu_index_ == NULL) {
+ return;
+ }
+ // The .debug_str.dwo section is shared by all CUs in the file.
+ string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo",
+ &string_buffer_size_);
+
+ version_ = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(cu_index_));
+
+ if (version_ == 1) {
+ nslots_ = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(cu_index_)
+ + 3 * sizeof(uint32));
+ phash_ = cu_index_ + 4 * sizeof(uint32);
+ pindex_ = phash_ + nslots_ * sizeof(uint64);
+ shndx_pool_ = pindex_ + nslots_ * sizeof(uint32);
+ if (shndx_pool_ >= cu_index_ + cu_index_size_) {
+ version_ = 0;
+ }
+ } else if (version_ == 2) {
+ ncolumns_ = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32));
+ nunits_ = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32));
+ nslots_ = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32));
+ phash_ = cu_index_ + 4 * sizeof(uint32);
+ pindex_ = phash_ + nslots_ * sizeof(uint64);
+ offset_table_ = pindex_ + nslots_ * sizeof(uint32);
+ size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32);
+ abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo",
+ &abbrev_size_);
+ info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_);
+ str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo",
+ &str_offsets_size_);
+ if (size_table_ >= cu_index_ + cu_index_size_) {
+ version_ = 0;
+ }
+ }
+}
+
+void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id,
+ SectionMap* sections) {
+ if (version_ == 1) {
+ int slot = LookupCU(dwo_id);
+ if (slot == -1) {
+ return;
+ }
+
+ // The index table points to the section index pool, where we
+ // can read a list of section indexes for the debug sections
+ // for the CU whose dwo_id we are looking for.
+ int index = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(pindex_)
+ + slot * sizeof(uint32));
+ const char* shndx_list = shndx_pool_ + index * sizeof(uint32);
+ for (;;) {
+ if (shndx_list >= cu_index_ + cu_index_size_) {
+ version_ = 0;
+ return;
+ }
+ unsigned int shndx = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(shndx_list));
+ shndx_list += sizeof(uint32);
+ if (shndx == 0)
+ break;
+ const char* section_name = elf_reader_->GetSectionName(shndx);
+ size_t section_size;
+ const char* section_data;
+ // We're only interested in these four debug sections.
+ // The section names in the .dwo file end with ".dwo", but we
+ // add them to the sections table with their normal names.
+ if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) {
+ section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
+ sections->insert(std::make_pair(
+ ".debug_abbrev",
+ std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ section_size)));
+ } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) {
+ section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
+ sections->insert(std::make_pair(
+ ".debug_info",
+ std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ section_size)));
+ } else if (!strncmp(section_name, ".debug_str_offsets",
+ strlen(".debug_str_offsets"))) {
+ section_data = elf_reader_->GetSectionByIndex(shndx, &section_size);
+ sections->insert(std::make_pair(
+ ".debug_str_offsets",
+ std::make_pair(reinterpret_cast<const uint8_t *> (section_data),
+ section_size)));
+ }
+ }
+ sections->insert(std::make_pair(
+ ".debug_str",
+ std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
+ string_buffer_size_)));
+ } else if (version_ == 2) {
+ uint32 index = LookupCUv2(dwo_id);
+ if (index == 0) {
+ return;
+ }
+
+ // The index points to a row in each of the section offsets table
+ // and the section size table, where we can read the offsets and sizes
+ // of the contributions to each debug section from the CU whose dwo_id
+ // we are looking for. Row 0 of the section offsets table has the
+ // section ids for each column of the table. The size table begins
+ // with row 1.
+ const char* id_row = offset_table_;
+ const char* offset_row = offset_table_
+ + index * ncolumns_ * sizeof(uint32);
+ const char* size_row =
+ size_table_ + (index - 1) * ncolumns_ * sizeof(uint32);
+ if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) {
+ version_ = 0;
+ return;
+ }
+ for (unsigned int col = 0u; col < ncolumns_; ++col) {
+ uint32 section_id =
+ byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row)
+ + col * sizeof(uint32));
+ uint32 offset = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(offset_row)
+ + col * sizeof(uint32));
+ uint32 size = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32));
+ if (section_id == DW_SECT_ABBREV) {
+ sections->insert(std::make_pair(
+ ".debug_abbrev",
+ std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_)
+ + offset, size)));
+ } else if (section_id == DW_SECT_INFO) {
+ sections->insert(std::make_pair(
+ ".debug_info",
+ std::make_pair(reinterpret_cast<const uint8_t *> (info_data_)
+ + offset, size)));
+ } else if (section_id == DW_SECT_STR_OFFSETS) {
+ sections->insert(std::make_pair(
+ ".debug_str_offsets",
+ std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_)
+ + offset, size)));
+ }
+ }
+ sections->insert(std::make_pair(
+ ".debug_str",
+ std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_),
+ string_buffer_size_)));
+ }
+}
+
+int DwpReader::LookupCU(uint64 dwo_id) {
+ uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
+ uint64 probe = byte_reader_.ReadEightBytes(
+ reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
+ if (probe != 0 && probe != dwo_id) {
+ uint32 secondary_hash =
+ (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
+ do {
+ slot = (slot + secondary_hash) & (nslots_ - 1);
+ probe = byte_reader_.ReadEightBytes(
+ reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
+ } while (probe != 0 && probe != dwo_id);
+ }
+ if (probe == 0)
+ return -1;
+ return slot;
+}
+
+uint32 DwpReader::LookupCUv2(uint64 dwo_id) {
+ uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1);
+ uint64 probe = byte_reader_.ReadEightBytes(
+ reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
+ uint32 index = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
+ if (index != 0 && probe != dwo_id) {
+ uint32 secondary_hash =
+ (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1;
+ do {
+ slot = (slot + secondary_hash) & (nslots_ - 1);
+ probe = byte_reader_.ReadEightBytes(
+ reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64));
+ index = byte_reader_.ReadFourBytes(
+ reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32));
+ } while (index != 0 && probe != dwo_id);
+ }
+ return index;
+}
+
+LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler):
- handler_(handler), reader_(reader), buffer_(buffer),
- buffer_length_(buffer_length) {
+ handler_(handler), reader_(reader), buffer_(buffer) {
+#ifndef NDEBUG
+ buffer_length_ = buffer_length;
+#endif
header_.std_opcode_lengths = NULL;
}
@@ -530,7 +919,7 @@ uint64 LineInfo::Start() {
// The header for a debug_line section is mildly complicated, because
// the line info is very tightly encoded.
void LineInfo::ReadHeader() {
- const char* lineptr = buffer_;
+ const uint8_t *lineptr = buffer_;
size_t initial_length_size;
const uint64 initial_length
@@ -553,6 +942,13 @@ void LineInfo::ReadHeader() {
header_.min_insn_length = reader_->ReadOneByte(lineptr);
lineptr += 1;
+ if (header_.version >= 4) {
+ __attribute__((unused)) uint8 max_ops_per_insn =
+ reader_->ReadOneByte(lineptr);
+ ++lineptr;
+ assert(max_ops_per_insn == 1);
+ }
+
header_.default_is_stmt = reader_->ReadOneByte(lineptr);
lineptr += 1;
@@ -577,7 +973,7 @@ void LineInfo::ReadHeader() {
if (*lineptr) {
uint32 dirindex = 1;
while (*lineptr) {
- const char* dirname = lineptr;
+ const char *dirname = reinterpret_cast<const char *>(lineptr);
handler_->DefineDir(dirname, dirindex);
lineptr += strlen(dirname) + 1;
dirindex++;
@@ -590,7 +986,7 @@ void LineInfo::ReadHeader() {
uint32 fileindex = 1;
size_t len;
while (*lineptr) {
- const char* filename = lineptr;
+ const char *filename = reinterpret_cast<const char *>(lineptr);
lineptr += strlen(filename) + 1;
uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len);
@@ -615,7 +1011,7 @@ void LineInfo::ReadHeader() {
bool LineInfo::ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
- const char* start,
+ const uint8_t *start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@@ -756,7 +1152,7 @@ bool LineInfo::ProcessOneOpcode(ByteReader* reader,
}
break;
case DW_LNE_define_file: {
- const char* filename = start;
+ const char *filename = reinterpret_cast<const char *>(start);
templen = strlen(filename) + 1;
start += templen;
@@ -803,7 +1199,7 @@ void LineInfo::ReadLines() {
// lengthstart is the place the length field is based on.
// It is the point in the header after the initial length field
- const char* lengthstart = buffer_;
+ const uint8_t *lengthstart = buffer_;
// In 64 bit dwarf, the initial length is 12 bytes, because of the
// 0xffffffff at the start.
@@ -812,7 +1208,7 @@ void LineInfo::ReadLines() {
else
lengthstart += 4;
- const char* lineptr = after_header_;
+ const uint8_t *lineptr = after_header_;
lsm.Reset(header_.default_is_stmt);
// The LineInfoHandler interface expects each line's length along
@@ -1311,7 +1707,7 @@ class CallFrameInfo::State {
const Entry *entry_;
// The next instruction to process.
- const char *cursor_;
+ const uint8_t *cursor_;
// The current set of rules.
RuleMap rules_;
@@ -1409,7 +1805,8 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
if (len > bytes_left || expression_length > bytes_left - len)
return ReportIncomplete();
cursor_ += len;
- operands->expression = string(cursor_, expression_length);
+ operands->expression = string(reinterpret_cast<const char *>(cursor_),
+ expression_length);
cursor_ += expression_length;
break;
}
@@ -1512,16 +1909,19 @@ bool CallFrameInfo::State::DoInstruction() {
// Change the base register used to compute the CFA.
case DW_CFA_def_cfa_register: {
+ if (!ParseOperands("r", &ops)) return false;
Rule *cfa_rule = rules_.CFARule();
if (!cfa_rule) {
- reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset());
+ if (!DoDefCFA(ops.register_number, ops.offset)) {
+ reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset());
+ return false;
+ }
+ } else {
+ cfa_rule->SetBaseRegister(ops.register_number);
+ if (!cfa_rule->Handle(handler_, address_,
+ Handler::kCFARegister))
return false;
}
- if (!ParseOperands("r", &ops)) return false;
- cfa_rule->SetBaseRegister(ops.register_number);
- if (!cfa_rule->Handle(handler_, address_,
- Handler::kCFARegister))
- return false;
break;
}
@@ -1759,8 +2159,8 @@ bool CallFrameInfo::State::DoRestore(unsigned reg) {
return DoRule(reg, rule);
}
-bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) {
- const char *buffer_end = buffer_ + buffer_length_;
+bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) {
+ const uint8_t *buffer_end = buffer_ + buffer_length_;
// Initialize enough of ENTRY for use in error reporting.
entry->offset = cursor - buffer_;
@@ -1838,7 +2238,7 @@ bool CallFrameInfo::ReadEntryPrologue(const char *cursor, Entry *entry) {
}
bool CallFrameInfo::ReadCIEFields(CIE *cie) {
- const char *cursor = cie->fields;
+ const uint8_t *cursor = cie->fields;
size_t len;
assert(cie->kind == kCIE);
@@ -1860,22 +2260,23 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
cursor++;
// If we don't recognize the version, we can't parse any more fields of the
- // CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a
- // version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well;
+ // CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a
+ // version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well;
// the difference between those versions seems to be the same as for
// .debug_frame.
- if (cie->version < 1 || cie->version > 3) {
+ if (cie->version < 1 || cie->version > 4) {
reporter_->UnrecognizedVersion(cie->offset, cie->version);
return false;
}
- const char *augmentation_start = cursor;
- const void *augmentation_end =
- memchr(augmentation_start, '\0', cie->end - augmentation_start);
+ const uint8_t *augmentation_start = cursor;
+ const uint8_t *augmentation_end =
+ reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0',
+ cie->end - augmentation_start));
if (! augmentation_end) return ReportIncomplete(cie);
- cursor = static_cast<const char *>(augmentation_end);
- cie->augmentation = string(augmentation_start,
- cursor - augmentation_start);
+ cursor = augmentation_end;
+ cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start),
+ cursor - augmentation_start);
// Skip the terminating '\0'.
cursor++;
@@ -1893,16 +2294,36 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
}
}
+ if (cie->version >= 4) {
+ uint8_t address_size = *cursor++;
+ if (address_size != 8) {
+ // TODO(scottmg): Only supporting x64 for now.
+ reporter_->UnexpectedAddressSize(cie->offset, address_size);
+ return false;
+ }
+
+ uint8_t segment_size = *cursor++;
+ if (segment_size != 0) {
+ // TODO(scottmg): Only supporting x64 for now.
+ // I would have perhaps expected 4 here, but LLVM emits a 0, near
+ // http://llvm.org/docs/doxygen/html/MCDwarf_8cpp_source.html#l00606. As
+ // we are not using the value, only succeed for now if it's the expected
+ // 0.
+ reporter_->UnexpectedSegmentSize(cie->offset, segment_size);
+ return false;
+ }
+ }
+
// Parse the code alignment factor.
cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len);
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
cursor += len;
-
+
// Parse the data alignment factor.
cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len);
if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie);
cursor += len;
-
+
// Parse the return address register. This is a ubyte in version 1, and
// a ULEB128 in version 3.
if (cie->version == 1) {
@@ -1921,9 +2342,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
if (size_t(cie->end - cursor) < len + data_size)
return ReportIncomplete(cie);
cursor += len;
- const char *data = cursor;
+ const uint8_t *data = cursor;
cursor += data_size;
- const char *data_end = cursor;
+ const uint8_t *data_end = cursor;
cie->has_z_lsda = false;
cie->has_z_personality = false;
@@ -2013,9 +2434,9 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
return true;
}
-
+
bool CallFrameInfo::ReadFDEFields(FDE *fde) {
- const char *cursor = fde->fields;
+ const uint8_t *cursor = fde->fields;
size_t size;
fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding,
@@ -2081,10 +2502,10 @@ bool CallFrameInfo::ReadFDEFields(FDE *fde) {
}
bool CallFrameInfo::Start() {
- const char *buffer_end = buffer_ + buffer_length_;
- const char *cursor;
+ const uint8_t *buffer_end = buffer_ + buffer_length_;
+ const uint8_t *cursor;
bool all_ok = true;
- const char *entry_end;
+ const uint8_t *entry_end;
bool ok;
// Traverse all the entries in buffer_, skipping CIEs and offering
@@ -2254,6 +2675,22 @@ void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) {
filename_.c_str(), offset, section_.c_str(), cie_offset);
}
+void CallFrameInfo::Reporter::UnexpectedAddressSize(uint64 offset,
+ uint8_t address_size) {
+ fprintf(stderr,
+ "%s: CFI frame description entry at offset 0x%llx in '%s':"
+ " CIE specifies unexpected address size: %d\n",
+ filename_.c_str(), offset, section_.c_str(), address_size);
+}
+
+void CallFrameInfo::Reporter::UnexpectedSegmentSize(uint64 offset,
+ uint8_t segment_size) {
+ fprintf(stderr,
+ "%s: CFI frame description entry at offset 0x%llx in '%s':"
+ " CIE specifies unexpected segment size: %d\n",
+ filename_.c_str(), offset, section_.c_str(), segment_size);
+}
+
void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) {
fprintf(stderr,
"%s: CFI frame description entry at offset 0x%llx in '%s':"
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.h b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.h
index ecf4eb2..5d2d7f6 100644
--- a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.h
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader.h
@@ -40,25 +40,30 @@
#ifndef COMMON_DWARF_DWARF2READER_H__
#define COMMON_DWARF_DWARF2READER_H__
+#include <stdint.h>
+
#include <list>
#include <map>
#include <string>
#include <utility>
#include <vector>
+#include <memory>
#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2enums.h"
#include "common/dwarf/types.h"
#include "common/using_std_string.h"
+#include "common/dwarf/elf_reader.h"
namespace dwarf2reader {
struct LineStateMachine;
class Dwarf2Handler;
class LineInfoHandler;
+class DwpReader;
// This maps from a string naming a section to a pair containing a
// the data for the section, and the size of the section.
-typedef std::map<string, std::pair<const char*, uint64> > SectionMap;
+typedef std::map<string, std::pair<const uint8_t *, uint64> > SectionMap;
typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
AttributeList;
typedef AttributeList::iterator AttributeIterator;
@@ -85,7 +90,7 @@ class LineInfo {
// to the beginning and length of the line information to read.
// Reader is a ByteReader class that has the endianness set
// properly.
- LineInfo(const char* buffer_, uint64 buffer_length,
+ LineInfo(const uint8_t *buffer_, uint64 buffer_length,
ByteReader* reader, LineInfoHandler* handler);
virtual ~LineInfo() {
@@ -111,7 +116,7 @@ class LineInfo {
static bool ProcessOneOpcode(ByteReader* reader,
LineInfoHandler* handler,
const struct LineInfoHeader &header,
- const char* start,
+ const uint8_t *start,
struct LineStateMachine* lsm,
size_t* len,
uintptr pc,
@@ -139,9 +144,11 @@ class LineInfo {
// buffer is the buffer for our line info, starting at exactly where
// the line info to read is. after_header is the place right after
// the end of the line information header.
- const char* buffer_;
+ const uint8_t *buffer_;
+#ifndef NDEBUG
uint64 buffer_length_;
- const char* after_header_;
+#endif
+ const uint8_t *after_header_;
};
// This class is the main interface between the line info reader and
@@ -180,6 +187,106 @@ class LineInfoHandler {
uint32 file_num, uint32 line_num, uint32 column_num) { }
};
+// This class is the main interface between the reader and the
+// client. The virtual functions inside this get called for
+// interesting events that happen during DWARF2 reading.
+// The default implementation skips everything.
+class Dwarf2Handler {
+ public:
+ Dwarf2Handler() { }
+
+ virtual ~Dwarf2Handler() { }
+
+ // Start to process a compilation unit at OFFSET from the beginning of the
+ // .debug_info section. Return false if you would like to skip this
+ // compilation unit.
+ virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
+ uint8 offset_size, uint64 cu_length,
+ uint8 dwarf_version) { return false; }
+
+ // When processing a skeleton compilation unit, resulting from a split
+ // DWARF compilation, once the skeleton debug info has been read,
+ // the reader will call this function to ask the client if it needs
+ // the full debug info from the .dwo or .dwp file. Return true if
+ // you need it, or false to skip processing the split debug info.
+ virtual bool NeedSplitDebugInfo() { return true; }
+
+ // Start to process a split compilation unit at OFFSET from the beginning of
+ // the debug_info section in the .dwp/.dwo file. Return false if you would
+ // like to skip this compilation unit.
+ virtual bool StartSplitCompilationUnit(uint64 offset,
+ uint64 cu_length) { return false; }
+
+ // Start to process a DIE at OFFSET from the beginning of the .debug_info
+ // section. Return false if you would like to skip this DIE.
+ virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; }
+
+ // Called when we have an attribute with unsigned data to give to our
+ // handler. The attribute is for the DIE at OFFSET from the beginning of the
+ // .debug_info section. Its name is ATTR, its form is FORM, and its value is
+ // DATA.
+ virtual void ProcessAttributeUnsigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data) { }
+
+ // Called when we have an attribute with signed data to give to our handler.
+ // The attribute is for the DIE at OFFSET from the beginning of the
+ // .debug_info section. Its name is ATTR, its form is FORM, and its value is
+ // DATA.
+ virtual void ProcessAttributeSigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ int64 data) { }
+
+ // Called when we have an attribute whose value is a reference to
+ // another DIE. The attribute belongs to the DIE at OFFSET from the
+ // beginning of the .debug_info section. Its name is ATTR, its form
+ // is FORM, and the offset of the DIE being referred to from the
+ // beginning of the .debug_info section is DATA.
+ virtual void ProcessAttributeReference(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data) { }
+
+ // Called when we have an attribute with a buffer of data to give to our
+ // handler. The attribute is for the DIE at OFFSET from the beginning of the
+ // .debug_info section. Its name is ATTR, its form is FORM, DATA points to
+ // the buffer's contents, and its length in bytes is LENGTH. The buffer is
+ // owned by the caller, not the callee, and may not persist for very long.
+ // If you want the data to be available later, it needs to be copied.
+ virtual void ProcessAttributeBuffer(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const uint8_t *data,
+ uint64 len) { }
+
+ // Called when we have an attribute with string data to give to our handler.
+ // The attribute is for the DIE at OFFSET from the beginning of the
+ // .debug_info section. Its name is ATTR, its form is FORM, and its value is
+ // DATA.
+ virtual void ProcessAttributeString(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const string& data) { }
+
+ // Called when we have an attribute whose value is the 64-bit signature
+ // of a type unit in the .debug_types section. OFFSET is the offset of
+ // the DIE whose attribute we're reporting. ATTR and FORM are the
+ // attribute's name and form. SIGNATURE is the type unit's signature.
+ virtual void ProcessAttributeSignature(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 signature) { }
+
+ // Called when finished processing the DIE at OFFSET.
+ // Because DWARF2/3 specifies a tree of DIEs, you may get starts
+ // before ends of the previous DIE, as we process children before
+ // ending the parent.
+ virtual void EndDIE(uint64 offset) { }
+
+};
+
// The base of DWARF2/3 debug info is a DIE (Debugging Information
// Entry.
// DWARF groups DIE's into a tree and calls the root of this tree a
@@ -221,12 +328,21 @@ class CompilationUnit {
// Initialize a compilation unit. This requires a map of sections,
// the offset of this compilation unit in the .debug_info section, a
// ByteReader, and a Dwarf2Handler class to call callbacks in.
- CompilationUnit(const SectionMap& sections, uint64 offset,
+ CompilationUnit(const string& path, const SectionMap& sections, uint64 offset,
ByteReader* reader, Dwarf2Handler* handler);
virtual ~CompilationUnit() {
if (abbrevs_) delete abbrevs_;
}
+ // Initialize a compilation unit from a .dwo or .dwp file.
+ // In this case, we need the .debug_addr section from the
+ // executable file that contains the corresponding skeleton
+ // compilation unit. We also inherit the Dwarf2Handler from
+ // the executable file, and call it as if we were still
+ // processing the original compilation unit.
+ void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length,
+ uint64 addr_base, uint64 ranges_base, uint64 dwo_id);
+
// Begin reading a Dwarf2 compilation unit, and calling the
// callbacks in the Dwarf2Handler
@@ -266,29 +382,104 @@ class CompilationUnit {
// Processes a single DIE for this compilation unit and return a new
// pointer just past the end of it
- const char* ProcessDIE(uint64 dieoffset,
- const char* start,
- const Abbrev& abbrev);
+ const uint8_t *ProcessDIE(uint64 dieoffset,
+ const uint8_t *start,
+ const Abbrev& abbrev);
// Processes a single attribute and return a new pointer just past the
// end of it
- const char* ProcessAttribute(uint64 dieoffset,
- const char* start,
- enum DwarfAttribute attr,
- enum DwarfForm form);
+ const uint8_t *ProcessAttribute(uint64 dieoffset,
+ const uint8_t *start,
+ enum DwarfAttribute attr,
+ enum DwarfForm form);
+
+ // Called when we have an attribute with unsigned data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of compilation unit, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA.
+ // If we see a DW_AT_GNU_dwo_id attribute, save the value so that
+ // we can find the debug info in a .dwo or .dwp file.
+ void ProcessAttributeUnsigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data) {
+ if (attr == DW_AT_GNU_dwo_id) {
+ dwo_id_ = data;
+ }
+ else if (attr == DW_AT_GNU_addr_base) {
+ addr_base_ = data;
+ }
+ else if (attr == DW_AT_GNU_ranges_base) {
+ ranges_base_ = data;
+ }
+ // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5,
+ // that base will apply to DW_AT_ranges attributes in the
+ // skeleton CU as well as in the .dwo/.dwp files.
+ else if (attr == DW_AT_ranges && is_split_dwarf_) {
+ data += ranges_base_;
+ }
+ handler_->ProcessAttributeUnsigned(offset, attr, form, data);
+ }
+
+ // Called when we have an attribute with signed data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of compilation unit, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA.
+ void ProcessAttributeSigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ int64 data) {
+ handler_->ProcessAttributeSigned(offset, attr, form, data);
+ }
+
+ // Called when we have an attribute with a buffer of data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of compilation unit, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA, and the
+ // length of the buffer is LENGTH.
+ void ProcessAttributeBuffer(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const uint8_t* data,
+ uint64 len) {
+ handler_->ProcessAttributeBuffer(offset, attr, form, data, len);
+ }
+
+ // Called when we have an attribute with string data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of compilation unit, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA.
+ // If we see a DW_AT_GNU_dwo_name attribute, save the value so
+ // that we can find the debug info in a .dwo or .dwp file.
+ void ProcessAttributeString(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const char* data) {
+ if (attr == DW_AT_GNU_dwo_name)
+ dwo_name_ = data;
+ handler_->ProcessAttributeString(offset, attr, form, data);
+ }
// Processes all DIEs for this compilation unit
void ProcessDIEs();
// Skips the die with attributes specified in ABBREV starting at
// START, and return the new place to position the stream to.
- const char* SkipDIE(const char* start,
- const Abbrev& abbrev);
+ const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev);
// Skips the attribute starting at START, with FORM, and return the
// new place to position the stream to.
- const char* SkipAttribute(const char* start,
- enum DwarfForm form);
+ const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form);
+
+ // Process the actual debug information in a split DWARF file.
+ void ProcessSplitDwarf();
+
+ // Read the debug sections from a .dwo file.
+ void ReadDebugSectionsFromDwo(ElfReader* elf_reader,
+ SectionMap* sections);
+
+ // Path of the file containing the debug information.
+ const string path_;
// Offset from section start is the offset of this compilation unit
// from the beginning of the .debug_info section.
@@ -297,9 +488,9 @@ class CompilationUnit {
// buffer is the buffer for our CU, starting at .debug_info + offset
// passed in from constructor.
// after_header points to right after the compilation unit header.
- const char* buffer_;
+ const uint8_t *buffer_;
uint64 buffer_length_;
- const char* after_header_;
+ const uint8_t *after_header_;
// The associated ByteReader that handles endianness issues for us
ByteReader* reader_;
@@ -318,97 +509,143 @@ class CompilationUnit {
// String section buffer and length, if we have a string section.
// This is here to avoid doing a section lookup for strings in
// ProcessAttribute, which is in the hot path for DWARF2 reading.
- const char* string_buffer_;
+ const uint8_t *string_buffer_;
uint64 string_buffer_length_;
-};
-// This class is the main interface between the reader and the
-// client. The virtual functions inside this get called for
-// interesting events that happen during DWARF2 reading.
-// The default implementation skips everything.
+ // String offsets section buffer and length, if we have a string offsets
+ // section (.debug_str_offsets or .debug_str_offsets.dwo).
+ const uint8_t* str_offsets_buffer_;
+ uint64 str_offsets_buffer_length_;
-class Dwarf2Handler {
+ // Address section buffer and length, if we have an address section
+ // (.debug_addr).
+ const uint8_t* addr_buffer_;
+ uint64 addr_buffer_length_;
+
+ // Flag indicating whether this compilation unit is part of a .dwo
+ // or .dwp file. If true, we are reading this unit because a
+ // skeleton compilation unit in an executable file had a
+ // DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute.
+ // In a .dwo file, we expect the string offsets section to
+ // have a ".dwo" suffix, and we will use the ".debug_addr" section
+ // associated with the skeleton compilation unit.
+ bool is_split_dwarf_;
+
+ // The value of the DW_AT_GNU_dwo_id attribute, if any.
+ uint64 dwo_id_;
+
+ // The value of the DW_AT_GNU_dwo_name attribute, if any.
+ const char* dwo_name_;
+
+ // If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute
+ // from the skeleton CU.
+ uint64 skeleton_dwo_id_;
+
+ // The value of the DW_AT_GNU_ranges_base attribute, if any.
+ uint64 ranges_base_;
+
+ // The value of the DW_AT_GNU_addr_base attribute, if any.
+ uint64 addr_base_;
+
+ // True if we have already looked for a .dwp file.
+ bool have_checked_for_dwp_;
+
+ // Path to the .dwp file.
+ string dwp_path_;
+
+ // ByteReader for the DWP file.
+ std::unique_ptr<ByteReader> dwp_byte_reader_;
+
+ // DWP reader.
+ std::unique_ptr<DwpReader> dwp_reader_;
+};
+
+// A Reader for a .dwp file. Supports the fetching of DWARF debug
+// info for a given dwo_id.
+//
+// There are two versions of .dwp files. In both versions, the
+// .dwp file is an ELF file containing only debug sections.
+// In Version 1, the file contains many copies of each debug
+// section, one for each .dwo file that is packaged in the .dwp
+// file, and the .debug_cu_index section maps from the dwo_id
+// to a set of section indexes. In Version 2, the file contains
+// one of each debug section, and the .debug_cu_index section
+// maps from the dwo_id to a set of offsets and lengths that
+// identify each .dwo file's contribution to the larger sections.
+
+class DwpReader {
public:
- Dwarf2Handler() { }
+ DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader);
- virtual ~Dwarf2Handler() { }
+ ~DwpReader();
- // Start to process a compilation unit at OFFSET from the beginning of the
- // .debug_info section. Return false if you would like to skip this
- // compilation unit.
- virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
- uint8 offset_size, uint64 cu_length,
- uint8 dwarf_version) { return false; }
+ // Read the CU index and initialize data members.
+ void Initialize();
- // Start to process a DIE at OFFSET from the beginning of the .debug_info
- // section. Return false if you would like to skip this DIE.
- virtual bool StartDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs) { return false; }
+ // Read the debug sections for the given dwo_id.
+ void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections);
- // Called when we have an attribute with unsigned data to give to our
- // handler. The attribute is for the DIE at OFFSET from the beginning of the
- // .debug_info section. Its name is ATTR, its form is FORM, and its value is
- // DATA.
- virtual void ProcessAttributeUnsigned(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 data) { }
+ private:
+ // Search a v1 hash table for "dwo_id". Returns the slot index
+ // where the dwo_id was found, or -1 if it was not found.
+ int LookupCU(uint64 dwo_id);
- // Called when we have an attribute with signed data to give to our handler.
- // The attribute is for the DIE at OFFSET from the beginning of the
- // .debug_info section. Its name is ATTR, its form is FORM, and its value is
- // DATA.
- virtual void ProcessAttributeSigned(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- int64 data) { }
+ // Search a v2 hash table for "dwo_id". Returns the row index
+ // in the offsets and sizes tables, or 0 if it was not found.
+ uint32 LookupCUv2(uint64 dwo_id);
- // Called when we have an attribute whose value is a reference to
- // another DIE. The attribute belongs to the DIE at OFFSET from the
- // beginning of the .debug_info section. Its name is ATTR, its form
- // is FORM, and the offset of the DIE being referred to from the
- // beginning of the .debug_info section is DATA.
- virtual void ProcessAttributeReference(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 data) { }
+ // The ELF reader for the .dwp file.
+ ElfReader* elf_reader_;
- // Called when we have an attribute with a buffer of data to give to our
- // handler. The attribute is for the DIE at OFFSET from the beginning of the
- // .debug_info section. Its name is ATTR, its form is FORM, DATA points to
- // the buffer's contents, and its length in bytes is LENGTH. The buffer is
- // owned by the caller, not the callee, and may not persist for very long.
- // If you want the data to be available later, it needs to be copied.
- virtual void ProcessAttributeBuffer(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- const char* data,
- uint64 len) { }
+ // The ByteReader for the .dwp file.
+ const ByteReader& byte_reader_;
- // Called when we have an attribute with string data to give to our handler.
- // The attribute is for the DIE at OFFSET from the beginning of the
- // .debug_info section. Its name is ATTR, its form is FORM, and its value is
- // DATA.
- virtual void ProcessAttributeString(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- const string& data) { }
+ // Pointer to the .debug_cu_index section.
+ const char* cu_index_;
- // Called when we have an attribute whose value is the 64-bit signature
- // of a type unit in the .debug_types section. OFFSET is the offset of
- // the DIE whose attribute we're reporting. ATTR and FORM are the
- // attribute's name and form. SIGNATURE is the type unit's signature.
- virtual void ProcessAttributeSignature(uint64 offset,
- enum DwarfAttribute attr,
- enum DwarfForm form,
- uint64 signature) { }
+ // Size of the .debug_cu_index section.
+ size_t cu_index_size_;
- // Called when finished processing the DIE at OFFSET.
- // Because DWARF2/3 specifies a tree of DIEs, you may get starts
- // before ends of the previous DIE, as we process children before
- // ending the parent.
- virtual void EndDIE(uint64 offset) { }
+ // Pointer to the .debug_str.dwo section.
+ const char* string_buffer_;
+ // Size of the .debug_str.dwo section.
+ size_t string_buffer_size_;
+
+ // Version of the .dwp file. We support versions 1 and 2 currently.
+ int version_;
+
+ // Number of columns in the section tables (version 2).
+ unsigned int ncolumns_;
+
+ // Number of units in the section tables (version 2).
+ unsigned int nunits_;
+
+ // Number of slots in the hash table.
+ unsigned int nslots_;
+
+ // Pointer to the beginning of the hash table.
+ const char* phash_;
+
+ // Pointer to the beginning of the index table.
+ const char* pindex_;
+
+ // Pointer to the beginning of the section index pool (version 1).
+ const char* shndx_pool_;
+
+ // Pointer to the beginning of the section offset table (version 2).
+ const char* offset_table_;
+
+ // Pointer to the beginning of the section size table (version 2).
+ const char* size_table_;
+
+ // Contents of the sections of interest (version 2).
+ const char* abbrev_data_;
+ size_t abbrev_size_;
+ const char* info_data_;
+ size_t info_size_;
+ const char* str_offsets_data_;
+ size_t str_offsets_size_;
};
// This class is a reader for DWARF's Call Frame Information. CFI
@@ -638,7 +875,7 @@ class CallFrameInfo {
// The mechanics of C++ exception handling, personality routines,
// and language-specific data areas are described here, rather nicely:
// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
- CallFrameInfo(const char *buffer, size_t buffer_length,
+ CallFrameInfo(const uint8_t *buffer, size_t buffer_length,
ByteReader *reader, Handler *handler, Reporter *reporter,
bool eh_frame = false)
: buffer_(buffer), buffer_length_(buffer_length),
@@ -666,7 +903,7 @@ class CallFrameInfo {
size_t offset;
// The start of this entry in the buffer.
- const char *start;
+ const uint8_t *start;
// Which kind of entry this is.
//
@@ -677,16 +914,16 @@ class CallFrameInfo {
// The end of this entry's common prologue (initial length and id), and
// the start of this entry's kind-specific fields.
- const char *fields;
+ const uint8_t *fields;
// The start of this entry's instructions.
- const char *instructions;
+ const uint8_t *instructions;
// The address past the entry's last byte in the buffer. (Note that
// since offset points to the entry's initial length field, and the
// length field is the number of bytes after that field, this is not
// simply buffer_ + offset + length.)
- const char *end;
+ const uint8_t *end;
// For both DWARF CFI and .eh_frame sections, this is the CIE id in a
// CIE, and the offset of the associated CIE in an FDE.
@@ -763,7 +1000,7 @@ class CallFrameInfo {
// true. On failure, report the problem, and return false. Even if we
// return false, set ENTRY->end to the first byte after the entry if we
// were able to figure that out, or NULL if we weren't.
- bool ReadEntryPrologue(const char *cursor, Entry *entry);
+ bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry);
// Parse the fields of a CIE after the entry prologue, including any 'z'
// augmentation data. Assume that the 'Entry' fields of CIE are
@@ -791,7 +1028,7 @@ class CallFrameInfo {
}
// The contents of the DWARF .debug_info section we're parsing.
- const char *buffer_;
+ const uint8_t *buffer_;
size_t buffer_length_;
// For reading multi-byte values with the appropriate endianness.
@@ -990,6 +1227,14 @@ class CallFrameInfo::Reporter {
// there is not a CIE.
virtual void BadCIEId(uint64 offset, uint64 cie_offset);
+ // The FDE at OFFSET refers to a CIE with an address size we don't know how
+ // to handle.
+ virtual void UnexpectedAddressSize(uint64 offset, uint8_t address_size);
+
+ // The FDE at OFFSET refers to a CIE with an segment descriptor size we
+ // don't know how to handle.
+ virtual void UnexpectedSegmentSize(uint64 offset, uint8_t segment_size);
+
// The FDE at OFFSET refers to a CIE with version number VERSION,
// which we don't recognize. We cannot parse DWARF CFI if it uses
// a version number we don't recognize.
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
new file mode 100644
index 0000000..38cc7ea
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
@@ -0,0 +1,2555 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+// The '.eh_frame' format, used by the Linux C++ ABI for exception
+// handling, is poorly specified. To help test our support for .eh_frame,
+// if you #define WRITE_ELF while compiling this file, and add the
+// 'include' directory from the binutils, gcc, or gdb source tree to the
+// #include path, then each test that calls the
+// PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write
+// an ELF file containing a .debug_frame or .eh_frame section; you can then
+// use tools like readelf to examine the test data, and check the tools'
+// interpretation against the test's intentions. Each ELF file is named
+// "cfitest-TEST", where TEST identifies the particular test.
+#ifdef WRITE_ELF
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+extern "C" {
+// To compile with WRITE_ELF, you should add the 'include' directory
+// of the binutils, gcc, or gdb source tree to your #include path;
+// that directory contains this header.
+#include "elf/common.h"
+}
+#endif
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf/bytereader-inl.h"
+#include "common/dwarf/cfi_assembler.h"
+#include "common/dwarf/dwarf2reader.h"
+#include "common/using_std_string.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+using google_breakpad::CFISection;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+using google_breakpad::test_assembler::Section;
+
+using dwarf2reader::DwarfPointerEncoding;
+using dwarf2reader::ENDIANNESS_BIG;
+using dwarf2reader::ENDIANNESS_LITTLE;
+using dwarf2reader::ByteReader;
+using dwarf2reader::CallFrameInfo;
+
+using std::vector;
+using testing::InSequence;
+using testing::Return;
+using testing::Sequence;
+using testing::Test;
+using testing::_;
+
+#ifdef WRITE_ELF
+void WriteELFFrameSection(const char *filename, const char *section_name,
+ const CFISection &section);
+#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \
+ WriteELFFrameSection("cfitest-" name, ".debug_frame", section);
+#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \
+ WriteELFFrameSection("cfitest-" name, ".eh_frame", section);
+#else
+#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section)
+#define PERHAPS_WRITE_EH_FRAME_FILE(name, section)
+#endif
+
+class MockCallFrameInfoHandler: public CallFrameInfo::Handler {
+ public:
+ MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length,
+ uint8 version, const string &augmentation,
+ unsigned return_address));
+ MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg));
+ MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg));
+ MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register,
+ long offset));
+ MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register,
+ long offset));
+ MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register));
+ MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg,
+ const string &expression));
+ MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg,
+ const string &expression));
+ MOCK_METHOD0(End, bool());
+ MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect));
+ MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect));
+ MOCK_METHOD0(SignalHandler, bool());
+};
+
+class MockCallFrameErrorReporter: public CallFrameInfo::Reporter {
+ public:
+ MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { }
+ MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind));
+ MOCK_METHOD1(EarlyEHTerminator, void(uint64));
+ MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64));
+ MOCK_METHOD2(BadCIEId, void(uint64, uint64));
+ MOCK_METHOD2(UnexpectedAddressSize, void(uint64, uint8_t));
+ MOCK_METHOD2(UnexpectedSegmentSize, void(uint64, uint8_t));
+ MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version));
+ MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &));
+ MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8));
+ MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8));
+ MOCK_METHOD2(RestoreInCIE, void(uint64, uint64));
+ MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64));
+ MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64));
+ MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64));
+};
+
+struct CFIFixture {
+
+ enum { kCFARegister = CallFrameInfo::Handler::kCFARegister };
+
+ CFIFixture() {
+ // Default expectations for the data handler.
+ //
+ // - Leave Entry and End without expectations, as it's probably a
+ // good idea to set those explicitly in each test.
+ //
+ // - Expect the *Rule functions to not be called,
+ // so that each test can simply list the calls they expect.
+ //
+ // I gather I could use StrictMock for this, but the manual seems
+ // to suggest using that only as a last resort, and this isn't so
+ // bad.
+ EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0);
+ EXPECT_CALL(handler, SameValueRule(_, _)).Times(0);
+ EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0);
+ EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0);
+ EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0);
+ EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0);
+ EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0);
+ EXPECT_CALL(handler, SignalHandler()).Times(0);
+
+ // Default expectations for the error/warning reporer.
+ EXPECT_CALL(reporter, Incomplete(_, _)).Times(0);
+ EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0);
+ EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0);
+ EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0);
+ EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0);
+ EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0);
+ EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0);
+ EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0);
+ EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0);
+ EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0);
+ EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0);
+ EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0);
+ }
+
+ MockCallFrameInfoHandler handler;
+ MockCallFrameErrorReporter reporter;
+};
+
+class CFI: public CFIFixture, public Test { };
+
+TEST_F(CFI, EmptyRegion) {
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+ static const uint8_t data[] = { 42 };
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+TEST_F(CFI, IncompleteLength32) {
+ CFISection section(kBigEndian, 8);
+ section
+ // Not even long enough for an initial length.
+ .D16(0xa0f)
+ // Padding to keep valgrind happy. We subtract these off when we
+ // construct the parser.
+ .D16(0);
+
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+
+ EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
+ .WillOnce(Return());
+
+ string contents;
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size() - 2,
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+TEST_F(CFI, IncompleteLength64) {
+ CFISection section(kLittleEndian, 4);
+ section
+ // An incomplete 64-bit DWARF initial length.
+ .D32(0xffffffff).D32(0x71fbaec2)
+ // Padding to keep valgrind happy. We subtract these off when we
+ // construct the parser.
+ .D32(0);
+
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+
+ EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
+ .WillOnce(Return());
+
+ string contents;
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size() - 4,
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+TEST_F(CFI, IncompleteId32) {
+ CFISection section(kBigEndian, 8);
+ section
+ .D32(3) // Initial length, not long enough for id
+ .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id
+ .CIEHeader(8727, 3983, 8889, 3, "")
+ .FinishEntry();
+
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+
+ EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown))
+ .WillOnce(Return());
+
+ string contents;
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+TEST_F(CFI, BadId32) {
+ CFISection section(kBigEndian, 8);
+ section
+ .D32(0x100) // Initial length
+ .D32(0xe802fade) // bogus ID
+ .Append(0x100 - 4, 0x42); // make the length true
+ section
+ .CIEHeader(1672, 9872, 8529, 3, "")
+ .FinishEntry();
+
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+
+ EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade))
+ .WillOnce(Return());
+
+ string contents;
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+// A lone CIE shouldn't cause any handler calls.
+TEST_F(CFI, SingleCIE) {
+ CFISection section(kLittleEndian, 4);
+ section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, "");
+ section.Append(10, dwarf2reader::DW_CFA_nop);
+ section.FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section);
+
+ EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, End()).Times(0);
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+// One FDE, one CIE.
+TEST_F(CFI, OneFDE) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "")
+ .FinishEntry()
+ .FDEHeader(cie, 0x7714740d, 0x3d5a10cd)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+// Two FDEs share a CIE.
+TEST_F(CFI, TwoFDEsOneCIE) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ // First FDE. readelf complains about this one because it makes
+ // a forward reference to its CIE.
+ .FDEHeader(cie, 0xa42744df, 0xa3b42121)
+ .FinishEntry()
+ // CIE.
+ .Mark(&cie)
+ .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "")
+ .FinishEntry()
+ // Second FDE.
+ .FDEHeader(cie, 0x6057d391, 0x700f608d)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+// Two FDEs, two CIEs.
+TEST_F(CFI, TwoFDEsTwoCIEs) {
+ CFISection section(kLittleEndian, 8);
+ Label cie1, cie2;
+ section
+ // First CIE.
+ .Mark(&cie1)
+ .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "")
+ .FinishEntry()
+ // First FDE which cites second CIE. readelf complains about
+ // this one because it makes a forward reference to its CIE.
+ .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL)
+ .FinishEntry()
+ // Second FDE, which cites first CIE.
+ .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL)
+ .FinishEntry()
+ // Second CIE.
+ .Mark(&cie2)
+ .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "")
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2,
+ "", 0x61d2c581))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3,
+ "", 0xbf45e65a))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_LITTLE);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+// An FDE whose CIE specifies a version we don't recognize.
+TEST_F(CFI, BadVersion) {
+ CFISection section(kBigEndian, 4);
+ Label cie1, cie2;
+ section
+ .Mark(&cie1)
+ .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "")
+ .FinishEntry()
+ // We should skip this entry, as its CIE specifies a version we
+ // don't recognize.
+ .FDEHeader(cie1, 0x08852292, 0x2204004a)
+ .FinishEntry()
+ // Despite the above, we should visit this entry.
+ .Mark(&cie2)
+ .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "")
+ .FinishEntry()
+ .FDEHeader(cie2, 0x2094735a, 0x6e875501)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section);
+
+ EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52))
+ .WillOnce(Return());
+
+ {
+ InSequence s;
+ // We should see no mention of the first FDE, but we should get
+ // a call to Entry for the second.
+ EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "",
+ 0x96cb3264))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+// An FDE whose CIE specifies an augmentation we don't recognize.
+TEST_F(CFI, BadAugmentation) {
+ CFISection section(kBigEndian, 4);
+ Label cie1, cie2;
+ section
+ .Mark(&cie1)
+ .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!")
+ .FinishEntry()
+ // We should skip this entry, as its CIE specifies an
+ // augmentation we don't recognize.
+ .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd)
+ .FinishEntry()
+ // Despite the above, we should visit this entry.
+ .Mark(&cie2)
+ .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "")
+ .FinishEntry()
+ .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section);
+
+ EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!"))
+ .WillOnce(Return());
+
+ {
+ InSequence s;
+ // We should see no mention of the first FDE, but we should get
+ // a call to Entry for the second.
+ EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "",
+ 0xf2f519b2))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+// The return address column field is a byte in CFI version 1
+// (DWARF2), but a ULEB128 value in version 3 (DWARF3).
+TEST_F(CFI, CIEVersion1ReturnColumn) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ // CIE, using the version 1 format: return column is a ubyte.
+ .Mark(&cie)
+ // Use a value for the return column that is parsed differently
+ // as a ubyte and as a ULEB128.
+ .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "")
+ .FinishEntry()
+ // FDE, citing that CIE.
+ .FDEHeader(cie, 0xb8d347b5, 0x825e55dc)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+// The return address column field is a byte in CFI version 1
+// (DWARF2), but a ULEB128 value in version 3 (DWARF3).
+TEST_F(CFI, CIEVersion3ReturnColumn) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ // CIE, using the version 3 format: return column is a ULEB128.
+ .Mark(&cie)
+ // Use a value for the return column that is parsed differently
+ // as a ubyte and as a ULEB128.
+ .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "")
+ .FinishEntry()
+ // FDE, citing that CIE.
+ .FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+TEST_F(CFI, CIEVersion4AdditionalFields) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ .Mark(&cie)
+ // CIE version 4 with expected address and segment size.
+ .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 8, 0)
+ .FinishEntry()
+ // FDE, citing that CIE.
+ .FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section);
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(4);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_TRUE(parser.Start());
+}
+
+TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+
+ section
+ .Mark(&cie)
+ // Unexpected address size.
+ .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 4, "", true, 3, 0)
+ .FinishEntry()
+ // FDE, citing that CIE.
+ .FDEHeader(cie, 0x86763f2b, 0x2a66dc23)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedAddress", section);
+
+ EXPECT_CALL(reporter, UnexpectedAddressSize(_, 3))
+ .WillOnce(Return());
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+
+ section
+ .Mark(&cie)
+ .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 4, "", true, 8, 7)
+ .FinishEntry()
+ .FDEHeader(cie, 0x7bf0fda0, 0xcbcd28d8)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedSegment", section);
+
+ EXPECT_CALL(reporter, UnexpectedSegmentSize(_, 7))
+ .WillOnce(Return());
+
+ string contents;
+ EXPECT_TRUE(section.GetContents(&contents));
+ ByteReader byte_reader(ENDIANNESS_BIG);
+ byte_reader.SetAddressSize(8);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ EXPECT_FALSE(parser.Start());
+}
+
+struct CFIInsnFixture: public CFIFixture {
+ CFIInsnFixture() : CFIFixture() {
+ data_factor = 0xb6f;
+ return_register = 0x9be1ed9f;
+ version = 3;
+ cfa_base_register = 0x383a3aa;
+ cfa_offset = 0xf748;
+ }
+
+ // Prepare SECTION to receive FDE instructions.
+ //
+ // - Append a stock CIE header that establishes the fixture's
+ // code_factor, data_factor, return_register, version, and
+ // augmentation values.
+ // - Have the CIE set up a CFA rule using cfa_base_register and
+ // cfa_offset.
+ // - Append a stock FDE header, referring to the above CIE, for the
+ // fde_size bytes at fde_start. Choose fde_start and fde_size
+ // appropriately for the section's address size.
+ // - Set appropriate expectations on handler in sequence s for the
+ // frame description entry and the CIE's CFA rule.
+ //
+ // On return, SECTION is ready to have FDE instructions appended to
+ // it, and its FinishEntry member called.
+ void StockCIEAndFDE(CFISection *section) {
+ // Choose appropriate constants for our address size.
+ if (section->AddressSize() == 4) {
+ fde_start = 0xc628ecfbU;
+ fde_size = 0x5dee04a2;
+ code_factor = 0x60b;
+ } else {
+ assert(section->AddressSize() == 8);
+ fde_start = 0x0005c57ce7806bd3ULL;
+ fde_size = 0x2699521b5e333100ULL;
+ code_factor = 0x01008e32855274a8ULL;
+ }
+
+ // Create the CIE.
+ (*section)
+ .Mark(&cie_label)
+ .CIEHeader(code_factor, data_factor, return_register, version,
+ "")
+ .D8(dwarf2reader::DW_CFA_def_cfa)
+ .ULEB128(cfa_base_register)
+ .ULEB128(cfa_offset)
+ .FinishEntry();
+
+ // Create the FDE.
+ section->FDEHeader(cie_label, fde_start, fde_size);
+
+ // Expect an Entry call for the FDE and a ValOffsetRule call for the
+ // CIE's CFA rule.
+ EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "",
+ return_register))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister,
+ cfa_base_register, cfa_offset))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ }
+
+ // Run the contents of SECTION through a CallFrameInfo parser,
+ // expecting parser.Start to return SUCCEEDS
+ void ParseSection(CFISection *section, bool succeeds = true) {
+ string contents;
+ EXPECT_TRUE(section->GetContents(&contents));
+ dwarf2reader::Endianness endianness;
+ if (section->endianness() == kBigEndian)
+ endianness = ENDIANNESS_BIG;
+ else {
+ assert(section->endianness() == kLittleEndian);
+ endianness = ENDIANNESS_LITTLE;
+ }
+ ByteReader byte_reader(endianness);
+ byte_reader.SetAddressSize(section->AddressSize());
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter);
+ if (succeeds)
+ EXPECT_TRUE(parser.Start());
+ else
+ EXPECT_FALSE(parser.Start());
+ }
+
+ Label cie_label;
+ Sequence s;
+ uint64 code_factor;
+ int data_factor;
+ unsigned return_register;
+ unsigned version;
+ unsigned cfa_base_register;
+ int cfa_offset;
+ uint64 fde_start, fde_size;
+};
+
+class CFIInsn: public CFIInsnFixture, public Test { };
+
+TEST_F(CFIInsn, DW_CFA_set_loc) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a)
+ // Use DW_CFA_def_cfa to force a handler call that we can use to
+ // check the effect of the DW_CFA_set_loc.
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_advance_loc) {
+ CFISection section(kBigEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a)
+ // Use DW_CFA_def_cfa to force a handler call that we can use to
+ // check the effect of the DW_CFA_advance_loc.
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start + 0x2a * code_factor,
+ kCFARegister, 0x5bbb3715, 0x0186c7bf))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_advance_loc1) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8)
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule((fde_start + 0xd8 * code_factor),
+ kCFARegister, 0x69d5696a, 0x1eb7fc93))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_advance_loc2) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb)
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule((fde_start + 0x3adb * code_factor),
+ kCFARegister, 0x3a368bed, 0x3194ee37))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_advance_loc4) {
+ CFISection section(kBigEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88)
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule((fde_start + 0x15813c88ULL * code_factor),
+ kCFARegister, 0x135270c5, 0x24bad7cb))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) {
+ code_factor = 0x2d;
+ CFISection section(kBigEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL)
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor),
+ kCFARegister, 0xe17ed602, 0x3d162e7f))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section);
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa_sf) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea)
+ .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7,
+ 0x9ea * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da,
+ -0x40a2 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa_register) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+// DW_CFA_def_cfa_register should have no effect when applied to a
+// non-base/offset rule.
+TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack")
+ .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValExpressionRule(fde_start, kCFARegister,
+ "needle in a haystack"))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa_offset) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
+ 0x1e8e3b9b))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970)
+ .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
+ 0x970 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, cfa_base_register,
+ -0x2cd * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+// DW_CFA_def_cfa_offset should have no effect when applied to a
+// non-base/offset rule.
+TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday")
+ .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday"))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_def_cfa_expression) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow")
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister,
+ "eating crow"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_undefined) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_same_value) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_offset) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_offset_extended) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_offset_extended_sf) {
+ CFISection section(kBigEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset_extended_sf)
+ .ULEB128(0x997c23ee).LEB128(0x2d00)
+ .D8(dwarf2reader::DW_CFA_offset_extended_sf)
+ .ULEB128(0x9519eb82).LEB128(-0xa77)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x997c23ee,
+ kCFARegister, 0x2d00 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x9519eb82,
+ kCFARegister, -0xa77 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_val_offset) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, 0x623562fe,
+ kCFARegister, 0x673 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_val_offset_sf) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab)
+ .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, 0x6f4f,
+ kCFARegister, 0xaab * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, 0x2483,
+ kCFARegister, -0x8a2 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_register) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_expression) {
+ CFISection section(kBigEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2)
+ .Block("plus ça change, plus c'est la même chose")
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ExpressionRule(fde_start, 0xa1619fb2,
+ "plus ça change, plus c'est la même chose"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_val_expression) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3)
+ .Block("he who has the gold makes the rules")
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValExpressionRule(fde_start, 0xc5e4a9e3,
+ "he who has the gold makes the rules"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_restore) {
+ CFISection section(kLittleEndian, 8);
+ code_factor = 0x01bd188a9b1fa083ULL;
+ data_factor = -0x1ac8;
+ return_register = 0x8c35b049;
+ version = 2;
+ fde_start = 0x2d70fe998298bbb1ULL;
+ fde_size = 0x46ccc2e63cf0b108ULL;
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(code_factor, data_factor, return_register, version,
+ "")
+ // Provide a CFA rule, because register rules require them.
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8)
+ // Provide an offset(N) rule for register 0x3c.
+ .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348)
+ .FinishEntry()
+ // In the FDE...
+ .FDEHeader(cie, fde_start, fde_size)
+ // At a second address, provide a new offset(N) rule for register 0x3c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x13)
+ .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50)
+ // At a third address, restore the original rule for register 0x3c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x01)
+ .D8(dwarf2reader::DW_CFA_restore | 0x3c)
+ .FinishEntry();
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, fde_start, fde_size, version, "", return_register))
+ .WillOnce(Return(true));
+ // CIE's CFA rule.
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8))
+ .WillOnce(Return(true));
+ // CIE's rule for register 0x3c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor))
+ .WillOnce(Return(true));
+ // FDE's rule for register 0x3c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start + 0x13 * code_factor, 0x3c,
+ kCFARegister, 0x9a50 * data_factor))
+ .WillOnce(Return(true));
+ // Restore CIE's rule for register 0x3c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c,
+ kCFARegister, 0xb348 * data_factor))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_restoreNoRule) {
+ CFISection section(kBigEndian, 4);
+ code_factor = 0x005f78143c1c3b82ULL;
+ data_factor = 0x25d0;
+ return_register = 0xe8;
+ version = 1;
+ fde_start = 0x4062e30f;
+ fde_size = 0x5302a389;
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(code_factor, data_factor, return_register, version, "")
+ // Provide a CFA rule, because register rules require them.
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127)
+ .FinishEntry()
+ // In the FDE...
+ .FDEHeader(cie, fde_start, fde_size)
+ // At a second address, provide an offset(N) rule for register 0x2c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x7)
+ .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47)
+ // At a third address, restore the (missing) CIE rule for register 0x2c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0xb)
+ .D8(dwarf2reader::DW_CFA_restore | 0x2c)
+ .FinishEntry();
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, fde_start, fde_size, version, "", return_register))
+ .WillOnce(Return(true));
+ // CIE's CFA rule.
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127))
+ .WillOnce(Return(true));
+ // FDE's rule for register 0x2c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start + 0x7 * code_factor, 0x2c,
+ kCFARegister, 0x1f47 * data_factor))
+ .WillOnce(Return(true));
+ // Restore CIE's (missing) rule for register 0x2c.
+ EXPECT_CALL(handler,
+ SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_restore_extended) {
+ CFISection section(kBigEndian, 4);
+ code_factor = 0x126e;
+ data_factor = -0xd8b;
+ return_register = 0x77711787;
+ version = 3;
+ fde_start = 0x01f55a45;
+ fde_size = 0x452adb80;
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(code_factor, data_factor, return_register, version,
+ "", true /* dwarf64 */ )
+ // Provide a CFA rule, because register rules require them.
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5)
+ // Provide an offset(N) rule for register 0x0f9b8a1c.
+ .D8(dwarf2reader::DW_CFA_offset_extended)
+ .ULEB128(0x0f9b8a1c).ULEB128(0xc979)
+ .FinishEntry()
+ // In the FDE...
+ .FDEHeader(cie, fde_start, fde_size)
+ // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x3)
+ .D8(dwarf2reader::DW_CFA_offset_extended)
+ .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b)
+ // At a third address, restore the original rule for register 0x0f9b8a1c.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 0x04)
+ .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c)
+ .FinishEntry();
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ Entry(_, fde_start, fde_size, version, "", return_register))
+ .WillOnce(Return(true));
+ // CIE's CFA rule.
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5))
+ .WillOnce(Return(true));
+ // CIE's rule for register 0x0f9b8a1c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister,
+ 0xc979 * data_factor))
+ .WillOnce(Return(true));
+ // FDE's rule for register 0x0f9b8a1c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c,
+ kCFARegister, 0x3b7b * data_factor))
+ .WillOnce(Return(true));
+ // Restore CIE's rule for register 0x0f9b8a1c.
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c,
+ kCFARegister, 0xc979 * data_factor))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+ }
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+
+ // We create a state, save it, modify it, and then restore. We
+ // refer to the state that is overridden the restore as the
+ // "outgoing" state, and the restored state the "incoming" state.
+ //
+ // Register outgoing incoming expect
+ // 1 offset(N) no rule new "same value" rule
+ // 2 register(R) offset(N) report changed rule
+ // 3 offset(N) offset(M) report changed offset
+ // 4 offset(N) offset(N) no report
+ // 5 offset(N) no rule new "same value" rule
+ section
+ // Create the "incoming" state, which we will save and later restore.
+ .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806)
+ .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d)
+ .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ // Advance to a new instruction; an implementation could legitimately
+ // ignore all but the final rule for a given register at a given address.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ // Create the "outgoing" state, which we will discard.
+ .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767)
+ .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29)
+ .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce)
+ // At a third address, restore the incoming state.
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ uint64 addr = fde_start;
+
+ // Expect the incoming rules to be reported.
+ EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+
+ addr += code_factor;
+
+ // After the save, we establish the outgoing rule set.
+ EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+
+ addr += code_factor;
+
+ // Finally, after the restore, expect to see the differences from
+ // the outgoing to the incoming rules reported.
+ EXPECT_CALL(handler, SameValueRule(addr, 1))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, SameValueRule(addr, 5))
+ .InSequence(s).WillOnce(Return(true));
+
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+// Check that restoring a rule set reports changes to the CFA rule.
+TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+
+ section
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister,
+ cfa_base_register, 0x90481102))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister,
+ cfa_base_register, cfa_offset))
+ .InSequence(s).WillOnce(Return(true));
+
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_nop) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_nop)
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b)
+ .D8(dwarf2reader::DW_CFA_nop)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_GNU_window_save) {
+ CFISection section(kBigEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_GNU_window_save)
+ .FinishEntry();
+
+ // Don't include all the rules in any particular sequence.
+
+ // The caller's %o0-%o7 have become the callee's %i0-%i7. This is
+ // the GCC register numbering.
+ for (int i = 8; i < 16; i++)
+ EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16))
+ .WillOnce(Return(true));
+ // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of
+ // its frame.
+ for (int i = 16; i < 32; i++)
+ EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_GNU_args_size) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520)
+ // Verify that we see this, meaning we parsed the above properly.
+ .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended)
+ .ULEB128(0x430cc87a).ULEB128(0x613)
+ .FinishEntry();
+
+ EXPECT_CALL(handler,
+ OffsetRule(fde_start, 0x430cc87a,
+ kCFARegister, -0x613 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+// Three FDEs: skip the second
+TEST_F(CFIInsn, SkipFDE) {
+ CFISection section(kBigEndian, 4);
+ Label cie;
+ section
+ // CIE, used by all FDEs.
+ .Mark(&cie)
+ .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "")
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad)
+ .FinishEntry()
+ // First FDE.
+ .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf)
+ .FinishEntry()
+ // Second FDE.
+ .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18)
+ .FinishEntry()
+ // Third FDE.
+ .FDEHeader(cie, 0xf681cfc8, 0x7e4594e)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4)
+ .FinishEntry();
+
+ {
+ InSequence s;
+
+ // Process the first FDE.
+ EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister,
+ 0x42ed390b, 0x98f43aad))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .WillOnce(Return(true));
+
+ // Skip the second FDE.
+ EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849))
+ .WillOnce(Return(false));
+
+ // Process the third FDE.
+ EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister,
+ 0x42ed390b, 0x98f43aad))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .WillOnce(Return(true));
+ }
+
+ ParseSection(&section);
+}
+
+// Quit processing in the middle of an entry's instructions.
+TEST_F(CFIInsn, QuitMidentry) {
+ CFISection section(kLittleEndian, 8);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431)
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat")
+ .FinishEntry();
+
+ EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431))
+ .InSequence(s).WillOnce(Return(false));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseSection(&section, false);
+}
+
+class CFIRestore: public CFIInsnFixture, public Test { };
+
+TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreUndefinedRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreSameValueRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, OffsetRule(fde_start, 0x14,
+ kCFARegister, 0xb6f * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreOffsetRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
+ kCFARegister, 0xeb7 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
+ kCFARegister, 0xeb7 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, OffsetRule(fde_start, 0x21,
+ kCFARegister, 0x134 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21,
+ kCFARegister, 0xf4f * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21,
+ kCFARegister, 0x134 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6,
+ kCFARegister, 0xe4c * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValOffsetRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6,
+ kCFARegister, 0xeb7 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6,
+ kCFARegister, 0xeb7 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b,
+ kCFARegister, 0x562 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b,
+ kCFARegister, 0xe88 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b,
+ kCFARegister, 0x562 * data_factor))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreRegisterRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5,
+ 0x095f1559))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a)
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1,
+ 0xbabb4742))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1,
+ 0x16607d6a))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreExpressionRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
+ "elf"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc")
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739,
+ "orc"))
+ .InSequence(s).WillOnce(Return(true));
+ // Expectations are not wishes.
+ EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
+ "smurf"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152)
+ .Block("hideous")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValExpressionRuleChanged) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46)
+ .Block("revolting")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section);
+
+ EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46,
+ "revolting"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) {
+ CFISection section(kLittleEndian, 4);
+ StockCIEAndFDE(&section);
+ section
+ .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
+ .Block("repulsive")
+ .D8(dwarf2reader::DW_CFA_remember_state)
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739)
+ .Block("nauseous")
+ .D8(dwarf2reader::DW_CFA_advance_loc | 1)
+ .D8(dwarf2reader::DW_CFA_restore_state)
+ .FinishEntry();
+
+ PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression",
+ section);
+
+ EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739,
+ "nauseous"))
+ .InSequence(s).WillOnce(Return(true));
+ // Expectations are not wishes.
+ EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739,
+ "repulsive"))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End()).WillOnce(Return(true));
+
+ ParseSection(&section);
+}
+
+struct EHFrameFixture: public CFIInsnFixture {
+ EHFrameFixture()
+ : CFIInsnFixture(), section(kBigEndian, 4, true) {
+ encoded_pointer_bases.cfi = 0x7f496cb2;
+ encoded_pointer_bases.text = 0x540f67b6;
+ encoded_pointer_bases.data = 0xe3eab768;
+ section.SetEncodedPointerBases(encoded_pointer_bases);
+ }
+ CFISection section;
+ CFISection::EncodedPointerBases encoded_pointer_bases;
+
+ // Parse CFIInsnFixture::ParseSection, but parse the section as
+ // .eh_frame data, supplying stock base addresses.
+ void ParseEHFrameSection(CFISection *section, bool succeeds = true) {
+ EXPECT_TRUE(section->ContainsEHFrame());
+ string contents;
+ EXPECT_TRUE(section->GetContents(&contents));
+ dwarf2reader::Endianness endianness;
+ if (section->endianness() == kBigEndian)
+ endianness = ENDIANNESS_BIG;
+ else {
+ assert(section->endianness() == kLittleEndian);
+ endianness = ENDIANNESS_LITTLE;
+ }
+ ByteReader byte_reader(endianness);
+ byte_reader.SetAddressSize(section->AddressSize());
+ byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi,
+ reinterpret_cast<const uint8_t *>(contents.data()));
+ byte_reader.SetTextBase(encoded_pointer_bases.text);
+ byte_reader.SetDataBase(encoded_pointer_bases.data);
+ CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()),
+ contents.size(),
+ &byte_reader, &handler, &reporter, true);
+ if (succeeds)
+ EXPECT_TRUE(parser.Start());
+ else
+ EXPECT_FALSE(parser.Start());
+ }
+
+};
+
+class EHFrame: public EHFrameFixture, public Test { };
+
+// A simple CIE, an FDE, and a terminator.
+TEST_F(EHFrame, Terminator) {
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(9968, 2466, 67, 1, "")
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372)
+ .FinishEntry()
+ .FDEHeader(cie, 0x848037a1, 0x7b30475e)
+ .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721)
+ .FinishEntry()
+ .D32(0) // Terminate the sequence.
+ // This FDE should be ignored.
+ .FDEHeader(cie, 0xf19629fe, 0x439fb09b)
+ .FinishEntry();
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section);
+
+ EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(reporter, EarlyEHTerminator(_))
+ .InSequence(s).WillOnce(Return());
+
+ ParseEHFrameSection(&section);
+}
+
+// The parser should recognize the Linux Standards Base 'z' augmentations.
+TEST_F(EHFrame, SimpleFDE) {
+ DwarfPointerEncoding lsda_encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect
+ | dwarf2reader::DW_EH_PE_datarel
+ | dwarf2reader::DW_EH_PE_sdata2);
+ DwarfPointerEncoding fde_encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
+ | dwarf2reader::DW_EH_PE_udata2);
+
+ section.SetPointerEncoding(fde_encoding);
+ section.SetEncodedPointerBases(encoded_pointer_bases);
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(4873, 7012, 100, 1, "zSLPR")
+ .ULEB128(7) // Augmentation data length
+ .D8(lsda_encoding) // LSDA pointer format
+ .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format
+ .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value
+ .D8(fde_encoding) // FDE pointer format
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31)
+ .FinishEntry()
+ .FDEHeader(cie, 0x540f6b56, 0xf686)
+ .ULEB128(2) // Augmentation data length
+ .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed
+ .D8(dwarf2reader::DW_CFA_set_loc)
+ .EncodedPointer(0x540fa4ce, fde_encoding)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e)
+ .FinishEntry()
+ .D32(0); // terminator
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section);
+
+ EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, SignalHandler())
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+// Check that we can handle an empty 'z' augmentation.
+TEST_F(EHFrame, EmptyZ) {
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(5955, 5805, 228, 1, "z")
+ .ULEB128(0) // Augmentation data length
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247)
+ .FinishEntry()
+ .FDEHeader(cie, 0xda007738, 0xfb55c641)
+ .ULEB128(0) // Augmentation data length
+ .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11)
+ .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769)
+ .FinishEntry();
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section);
+
+ EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+// Check that we recognize bad 'z' augmentation characters.
+TEST_F(EHFrame, BadZ) {
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(6937, 1045, 142, 1, "zQ")
+ .ULEB128(0) // Augmentation data length
+ .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725)
+ .FinishEntry()
+ .FDEHeader(cie, 0x1293efa8, 0x236f53f2)
+ .ULEB128(0) // Augmentation data length
+ .D8(dwarf2reader::DW_CFA_advance_loc | 12)
+ .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462)
+ .FinishEntry();
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section);
+
+ EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ"))
+ .WillOnce(Return());
+
+ ParseEHFrameSection(&section, false);
+}
+
+TEST_F(EHFrame, zL) {
+ Label cie;
+ DwarfPointerEncoding lsda_encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel
+ | dwarf2reader::DW_EH_PE_udata2);
+ section
+ .Mark(&cie)
+ .CIEHeader(9285, 9959, 54, 1, "zL")
+ .ULEB128(1) // Augmentation data length
+ .D8(lsda_encoding) // encoding for LSDA pointer in FDE
+
+ .FinishEntry()
+ .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
+ .ULEB128(2) // Augmentation data length
+ .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer
+ .FinishEntry()
+ .D32(0); // terminator
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section);
+
+ EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+TEST_F(EHFrame, zP) {
+ Label cie;
+ DwarfPointerEncoding personality_encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel
+ | dwarf2reader::DW_EH_PE_udata2);
+ section
+ .Mark(&cie)
+ .CIEHeader(1097, 6313, 17, 1, "zP")
+ .ULEB128(3) // Augmentation data length
+ .D8(personality_encoding) // encoding for personality routine
+ .EncodedPointer(0xe3eaccac, personality_encoding) // value
+ .FinishEntry()
+ .FDEHeader(cie, 0x0c8350c9, 0xbef11087)
+ .ULEB128(0) // Augmentation data length
+ .FinishEntry()
+ .D32(0); // terminator
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section);
+
+ EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+TEST_F(EHFrame, zR) {
+ Label cie;
+ DwarfPointerEncoding pointer_encoding =
+ DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel
+ | dwarf2reader::DW_EH_PE_sdata2);
+ section.SetPointerEncoding(pointer_encoding);
+ section
+ .Mark(&cie)
+ .CIEHeader(8011, 5496, 75, 1, "zR")
+ .ULEB128(1) // Augmentation data length
+ .D8(pointer_encoding) // encoding for FDE addresses
+ .FinishEntry()
+ .FDEHeader(cie, 0x540f9431, 0xbd0)
+ .ULEB128(0) // Augmentation data length
+ .FinishEntry()
+ .D32(0); // terminator
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section);
+
+ EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+TEST_F(EHFrame, zS) {
+ Label cie;
+ section
+ .Mark(&cie)
+ .CIEHeader(9217, 7694, 57, 1, "zS")
+ .ULEB128(0) // Augmentation data length
+ .FinishEntry()
+ .FDEHeader(cie, 0xd40091aa, 0x9aa6e746)
+ .ULEB128(0) // Augmentation data length
+ .FinishEntry()
+ .D32(0); // terminator
+
+ PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section);
+
+ EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57))
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, SignalHandler())
+ .InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(handler, End())
+ .InSequence(s).WillOnce(Return(true));
+
+ ParseEHFrameSection(&section);
+}
+
+// These tests require manual inspection of the test output.
+struct CFIReporterFixture {
+ CFIReporterFixture() : reporter("test file name", "test section name") { }
+ CallFrameInfo::Reporter reporter;
+};
+
+class CFIReporter: public CFIReporterFixture, public Test { };
+
+TEST_F(CFIReporter, Incomplete) {
+ reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown);
+}
+
+TEST_F(CFIReporter, EarlyEHTerminator) {
+ reporter.EarlyEHTerminator(0x0102030405060708ULL);
+}
+
+TEST_F(CFIReporter, CIEPointerOutOfRange) {
+ reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, BadCIEId) {
+ reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, UnrecognizedVersion) {
+ reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43);
+}
+
+TEST_F(CFIReporter, UnrecognizedAugmentation) {
+ reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles");
+}
+
+TEST_F(CFIReporter, InvalidPointerEncoding) {
+ reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42);
+}
+
+TEST_F(CFIReporter, UnusablePointerEncoding) {
+ reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42);
+}
+
+TEST_F(CFIReporter, RestoreInCIE) {
+ reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, BadInstruction) {
+ reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE,
+ 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, NoCFARule) {
+ reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE,
+ 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, EmptyStateStack) {
+ reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator,
+ 0xfedcba9876543210ULL);
+}
+
+TEST_F(CFIReporter, ClearingCFARule) {
+ reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE,
+ 0xfedcba9876543210ULL);
+}
+
+#ifdef WRITE_ELF
+// See comments at the top of the file mentioning WRITE_ELF for details.
+
+using google_breakpad::test_assembler::Section;
+
+struct ELFSectionHeader {
+ ELFSectionHeader(unsigned int set_type)
+ : type(set_type), flags(0), address(0), link(0), info(0),
+ alignment(1), entry_size(0) { }
+ Label name;
+ unsigned int type;
+ uint64_t flags;
+ uint64_t address;
+ Label file_offset;
+ Label file_size;
+ unsigned int link;
+ unsigned int info;
+ uint64_t alignment;
+ uint64_t entry_size;
+};
+
+void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
+ (*table)
+ .D32(header.name) // name, index in string tbl
+ .D32(header.type) // type
+ .Address(header.flags) // flags
+ .Address(header.address) // address in memory
+ .Address(header.file_offset) // offset in ELF file
+ .Address(header.file_size) // length in bytes
+ .D32(header.link) // link to related section
+ .D32(header.info) // miscellaneous
+ .Address(header.alignment) // alignment
+ .Address(header.entry_size); // entry size
+}
+
+void WriteELFFrameSection(const char *filename, const char *cfi_name,
+ const CFISection &cfi) {
+ int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64;
+ int elf_data = (cfi.endianness() == kBigEndian
+ ? ELFDATA2MSB : ELFDATA2LSB);
+ CFISection elf(cfi.endianness(), cfi.AddressSize());
+ Label elf_header_size, section_table_offset;
+ elf
+ .Append("\x7f" "ELF")
+ .D8(elf_class) // 32-bit or 64-bit ELF
+ .D8(elf_data) // endianness
+ .D8(1) // ELF version
+ .D8(ELFOSABI_LINUX) // Operating System/ABI indication
+ .D8(0) // ABI version
+ .Append(7, 0xda) // padding
+ .D16(ET_EXEC) // file type: executable file
+ .D16(EM_386) // architecture: Intel IA-32
+ .D32(EV_CURRENT); // ELF version
+ elf
+ .Address(0x0123456789abcdefULL) // program entry point
+ .Address(0) // program header offset
+ .Address(section_table_offset) // section header offset
+ .D32(0) // processor-specific flags
+ .D16(elf_header_size) // ELF header size in bytes */
+ .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size
+ .D16(0) // program header table entry count
+ .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size
+ .D16(3) // section count
+ .D16(1) // section name string table
+ .Mark(&elf_header_size);
+
+ // The null section. Every ELF file has one, as the first entry in
+ // the section header table.
+ ELFSectionHeader null_header(SHT_NULL);
+ null_header.file_offset = 0;
+ null_header.file_size = 0;
+
+ // The CFI section. The whole reason for writing out this ELF file
+ // is to put this in it so that we can run other dumping programs on
+ // it to check its contents.
+ ELFSectionHeader cfi_header(SHT_PROGBITS);
+ cfi_header.file_size = cfi.Size();
+
+ // The section holding the names of the sections. This is the
+ // section whose index appears in the e_shstrndx member of the ELF
+ // header.
+ ELFSectionHeader section_names_header(SHT_STRTAB);
+ CFISection section_names(cfi.endianness(), cfi.AddressSize());
+ section_names
+ .Mark(&null_header.name)
+ .AppendCString("")
+ .Mark(&section_names_header.name)
+ .AppendCString(".shstrtab")
+ .Mark(&cfi_header.name)
+ .AppendCString(cfi_name)
+ .Mark(&section_names_header.file_size);
+
+ // Create the section table. The ELF header's e_shoff member refers
+ // to this, and the e_shnum member gives the number of entries it
+ // contains.
+ CFISection section_table(cfi.endianness(), cfi.AddressSize());
+ AppendSectionHeader(&section_table, null_header);
+ AppendSectionHeader(&section_table, section_names_header);
+ AppendSectionHeader(&section_table, cfi_header);
+
+ // Append the section table and the section contents to the ELF file.
+ elf
+ .Mark(&section_table_offset)
+ .Append(section_table)
+ .Mark(&section_names_header.file_offset)
+ .Append(section_names)
+ .Mark(&cfi_header.file_offset)
+ .Append(cfi);
+
+ string contents;
+ if (!elf.GetContents(&contents)) {
+ fprintf(stderr, "failed to get ELF file contents\n");
+ exit(1);
+ }
+
+ FILE *out = fopen(filename, "w");
+ if (!out) {
+ fprintf(stderr, "error opening ELF file '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) {
+ fprintf(stderr, "error writing ELF data to '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+
+ if (fclose(out) == EOF) {
+ fprintf(stderr, "error closing ELF file '%s': %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+}
+#endif
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
new file mode 100644
index 0000000..71418eb
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
@@ -0,0 +1,487 @@
+// Copyright (c) 2012, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf/bytereader-inl.h"
+#include "common/dwarf/dwarf2reader_test_common.h"
+#include "common/dwarf/dwarf2reader.h"
+#include "common/using_std_string.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+using google_breakpad::test_assembler::Endianness;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+
+using dwarf2reader::ByteReader;
+using dwarf2reader::CompilationUnit;
+using dwarf2reader::Dwarf2Handler;
+using dwarf2reader::DwarfAttribute;
+using dwarf2reader::DwarfForm;
+using dwarf2reader::DwarfHasChild;
+using dwarf2reader::DwarfTag;
+using dwarf2reader::ENDIANNESS_BIG;
+using dwarf2reader::ENDIANNESS_LITTLE;
+using dwarf2reader::SectionMap;
+
+using std::vector;
+using testing::InSequence;
+using testing::Pointee;
+using testing::Return;
+using testing::Sequence;
+using testing::Test;
+using testing::TestWithParam;
+using testing::_;
+
+class MockDwarf2Handler: public Dwarf2Handler {
+ public:
+ MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size,
+ uint8 offset_size, uint64 cu_length,
+ uint8 dwarf_version));
+ MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag));
+ MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset,
+ DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data));
+ MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ int64 data));
+ MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data));
+ MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const uint8_t *data,
+ uint64 len));
+ MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const string& data));
+ MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
+ DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 signature));
+ MOCK_METHOD1(EndDIE, void(uint64 offset));
+};
+
+struct DIEFixture {
+
+ DIEFixture() {
+ // Fix the initial offset of the .debug_info and .debug_abbrev sections.
+ info.start() = 0;
+ abbrevs.start() = 0;
+
+ // Default expectations for the data handler.
+ EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
+ EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
+ EXPECT_CALL(handler, EndDIE(_)).Times(0);
+ }
+
+ // Return a reference to a section map whose .debug_info section refers
+ // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
+ // function returns a reference to the same SectionMap each time; new
+ // calls wipe out maps established by earlier calls.
+ const SectionMap &MakeSectionMap() {
+ // Copy the sections' contents into strings that will live as long as
+ // the map itself.
+ assert(info.GetContents(&info_contents));
+ assert(abbrevs.GetContents(&abbrevs_contents));
+ section_map.clear();
+ section_map[".debug_info"].first
+ = reinterpret_cast<const uint8_t *>(info_contents.data());
+ section_map[".debug_info"].second = info_contents.size();
+ section_map[".debug_abbrev"].first
+ = reinterpret_cast<const uint8_t *>(abbrevs_contents.data());
+ section_map[".debug_abbrev"].second = abbrevs_contents.size();
+ return section_map;
+ }
+
+ TestCompilationUnit info;
+ TestAbbrevTable abbrevs;
+ MockDwarf2Handler handler;
+ string abbrevs_contents, info_contents;
+ SectionMap section_map;
+};
+
+struct DwarfHeaderParams {
+ DwarfHeaderParams(Endianness endianness, size_t format_size,
+ int version, size_t address_size)
+ : endianness(endianness), format_size(format_size),
+ version(version), address_size(address_size) { }
+ Endianness endianness;
+ size_t format_size; // 4-byte or 8-byte DWARF offsets
+ int version;
+ size_t address_size;
+};
+
+class DwarfHeader: public DIEFixture,
+ public TestWithParam<DwarfHeaderParams> { };
+
+TEST_P(DwarfHeader, Header) {
+ Label abbrev_table = abbrevs.Here();
+ abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
+ dwarf2reader::DW_children_yes)
+ .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
+ .EndAbbrev()
+ .EndTable();
+
+ info.set_format_size(GetParam().format_size);
+ info.set_endianness(GetParam().endianness);
+
+ info.Header(GetParam().version, abbrev_table, GetParam().address_size)
+ .ULEB128(1) // DW_TAG_compile_unit, with children
+ .AppendCString("sam") // DW_AT_name, DW_FORM_string
+ .D8(0); // end of children
+ info.Finish();
+
+ {
+ InSequence s;
+ EXPECT_CALL(handler,
+ StartCompilationUnit(0, GetParam().address_size,
+ GetParam().format_size, _,
+ GetParam().version))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_string,
+ "sam"))
+ .WillOnce(Return());
+ EXPECT_CALL(handler, EndDIE(_))
+ .WillOnce(Return());
+ }
+
+ ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
+ ENDIANNESS_LITTLE : ENDIANNESS_BIG);
+ CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
+ EXPECT_EQ(parser.Start(), info_contents.size());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ HeaderVariants, DwarfHeader,
+ ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 2, 8),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 8),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 8),
+ DwarfHeaderParams(kBigEndian, 4, 2, 4),
+ DwarfHeaderParams(kBigEndian, 4, 2, 8),
+ DwarfHeaderParams(kBigEndian, 4, 3, 4),
+ DwarfHeaderParams(kBigEndian, 4, 3, 8),
+ DwarfHeaderParams(kBigEndian, 4, 4, 4),
+ DwarfHeaderParams(kBigEndian, 4, 4, 8),
+ DwarfHeaderParams(kBigEndian, 8, 2, 4),
+ DwarfHeaderParams(kBigEndian, 8, 2, 8),
+ DwarfHeaderParams(kBigEndian, 8, 3, 4),
+ DwarfHeaderParams(kBigEndian, 8, 3, 8),
+ DwarfHeaderParams(kBigEndian, 8, 4, 4),
+ DwarfHeaderParams(kBigEndian, 8, 4, 8)));
+
+struct DwarfFormsFixture: public DIEFixture {
+ // Start a compilation unit, as directed by |params|, containing one
+ // childless DIE of the given tag, with one attribute of the given name
+ // and form. The 'info' fixture member is left just after the abbrev
+ // code, waiting for the attribute value to be appended.
+ void StartSingleAttributeDIE(const DwarfHeaderParams &params,
+ DwarfTag tag, DwarfAttribute name,
+ DwarfForm form) {
+ // Create the abbreviation table.
+ Label abbrev_table = abbrevs.Here();
+ abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
+ .Attribute(name, form)
+ .EndAbbrev()
+ .EndTable();
+
+ // Create the compilation unit, up to the attribute value.
+ info.set_format_size(params.format_size);
+ info.set_endianness(params.endianness);
+ info.Header(params.version, abbrev_table, params.address_size)
+ .ULEB128(1); // abbrev code
+ }
+
+ // Set up handler to expect a compilation unit matching |params|,
+ // containing one childless DIE of the given tag, in the sequence s. Stop
+ // just before the expectations.
+ void ExpectBeginCompilationUnit(const DwarfHeaderParams &params,
+ DwarfTag tag, uint64 offset=0) {
+ EXPECT_CALL(handler,
+ StartCompilationUnit(offset, params.address_size,
+ params.format_size, _,
+ params.version))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(handler, StartDIE(_, tag))
+ .InSequence(s)
+ .WillOnce(Return(true));
+ }
+
+ void ExpectEndCompilationUnit() {
+ EXPECT_CALL(handler, EndDIE(_))
+ .InSequence(s)
+ .WillOnce(Return());
+ }
+
+ void ParseCompilationUnit(const DwarfHeaderParams &params, uint64 offset=0) {
+ ByteReader byte_reader(params.endianness == kLittleEndian ?
+ ENDIANNESS_LITTLE : ENDIANNESS_BIG);
+ CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler);
+ EXPECT_EQ(offset + parser.Start(), info_contents.size());
+ }
+
+ // The sequence to which the fixture's methods append expectations.
+ Sequence s;
+};
+
+struct DwarfForms: public DwarfFormsFixture,
+ public TestWithParam<DwarfHeaderParams> { };
+
+TEST_P(DwarfForms, addr) {
+ StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
+ dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr);
+ uint64_t value;
+ if (GetParam().address_size == 4) {
+ value = 0xc8e9ffcc;
+ info.D32(value);
+ } else {
+ value = 0xe942517fc2768564ULL;
+ info.D64(value);
+ }
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
+ EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr,
+ value))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, block2_empty) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
+ (DwarfAttribute) 0xe52c4463,
+ dwarf2reader::DW_FORM_block2);
+ info.D16(0);
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
+ EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
+ dwarf2reader::DW_FORM_block2,
+ _, 0))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, block2) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
+ (DwarfAttribute) 0xe52c4463,
+ dwarf2reader::DW_FORM_block2);
+ unsigned char data[258];
+ memset(data, '*', sizeof(data));
+ info.D16(sizeof(data))
+ .Append(data, sizeof(data));
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
+ EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
+ dwarf2reader::DW_FORM_block2,
+ Pointee('*'), 258))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, flag_present) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
+ (DwarfAttribute) 0x359d1972,
+ dwarf2reader::DW_FORM_flag_present);
+ // DW_FORM_flag_present occupies no space in the DIE.
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
+ EXPECT_CALL(handler,
+ ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
+ dwarf2reader::DW_FORM_flag_present,
+ 1))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, sec_offset) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
+ (DwarfAttribute) 0xa060bfd1,
+ dwarf2reader::DW_FORM_sec_offset);
+ uint64_t value;
+ if (GetParam().format_size == 4) {
+ value = 0xacc9c388;
+ info.D32(value);
+ } else {
+ value = 0xcffe5696ffe3ed0aULL;
+ info.D64(value);
+ }
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
+ EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
+ dwarf2reader::DW_FORM_sec_offset,
+ value))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, exprloc) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
+ (DwarfAttribute) 0xba3ae5cb,
+ dwarf2reader::DW_FORM_exprloc);
+ info.ULEB128(29)
+ .Append(29, 173);
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
+ EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
+ dwarf2reader::DW_FORM_exprloc,
+ Pointee(173), 29))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+TEST_P(DwarfForms, ref_sig8) {
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
+ (DwarfAttribute) 0xd708d908,
+ dwarf2reader::DW_FORM_ref_sig8);
+ info.D64(0xf72fa0cb6ddcf9d6ULL);
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
+ EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
+ dwarf2reader::DW_FORM_ref_sig8,
+ 0xf72fa0cb6ddcf9d6ULL))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam());
+}
+
+// A value passed to ProcessAttributeSignature is just an absolute number,
+// not an offset within the compilation unit as most of the other
+// DW_FORM_ref forms are. Check that the reader doesn't try to apply any
+// offset to the signature, by reading it from a compilation unit that does
+// not start at the beginning of the section.
+TEST_P(DwarfForms, ref_sig8_not_first) {
+ info.Append(98, '*');
+ StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
+ (DwarfAttribute) 0xd708d908,
+ dwarf2reader::DW_FORM_ref_sig8);
+ info.D64(0xf72fa0cb6ddcf9d6ULL);
+ info.Finish();
+
+ ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
+ EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
+ dwarf2reader::DW_FORM_ref_sig8,
+ 0xf72fa0cb6ddcf9d6ULL))
+ .InSequence(s)
+ .WillOnce(Return());
+ ExpectEndCompilationUnit();
+
+ ParseCompilationUnit(GetParam(), 98);
+}
+
+// Tests for the other attribute forms could go here.
+
+INSTANTIATE_TEST_CASE_P(
+ HeaderVariants, DwarfForms,
+ ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 2, 8),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 3, 8),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 4),
+ DwarfHeaderParams(kLittleEndian, 4, 4, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 2, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 3, 8),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 4),
+ DwarfHeaderParams(kLittleEndian, 8, 4, 8),
+ DwarfHeaderParams(kBigEndian, 4, 2, 4),
+ DwarfHeaderParams(kBigEndian, 4, 2, 8),
+ DwarfHeaderParams(kBigEndian, 4, 3, 4),
+ DwarfHeaderParams(kBigEndian, 4, 3, 8),
+ DwarfHeaderParams(kBigEndian, 4, 4, 4),
+ DwarfHeaderParams(kBigEndian, 4, 4, 8),
+ DwarfHeaderParams(kBigEndian, 8, 2, 4),
+ DwarfHeaderParams(kBigEndian, 8, 2, 8),
+ DwarfHeaderParams(kBigEndian, 8, 3, 4),
+ DwarfHeaderParams(kBigEndian, 8, 3, 8),
+ DwarfHeaderParams(kBigEndian, 8, 4, 4),
+ DwarfHeaderParams(kBigEndian, 8, 4, 8)));
diff --git a/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_test_common.h b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_test_common.h
new file mode 100644
index 0000000..e91de90
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/dwarf2reader_test_common.h
@@ -0,0 +1,149 @@
+// -*- mode: c++ -*-
+
+// Copyright (c) 2012, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf2reader_test_common.h: Define TestCompilationUnit and
+// TestAbbrevTable, classes for creating properly (and improperly)
+// formatted DWARF compilation unit data for unit tests.
+
+#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
+#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
+
+#include "common/test_assembler.h"
+#include "common/dwarf/dwarf2enums.h"
+
+// A subclass of test_assembler::Section, specialized for constructing
+// DWARF compilation units.
+class TestCompilationUnit: public google_breakpad::test_assembler::Section {
+ public:
+ typedef dwarf2reader::DwarfTag DwarfTag;
+ typedef dwarf2reader::DwarfAttribute DwarfAttribute;
+ typedef dwarf2reader::DwarfForm DwarfForm;
+ typedef google_breakpad::test_assembler::Label Label;
+
+ // Set the section's DWARF format size (the 32-bit DWARF format or the
+ // 64-bit DWARF format, for lengths and section offsets --- not the
+ // address size) to format_size.
+ void set_format_size(size_t format_size) {
+ assert(format_size == 4 || format_size == 8);
+ format_size_ = format_size;
+ }
+
+ // Append a DWARF section offset value, of the appropriate size for this
+ // compilation unit.
+ template<typename T>
+ void SectionOffset(T offset) {
+ if (format_size_ == 4)
+ D32(offset);
+ else
+ D64(offset);
+ }
+
+ // Append a DWARF compilation unit header to the section, with the given
+ // DWARF version, abbrev table offset, and address size.
+ TestCompilationUnit &Header(int version, const Label &abbrev_offset,
+ size_t address_size) {
+ if (format_size_ == 4) {
+ D32(length_);
+ } else {
+ D32(0xffffffff);
+ D64(length_);
+ }
+ post_length_offset_ = Size();
+ D16(version);
+ SectionOffset(abbrev_offset);
+ D8(address_size);
+ return *this;
+ }
+
+ // Mark the end of this header's DIEs.
+ TestCompilationUnit &Finish() {
+ length_ = Size() - post_length_offset_;
+ return *this;
+ }
+
+ private:
+ // The DWARF format size for this compilation unit.
+ size_t format_size_;
+
+ // The offset of the point in the compilation unit header immediately
+ // after the initial length field.
+ uint64_t post_length_offset_;
+
+ // The length of the compilation unit, not including the initial length field.
+ Label length_;
+};
+
+// A subclass of test_assembler::Section specialized for constructing DWARF
+// abbreviation tables.
+class TestAbbrevTable: public google_breakpad::test_assembler::Section {
+ public:
+ typedef dwarf2reader::DwarfTag DwarfTag;
+ typedef dwarf2reader::DwarfAttribute DwarfAttribute;
+ typedef dwarf2reader::DwarfForm DwarfForm;
+ typedef dwarf2reader::DwarfHasChild DwarfHasChild;
+ typedef google_breakpad::test_assembler::Label Label;
+
+ // Start a new abbreviation table entry for abbreviation code |code|,
+ // encoding a DIE whose tag is |tag|, and which has children if and only
+ // if |has_children| is true.
+ TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
+ assert(code != 0);
+ ULEB128(code);
+ ULEB128(static_cast<unsigned>(tag));
+ D8(static_cast<unsigned>(has_children));
+ return *this;
+ };
+
+ // Add an attribute to the current abbreviation code whose name is |name|
+ // and whose form is |form|.
+ TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) {
+ ULEB128(static_cast<unsigned>(name));
+ ULEB128(static_cast<unsigned>(form));
+ return *this;
+ }
+
+ // Finish the current abbreviation code.
+ TestAbbrevTable &EndAbbrev() {
+ ULEB128(0);
+ ULEB128(0);
+ return *this;
+ }
+
+ // Finish the current abbreviation table.
+ TestAbbrevTable &EndTable() {
+ ULEB128(0);
+ return *this;
+ }
+};
+
+#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
diff --git a/3rdParty/Breakpad/src/common/dwarf/elf_reader.cc b/3rdParty/Breakpad/src/common/dwarf/elf_reader.cc
new file mode 100644
index 0000000..4135a51
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/elf_reader.cc
@@ -0,0 +1,1273 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+// Author: chatham@google.com (Andrew Chatham)
+// Author: satorux@google.com (Satoru Takabayashi)
+//
+// Code for reading in ELF files.
+//
+// For information on the ELF format, see
+// http://www.x86.org/ftp/manuals/tools/elf.pdf
+//
+// I also liked:
+// http://www.caldera.com/developers/gabi/1998-04-29/contents.html
+//
+// A note about types: When dealing with the file format, we use types
+// like Elf32_Word, but in the public interfaces we treat all
+// addresses as uint64. As a result, we should be able to symbolize
+// 64-bit binaries from a 32-bit process (which we don't do,
+// anyway). size_t should therefore be avoided, except where required
+// by things like mmap().
+//
+// Although most of this code can deal with arbitrary ELF files of
+// either word size, the public ElfReader interface only examines
+// files loaded into the current address space, which must all match
+// __WORDSIZE. This code cannot handle ELF files with a non-native
+// byte ordering.
+//
+// TODO(chatham): It would be nice if we could accomplish this task
+// without using malloc(), so we could use it as the process is dying.
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE // needed for pread()
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+// TODO(saugustine): Add support for compressed debug.
+// Also need to add configure tests for zlib.
+//#include "zlib.h"
+
+#include "third_party/musl/include/elf.h"
+#include "elf_reader.h"
+#include "common/using_std_string.h"
+
+// EM_AARCH64 is not defined by elf.h of GRTE v3 on x86.
+// TODO(dougkwan): Remove this when v17 is retired.
+#if !defined(EM_AARCH64)
+#define EM_AARCH64 183 /* ARM AARCH64 */
+#endif
+
+// Map Linux macros to their Apple equivalents.
+#if __APPLE__
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#endif // __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif // __BIG_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __BYTE_ORDER__
+#endif // __BYTE_ORDER
+#endif // __APPLE__
+
+// TODO(dthomson): Can be removed once all Java code is using the Google3
+// launcher. We need to avoid processing PLT functions as it causes memory
+// fragmentation in malloc, which is fixed in tcmalloc - and if the Google3
+// launcher is used the JVM will then use tcmalloc. b/13735638
+//DEFINE_bool(elfreader_process_dynsyms, true,
+// "Activate PLT function processing");
+
+using std::vector;
+
+namespace {
+
+// The lowest bit of an ARM symbol value is used to indicate a Thumb address.
+const int kARMThumbBitOffset = 0;
+
+// Converts an ARM Thumb symbol value to a true aligned address value.
+template <typename T>
+T AdjustARMThumbSymbolValue(const T& symbol_table_value) {
+ return symbol_table_value & ~(1 << kARMThumbBitOffset);
+}
+
+// Names of PLT-related sections.
+const char kElfPLTRelSectionName[] = ".rel.plt"; // Use Rel struct.
+const char kElfPLTRelaSectionName[] = ".rela.plt"; // Use Rela struct.
+const char kElfPLTSectionName[] = ".plt";
+const char kElfDynSymSectionName[] = ".dynsym";
+
+const int kX86PLTCodeSize = 0x10; // Size of one x86 PLT function in bytes.
+const int kARMPLTCodeSize = 0xc;
+const int kAARCH64PLTCodeSize = 0x10;
+
+const int kX86PLT0Size = 0x10; // Size of the special PLT0 entry.
+const int kARMPLT0Size = 0x14;
+const int kAARCH64PLT0Size = 0x20;
+
+// Suffix for PLT functions when it needs to be explicitly identified as such.
+const char kPLTFunctionSuffix[] = "@plt";
+
+} // namespace
+
+namespace dwarf2reader {
+
+template <class ElfArch> class ElfReaderImpl;
+
+// 32-bit and 64-bit ELF files are processed exactly the same, except
+// for various field sizes. Elf32 and Elf64 encompass all of the
+// differences between the two formats, and all format-specific code
+// in this file is templated on one of them.
+class Elf32 {
+ public:
+ typedef Elf32_Ehdr Ehdr;
+ typedef Elf32_Shdr Shdr;
+ typedef Elf32_Phdr Phdr;
+ typedef Elf32_Word Word;
+ typedef Elf32_Sym Sym;
+ typedef Elf32_Rel Rel;
+ typedef Elf32_Rela Rela;
+
+ // What should be in the EI_CLASS header.
+ static const int kElfClass = ELFCLASS32;
+
+ // Given a symbol pointer, return the binding type (eg STB_WEAK).
+ static char Bind(const Elf32_Sym *sym) {
+ return ELF32_ST_BIND(sym->st_info);
+ }
+ // Given a symbol pointer, return the symbol type (eg STT_FUNC).
+ static char Type(const Elf32_Sym *sym) {
+ return ELF32_ST_TYPE(sym->st_info);
+ }
+
+ // Extract the symbol index from the r_info field of a relocation.
+ static int r_sym(const Elf32_Word r_info) {
+ return ELF32_R_SYM(r_info);
+ }
+};
+
+
+class Elf64 {
+ public:
+ typedef Elf64_Ehdr Ehdr;
+ typedef Elf64_Shdr Shdr;
+ typedef Elf64_Phdr Phdr;
+ typedef Elf64_Word Word;
+ typedef Elf64_Sym Sym;
+ typedef Elf64_Rel Rel;
+ typedef Elf64_Rela Rela;
+
+ // What should be in the EI_CLASS header.
+ static const int kElfClass = ELFCLASS64;
+
+ static char Bind(const Elf64_Sym *sym) {
+ return ELF64_ST_BIND(sym->st_info);
+ }
+ static char Type(const Elf64_Sym *sym) {
+ return ELF64_ST_TYPE(sym->st_info);
+ }
+ static int r_sym(const Elf64_Xword r_info) {
+ return ELF64_R_SYM(r_info);
+ }
+};
+
+
+// ElfSectionReader mmaps a section of an ELF file ("section" is ELF
+// terminology). The ElfReaderImpl object providing the section header
+// must exist for the lifetime of this object.
+//
+// The motivation for mmaping individual sections of the file is that
+// many Google executables are large enough when unstripped that we
+// have to worry about running out of virtual address space.
+//
+// For compressed sections we have no choice but to allocate memory.
+template<class ElfArch>
+class ElfSectionReader {
+ public:
+ ElfSectionReader(const char *name, const string &path, int fd,
+ const typename ElfArch::Shdr &section_header)
+ : contents_aligned_(NULL),
+ contents_(NULL),
+ header_(section_header) {
+ // Back up to the beginning of the page we're interested in.
+ const size_t additional = header_.sh_offset % getpagesize();
+ const size_t offset_aligned = header_.sh_offset - additional;
+ section_size_ = header_.sh_size;
+ size_aligned_ = section_size_ + additional;
+ // If the section has been stripped or is empty, do not attempt
+ // to process its contents.
+ if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0)
+ return;
+ contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED,
+ fd, offset_aligned);
+ // Set where the offset really should begin.
+ contents_ = reinterpret_cast<char *>(contents_aligned_) +
+ (header_.sh_offset - offset_aligned);
+
+ // Check for and handle any compressed contents.
+ //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0)
+ // DecompressZlibContents();
+ // TODO(saugustine): Add support for proposed elf-section flag
+ // "SHF_COMPRESS".
+ }
+
+ ~ElfSectionReader() {
+ if (contents_aligned_ != NULL)
+ munmap(contents_aligned_, size_aligned_);
+ else
+ delete[] contents_;
+ }
+
+ // Return the section header for this section.
+ typename ElfArch::Shdr const &header() const { return header_; }
+
+ // Return memory at the given offset within this section.
+ const char *GetOffset(typename ElfArch::Word bytes) const {
+ return contents_ + bytes;
+ }
+
+ const char *contents() const { return contents_; }
+ size_t section_size() const { return section_size_; }
+
+ private:
+ // page-aligned file contents
+ void *contents_aligned_;
+ // contents as usable by the client. For non-compressed sections,
+ // pointer within contents_aligned_ to where the section data
+ // begins; for compressed sections, pointer to the decompressed
+ // data.
+ char *contents_;
+ // size of contents_aligned_
+ size_t size_aligned_;
+ // size of contents.
+ size_t section_size_;
+ const typename ElfArch::Shdr header_;
+};
+
+// An iterator over symbols in a given section. It handles walking
+// through the entries in the specified section and mapping symbol
+// entries to their names in the appropriate string table (in
+// another section).
+template<class ElfArch>
+class SymbolIterator {
+ public:
+ SymbolIterator(ElfReaderImpl<ElfArch> *reader,
+ typename ElfArch::Word section_type)
+ : symbol_section_(reader->GetSectionByType(section_type)),
+ string_section_(NULL),
+ num_symbols_in_section_(0),
+ symbol_within_section_(0) {
+
+ // If this section type doesn't exist, leave
+ // num_symbols_in_section_ as zero, so this iterator is already
+ // done().
+ if (symbol_section_ != NULL) {
+ num_symbols_in_section_ = symbol_section_->header().sh_size /
+ symbol_section_->header().sh_entsize;
+
+ // Symbol sections have sh_link set to the section number of
+ // the string section containing the symbol names.
+ string_section_ = reader->GetSection(symbol_section_->header().sh_link);
+ }
+ }
+
+ // Return true iff we have passed all symbols in this section.
+ bool done() const {
+ return symbol_within_section_ >= num_symbols_in_section_;
+ }
+
+ // Advance to the next symbol in this section.
+ // REQUIRES: !done()
+ void Next() { ++symbol_within_section_; }
+
+ // Return a pointer to the current symbol.
+ // REQUIRES: !done()
+ const typename ElfArch::Sym *GetSymbol() const {
+ return reinterpret_cast<const typename ElfArch::Sym*>(
+ symbol_section_->GetOffset(symbol_within_section_ *
+ symbol_section_->header().sh_entsize));
+ }
+
+ // Return the name of the current symbol, NULL if it has none.
+ // REQUIRES: !done()
+ const char *GetSymbolName() const {
+ int name_offset = GetSymbol()->st_name;
+ if (name_offset == 0)
+ return NULL;
+ return string_section_->GetOffset(name_offset);
+ }
+
+ int GetCurrentSymbolIndex() const {
+ return symbol_within_section_;
+ }
+
+ private:
+ const ElfSectionReader<ElfArch> *const symbol_section_;
+ const ElfSectionReader<ElfArch> *string_section_;
+ int num_symbols_in_section_;
+ int symbol_within_section_;
+};
+
+
+// Copied from strings/strutil.h. Per chatham,
+// this library should not depend on strings.
+
+static inline bool MyHasSuffixString(const string& str, const string& suffix) {
+ int len = str.length();
+ int suflen = suffix.length();
+ return (suflen <= len) && (str.compare(len-suflen, suflen, suffix) == 0);
+}
+
+
+// ElfReader loads an ELF binary and can provide information about its
+// contents. It is most useful for matching addresses to function
+// names. It does not understand debugging formats (eg dwarf2), so it
+// can't print line numbers. It takes a path to an elf file and a
+// readable file descriptor for that file, which it does not assume
+// ownership of.
+template<class ElfArch>
+class ElfReaderImpl {
+ public:
+ explicit ElfReaderImpl(const string &path, int fd)
+ : path_(path),
+ fd_(fd),
+ section_headers_(NULL),
+ program_headers_(NULL),
+ opd_section_(NULL),
+ base_for_text_(0),
+ plts_supported_(false),
+ plt_code_size_(0),
+ plt0_size_(0),
+ visited_relocation_entries_(false) {
+ string error;
+ is_dwp_ = MyHasSuffixString(path, ".dwp");
+ ParseHeaders(fd, path);
+ // Currently we need some extra information for PowerPC64 binaries
+ // including a way to read the .opd section for function descriptors and a
+ // way to find the linked base for function symbols.
+ if (header_.e_machine == EM_PPC64) {
+ // "opd_section_" must always be checked for NULL before use.
+ opd_section_ = GetSectionInfoByName(".opd", &opd_info_);
+ for (unsigned int k = 0u; k < GetNumSections(); ++k) {
+ const char *name = GetSectionName(section_headers_[k].sh_name);
+ if (strncmp(name, ".text", strlen(".text")) == 0) {
+ base_for_text_ =
+ section_headers_[k].sh_addr - section_headers_[k].sh_offset;
+ break;
+ }
+ }
+ }
+ // Turn on PLTs.
+ if (header_.e_machine == EM_386 || header_.e_machine == EM_X86_64) {
+ plt_code_size_ = kX86PLTCodeSize;
+ plt0_size_ = kX86PLT0Size;
+ plts_supported_ = true;
+ } else if (header_.e_machine == EM_ARM) {
+ plt_code_size_ = kARMPLTCodeSize;
+ plt0_size_ = kARMPLT0Size;
+ plts_supported_ = true;
+ } else if (header_.e_machine == EM_AARCH64) {
+ plt_code_size_ = kAARCH64PLTCodeSize;
+ plt0_size_ = kAARCH64PLT0Size;
+ plts_supported_ = true;
+ }
+ }
+
+ ~ElfReaderImpl() {
+ for (unsigned int i = 0u; i < sections_.size(); ++i)
+ delete sections_[i];
+ delete [] section_headers_;
+ delete [] program_headers_;
+ }
+
+ // Examine the headers of the file and return whether the file looks
+ // like an ELF file for this architecture. Takes an already-open
+ // file descriptor for the candidate file, reading in the prologue
+ // to see if the ELF file appears to match the current
+ // architecture. If error is non-NULL, it will be set with a reason
+ // in case of failure.
+ static bool IsArchElfFile(int fd, string *error) {
+ unsigned char header[EI_NIDENT];
+ if (pread(fd, header, sizeof(header), 0) != sizeof(header)) {
+ if (error != NULL) *error = "Could not read header";
+ return false;
+ }
+
+ if (memcmp(header, ELFMAG, SELFMAG) != 0) {
+ if (error != NULL) *error = "Missing ELF magic";
+ return false;
+ }
+
+ if (header[EI_CLASS] != ElfArch::kElfClass) {
+ if (error != NULL) *error = "Different word size";
+ return false;
+ }
+
+ int endian = 0;
+ if (header[EI_DATA] == ELFDATA2LSB)
+ endian = __LITTLE_ENDIAN;
+ else if (header[EI_DATA] == ELFDATA2MSB)
+ endian = __BIG_ENDIAN;
+ if (endian != __BYTE_ORDER) {
+ if (error != NULL) *error = "Different byte order";
+ return false;
+ }
+
+ return true;
+ }
+
+ // Return true if we can use this symbol in Address-to-Symbol map.
+ bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) {
+ // For now we only save FUNC and NOTYPE symbols. For now we just
+ // care about functions, but some functions written in assembler
+ // don't have a proper ELF type attached to them, so we store
+ // NOTYPE symbols as well. The remaining significant type is
+ // OBJECT (eg global variables), which represent about 25% of
+ // the symbols in a typical google3 binary.
+ if (ElfArch::Type(sym) != STT_FUNC &&
+ ElfArch::Type(sym) != STT_NOTYPE) {
+ return false;
+ }
+
+ // Target specific filtering.
+ switch (header_.e_machine) {
+ case EM_AARCH64:
+ case EM_ARM:
+ // Filter out '$x' special local symbols used by tools
+ return name[0] != '$' || ElfArch::Bind(sym) != STB_LOCAL;
+ case EM_X86_64:
+ // Filter out read-only constants like .LC123.
+ return name[0] != '.' || ElfArch::Bind(sym) != STB_LOCAL;
+ default:
+ return true;
+ }
+ }
+
+ // Iterate over the symbols in a section, either SHT_DYNSYM or
+ // SHT_SYMTAB. Add all symbols to the given SymbolMap.
+ /*
+ void GetSymbolPositions(SymbolMap *symbols,
+ typename ElfArch::Word section_type,
+ uint64 mem_offset,
+ uint64 file_offset) {
+ // This map is used to filter out "nested" functions.
+ // See comment below.
+ AddrToSymMap addr_to_sym_map;
+ for (SymbolIterator<ElfArch> it(this, section_type);
+ !it.done(); it.Next()) {
+ const char *name = it.GetSymbolName();
+ if (name == NULL)
+ continue;
+ const typename ElfArch::Sym *sym = it.GetSymbol();
+ if (CanUseSymbol(name, sym)) {
+ const int sec = sym->st_shndx;
+
+ // We don't support special section indices. The most common
+ // is SHN_ABS, for absolute symbols used deep in the bowels of
+ // glibc. Also ignore any undefined symbols.
+ if (sec == SHN_UNDEF ||
+ (sec >= SHN_LORESERVE && sec <= SHN_HIRESERVE)) {
+ continue;
+ }
+
+ const typename ElfArch::Shdr& hdr = section_headers_[sec];
+
+ // Adjust for difference between where we expected to mmap
+ // this section, and where it was actually mmapped.
+ const int64 expected_base = hdr.sh_addr - hdr.sh_offset;
+ const int64 real_base = mem_offset - file_offset;
+ const int64 adjust = real_base - expected_base;
+
+ uint64 start = sym->st_value + adjust;
+
+ // Adjust function symbols for PowerPC64 by dereferencing and adjusting
+ // the function descriptor to get the function address.
+ if (header_.e_machine == EM_PPC64 && ElfArch::Type(sym) == STT_FUNC) {
+ const uint64 opd_addr =
+ AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value);
+ // Only adjust the returned value if the function address was found.
+ if (opd_addr != sym->st_value) {
+ const int64 adjust_function_symbols =
+ real_base - base_for_text_;
+ start = opd_addr + adjust_function_symbols;
+ }
+ }
+
+ addr_to_sym_map.push_back(std::make_pair(start, sym));
+ }
+ }
+ std::sort(addr_to_sym_map.begin(), addr_to_sym_map.end(), &AddrToSymSorter);
+ addr_to_sym_map.erase(std::unique(addr_to_sym_map.begin(),
+ addr_to_sym_map.end(), &AddrToSymEquals),
+ addr_to_sym_map.end());
+
+ // Squeeze out any "nested functions".
+ // Nested functions are not allowed in C, but libc plays tricks.
+ //
+ // For example, here is disassembly of /lib64/tls/libc-2.3.5.so:
+ // 0x00000000000aa380 <read+0>: cmpl $0x0,0x2781b9(%rip)
+ // 0x00000000000aa387 <read+7>: jne 0xaa39b <read+27>
+ // 0x00000000000aa389 <__read_nocancel+0>: mov $0x0,%rax
+ // 0x00000000000aa390 <__read_nocancel+7>: syscall
+ // 0x00000000000aa392 <__read_nocancel+9>: cmp $0xfffffffffffff001,%rax
+ // 0x00000000000aa398 <__read_nocancel+15>: jae 0xaa3ef <read+111>
+ // 0x00000000000aa39a <__read_nocancel+17>: retq
+ // 0x00000000000aa39b <read+27>: sub $0x28,%rsp
+ // 0x00000000000aa39f <read+31>: mov %rdi,0x8(%rsp)
+ // ...
+ // Without removing __read_nocancel, symbolizer will return NULL
+ // given e.g. 0xaa39f (because the lower bound is __read_nocancel,
+ // but 0xaa39f is beyond its end.
+ if (addr_to_sym_map.empty()) {
+ return;
+ }
+ const ElfSectionReader<ElfArch> *const symbol_section =
+ this->GetSectionByType(section_type);
+ const ElfSectionReader<ElfArch> *const string_section =
+ this->GetSection(symbol_section->header().sh_link);
+
+ typename AddrToSymMap::iterator curr = addr_to_sym_map.begin();
+ // Always insert the first symbol.
+ symbols->AddSymbol(string_section->GetOffset(curr->second->st_name),
+ curr->first, curr->second->st_size);
+ typename AddrToSymMap::iterator prev = curr++;
+ for (; curr != addr_to_sym_map.end(); ++curr) {
+ const uint64 prev_addr = prev->first;
+ const uint64 curr_addr = curr->first;
+ const typename ElfArch::Sym *const prev_sym = prev->second;
+ const typename ElfArch::Sym *const curr_sym = curr->second;
+ if (prev_addr + prev_sym->st_size <= curr_addr ||
+ // The next condition is true if two symbols overlap like this:
+ //
+ // Previous symbol |----------------------------|
+ // Current symbol |-------------------------------|
+ //
+ // These symbols are not found in google3 codebase, but in
+ // jdk1.6.0_01_gg1/jre/lib/i386/server/libjvm.so.
+ //
+ // 0619e040 00000046 t CardTableModRefBS::write_region_work()
+ // 0619e070 00000046 t CardTableModRefBS::write_ref_array_work()
+ //
+ // We allow overlapped symbols rather than ignore these.
+ // Due to the way SymbolMap::GetSymbolAtPosition() works,
+ // lookup for any address in [curr_addr, curr_addr + its size)
+ // (e.g. 0619e071) will produce the current symbol,
+ // which is the desired outcome.
+ prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) {
+ const char *name = string_section->GetOffset(curr_sym->st_name);
+ symbols->AddSymbol(name, curr_addr, curr_sym->st_size);
+ prev = curr;
+ } else {
+ // Current symbol is "nested" inside previous one like this:
+ //
+ // Previous symbol |----------------------------|
+ // Current symbol |---------------------|
+ //
+ // This happens within glibc, e.g. __read_nocancel is nested
+ // "inside" __read. Ignore "inner" symbol.
+ //DCHECK_LE(curr_addr + curr_sym->st_size,
+ // prev_addr + prev_sym->st_size);
+ ;
+ }
+ }
+ }
+*/
+
+ void VisitSymbols(typename ElfArch::Word section_type,
+ ElfReader::SymbolSink *sink) {
+ VisitSymbols(section_type, sink, -1, -1, false);
+ }
+
+ void VisitSymbols(typename ElfArch::Word section_type,
+ ElfReader::SymbolSink *sink,
+ int symbol_binding,
+ int symbol_type,
+ bool get_raw_symbol_values) {
+ for (SymbolIterator<ElfArch> it(this, section_type);
+ !it.done(); it.Next()) {
+ const char *name = it.GetSymbolName();
+ if (!name) continue;
+ const typename ElfArch::Sym *sym = it.GetSymbol();
+ if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) &&
+ (symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) {
+ typename ElfArch::Sym symbol = *sym;
+ // Add a PLT symbol in addition to the main undefined symbol.
+ // Only do this for SHT_DYNSYM, because PLT symbols are dynamic.
+ int symbol_index = it.GetCurrentSymbolIndex();
+ // TODO(dthomson): Can be removed once all Java code is using the
+ // Google3 launcher.
+ if (section_type == SHT_DYNSYM &&
+ static_cast<unsigned int>(symbol_index) < symbols_plt_offsets_.size() &&
+ symbols_plt_offsets_[symbol_index] != 0) {
+ string plt_name = string(name) + kPLTFunctionSuffix;
+ if (plt_function_names_[symbol_index].empty()) {
+ plt_function_names_[symbol_index] = plt_name;
+ } else if (plt_function_names_[symbol_index] != plt_name) {
+ ;
+ }
+ sink->AddSymbol(plt_function_names_[symbol_index].c_str(),
+ symbols_plt_offsets_[it.GetCurrentSymbolIndex()],
+ plt_code_size_);
+ }
+ if (!get_raw_symbol_values)
+ AdjustSymbolValue(&symbol);
+ sink->AddSymbol(name, symbol.st_value, symbol.st_size);
+ }
+ }
+ }
+
+ void VisitRelocationEntries() {
+ if (visited_relocation_entries_) {
+ return;
+ }
+ visited_relocation_entries_ = true;
+
+ if (!plts_supported_) {
+ return;
+ }
+ // First determine if PLTs exist. If not, then there is nothing to do.
+ ElfReader::SectionInfo plt_section_info;
+ const char* plt_section =
+ GetSectionInfoByName(kElfPLTSectionName, &plt_section_info);
+ if (!plt_section) {
+ return;
+ }
+ if (plt_section_info.size == 0) {
+ return;
+ }
+
+ // The PLTs could be referenced by either a Rel or Rela (Rel with Addend)
+ // section.
+ ElfReader::SectionInfo rel_section_info;
+ ElfReader::SectionInfo rela_section_info;
+ const char* rel_section =
+ GetSectionInfoByName(kElfPLTRelSectionName, &rel_section_info);
+ const char* rela_section =
+ GetSectionInfoByName(kElfPLTRelaSectionName, &rela_section_info);
+
+ const typename ElfArch::Rel* rel =
+ reinterpret_cast<const typename ElfArch::Rel*>(rel_section);
+ const typename ElfArch::Rela* rela =
+ reinterpret_cast<const typename ElfArch::Rela*>(rela_section);
+
+ if (!rel_section && !rela_section) {
+ return;
+ }
+
+ // Use either Rel or Rela section, depending on which one exists.
+ size_t section_size = rel_section ? rel_section_info.size
+ : rela_section_info.size;
+ size_t entry_size = rel_section ? sizeof(typename ElfArch::Rel)
+ : sizeof(typename ElfArch::Rela);
+
+ // Determine the number of entries in the dynamic symbol table.
+ ElfReader::SectionInfo dynsym_section_info;
+ const char* dynsym_section =
+ GetSectionInfoByName(kElfDynSymSectionName, &dynsym_section_info);
+ // The dynsym section might not exist, or it might be empty. In either case
+ // there is nothing to be done so return.
+ if (!dynsym_section || dynsym_section_info.size == 0) {
+ return;
+ }
+ size_t num_dynamic_symbols =
+ dynsym_section_info.size / dynsym_section_info.entsize;
+ symbols_plt_offsets_.resize(num_dynamic_symbols, 0);
+
+ // TODO(dthomson): Can be removed once all Java code is using the
+ // Google3 launcher.
+ // Make storage room for PLT function name strings.
+ plt_function_names_.resize(num_dynamic_symbols);
+
+ for (size_t i = 0; i < section_size / entry_size; ++i) {
+ // Determine symbol index from the |r_info| field.
+ int sym_index = ElfArch::r_sym(rel_section ? rel[i].r_info
+ : rela[i].r_info);
+ if (static_cast<unsigned int>(sym_index) >= symbols_plt_offsets_.size()) {
+ continue;
+ }
+ symbols_plt_offsets_[sym_index] =
+ plt_section_info.addr + plt0_size_ + i * plt_code_size_;
+ }
+ }
+
+ // Return an ElfSectionReader for the first section of the given
+ // type by iterating through all section headers. Returns NULL if
+ // the section type is not found.
+ const ElfSectionReader<ElfArch> *GetSectionByType(
+ typename ElfArch::Word section_type) {
+ for (unsigned int k = 0u; k < GetNumSections(); ++k) {
+ if (section_headers_[k].sh_type == section_type) {
+ return GetSection(k);
+ }
+ }
+ return NULL;
+ }
+
+ // Return the name of section "shndx". Returns NULL if the section
+ // is not found.
+ const char *GetSectionNameByIndex(int shndx) {
+ return GetSectionName(section_headers_[shndx].sh_name);
+ }
+
+ // Return a pointer to section "shndx", and store the size in
+ // "size". Returns NULL if the section is not found.
+ const char *GetSectionContentsByIndex(int shndx, size_t *size) {
+ const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ if (section != NULL) {
+ *size = section->section_size();
+ return section->contents();
+ }
+ return NULL;
+ }
+
+ // Return a pointer to the first section of the given name by
+ // iterating through all section headers, and store the size in
+ // "size". Returns NULL if the section name is not found.
+ const char *GetSectionContentsByName(const string &section_name,
+ size_t *size) {
+ for (unsigned int k = 0u; k < GetNumSections(); ++k) {
+ // When searching for sections in a .dwp file, the sections
+ // we're looking for will always be at the end of the section
+ // table, so reverse the direction of iteration.
+ int shndx = is_dwp_ ? GetNumSections() - k - 1 : k;
+ const char *name = GetSectionName(section_headers_[shndx].sh_name);
+ if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) {
+ const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ if (section == NULL) {
+ return NULL;
+ } else {
+ *size = section->section_size();
+ return section->contents();
+ }
+ }
+ }
+ return NULL;
+ }
+
+ // This is like GetSectionContentsByName() but it returns a lot of extra
+ // information about the section.
+ const char *GetSectionInfoByName(const string &section_name,
+ ElfReader::SectionInfo *info) {
+ for (unsigned int k = 0u; k < GetNumSections(); ++k) {
+ // When searching for sections in a .dwp file, the sections
+ // we're looking for will always be at the end of the section
+ // table, so reverse the direction of iteration.
+ int shndx = is_dwp_ ? GetNumSections() - k - 1 : k;
+ const char *name = GetSectionName(section_headers_[shndx].sh_name);
+ if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) {
+ const ElfSectionReader<ElfArch> *section = GetSection(shndx);
+ if (section == NULL) {
+ return NULL;
+ } else {
+ info->type = section->header().sh_type;
+ info->flags = section->header().sh_flags;
+ info->addr = section->header().sh_addr;
+ info->offset = section->header().sh_offset;
+ info->size = section->header().sh_size;
+ info->link = section->header().sh_link;
+ info->info = section->header().sh_info;
+ info->addralign = section->header().sh_addralign;
+ info->entsize = section->header().sh_entsize;
+ return section->contents();
+ }
+ }
+ }
+ return NULL;
+ }
+
+ // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
+ // segments are present. This is the address an ELF image was linked
+ // (by static linker) to be loaded at. Usually (but not always) 0 for
+ // shared libraries and position-independent executables.
+ uint64 VaddrOfFirstLoadSegment() const {
+ // Relocatable objects (of type ET_REL) do not have LOAD segments.
+ if (header_.e_type == ET_REL) {
+ return 0;
+ }
+ for (int i = 0; i < GetNumProgramHeaders(); ++i) {
+ if (program_headers_[i].p_type == PT_LOAD) {
+ return program_headers_[i].p_vaddr;
+ }
+ }
+ return 0;
+ }
+
+ // According to the LSB ("ELF special sections"), sections with debug
+ // info are prefixed by ".debug". The names are not specified, but they
+ // look like ".debug_line", ".debug_info", etc.
+ bool HasDebugSections() {
+ // Debug sections are likely to be near the end, so reverse the
+ // direction of iteration.
+ for (int k = GetNumSections() - 1; k >= 0; --k) {
+ const char *name = GetSectionName(section_headers_[k].sh_name);
+ if (strncmp(name, ".debug", strlen(".debug")) == 0) return true;
+ if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true;
+ }
+ return false;
+ }
+
+ bool IsDynamicSharedObject() const {
+ return header_.e_type == ET_DYN;
+ }
+
+ // Return the number of sections.
+ uint64_t GetNumSections() const {
+ if (HasManySections())
+ return first_section_header_.sh_size;
+ return header_.e_shnum;
+ }
+
+ private:
+ typedef vector<pair<uint64, const typename ElfArch::Sym *> > AddrToSymMap;
+
+ static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs,
+ const typename AddrToSymMap::value_type& rhs) {
+ return lhs.first < rhs.first;
+ }
+
+ static bool AddrToSymEquals(const typename AddrToSymMap::value_type& lhs,
+ const typename AddrToSymMap::value_type& rhs) {
+ return lhs.first == rhs.first;
+ }
+
+ // Does this ELF file have too many sections to fit in the program header?
+ bool HasManySections() const {
+ return header_.e_shnum == SHN_UNDEF;
+ }
+
+ // Return the number of program headers.
+ int GetNumProgramHeaders() const {
+ if (HasManySections() && header_.e_phnum == 0xffff &&
+ first_section_header_.sh_info != 0)
+ return first_section_header_.sh_info;
+ return header_.e_phnum;
+ }
+
+ // Return the index of the string table.
+ int GetStringTableIndex() const {
+ if (HasManySections()) {
+ if (header_.e_shstrndx == 0xffff)
+ return first_section_header_.sh_link;
+ else if (header_.e_shstrndx >= GetNumSections())
+ return 0;
+ }
+ return header_.e_shstrndx;
+ }
+
+ // Given an offset into the section header string table, return the
+ // section name.
+ const char *GetSectionName(typename ElfArch::Word sh_name) {
+ const ElfSectionReader<ElfArch> *shstrtab =
+ GetSection(GetStringTableIndex());
+ if (shstrtab != NULL) {
+ return shstrtab->GetOffset(sh_name);
+ }
+ return NULL;
+ }
+
+ // Return an ElfSectionReader for the given section. The reader will
+ // be freed when this object is destroyed.
+ const ElfSectionReader<ElfArch> *GetSection(int num) {
+ const char *name;
+ // Hard-coding the name for the section-name string table prevents
+ // infinite recursion.
+ if (num == GetStringTableIndex())
+ name = ".shstrtab";
+ else
+ name = GetSectionNameByIndex(num);
+ ElfSectionReader<ElfArch> *& reader = sections_[num];
+ if (reader == NULL)
+ reader = new ElfSectionReader<ElfArch>(name, path_, fd_,
+ section_headers_[num]);
+ return reader;
+ }
+
+ // Parse out the overall header information from the file and assert
+ // that it looks sane. This contains information like the magic
+ // number and target architecture.
+ bool ParseHeaders(int fd, const string &path) {
+ // Read in the global ELF header.
+ if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) {
+ return false;
+ }
+
+ // Must be an executable, dynamic shared object or relocatable object
+ if (header_.e_type != ET_EXEC &&
+ header_.e_type != ET_DYN &&
+ header_.e_type != ET_REL) {
+ return false;
+ }
+ // Need a section header.
+ if (header_.e_shoff == 0) {
+ return false;
+ }
+
+ if (header_.e_shnum == SHN_UNDEF) {
+ // The number of sections in the program header is only a 16-bit value. In
+ // the event of overflow (greater than SHN_LORESERVE sections), e_shnum
+ // will read SHN_UNDEF and the true number of section header table entries
+ // is found in the sh_size field of the first section header.
+ // See: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html
+ if (pread(fd, &first_section_header_, sizeof(first_section_header_),
+ header_.e_shoff) != sizeof(first_section_header_)) {
+ return false;
+ }
+ }
+
+ // Dynamically allocate enough space to store the section headers
+ // and read them out of the file.
+ const int section_headers_size =
+ GetNumSections() * sizeof(*section_headers_);
+ section_headers_ = new typename ElfArch::Shdr[section_headers_size];
+ if (pread(fd, section_headers_, section_headers_size, header_.e_shoff) !=
+ section_headers_size) {
+ return false;
+ }
+
+ // Dynamically allocate enough space to store the program headers
+ // and read them out of the file.
+ //const int program_headers_size =
+ // GetNumProgramHeaders() * sizeof(*program_headers_);
+ program_headers_ = new typename ElfArch::Phdr[GetNumProgramHeaders()];
+
+ // Presize the sections array for efficiency.
+ sections_.resize(GetNumSections(), NULL);
+ return true;
+ }
+
+ // Given the "value" of a function descriptor return the address of the
+ // function (i.e. the dereferenced value). Otherwise return "value".
+ uint64 AdjustPPC64FunctionDescriptorSymbolValue(uint64 value) {
+ if (opd_section_ != NULL &&
+ opd_info_.addr <= value &&
+ value < opd_info_.addr + opd_info_.size) {
+ uint64 offset = value - opd_info_.addr;
+ return (*reinterpret_cast<const uint64*>(opd_section_ + offset));
+ }
+ return value;
+ }
+
+ void AdjustSymbolValue(typename ElfArch::Sym* sym) {
+ switch (header_.e_machine) {
+ case EM_ARM:
+ // For ARM architecture, if the LSB of the function symbol offset is set,
+ // it indicates a Thumb function. This bit should not be taken literally.
+ // Clear it.
+ if (ElfArch::Type(sym) == STT_FUNC)
+ sym->st_value = AdjustARMThumbSymbolValue(sym->st_value);
+ break;
+ case EM_386:
+ // No adjustment needed for Intel x86 architecture. However, explicitly
+ // define this case as we use it quite often.
+ break;
+ case EM_PPC64:
+ // PowerPC64 currently has function descriptors as part of the ABI.
+ // Function symbols need to be adjusted accordingly.
+ if (ElfArch::Type(sym) == STT_FUNC)
+ sym->st_value = AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value);
+ break;
+ default:
+ break;
+ }
+ }
+
+ friend class SymbolIterator<ElfArch>;
+
+ // The file we're reading.
+ const string path_;
+ // Open file descriptor for path_. Not owned by this object.
+ const int fd_;
+
+ // The global header of the ELF file.
+ typename ElfArch::Ehdr header_;
+
+ // The header of the first section. This may be used to supplement the ELF
+ // file header.
+ typename ElfArch::Shdr first_section_header_;
+
+ // Array of GetNumSections() section headers, allocated when we read
+ // in the global header.
+ typename ElfArch::Shdr *section_headers_;
+
+ // Array of GetNumProgramHeaders() program headers, allocated when we read
+ // in the global header.
+ typename ElfArch::Phdr *program_headers_;
+
+ // An array of pointers to ElfSectionReaders. Sections are
+ // mmaped as they're needed and not released until this object is
+ // destroyed.
+ vector<ElfSectionReader<ElfArch>*> sections_;
+
+ // For PowerPC64 we need to keep track of function descriptors when looking up
+ // values for funtion symbols values. Function descriptors are kept in the
+ // .opd section and are dereferenced to find the function address.
+ ElfReader::SectionInfo opd_info_;
+ const char *opd_section_; // Must be checked for NULL before use.
+ int64 base_for_text_;
+
+ // Read PLT-related sections for the current architecture.
+ bool plts_supported_;
+ // Code size of each PLT function for the current architecture.
+ size_t plt_code_size_;
+ // Size of the special first entry in the .plt section that calls the runtime
+ // loader resolution routine, and that all other entries jump to when doing
+ // lazy symbol binding.
+ size_t plt0_size_;
+
+ // Maps a dynamic symbol index to a PLT offset.
+ // The vector entry index is the dynamic symbol index.
+ std::vector<uint64> symbols_plt_offsets_;
+
+ // Container for PLT function name strings. These strings are passed by
+ // reference to SymbolSink::AddSymbol() so they need to be stored somewhere.
+ std::vector<string> plt_function_names_;
+
+ bool visited_relocation_entries_;
+
+ // True if this is a .dwp file.
+ bool is_dwp_;
+};
+
+ElfReader::ElfReader(const string &path)
+ : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) {
+ // linux 2.6.XX kernel can show deleted files like this:
+ // /var/run/nscd/dbYLJYaE (deleted)
+ // and the kernel-supplied vdso and vsyscall mappings like this:
+ // [vdso]
+ // [vsyscall]
+ if (MyHasSuffixString(path, " (deleted)"))
+ return;
+ if (path == "[vdso]")
+ return;
+ if (path == "[vsyscall]")
+ return;
+
+ fd_ = open(path.c_str(), O_RDONLY);
+}
+
+ElfReader::~ElfReader() {
+ if (fd_ != -1)
+ close(fd_);
+ if (impl32_ != NULL)
+ delete impl32_;
+ if (impl64_ != NULL)
+ delete impl64_;
+}
+
+
+// The only word-size specific part of this file is IsNativeElfFile().
+#if __WORDSIZE == 32
+#define NATIVE_ELF_ARCH Elf32
+#elif __WORDSIZE == 64
+#define NATIVE_ELF_ARCH Elf64
+#else
+#error "Invalid word size"
+#endif
+
+template <typename ElfArch>
+static bool IsElfFile(const int fd, const string &path) {
+ if (fd < 0)
+ return false;
+ if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) {
+ // No error message here. IsElfFile gets called many times.
+ return false;
+ }
+ return true;
+}
+
+bool ElfReader::IsNativeElfFile() const {
+ return IsElfFile<NATIVE_ELF_ARCH>(fd_, path_);
+}
+
+bool ElfReader::IsElf32File() const {
+ return IsElfFile<Elf32>(fd_, path_);
+}
+
+bool ElfReader::IsElf64File() const {
+ return IsElfFile<Elf64>(fd_, path_);
+}
+
+/*
+void ElfReader::AddSymbols(SymbolMap *symbols,
+ uint64 mem_offset, uint64 file_offset,
+ uint64 length) {
+ if (fd_ < 0)
+ return;
+ // TODO(chatham): Actually use the information about file offset and
+ // the length of the mapped section. On some machines the data
+ // section gets mapped as executable, and we'll end up reading the
+ // file twice and getting some of the offsets wrong.
+ if (IsElf32File()) {
+ GetImpl32()->GetSymbolPositions(symbols, SHT_SYMTAB,
+ mem_offset, file_offset);
+ GetImpl32()->GetSymbolPositions(symbols, SHT_DYNSYM,
+ mem_offset, file_offset);
+ } else if (IsElf64File()) {
+ GetImpl64()->GetSymbolPositions(symbols, SHT_SYMTAB,
+ mem_offset, file_offset);
+ GetImpl64()->GetSymbolPositions(symbols, SHT_DYNSYM,
+ mem_offset, file_offset);
+ }
+}
+*/
+
+void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) {
+ VisitSymbols(sink, -1, -1);
+}
+
+void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink,
+ int symbol_binding,
+ int symbol_type) {
+ VisitSymbols(sink, symbol_binding, symbol_type, false);
+}
+
+void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink,
+ int symbol_binding,
+ int symbol_type,
+ bool get_raw_symbol_values) {
+ if (IsElf32File()) {
+ GetImpl32()->VisitRelocationEntries();
+ GetImpl32()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type,
+ get_raw_symbol_values);
+ GetImpl32()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type,
+ get_raw_symbol_values);
+ } else if (IsElf64File()) {
+ GetImpl64()->VisitRelocationEntries();
+ GetImpl64()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type,
+ get_raw_symbol_values);
+ GetImpl64()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type,
+ get_raw_symbol_values);
+ }
+}
+
+uint64 ElfReader::VaddrOfFirstLoadSegment() {
+ if (IsElf32File()) {
+ return GetImpl32()->VaddrOfFirstLoadSegment();
+ } else if (IsElf64File()) {
+ return GetImpl64()->VaddrOfFirstLoadSegment();
+ } else {
+ return 0;
+ }
+}
+
+const char *ElfReader::GetSectionName(int shndx) {
+ if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL;
+ if (IsElf32File()) {
+ return GetImpl32()->GetSectionNameByIndex(shndx);
+ } else if (IsElf64File()) {
+ return GetImpl64()->GetSectionNameByIndex(shndx);
+ } else {
+ return NULL;
+ }
+}
+
+uint64 ElfReader::GetNumSections() {
+ if (IsElf32File()) {
+ return GetImpl32()->GetNumSections();
+ } else if (IsElf64File()) {
+ return GetImpl64()->GetNumSections();
+ } else {
+ return 0;
+ }
+}
+
+const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) {
+ if (IsElf32File()) {
+ return GetImpl32()->GetSectionContentsByIndex(shndx, size);
+ } else if (IsElf64File()) {
+ return GetImpl64()->GetSectionContentsByIndex(shndx, size);
+ } else {
+ return NULL;
+ }
+}
+
+const char *ElfReader::GetSectionByName(const string &section_name,
+ size_t *size) {
+ if (IsElf32File()) {
+ return GetImpl32()->GetSectionContentsByName(section_name, size);
+ } else if (IsElf64File()) {
+ return GetImpl64()->GetSectionContentsByName(section_name, size);
+ } else {
+ return NULL;
+ }
+}
+
+const char *ElfReader::GetSectionInfoByName(const string &section_name,
+ SectionInfo *info) {
+ if (IsElf32File()) {
+ return GetImpl32()->GetSectionInfoByName(section_name, info);
+ } else if (IsElf64File()) {
+ return GetImpl64()->GetSectionInfoByName(section_name, info);
+ } else {
+ return NULL;
+ }
+}
+
+bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) {
+ if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) {
+ const string name_suffix(name, strlen(".debug_"));
+ const string sh_name_suffix(sh_name, strlen(".zdebug_"));
+ return name_suffix == sh_name_suffix;
+ }
+ return name == sh_name;
+}
+
+bool ElfReader::IsDynamicSharedObject() {
+ if (IsElf32File()) {
+ return GetImpl32()->IsDynamicSharedObject();
+ } else if (IsElf64File()) {
+ return GetImpl64()->IsDynamicSharedObject();
+ } else {
+ return false;
+ }
+}
+
+ElfReaderImpl<Elf32> *ElfReader::GetImpl32() {
+ if (impl32_ == NULL) {
+ impl32_ = new ElfReaderImpl<Elf32>(path_, fd_);
+ }
+ return impl32_;
+}
+
+ElfReaderImpl<Elf64> *ElfReader::GetImpl64() {
+ if (impl64_ == NULL) {
+ impl64_ = new ElfReaderImpl<Elf64>(path_, fd_);
+ }
+ return impl64_;
+}
+
+// Return true if file is an ELF binary of ElfArch, with unstripped
+// debug info (debug_only=true) or symbol table (debug_only=false).
+// Otherwise, return false.
+template <typename ElfArch>
+static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd,
+ bool debug_only) {
+ if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) return false;
+ ElfReaderImpl<ElfArch> elf_reader(path, fd);
+ return debug_only ?
+ elf_reader.HasDebugSections()
+ : (elf_reader.GetSectionByType(SHT_SYMTAB) != NULL);
+}
+
+// Helper for the IsNon[Debug]StrippedELFBinary functions.
+static bool IsNonStrippedELFBinaryHelper(const string &path,
+ bool debug_only) {
+ const int fd = open(path.c_str(), O_RDONLY);
+ if (fd == -1) {
+ return false;
+ }
+
+ if (IsNonStrippedELFBinaryImpl<Elf32>(path, fd, debug_only) ||
+ IsNonStrippedELFBinaryImpl<Elf64>(path, fd, debug_only)) {
+ close(fd);
+ return true;
+ }
+ close(fd);
+ return false;
+}
+
+bool ElfReader::IsNonStrippedELFBinary(const string &path) {
+ return IsNonStrippedELFBinaryHelper(path, false);
+}
+
+bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) {
+ return IsNonStrippedELFBinaryHelper(path, true);
+}
+} // namespace dwarf2reader
diff --git a/3rdParty/Breakpad/src/common/dwarf/elf_reader.h b/3rdParty/Breakpad/src/common/dwarf/elf_reader.h
new file mode 100644
index 0000000..b1bb67a
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/elf_reader.h
@@ -0,0 +1,166 @@
+// Copyright 2005 Google Inc. All Rights Reserved.
+// Author: chatham@google.com (Andrew Chatham)
+// Author: satorux@google.com (Satoru Takabayashi)
+//
+// ElfReader handles reading in ELF. It can extract symbols from the
+// current process, which may be used to symbolize stack traces
+// without having to make a potentially dangerous call to fork().
+//
+// ElfReader dynamically allocates memory, so it is not appropriate to
+// use once the address space might be corrupted, such as during
+// process death.
+//
+// ElfReader supports both 32-bit and 64-bit ELF binaries.
+
+#ifndef COMMON_DWARF_ELF_READER_H__
+#define COMMON_DWARF_ELF_READER_H__
+
+#include <string>
+#include <vector>
+
+#include "common/dwarf/types.h"
+#include "common/using_std_string.h"
+
+using std::vector;
+using std::pair;
+
+namespace dwarf2reader {
+
+class SymbolMap;
+class Elf32;
+class Elf64;
+template<typename ElfArch>
+class ElfReaderImpl;
+
+class ElfReader {
+ public:
+ explicit ElfReader(const string &path);
+ ~ElfReader();
+
+ // Parse the ELF prologue of this file and return whether it was
+ // successfully parsed and matches the word size and byte order of
+ // the current process.
+ bool IsNativeElfFile() const;
+
+ // Similar to IsNativeElfFile but checks if it's a 32-bit ELF file.
+ bool IsElf32File() const;
+
+ // Similar to IsNativeElfFile but checks if it's a 64-bit ELF file.
+ bool IsElf64File() const;
+
+ // Checks if it's an ELF file of type ET_DYN (shared object file).
+ bool IsDynamicSharedObject();
+
+ // Add symbols in the given ELF file into the provided SymbolMap,
+ // assuming that the file has been loaded into the specified
+ // offset.
+ //
+ // The remaining arguments are typically taken from a
+ // ProcMapsIterator (base/sysinfo.h) and describe which portions of
+ // the ELF file are mapped into which parts of memory:
+ //
+ // mem_offset - position at which the segment is mapped into memory
+ // file_offset - offset in the file where the mapping begins
+ // length - length of the mapped segment
+ void AddSymbols(SymbolMap *symbols,
+ uint64 mem_offset, uint64 file_offset,
+ uint64 length);
+
+ class SymbolSink {
+ public:
+ virtual ~SymbolSink() {}
+ virtual void AddSymbol(const char *name, uint64 address, uint64 size) = 0;
+ };
+
+ // Like AddSymbols above, but with no address correction.
+ // Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
+ void VisitSymbols(SymbolSink *sink);
+
+ // Like VisitSymbols above, but for a specific symbol binding/type.
+ // A negative value for the binding and type parameters means any
+ // binding or type.
+ void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type);
+
+ // Like VisitSymbols above but can optionally export raw symbol values instead
+ // of adjusted ones.
+ void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type,
+ bool get_raw_symbol_values);
+
+ // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
+ // segments are present. This is the address an ELF image was linked
+ // (by static linker) to be loaded at. Usually (but not always) 0 for
+ // shared libraries and position-independent executables.
+ uint64 VaddrOfFirstLoadSegment();
+
+ // Return the name of section "shndx". Returns NULL if the section
+ // is not found.
+ const char *GetSectionName(int shndx);
+
+ // Return the number of sections in the given ELF file.
+ uint64 GetNumSections();
+
+ // Get section "shndx" from the given ELF file. On success, return
+ // the pointer to the section and store the size in "size".
+ // On error, return NULL. The returned section data is only valid
+ // until the ElfReader gets destroyed.
+ const char *GetSectionByIndex(int shndx, size_t *size);
+
+ // Get section with "section_name" (ex. ".text", ".symtab") in the
+ // given ELF file. On success, return the pointer to the section
+ // and store the size in "size". On error, return NULL. The
+ // returned section data is only valid until the ElfReader gets
+ // destroyed.
+ const char *GetSectionByName(const string &section_name, size_t *size);
+
+ // This is like GetSectionByName() but it returns a lot of extra information
+ // about the section. The SectionInfo structure is almost identical to
+ // the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
+ // here so that the many short macro names in <elf.h> don't have to be
+ // added to our already cluttered namespace.
+ struct SectionInfo {
+ uint32 type; // Section type (SHT_xxx constant from elf.h).
+ uint64 flags; // Section flags (SHF_xxx constants from elf.h).
+ uint64 addr; // Section virtual address at execution.
+ uint64 offset; // Section file offset.
+ uint64 size; // Section size in bytes.
+ uint32 link; // Link to another section.
+ uint32 info; // Additional section information.
+ uint64 addralign; // Section alignment.
+ uint64 entsize; // Entry size if section holds a table.
+ };
+ const char *GetSectionInfoByName(const string &section_name,
+ SectionInfo *info);
+
+ // Check if "path" is an ELF binary that has not been stripped of symbol
+ // tables. This function supports both 32-bit and 64-bit ELF binaries.
+ static bool IsNonStrippedELFBinary(const string &path);
+
+ // Check if "path" is an ELF binary that has not been stripped of debug
+ // info. Unlike IsNonStrippedELFBinary, this function will return
+ // false for binaries passed through "strip -S".
+ static bool IsNonDebugStrippedELFBinary(const string &path);
+
+ // Match a requested section name with the section name as it
+ // appears in the elf-file, adjusting for compressed debug section
+ // names. For example, returns true if name == ".debug_abbrev" and
+ // sh_name == ".zdebug_abbrev"
+ static bool SectionNamesMatch(const string &name, const string &sh_name);
+
+ private:
+ // Lazily initialize impl32_ and return it.
+ ElfReaderImpl<Elf32> *GetImpl32();
+ // Ditto for impl64_.
+ ElfReaderImpl<Elf64> *GetImpl64();
+
+ // Path of the file we're reading.
+ const string path_;
+ // Read-only file descriptor for the file. May be -1 if there was an
+ // error during open.
+ int fd_;
+ ElfReaderImpl<Elf32> *impl32_;
+ ElfReaderImpl<Elf64> *impl64_;
+};
+
+} // namespace dwarf2reader
+
+#endif // COMMON_DWARF_ELF_READER_H__
diff --git a/3rdParty/Breakpad/src/common/dwarf/functioninfo.cc b/3rdParty/Breakpad/src/common/dwarf/functioninfo.cc
new file mode 100644
index 0000000..55a255e
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/functioninfo.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2010 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This is a client for the dwarf2reader to extract function and line
+// information from the debug info.
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "common/dwarf/functioninfo.h"
+#include "common/dwarf/bytereader.h"
+#include "common/scoped_ptr.h"
+#include "common/using_std_string.h"
+
+using google_breakpad::scoped_ptr;
+
+namespace dwarf2reader {
+
+CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
+ std::vector<string>* dirs,
+ LineMap* linemap):linemap_(linemap),
+ files_(files),
+ dirs_(dirs) {
+ // The dirs and files are 1 indexed, so just make sure we put
+ // nothing in the 0 vector.
+ assert(dirs->size() == 0);
+ assert(files->size() == 0);
+ dirs->push_back("");
+ SourceFileInfo s;
+ s.name = "";
+ s.lowpc = ULLONG_MAX;
+ files->push_back(s);
+}
+
+void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
+ // These should never come out of order, actually
+ assert(dir_num == dirs_->size());
+ dirs_->push_back(name);
+}
+
+void CULineInfoHandler::DefineFile(const string& name,
+ int32 file_num, uint32 dir_num,
+ uint64 mod_time, uint64 length) {
+ assert(dir_num >= 0);
+ assert(dir_num < dirs_->size());
+
+ // These should never come out of order, actually.
+ if (file_num == (int32)files_->size() || file_num == -1) {
+ string dir = dirs_->at(dir_num);
+
+ SourceFileInfo s;
+ s.lowpc = ULLONG_MAX;
+
+ if (dir == "") {
+ s.name = name;
+ } else {
+ s.name = dir + "/" + name;
+ }
+
+ files_->push_back(s);
+ } else {
+ fprintf(stderr, "error in DefineFile");
+ }
+}
+
+void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
+ uint32 line_num, uint32 column_num) {
+ if (file_num < files_->size()) {
+ linemap_->insert(
+ std::make_pair(address,
+ std::make_pair(files_->at(file_num).name.c_str(),
+ line_num)));
+
+ if (address < files_->at(file_num).lowpc) {
+ files_->at(file_num).lowpc = address;
+ }
+ } else {
+ fprintf(stderr, "error in AddLine");
+ }
+}
+
+bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
+ uint8 address_size,
+ uint8 offset_size,
+ uint64 cu_length,
+ uint8 dwarf_version) {
+ current_compilation_unit_offset_ = offset;
+ return true;
+}
+
+
+// For function info, we only care about subprograms and inlined
+// subroutines. For line info, the DW_AT_stmt_list lives in the
+// compile unit tag.
+
+bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) {
+ switch (tag) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine: {
+ current_function_info_ = new FunctionInfo;
+ current_function_info_->lowpc = current_function_info_->highpc = 0;
+ current_function_info_->name = "";
+ current_function_info_->line = 0;
+ current_function_info_->file = "";
+ offset_to_funcinfo_->insert(std::make_pair(offset,
+ current_function_info_));
+ };
+ // FALLTHROUGH
+ case DW_TAG_compile_unit:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+// Only care about the name attribute for functions
+
+void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const string &data) {
+ if (current_function_info_) {
+ if (attr == DW_AT_name)
+ current_function_info_->name = data;
+ else if (attr == DW_AT_MIPS_linkage_name)
+ current_function_info_->mangled_name = data;
+ }
+}
+
+void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data) {
+ if (attr == DW_AT_stmt_list) {
+ SectionMap::const_iterator iter = sections_.find("__debug_line");
+ assert(iter != sections_.end());
+
+ scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
+ iter->second.second - data,
+ reader_, linehandler_));
+ lireader->Start();
+ } else if (current_function_info_) {
+ switch (attr) {
+ case DW_AT_low_pc:
+ current_function_info_->lowpc = data;
+ break;
+ case DW_AT_high_pc:
+ current_function_info_->highpc = data;
+ break;
+ case DW_AT_decl_line:
+ current_function_info_->line = data;
+ break;
+ case DW_AT_decl_file:
+ current_function_info_->file = files_->at(data).name;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data) {
+ if (current_function_info_) {
+ switch (attr) {
+ case DW_AT_specification: {
+ // Some functions have a "specification" attribute
+ // which means they were defined elsewhere. The name
+ // attribute is not repeated, and must be taken from
+ // the specification DIE. Here we'll assume that
+ // any DIE referenced in this manner will already have
+ // been seen, but that's not really required by the spec.
+ FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
+ if (iter != offset_to_funcinfo_->end()) {
+ current_function_info_->name = iter->second->name;
+ current_function_info_->mangled_name = iter->second->mangled_name;
+ } else {
+ // If you hit this, this code probably needs to be rewritten.
+ fprintf(stderr,
+ "Error: DW_AT_specification was seen before the referenced "
+ "DIE! (Looking for DIE at offset %08llx, in DIE at "
+ "offset %08llx)\n", data, offset);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void CUFunctionInfoHandler::EndDIE(uint64 offset) {
+ if (current_function_info_ && current_function_info_->lowpc)
+ address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
+ current_function_info_));
+}
+
+} // namespace dwarf2reader
diff --git a/3rdParty/Breakpad/src/common/dwarf/functioninfo.h b/3rdParty/Breakpad/src/common/dwarf/functioninfo.h
new file mode 100644
index 0000000..0b08a5f
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf/functioninfo.h
@@ -0,0 +1,188 @@
+// Copyright (c) 2010 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This file contains the definitions for a DWARF2/3 information
+// collector that uses the DWARF2/3 reader interface to build a mapping
+// of addresses to files, lines, and functions.
+
+#ifndef COMMON_DWARF_FUNCTIONINFO_H__
+#define COMMON_DWARF_FUNCTIONINFO_H__
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "common/dwarf/dwarf2reader.h"
+#include "common/using_std_string.h"
+
+
+namespace dwarf2reader {
+
+struct FunctionInfo {
+ // Name of the function
+ string name;
+ // Mangled name of the function
+ string mangled_name;
+ // File containing this function
+ string file;
+ // Line number for start of function.
+ uint32 line;
+ // Beginning address for this function
+ uint64 lowpc;
+ // End address for this function.
+ uint64 highpc;
+};
+
+struct SourceFileInfo {
+ // Name of the source file name
+ string name;
+ // Low address of source file name
+ uint64 lowpc;
+};
+
+typedef std::map<uint64, FunctionInfo*> FunctionMap;
+typedef std::map<uint64, std::pair<string, uint32> > LineMap;
+
+// This class is a basic line info handler that fills in the dirs,
+// file, and linemap passed into it with the data produced from the
+// LineInfoHandler.
+class CULineInfoHandler: public LineInfoHandler {
+ public:
+
+ //
+ CULineInfoHandler(std::vector<SourceFileInfo>* files,
+ std::vector<string>* dirs,
+ LineMap* linemap);
+ virtual ~CULineInfoHandler() { }
+
+ // Called when we define a directory. We just place NAME into dirs_
+ // at position DIR_NUM.
+ virtual void DefineDir(const string& name, uint32 dir_num);
+
+ // Called when we define a filename. We just place
+ // concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM.
+ virtual void DefineFile(const string& name, int32 file_num,
+ uint32 dir_num, uint64 mod_time, uint64 length);
+
+
+ // Called when the line info reader has a new line, address pair
+ // ready for us. ADDRESS is the address of the code, LENGTH is the
+ // length of its machine code in bytes, FILE_NUM is the file number
+ // containing the code, LINE_NUM is the line number in that file for
+ // the code, and COLUMN_NUM is the column number the code starts at,
+ // if we know it (0 otherwise).
+ virtual void AddLine(uint64 address, uint64 length,
+ uint32 file_num, uint32 line_num, uint32 column_num);
+
+ private:
+ LineMap* linemap_;
+ std::vector<SourceFileInfo>* files_;
+ std::vector<string>* dirs_;
+};
+
+class CUFunctionInfoHandler: public Dwarf2Handler {
+ public:
+ CUFunctionInfoHandler(std::vector<SourceFileInfo>* files,
+ std::vector<string>* dirs,
+ LineMap* linemap,
+ FunctionMap* offset_to_funcinfo,
+ FunctionMap* address_to_funcinfo,
+ CULineInfoHandler* linehandler,
+ const SectionMap& sections,
+ ByteReader* reader)
+ : files_(files), dirs_(dirs), linemap_(linemap),
+ offset_to_funcinfo_(offset_to_funcinfo),
+ address_to_funcinfo_(address_to_funcinfo),
+ linehandler_(linehandler), sections_(sections),
+ reader_(reader), current_function_info_(NULL) { }
+
+ virtual ~CUFunctionInfoHandler() { }
+
+ // Start to process a compilation unit at OFFSET from the beginning of the
+ // .debug_info section. We want to see all compilation units, so we
+ // always return true.
+
+ virtual bool StartCompilationUnit(uint64 offset, uint8 address_size,
+ uint8 offset_size, uint64 cu_length,
+ uint8 dwarf_version);
+
+ // Start to process a DIE at OFFSET from the beginning of the
+ // .debug_info section. We only care about function related DIE's.
+ virtual bool StartDIE(uint64 offset, enum DwarfTag tag);
+
+ // Called when we have an attribute with unsigned data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of the .debug_info section, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA.
+ virtual void ProcessAttributeUnsigned(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data);
+
+ // Called when we have an attribute with a DIE reference to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of the .debug_info section, has a name of ATTR, a form of
+ // FORM, and the offset of the referenced DIE from the start of the
+ // .debug_info section is in DATA.
+ virtual void ProcessAttributeReference(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ uint64 data);
+
+ // Called when we have an attribute with string data to give to
+ // our handler. The attribute is for the DIE at OFFSET from the
+ // beginning of the .debug_info section, has a name of ATTR, a form of
+ // FORM, and the actual data of the attribute is in DATA.
+ virtual void ProcessAttributeString(uint64 offset,
+ enum DwarfAttribute attr,
+ enum DwarfForm form,
+ const string& data);
+
+ // Called when finished processing the DIE at OFFSET.
+ // Because DWARF2/3 specifies a tree of DIEs, you may get starts
+ // before ends of the previous DIE, as we process children before
+ // ending the parent.
+ virtual void EndDIE(uint64 offset);
+
+ private:
+ std::vector<SourceFileInfo>* files_;
+ std::vector<string>* dirs_;
+ LineMap* linemap_;
+ FunctionMap* offset_to_funcinfo_;
+ FunctionMap* address_to_funcinfo_;
+ CULineInfoHandler* linehandler_;
+ const SectionMap& sections_;
+ ByteReader* reader_;
+ FunctionInfo* current_function_info_;
+ uint64 current_compilation_unit_offset_;
+};
+
+} // namespace dwarf2reader
+#endif // COMMON_DWARF_FUNCTIONINFO_H__
diff --git a/3rdParty/Breakpad/src/common/dwarf/types.h b/3rdParty/Breakpad/src/common/dwarf/types.h
index 61ca457..59dda31 100644
--- a/3rdParty/Breakpad/src/common/dwarf/types.h
+++ b/3rdParty/Breakpad/src/common/dwarf/types.h
@@ -45,11 +45,7 @@ typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
-#ifdef __PTRDIFF_TYPE__
-typedef __PTRDIFF_TYPE__ intptr;
-typedef unsigned __PTRDIFF_TYPE__ uintptr;
-#else
-#error "Can't find pointer-sized integral types."
-#endif
+typedef intptr_t intptr;
+typedef uintptr_t uintptr;
#endif // _COMMON_DWARF_TYPES_H__
diff --git a/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.cc b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.cc
index 15904d7..bd298a2 100644
--- a/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.cc
+++ b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.cc
@@ -105,6 +105,43 @@ vector<string> DwarfCFIToModule::RegisterNames::ARM() {
return MakeVector(names, sizeof(names) / sizeof(names[0]));
}
+// Per ARM IHI 0057A, section 3.1
+vector<string> DwarfCFIToModule::RegisterNames::ARM64() {
+ static const char *const names[] = {
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+ };
+
+ return MakeVector(names, sizeof(names) / sizeof(names[0]));
+}
+
+vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
+ static const char* const kRegisterNames[] = {
+ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+ "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
+ "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+ "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+ "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5",
+ "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13",
+ "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20",
+ "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
+ "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir"
+ };
+
+ return MakeVector(kRegisterNames,
+ sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
+}
+
bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
uint8 version, const string &augmentation,
unsigned return_address) {
@@ -158,7 +195,7 @@ void DwarfCFIToModule::Record(Module::Address address, int reg,
// Place the name in our global set of strings, and then use the string
// from the set. Even though the assignment looks like a copy, all the
- // major std::string implementations use reference counting internally,
+ // major string implementations use reference counting internally,
// so the effect is to have all our data structures share copies of rules
// whenever possible. Since register names are drawn from a
// vector<string>, register names are already shared.
diff --git a/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.h b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.h
index 7db552a..a5302e1 100644
--- a/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.h
+++ b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module.h
@@ -109,6 +109,12 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// ARM.
static vector<string> ARM();
+ // ARM64, aka AARCH64.
+ static vector<string> ARM64();
+
+ // MIPS.
+ static vector<string> MIPS();
+
private:
// Given STRINGS, an array of C strings with SIZE elements, return an
// equivalent vector<string>.
@@ -175,15 +181,15 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// The names of the return address and canonical frame address. Putting
// these here instead of using string literals allows us to share their
- // texts in reference-counted std::string implementations (all the
+ // texts in reference-counted string implementations (all the
// popular ones). Many, many rules cite these strings.
string cfa_name_, ra_name_;
// A set of strings used by this CFI. Before storing a string in one of
// our data structures, insert it into this set, and then use the string
// from the set.
- //
- // Because std::string uses reference counting internally, simply using
+ //
+ // Because string uses reference counting internally, simply using
// strings from this set, even if passed by value, assigned, or held
// directly in structures and containers (map<string, ...>, for example),
// causes those strings to share a single instance of each distinct piece
diff --git a/3rdParty/Breakpad/src/common/dwarf_cfi_to_module_unittest.cc b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module_unittest.cc
new file mode 100644
index 0000000..807d1b2
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf_cfi_to_module_unittest.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
+
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf_cfi_to_module.h"
+#include "common/using_std_string.h"
+
+using std::vector;
+
+using google_breakpad::Module;
+using google_breakpad::DwarfCFIToModule;
+using testing::ContainerEq;
+using testing::Test;
+using testing::_;
+
+struct MockCFIReporter: public DwarfCFIToModule::Reporter {
+ MockCFIReporter(const string &file, const string &section)
+ : Reporter(file, section) { }
+ MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
+ MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string &reg));
+ MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string &reg));
+};
+
+struct DwarfCFIToModuleFixture {
+ DwarfCFIToModuleFixture()
+ : module("module name", "module os", "module arch", "module id"),
+ reporter("reporter file", "reporter section"),
+ handler(&module, register_names, &reporter) {
+ register_names.push_back("reg0");
+ register_names.push_back("reg1");
+ register_names.push_back("reg2");
+ register_names.push_back("reg3");
+ register_names.push_back("reg4");
+ register_names.push_back("reg5");
+ register_names.push_back("reg6");
+ register_names.push_back("reg7");
+ register_names.push_back("sp");
+ register_names.push_back("pc");
+ register_names.push_back("");
+
+ EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
+ EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
+ EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
+ }
+
+ Module module;
+ vector<string> register_names;
+ MockCFIReporter reporter;
+ DwarfCFIToModule handler;
+ vector<Module::StackFrameEntry *> entries;
+};
+
+class Entry: public DwarfCFIToModuleFixture, public Test { };
+
+TEST_F(Entry, Accept) {
+ ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
+ 0xb440ce248169c8d6ULL, 3, "", 0xea93c106));
+ ASSERT_TRUE(handler.End());
+ module.GetStackFrameEntries(&entries);
+ EXPECT_EQ(1U, entries.size());
+ EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address);
+ EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size);
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Entry, AcceptOldVersion) {
+ ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL,
+ 0xc771f44958d40bbcULL, 1, "", 0x093c945e));
+ ASSERT_TRUE(handler.End());
+ module.GetStackFrameEntries(&entries);
+ EXPECT_EQ(1U, entries.size());
+ EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address);
+ EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size);
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+struct RuleFixture: public DwarfCFIToModuleFixture {
+ RuleFixture() : DwarfCFIToModuleFixture() {
+ entry_address = 0x89327ebf86b47492ULL;
+ entry_size = 0x2f8cd573072fe02aULL;
+ return_reg = 0x7886a346;
+ }
+ void StartEntry() {
+ ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size,
+ 3, "", return_reg));
+ }
+ void CheckEntry() {
+ module.GetStackFrameEntries(&entries);
+ EXPECT_EQ(1U, entries.size());
+ EXPECT_EQ(entry_address, entries[0]->address);
+ EXPECT_EQ(entry_size, entries[0]->size);
+ }
+ uint64 entry_address, entry_size;
+ unsigned return_reg;
+};
+
+class Rule: public RuleFixture, public Test { };
+
+TEST_F(Rule, UndefinedRule) {
+ EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
+ StartEntry();
+ ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, RegisterWithEmptyName) {
+ EXPECT_CALL(reporter, UnnamedRegister(_, 10));
+ EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10"));
+ StartEntry();
+ ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, SameValueRule) {
+ StartEntry();
+ ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ Module::RuleMap expected_initial;
+ expected_initial["reg6"] = "reg6";
+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, OffsetRule) {
+ StartEntry();
+ ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
+ DwarfCFIToModule::kCFARegister,
+ 16927065));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ Module::RuleChangeMap expected_changes;
+ expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^";
+ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
+}
+
+TEST_F(Rule, OffsetRuleNegative) {
+ StartEntry();
+ ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
+ DwarfCFIToModule::kCFARegister, 4, -34530721));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ Module::RuleChangeMap expected_changes;
+ expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^";
+ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
+}
+
+TEST_F(Rule, ValOffsetRule) {
+ // Use an unnamed register number, to exercise that branch of RegisterName.
+ EXPECT_CALL(reporter, UnnamedRegister(_, 11));
+ StartEntry();
+ ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
+ DwarfCFIToModule::kCFARegister,
+ 11, 61812979));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ Module::RuleChangeMap expected_changes;
+ expected_changes[entry_address + 0x5ab7][".cfa"] =
+ "unnamed_register11 61812979 +";
+ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
+}
+
+TEST_F(Rule, RegisterRule) {
+ StartEntry();
+ ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ Module::RuleMap expected_initial;
+ expected_initial[".ra"] = "reg3";
+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, ExpressionRule) {
+ EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
+ StartEntry();
+ ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
+ "it takes two to tango"));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, ValExpressionRule) {
+ EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
+ StartEntry();
+ ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
+ "bit off more than he could chew"));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ EXPECT_EQ(0U, entries[0]->initial_rules.size());
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, DefaultReturnAddressRule) {
+ return_reg = 2;
+ StartEntry();
+ ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ Module::RuleMap expected_initial;
+ expected_initial[".ra"] = "reg2";
+ expected_initial["reg0"] = "reg1";
+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, DefaultReturnAddressRuleOverride) {
+ return_reg = 2;
+ StartEntry();
+ ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ Module::RuleMap expected_initial;
+ expected_initial[".ra"] = "reg1";
+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
+ EXPECT_EQ(0U, entries[0]->rule_changes.size());
+}
+
+TEST_F(Rule, DefaultReturnAddressRuleLater) {
+ return_reg = 2;
+ StartEntry();
+ ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
+ ASSERT_TRUE(handler.End());
+ CheckEntry();
+ Module::RuleMap expected_initial;
+ expected_initial[".ra"] = "reg2";
+ EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
+ Module::RuleChangeMap expected_changes;
+ expected_changes[entry_address + 1][".ra"] = "reg1";
+ EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
+}
+
+TEST(RegisterNames, I386) {
+ vector<string> names = DwarfCFIToModule::RegisterNames::I386();
+
+ EXPECT_EQ("$eax", names[0]);
+ EXPECT_EQ("$ecx", names[1]);
+ EXPECT_EQ("$esp", names[4]);
+ EXPECT_EQ("$eip", names[8]);
+}
+
+TEST(RegisterNames, ARM) {
+ vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
+
+ EXPECT_EQ("r0", names[0]);
+ EXPECT_EQ("r10", names[10]);
+ EXPECT_EQ("sp", names[13]);
+ EXPECT_EQ("lr", names[14]);
+ EXPECT_EQ("pc", names[15]);
+}
+
+TEST(RegisterNames, X86_64) {
+ vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
+
+ EXPECT_EQ("$rax", names[0]);
+ EXPECT_EQ("$rdx", names[1]);
+ EXPECT_EQ("$rbp", names[6]);
+ EXPECT_EQ("$rsp", names[7]);
+ EXPECT_EQ("$rip", names[16]);
+}
diff --git a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
index ded5f83..a16bee7 100644
--- a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
+++ b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.cc
@@ -40,23 +40,24 @@
#include <assert.h>
#include <inttypes.h>
+#include <stdint.h>
#include <stdio.h>
#include <algorithm>
-#include <set>
#include <utility>
#include "common/dwarf_line_to_module.h"
+#include "common/unordered.h"
namespace google_breakpad {
using std::map;
using std::pair;
-using std::set;
+using std::sort;
using std::vector;
// Data provided by a DWARF specification DIE.
-//
+//
// In DWARF, the DIE for a definition may contain a DW_AT_specification
// attribute giving the offset of the corresponding declaration DIE, and
// the definition DIE may omit information given in the declaration. For
@@ -73,6 +74,9 @@ using std::vector;
// A Specification holds information gathered from a declaration DIE that
// we may need if we find a DW_AT_specification link pointing to it.
struct DwarfCUToModule::Specification {
+ // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name.
+ string qualified_name;
+
// The name of the enclosing scope, or the empty string if there is none.
string enclosing_name;
@@ -84,7 +88,7 @@ struct DwarfCUToModule::Specification {
// An abstract origin -- base definition of an inline function.
struct AbstractOrigin {
AbstractOrigin() : name() {}
- AbstractOrigin(const string& name) : name(name) {}
+ explicit AbstractOrigin(const string& name) : name(name) {}
string name;
};
@@ -97,13 +101,21 @@ struct DwarfCUToModule::FilePrivate {
// A set of strings used in this CU. Before storing a string in one of
// our data structures, insert it into this set, and then use the string
// from the set.
- //
- // Because std::string uses reference counting internally, simply using
- // strings from this set, even if passed by value, assigned, or held
- // directly in structures and containers (map<string, ...>, for example),
- // causes those strings to share a single instance of each distinct piece
- // of text.
- set<string> common_strings;
+ //
+ // In some STL implementations, strings are reference-counted internally,
+ // meaning that simply using strings from this set, even if passed by
+ // value, assigned, or held directly in structures and containers
+ // (map<string, ...>, for example), causes those strings to share a
+ // single instance of each distinct piece of text. GNU's libstdc++ uses
+ // reference counts, and I believe MSVC did as well, at some point.
+ // However, C++ '11 implementations are moving away from reference
+ // counting.
+ //
+ // In other implementations, string assignments copy the string's text,
+ // so this set will actually hold yet another copy of the string (although
+ // everything will still work). To improve memory consumption portably,
+ // we will probably need to use pointers to strings held in this set.
+ unordered_set<string> common_strings;
// A map from offsets of DIEs within the .debug_info section to
// Specifications describing those DIEs. Specification references can
@@ -113,14 +125,42 @@ struct DwarfCUToModule::FilePrivate {
AbstractOriginByOffset origins;
};
-DwarfCUToModule::FileContext::FileContext(const string &filename_arg,
- Module *module_arg)
- : filename(filename_arg), module(module_arg) {
- file_private = new FilePrivate();
+DwarfCUToModule::FileContext::FileContext(const string &filename,
+ Module *module,
+ bool handle_inter_cu_refs)
+ : filename_(filename),
+ module_(module),
+ handle_inter_cu_refs_(handle_inter_cu_refs),
+ file_private_(new FilePrivate()) {
}
DwarfCUToModule::FileContext::~FileContext() {
- delete file_private;
+}
+
+void DwarfCUToModule::FileContext::AddSectionToSectionMap(
+ const string& name, const uint8_t *contents, uint64 length) {
+ section_map_[name] = std::make_pair(contents, length);
+}
+
+void DwarfCUToModule::FileContext::ClearSectionMapForTest() {
+ section_map_.clear();
+}
+
+const dwarf2reader::SectionMap&
+DwarfCUToModule::FileContext::section_map() const {
+ return section_map_;
+}
+
+void DwarfCUToModule::FileContext::ClearSpecifications() {
+ if (!handle_inter_cu_refs_)
+ file_private_->specifications.clear();
+}
+
+bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference(
+ uint64 offset, uint64 compilation_unit_start) const {
+ if (handle_inter_cu_refs_)
+ return false;
+ return offset < compilation_unit_start;
}
// Information global to the particular compilation unit we're
@@ -130,11 +170,13 @@ struct DwarfCUToModule::CUContext {
CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg)
: file_context(file_context_arg),
reporter(reporter_arg),
- language(Language::CPlusPlus) { }
+ language(Language::CPlusPlus) {}
+
~CUContext() {
for (vector<Module::Function *>::iterator it = functions.begin();
- it != functions.end(); it++)
+ it != functions.end(); ++it) {
delete *it;
+ }
};
// The DWARF-bearing file into which this CU was incorporated.
@@ -218,6 +260,14 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
DIEContext *parent_context_;
uint64 offset_;
+ // Place the name in the global set of strings. Even though this looks
+ // like a copy, all the major string implementations use reference
+ // counting internally, so the effect is to have all the data structures
+ // share copies of strings whenever possible.
+ // FIXME: Should this return something like a string_ref to avoid the
+ // assumption about how strings are implemented?
+ string AddStringToPool(const string &str);
+
// If this DIE has a DW_AT_declaration attribute, this is its value.
// It is false on DIEs with no DW_AT_declaration attribute.
bool declaration_;
@@ -230,6 +280,11 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// The value of the DW_AT_name attribute, or the empty string if the
// DIE has no such attribute.
string name_attribute_;
+
+ // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty
+ // string if the DIE has no such attribute or its content could not be
+ // demangled.
+ string demangled_name_;
};
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned(
@@ -248,14 +303,19 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
uint64 data) {
switch (attr) {
case dwarf2reader::DW_AT_specification: {
+ FileContext *file_context = cu_context_->file_context;
+ if (file_context->IsUnhandledInterCUReference(
+ data, cu_context_->reporter->cu_offset())) {
+ cu_context_->reporter->UnhandledInterCUReference(offset_, data);
+ break;
+ }
// Find the Specification to which this attribute refers, and
// set specification_ appropriately. We could do more processing
// here, but it's better to leave the real work to our
// EndAttribute member function, at which point we know we have
// seen all the DIE's attributes.
- FileContext *file_context = cu_context_->file_context;
- SpecificationByOffset *specifications
- = &file_context->file_private->specifications;
+ SpecificationByOffset *specifications =
+ &file_context->file_private_->specifications;
SpecificationByOffset::iterator spec = specifications->find(data);
if (spec != specifications->end()) {
specification_ = &spec->second;
@@ -273,20 +333,37 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
}
}
+string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
+ pair<unordered_set<string>::iterator, bool> result =
+ cu_context_->file_context->file_private_->common_strings.insert(str);
+ return *result.first;
+}
+
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
switch (attr) {
- case dwarf2reader::DW_AT_name: {
- // Place the name in our global set of strings, and then use the
- // string from the set. Even though the assignment looks like a copy,
- // all the major std::string implementations use reference counting
- // internally, so the effect is to have all our data structures share
- // copies of strings whenever possible.
- pair<set<string>::iterator, bool> result =
- cu_context_->file_context->file_private->common_strings.insert(data);
- name_attribute_ = *result.first;
+ case dwarf2reader::DW_AT_name:
+ name_attribute_ = AddStringToPool(data);
+ break;
+ case dwarf2reader::DW_AT_MIPS_linkage_name:
+ case dwarf2reader::DW_AT_linkage_name: {
+ string demangled;
+ Language::DemangleResult result =
+ cu_context_->language->DemangleName(data, &demangled);
+ switch (result) {
+ case Language::kDemangleSuccess:
+ demangled_name_ = AddStringToPool(demangled);
+ break;
+
+ case Language::kDemangleFailure:
+ cu_context_->reporter->DemangleError(data);
+ // fallthrough
+ case Language::kDontDemangle:
+ demangled_name_.clear();
+ break;
+ }
break;
}
default: break;
@@ -294,37 +371,64 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
}
string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
- // Find our unqualified name. If the DIE has its own DW_AT_name
- // attribute, then use that; otherwise, check our specification.
- const string *unqualified_name;
- if (name_attribute_.empty() && specification_)
- unqualified_name = &specification_->unqualified_name;
- else
- unqualified_name = &name_attribute_;
-
- // Find the name of our enclosing context. If we have a
- // specification, it's the specification's enclosing context that
- // counts; otherwise, use this DIE's context.
+ // Use the demangled name, if one is available. Demangled names are
+ // preferable to those inferred from the DWARF structure because they
+ // include argument types.
+ const string *qualified_name = NULL;
+ if (!demangled_name_.empty()) {
+ // Found it is this DIE.
+ qualified_name = &demangled_name_;
+ } else if (specification_ && !specification_->qualified_name.empty()) {
+ // Found it on the specification.
+ qualified_name = &specification_->qualified_name;
+ }
+
+ const string *unqualified_name = NULL;
const string *enclosing_name;
- if (specification_)
- enclosing_name = &specification_->enclosing_name;
- else
- enclosing_name = &parent_context_->name;
+ if (!qualified_name) {
+ // Find the unqualified name. If the DIE has its own DW_AT_name
+ // attribute, then use that; otherwise, check the specification.
+ if (!name_attribute_.empty())
+ unqualified_name = &name_attribute_;
+ else if (specification_)
+ unqualified_name = &specification_->unqualified_name;
+
+ // Find the name of the enclosing context. If this DIE has a
+ // specification, it's the specification's enclosing context that
+ // counts; otherwise, use this DIE's context.
+ if (specification_)
+ enclosing_name = &specification_->enclosing_name;
+ else
+ enclosing_name = &parent_context_->name;
+ }
+
+ // Prepare the return value before upcoming mutations possibly invalidate the
+ // existing pointers.
+ string return_value;
+ if (qualified_name) {
+ return_value = *qualified_name;
+ } else if (unqualified_name && enclosing_name) {
+ // Combine the enclosing name and unqualified name to produce our
+ // own fully-qualified name.
+ return_value = cu_context_->language->MakeQualifiedName(*enclosing_name,
+ *unqualified_name);
+ }
// If this DIE was marked as a declaration, record its names in the
// specification table.
- if (declaration_) {
- FileContext *file_context = cu_context_->file_context;
+ if ((declaration_ && qualified_name) ||
+ (unqualified_name && enclosing_name)) {
Specification spec;
- spec.enclosing_name = *enclosing_name;
- spec.unqualified_name = *unqualified_name;
- file_context->file_private->specifications[offset_] = spec;
+ if (qualified_name) {
+ spec.qualified_name = *qualified_name;
+ } else {
+ spec.enclosing_name = *enclosing_name;
+ spec.unqualified_name = *unqualified_name;
+ }
+ cu_context_->file_context->file_private_->specifications[offset_] = spec;
}
- // Combine the enclosing name and unqualified name to produce our
- // own fully-qualified name.
- return cu_context_->language->MakeQualifiedName(*enclosing_name,
- *unqualified_name);
+ return return_value;
}
// A handler class for DW_TAG_subprogram DIEs.
@@ -333,7 +437,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
FuncHandler(CUContext *cu_context, DIEContext *parent_context,
uint64 offset)
: GenericDIEHandler(cu_context, parent_context, offset),
- low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { }
+ low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr),
+ abstract_origin_(NULL), inline_(false) { }
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data);
@@ -352,6 +457,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
// specification_, parent_context_. Computed in EndAttributes.
string name_;
uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc
+ DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address.
const AbstractOrigin* abstract_origin_;
bool inline_;
};
@@ -367,7 +473,11 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
case dwarf2reader::DW_AT_inline: inline_ = true; break;
case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break;
- case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break;
+ case dwarf2reader::DW_AT_high_pc:
+ high_pc_form_ = form;
+ high_pc_ = data;
+ break;
+
default:
GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
break;
@@ -393,10 +503,10 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeReference(
enum DwarfAttribute attr,
enum DwarfForm form,
uint64 data) {
- switch(attr) {
+ switch (attr) {
case dwarf2reader::DW_AT_abstract_origin: {
const AbstractOriginByOffset& origins =
- cu_context_->file_context->file_private->origins;
+ cu_context_->file_context->file_private_->origins;
AbstractOriginByOffset::const_iterator origin = origins.find(data);
if (origin != origins.end()) {
abstract_origin_ = &(origin->second);
@@ -421,33 +531,39 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() {
}
void DwarfCUToModule::FuncHandler::Finish() {
+ // Make high_pc_ an address, if it isn't already.
+ if (high_pc_form_ != dwarf2reader::DW_FORM_addr) {
+ high_pc_ += low_pc_;
+ }
+
// Did we collect the information we need? Not all DWARF function
// entries have low and high addresses (for example, inlined
// functions that were never used), but all the ones we're
// interested in cover a non-empty range of bytes.
if (low_pc_ < high_pc_) {
- // Create a Module::Function based on the data we've gathered, and
- // add it to the functions_ list.
- Module::Function *func = new Module::Function;
// Malformed DWARF may omit the name, but all Module::Functions must
// have names.
+ string name;
if (!name_.empty()) {
- func->name = name_;
+ name = name_;
} else {
cu_context_->reporter->UnnamedFunction(offset_);
- func->name = "<name omitted>";
+ name = "<name omitted>";
}
- func->address = low_pc_;
+
+ // Create a Module::Function based on the data we've gathered, and
+ // add it to the functions_ list.
+ scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
func->size = high_pc_ - low_pc_;
func->parameter_size = 0;
if (func->address) {
// If the function address is zero this is a sign that this function
// description is just empty debug data and should just be discarded.
- cu_context_->functions.push_back(func);
+ cu_context_->functions.push_back(func.release());
}
} else if (inline_) {
AbstractOrigin origin(name_);
- cu_context_->file_context->file_private->origins[offset_] = origin;
+ cu_context_->file_context->file_private_->origins[offset_] = origin;
}
}
@@ -459,8 +575,7 @@ class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler {
uint64 offset)
: GenericDIEHandler(cu_context, parent_context, offset) { }
bool EndAttributes();
- DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
- const AttributeList &attrs);
+ DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
private:
DIEContext child_context_; // A context for our children.
@@ -473,8 +588,7 @@ bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
uint64 offset,
- enum DwarfTag tag,
- const AttributeList &attrs) {
+ enum DwarfTag tag) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
return new FuncHandler(cu_context_, &child_context_, offset);
@@ -561,17 +675,31 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
filename_.c_str(), offset);
}
+void DwarfCUToModule::WarningReporter::DemangleError(const string &input) {
+ CUHeading();
+ fprintf(stderr, "%s: warning: failed to demangle %s\n",
+ filename_.c_str(), input.c_str());
+}
+
+void DwarfCUToModule::WarningReporter::UnhandledInterCUReference(
+ uint64 offset, uint64 target) {
+ CUHeading();
+ fprintf(stderr, "%s: warning: the DIE at offset 0x%llx has a "
+ "DW_FORM_ref_addr attribute with an inter-CU reference to "
+ "0x%llx, but inter-CU reference handling is turned off.\n",
+ filename_.c_str(), offset, target);
+}
+
DwarfCUToModule::DwarfCUToModule(FileContext *file_context,
- LineToModuleFunctor *line_reader,
+ LineToModuleHandler *line_reader,
WarningReporter *reporter)
- : line_reader_(line_reader), has_source_line_info_(false) {
- cu_context_ = new CUContext(file_context, reporter);
- child_context_ = new DIEContext();
+ : line_reader_(line_reader),
+ cu_context_(new CUContext(file_context, reporter)),
+ child_context_(new DIEContext()),
+ has_source_line_info_(false) {
}
DwarfCUToModule::~DwarfCUToModule() {
- delete cu_context_;
- delete child_context_;
}
void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr,
@@ -605,8 +733,16 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
- if (attr == dwarf2reader::DW_AT_name)
- cu_context_->reporter->SetCUName(data);
+ switch (attr) {
+ case dwarf2reader::DW_AT_name:
+ cu_context_->reporter->SetCUName(data);
+ break;
+ case dwarf2reader::DW_AT_comp_dir:
+ line_reader_->StartCompilationUnit(data);
+ break;
+ default:
+ break;
+ }
}
bool DwarfCUToModule::EndAttributes() {
@@ -615,16 +751,17 @@ bool DwarfCUToModule::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
uint64 offset,
- enum DwarfTag tag,
- const AttributeList &attrs) {
+ enum DwarfTag tag) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
- return new FuncHandler(cu_context_, child_context_, offset);
+ return new FuncHandler(cu_context_.get(), child_context_.get(), offset);
case dwarf2reader::DW_TAG_namespace:
case dwarf2reader::DW_TAG_class_type:
case dwarf2reader::DW_TAG_structure_type:
case dwarf2reader::DW_TAG_union_type:
- return new NamedScopeHandler(cu_context_, child_context_, offset);
+ case dwarf2reader::DW_TAG_module:
+ return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
+ offset);
default:
return NULL;
}
@@ -636,6 +773,14 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
cu_context_->language = Language::Java;
break;
+ case dwarf2reader::DW_LANG_Swift:
+ cu_context_->language = Language::Swift;
+ break;
+
+ case dwarf2reader::DW_LANG_Rust:
+ cu_context_->language = Language::Rust;
+ break;
+
// DWARF has no generic language code for assembly language; this is
// what the GNU toolchain uses.
case dwarf2reader::DW_LANG_Mips_Assembler:
@@ -649,7 +794,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
// Objective C and Objective C++ seem to create entries for
// methods whose DW_AT_name values are already fully-qualified:
// "-[Classname method:]". These appear at the top level.
- //
+ //
// DWARF data for C should never include namespaces or functions
// nested in struct types, but if it ever does, then C++'s
// notation is probably not a bad choice for that.
@@ -667,7 +812,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
void DwarfCUToModule::ReadSourceLines(uint64 offset) {
const dwarf2reader::SectionMap &section_map
- = cu_context_->file_context->section_map;
+ = cu_context_->file_context->section_map();
dwarf2reader::SectionMap::const_iterator map_entry
= section_map.find(".debug_line");
// Mac OS X puts DWARF data in sections whose names begin with "__"
@@ -678,14 +823,14 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
cu_context_->reporter->MissingSection(".debug_line");
return;
}
- const char *section_start = map_entry->second.first;
+ const uint8_t *section_start = map_entry->second.first;
uint64 section_length = map_entry->second.second;
if (offset >= section_length) {
cu_context_->reporter->BadLineInfoOffset(offset);
return;
}
- (*line_reader_)(section_start + offset, section_length - offset,
- cu_context_->file_context->module, &lines_);
+ line_reader_->ReadProgram(section_start + offset, section_length - offset,
+ cu_context_->file_context->module_, &lines_);
}
namespace {
@@ -715,9 +860,9 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// complexity from here on out is linear.
// Put both our functions and lines in order by address.
- sort(functions->begin(), functions->end(),
- Module::Function::CompareByAddress);
- sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
+ std::sort(functions->begin(), functions->end(),
+ Module::Function::CompareByAddress);
+ std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
// The last line that we used any piece of. We use this only for
// generating warnings.
@@ -852,7 +997,7 @@ void DwarfCUToModule::AssignLinesToFunctions() {
// both func and line begin after CURRENT. The next transition
// is the start of the next function or next line, whichever
// is earliest.
- assert (func || line);
+ assert(func || line);
if (func && line)
next_transition = std::min(func->address, line->address);
else if (func)
@@ -910,12 +1055,14 @@ void DwarfCUToModule::Finish() {
// Add our functions, which now have source lines assigned to them,
// to module_.
- cu_context_->file_context->module->AddFunctions(functions->begin(),
- functions->end());
+ cu_context_->file_context->module_->AddFunctions(functions->begin(),
+ functions->end());
// Ownership of the function objects has shifted from cu_context to
// the Module.
functions->clear();
+
+ cu_context_->file_context->ClearSpecifications();
}
bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
@@ -926,8 +1073,7 @@ bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
return dwarf_version >= 2;
}
-bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs) {
+bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag) {
// We don't deal with partial compilation units (the only other tag
// likely to be used for root DIE).
return tag == dwarf2reader::DW_TAG_compile_unit;
diff --git a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.h b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.h
index ac62846..a36b82b 100644
--- a/3rdParty/Breakpad/src/common/dwarf_cu_to_module.h
+++ b/3rdParty/Breakpad/src/common/dwarf_cu_to_module.h
@@ -39,6 +39,8 @@
#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__
#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__
+#include <stdint.h>
+
#include <string>
#include "common/language.h"
@@ -46,11 +48,11 @@
#include "common/dwarf/bytereader.h"
#include "common/dwarf/dwarf2diehandler.h"
#include "common/dwarf/dwarf2reader.h"
+#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
namespace google_breakpad {
-using dwarf2reader::AttributeList;
using dwarf2reader::DwarfAttribute;
using dwarf2reader::DwarfForm;
using dwarf2reader::DwarfLanguage;
@@ -66,7 +68,6 @@ using dwarf2reader::DwarfTag;
class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
struct FilePrivate;
public:
-
// Information global to the DWARF-bearing file we are processing,
// for use by DwarfCUToModule. Each DwarfCUToModule instance deals
// with a single compilation unit within the file, but information
@@ -74,40 +75,75 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// for filling it in appropriately (except for the 'file_private'
// field, which the constructor and destructor take care of), and
// then providing it to the DwarfCUToModule instance for each
- // compilation unit we process in that file.
- struct FileContext {
- FileContext(const string &filename_arg, Module *module_arg);
+ // compilation unit we process in that file. Set HANDLE_INTER_CU_REFS
+ // to true to handle debugging symbols with DW_FORM_ref_addr entries.
+ class FileContext {
+ public:
+ FileContext(const string &filename,
+ Module *module,
+ bool handle_inter_cu_refs);
~FileContext();
+ // Add CONTENTS of size LENGTH to the section map as NAME.
+ void AddSectionToSectionMap(const string& name,
+ const uint8_t *contents,
+ uint64 length);
+
+ // Clear the section map for testing.
+ void ClearSectionMapForTest();
+
+ const dwarf2reader::SectionMap& section_map() const;
+
+ private:
+ friend class DwarfCUToModule;
+
+ // Clears all the Specifications if HANDLE_INTER_CU_REFS_ is false.
+ void ClearSpecifications();
+
+ // Given an OFFSET and a CU that starts at COMPILATION_UNIT_START, returns
+ // true if this is an inter-compilation unit reference that is not being
+ // handled.
+ bool IsUnhandledInterCUReference(uint64 offset,
+ uint64 compilation_unit_start) const;
+
// The name of this file, for use in error messages.
- string filename;
+ const string filename_;
// A map of this file's sections, used for finding other DWARF
// sections that the .debug_info section may refer to.
- dwarf2reader::SectionMap section_map;
+ dwarf2reader::SectionMap section_map_;
// The Module to which we're contributing definitions.
- Module *module;
+ Module *module_;
+
+ // True if we are handling references between compilation units.
+ const bool handle_inter_cu_refs_;
// Inter-compilation unit data used internally by the handlers.
- FilePrivate *file_private;
+ scoped_ptr<FilePrivate> file_private_;
};
- // An abstract base class for functors that handle DWARF line data
+ // An abstract base class for handlers that handle DWARF line data
// for DwarfCUToModule. DwarfCUToModule could certainly just use
// dwarf2reader::LineInfo itself directly, but decoupling things
// this way makes unit testing a little easier.
- class LineToModuleFunctor {
+ class LineToModuleHandler {
public:
- LineToModuleFunctor() { }
- virtual ~LineToModuleFunctor() { }
+ LineToModuleHandler() { }
+ virtual ~LineToModuleHandler() { }
+
+ // Called at the beginning of a new compilation unit, prior to calling
+ // ReadProgram(). compilation_dir will indicate the path that the
+ // current compilation unit was compiled in, consistent with the
+ // DW_AT_comp_dir DIE.
+ virtual void StartCompilationUnit(const string& compilation_dir) = 0;
// Populate MODULE and LINES with source file names and code/line
// mappings, given a pointer to some DWARF line number data
// PROGRAM, and an overestimate of its size. Add no zero-length
// lines to LINES.
- virtual void operator()(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines) = 0;
+ virtual void ReadProgram(const uint8_t *program, uint64 length,
+ Module *module, vector<Module::Line> *lines) = 0;
};
// The interface DwarfCUToModule uses to report warnings. The member
@@ -165,9 +201,20 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// link.
virtual void UnnamedFunction(uint64 offset);
+ // __cxa_demangle() failed to demangle INPUT.
+ virtual void DemangleError(const string &input);
+
+ // The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
+ // FilePrivate did not retain the inter-CU specification data.
+ virtual void UnhandledInterCUReference(uint64 offset, uint64 target);
+
+ uint64 cu_offset() const {
+ return cu_offset_;
+ }
+
protected:
- string filename_;
- uint64 cu_offset_;
+ const string filename_;
+ const uint64 cu_offset_;
string cu_name_;
bool printed_cu_header_;
bool printed_unpaired_header_;
@@ -187,7 +234,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// unit's line number data. Use REPORTER to report problems with the
// data we find.
DwarfCUToModule(FileContext *file_context,
- LineToModuleFunctor *line_reader,
+ LineToModuleHandler *line_reader,
WarningReporter *reporter);
~DwarfCUToModule();
@@ -201,8 +248,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
enum DwarfForm form,
const string &data);
bool EndAttributes();
- DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
- const AttributeList &attrs);
+ DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
// Assign all our source Lines to the Functions that cover their
// addresses, and then add them to module_.
@@ -211,17 +257,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
bool StartCompilationUnit(uint64 offset, uint8 address_size,
uint8 offset_size, uint64 cu_length,
uint8 dwarf_version);
- bool StartRootDIE(uint64 offset, enum DwarfTag tag,
- const AttributeList& attrs);
+ bool StartRootDIE(uint64 offset, enum DwarfTag tag);
private:
-
// Used internally by the handler. Full definitions are in
// dwarf_cu_to_module.cc.
- struct FilePrivate;
- struct Specification;
struct CUContext;
struct DIEContext;
+ struct Specification;
class GenericDIEHandler;
class FuncHandler;
class NamedScopeHandler;
@@ -231,7 +274,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// Set this compilation unit's source language to LANGUAGE.
void SetLanguage(DwarfLanguage language);
-
+
// Read source line information at OFFSET in the .debug_line
// section. Record source files in module_, but record source lines
// in lines_; we apportion them to functions in
@@ -250,14 +293,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// owned by this DwarfCUToModule: the constructor sets them, and the
// destructor deletes them.
- // The functor to use to handle line number data.
- LineToModuleFunctor *line_reader_;
+ // The handler to use to handle line number data.
+ LineToModuleHandler *line_reader_;
// This compilation unit's context.
- CUContext *cu_context_;
+ scoped_ptr<CUContext> cu_context_;
// A context for our children.
- DIEContext *child_context_;
+ scoped_ptr<DIEContext> child_context_;
// True if this compilation unit has source line information.
bool has_source_line_info_;
@@ -272,6 +315,6 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
vector<Module::Line> lines_;
};
-} // namespace google_breakpad
+} // namespace google_breakpad
#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__
diff --git a/3rdParty/Breakpad/src/common/dwarf_cu_to_module_unittest.cc b/3rdParty/Breakpad/src/common/dwarf_cu_to_module_unittest.cc
new file mode 100644
index 0000000..2ce4a60
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf_cu_to_module_unittest.cc
@@ -0,0 +1,1852 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf_cu_to_module.h"
+#include "common/using_std_string.h"
+
+using std::make_pair;
+using std::vector;
+
+using dwarf2reader::DIEHandler;
+using dwarf2reader::DwarfTag;
+using dwarf2reader::DwarfAttribute;
+using dwarf2reader::DwarfForm;
+using dwarf2reader::DwarfInline;
+using dwarf2reader::RootDIEHandler;
+using google_breakpad::DwarfCUToModule;
+using google_breakpad::Module;
+
+using ::testing::_;
+using ::testing::AtMost;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::Test;
+using ::testing::TestWithParam;
+using ::testing::Values;
+using ::testing::ValuesIn;
+
+// Mock classes.
+
+class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler {
+ public:
+ MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir));
+ MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64 length,
+ Module *module, vector<Module::Line> *lines));
+};
+
+class MockWarningReporter: public DwarfCUToModule::WarningReporter {
+ public:
+ MockWarningReporter(const string &filename, uint64 cu_offset)
+ : DwarfCUToModule::WarningReporter(filename, cu_offset) { }
+ MOCK_METHOD1(SetCUName, void(const string &name));
+ MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target));
+ MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target));
+ MOCK_METHOD1(MissingSection, void(const string &section_name));
+ MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset));
+ MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function));
+ MOCK_METHOD1(UncoveredLine, void(const Module::Line &line));
+ MOCK_METHOD1(UnnamedFunction, void(uint64 offset));
+ MOCK_METHOD1(DemangleError, void(const string &input));
+ MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target));
+};
+
+// A fixture class including all the objects needed to handle a
+// compilation unit, and their entourage. It includes member functions
+// for doing common kinds of setup and tests.
+class CUFixtureBase {
+ public:
+ // If we have:
+ //
+ // vector<Module::Line> lines;
+ // AppendLinesFunctor appender(lines);
+ //
+ // then doing:
+ //
+ // appender(line_program, length, module, line_vector);
+ //
+ // will append lines to the end of line_vector. We can use this with
+ // MockLineToModuleHandler like this:
+ //
+ // MockLineToModuleHandler l2m;
+ // EXPECT_CALL(l2m, ReadProgram(_,_,_,_))
+ // .WillOnce(DoAll(Invoke(appender), Return()));
+ //
+ // in which case calling l2m with some line vector will append lines.
+ class AppendLinesFunctor {
+ public:
+ explicit AppendLinesFunctor(
+ const vector<Module::Line> *lines) : lines_(lines) { }
+ void operator()(const uint8_t *program, uint64 length,
+ Module *module, vector<Module::Line> *lines) {
+ lines->insert(lines->end(), lines_->begin(), lines_->end());
+ }
+ private:
+ const vector<Module::Line> *lines_;
+ };
+
+ CUFixtureBase()
+ : module_("module-name", "module-os", "module-arch", "module-id"),
+ file_context_("dwarf-filename", &module_, true),
+ language_(dwarf2reader::DW_LANG_none),
+ language_signed_(false),
+ appender_(&lines_),
+ reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL),
+ root_handler_(&file_context_, &line_reader_, &reporter_),
+ functions_filled_(false) {
+ // By default, expect no warnings to be reported, and expect the
+ // compilation unit's name to be provided. The test can override
+ // these expectations.
+ EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1);
+ EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0);
+ EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0);
+ EXPECT_CALL(reporter_, MissingSection(_)).Times(0);
+ EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0);
+ EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0);
+ EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0);
+ EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0);
+ EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0);
+
+ // By default, expect the line program reader not to be invoked. We
+ // may override this in StartCU.
+ EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0);
+ EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0);
+
+ // The handler will consult this section map to decide what to
+ // pass to our line reader.
+ file_context_.AddSectionToSectionMap(".debug_line",
+ dummy_line_program_,
+ dummy_line_size_);
+ }
+
+ // Add a line with the given address, size, filename, and line
+ // number to the end of the statement list the handler will receive
+ // when it invokes its LineToModuleHandler. Call this before calling
+ // StartCU.
+ void PushLine(Module::Address address, Module::Address size,
+ const string &filename, int line_number);
+
+ // Use LANGUAGE for the compilation unit. More precisely, arrange
+ // for StartCU to pass the compilation unit's root DIE a
+ // DW_AT_language attribute whose value is LANGUAGE.
+ void SetLanguage(dwarf2reader::DwarfLanguage language) {
+ language_ = language;
+ }
+
+ // If SIGNED true, have StartCU report DW_AT_language as a signed
+ // attribute; if false, have it report it as unsigned.
+ void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; }
+
+ // Call the handler this.root_handler_'s StartCompilationUnit and
+ // StartRootDIE member functions, passing it appropriate attributes as
+ // determined by prior calls to PushLine and SetLanguage. Leave
+ // this.root_handler_ ready to hear about children: call
+ // this.root_handler_.EndAttributes, but not this.root_handler_.Finish.
+ void StartCU();
+
+ // Have HANDLER process some strange attribute/form/value triples.
+ void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler);
+
+ // Start a child DIE of PARENT with the given tag and name. Leave
+ // the handler ready to hear about children: call EndAttributes, but
+ // not Finish.
+ DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag,
+ const string &name);
+
+ // Start a child DIE of PARENT with the given tag and a
+ // DW_AT_specification attribute whose value is SPECIFICATION. Leave
+ // the handler ready to hear about children: call EndAttributes, but
+ // not Finish. If NAME is non-zero, use it as the DW_AT_name
+ // attribute.
+ DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag,
+ uint64 specification, const char *name = NULL);
+
+ // Define a function as a child of PARENT with the given name, address, and
+ // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute
+ // will be written as an address; otherwise it will be written as the
+ // function's size. Call EndAttributes and Finish; one cannot define
+ // children of the defined function's DIE.
+ void DefineFunction(DIEHandler *parent, const string &name,
+ Module::Address address, Module::Address size,
+ const char* mangled_name,
+ DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr);
+
+ // Create a declaration DIE as a child of PARENT with the given
+ // offset, tag and name. If NAME is the empty string, don't provide
+ // a DW_AT_name attribute. Call EndAttributes and Finish.
+ void DeclarationDIE(DIEHandler *parent, uint64 offset,
+ DwarfTag tag, const string &name,
+ const string &mangled_name);
+
+ // Create a definition DIE as a child of PARENT with the given tag
+ // that refers to the declaration DIE at offset SPECIFICATION as its
+ // specification. If NAME is non-empty, pass it as the DW_AT_name
+ // attribute. If SIZE is non-zero, record ADDRESS and SIZE as
+ // low_pc/high_pc attributes.
+ void DefinitionDIE(DIEHandler *parent, DwarfTag tag,
+ uint64 specification, const string &name,
+ Module::Address address = 0, Module::Address size = 0);
+
+ // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If
+ // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at
+ // offset SPECIFICATION as its specification. If Name is non-empty, pass it
+ // as the DW_AT_name attribute.
+ void AbstractInstanceDIE(DIEHandler *parent, uint64 offset,
+ DwarfInline type, uint64 specification,
+ const string &name,
+ DwarfForm form = dwarf2reader::DW_FORM_data1);
+
+ // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to
+ // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty
+ // string, don't provide a DW_AT_name attribute.
+ void DefineInlineInstanceDIE(DIEHandler *parent, const string &name,
+ uint64 origin, Module::Address address,
+ Module::Address size);
+
+ // The following Test* functions should be called after calling
+ // this.root_handler_.Finish. After that point, no further calls
+ // should be made on the handler.
+
+ // Test that the number of functions defined in the module this.module_ is
+ // equal to EXPECTED.
+ void TestFunctionCount(size_t expected);
+
+ // Test that the I'th function (ordered by address) in the module
+ // this.module_ has the given name, address, and size, and that its
+ // parameter size is zero.
+ void TestFunction(int i, const string &name,
+ Module::Address address, Module::Address size);
+
+ // Test that the number of source lines owned by the I'th function
+ // in the module this.module_ is equal to EXPECTED.
+ void TestLineCount(int i, size_t expected);
+
+ // Test that the J'th line (ordered by address) of the I'th function
+ // (again, by address) has the given address, size, filename, and
+ // line number.
+ void TestLine(int i, int j, Module::Address address, Module::Address size,
+ const string &filename, int number);
+
+ // Actual objects under test.
+ Module module_;
+ DwarfCUToModule::FileContext file_context_;
+
+ // If this is not DW_LANG_none, we'll pass it as a DW_AT_language
+ // attribute to the compilation unit. This defaults to DW_LANG_none.
+ dwarf2reader::DwarfLanguage language_;
+
+ // If this is true, report DW_AT_language as a signed value; if false,
+ // report it as an unsigned value.
+ bool language_signed_;
+
+ // If this is not empty, we'll give the CU a DW_AT_comp_dir attribute that
+ // indicates the path that this compilation unit was compiled in.
+ string compilation_dir_;
+
+ // If this is not empty, we'll give the CU a DW_AT_stmt_list
+ // attribute that, when passed to line_reader_, adds these lines to the
+ // provided lines array.
+ vector<Module::Line> lines_;
+
+ // Mock line program reader.
+ MockLineToModuleHandler line_reader_;
+ AppendLinesFunctor appender_;
+ static const uint8_t dummy_line_program_[];
+ static const size_t dummy_line_size_;
+
+ MockWarningReporter reporter_;
+ DwarfCUToModule root_handler_;
+
+ private:
+ // Fill functions_, if we haven't already.
+ void FillFunctions();
+
+ // If functions_filled_ is true, this is a table of functions we've
+ // extracted from module_, sorted by address.
+ vector<Module::Function *> functions_;
+ // True if we have filled the above vector with this.module_'s function list.
+ bool functions_filled_;
+};
+
+const uint8_t CUFixtureBase::dummy_line_program_[] = "lots of fun data";
+const size_t CUFixtureBase::dummy_line_size_ =
+ sizeof(CUFixtureBase::dummy_line_program_);
+
+void CUFixtureBase::PushLine(Module::Address address, Module::Address size,
+ const string &filename, int line_number) {
+ Module::Line l;
+ l.address = address;
+ l.size = size;
+ l.file = module_.FindFile(filename);
+ l.number = line_number;
+ lines_.push_back(l);
+}
+
+void CUFixtureBase::StartCU() {
+ if (!compilation_dir_.empty())
+ EXPECT_CALL(line_reader_,
+ StartCompilationUnit(compilation_dir_)).Times(1);
+
+ // If we have lines, make the line reader expect to be invoked at
+ // most once. (Hey, if the handler can pass its tests without
+ // bothering to read the line number data, that's great.)
+ // Have it add the lines passed to PushLine. Otherwise, leave the
+ // initial expectation (no calls) in force.
+ if (!lines_.empty())
+ EXPECT_CALL(line_reader_,
+ ReadProgram(&dummy_line_program_[0], dummy_line_size_,
+ &module_, _))
+ .Times(AtMost(1))
+ .WillOnce(DoAll(Invoke(appender_), Return()));
+
+ ASSERT_TRUE(root_handler_
+ .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44,
+ 0x4241b4f33720dd5cULL, 3));
+ {
+ ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
+ dwarf2reader::DW_TAG_compile_unit));
+ }
+ root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ "compilation-unit-name");
+ if (!compilation_dir_.empty())
+ root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir,
+ dwarf2reader::DW_FORM_strp,
+ compilation_dir_);
+ if (!lines_.empty())
+ root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
+ dwarf2reader::DW_FORM_ref4,
+ 0);
+ if (language_ != dwarf2reader::DW_LANG_none) {
+ if (language_signed_)
+ root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language,
+ dwarf2reader::DW_FORM_sdata,
+ language_);
+ else
+ root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language,
+ dwarf2reader::DW_FORM_udata,
+ language_);
+ }
+ ASSERT_TRUE(root_handler_.EndAttributes());
+}
+
+void CUFixtureBase::ProcessStrangeAttributes(
+ dwarf2reader::DIEHandler *handler) {
+ handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead,
+ (DwarfForm) 0x4106e4db,
+ 0xa592571997facda1ULL);
+ handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095,
+ (DwarfForm) 0x0f16fe87,
+ 0x12602a4e3bf1f446LL);
+ handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f,
+ (DwarfForm) 0x829e038a,
+ 0x50fddef44734fdecULL);
+ static const uint8_t buffer[10] = "frobynode";
+ handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51,
+ (DwarfForm) 0x2f43b041,
+ buffer, sizeof(buffer));
+ handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041,
+ (DwarfForm) 0x895ffa23,
+ "strange string");
+}
+
+DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent,
+ DwarfTag tag,
+ const string &name) {
+ dwarf2reader::DIEHandler *handler
+ = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
+ if (!handler)
+ return NULL;
+ handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ ProcessStrangeAttributes(handler);
+ if (!handler->EndAttributes()) {
+ handler->Finish();
+ delete handler;
+ return NULL;
+ }
+
+ return handler;
+}
+
+DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
+ DwarfTag tag,
+ uint64 specification,
+ const char *name) {
+ dwarf2reader::DIEHandler *handler
+ = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag);
+ if (!handler)
+ return NULL;
+ if (name)
+ handler->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
+ dwarf2reader::DW_FORM_ref4,
+ specification);
+ if (!handler->EndAttributes()) {
+ handler->Finish();
+ delete handler;
+ return NULL;
+ }
+
+ return handler;
+}
+
+void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
+ const string &name, Module::Address address,
+ Module::Address size,
+ const char* mangled_name,
+ DwarfForm high_pc_form) {
+ dwarf2reader::DIEHandler *func
+ = parent->FindChildHandler(0xe34797c7e68590a8LL,
+ dwarf2reader::DW_TAG_subprogram);
+ ASSERT_TRUE(func != NULL);
+ func->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr,
+ address);
+
+ Module::Address high_pc = size;
+ if (high_pc_form == dwarf2reader::DW_FORM_addr) {
+ high_pc += address;
+ }
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
+ high_pc_form,
+ high_pc);
+
+ if (mangled_name)
+ func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
+ dwarf2reader::DW_FORM_strp,
+ mangled_name);
+
+ ProcessStrangeAttributes(func);
+ EXPECT_TRUE(func->EndAttributes());
+ func->Finish();
+ delete func;
+}
+
+void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset,
+ DwarfTag tag,
+ const string &name,
+ const string &mangled_name) {
+ dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag);
+ ASSERT_TRUE(die != NULL);
+ if (!name.empty())
+ die->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ if (!mangled_name.empty())
+ die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
+ dwarf2reader::DW_FORM_strp,
+ mangled_name);
+
+ die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration,
+ dwarf2reader::DW_FORM_flag,
+ 1);
+ EXPECT_TRUE(die->EndAttributes());
+ die->Finish();
+ delete die;
+}
+
+void CUFixtureBase::DefinitionDIE(DIEHandler *parent,
+ DwarfTag tag,
+ uint64 specification,
+ const string &name,
+ Module::Address address,
+ Module::Address size) {
+ dwarf2reader::DIEHandler *die
+ = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag);
+ ASSERT_TRUE(die != NULL);
+ die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
+ dwarf2reader::DW_FORM_ref4,
+ specification);
+ if (!name.empty())
+ die->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ if (size) {
+ die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr,
+ address);
+ die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
+ dwarf2reader::DW_FORM_addr,
+ address + size);
+ }
+ EXPECT_TRUE(die->EndAttributes());
+ die->Finish();
+ delete die;
+}
+
+void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent,
+ uint64 offset,
+ DwarfInline type,
+ uint64 specification,
+ const string &name,
+ DwarfForm form) {
+ dwarf2reader::DIEHandler *die
+ = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram);
+ ASSERT_TRUE(die != NULL);
+ if (specification != 0ULL)
+ die->ProcessAttributeReference(dwarf2reader::DW_AT_specification,
+ dwarf2reader::DW_FORM_ref4,
+ specification);
+ if (form == dwarf2reader::DW_FORM_sdata) {
+ die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type);
+ } else {
+ die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type);
+ }
+ if (!name.empty())
+ die->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+
+ EXPECT_TRUE(die->EndAttributes());
+ die->Finish();
+ delete die;
+}
+
+void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent,
+ const string &name,
+ uint64 origin,
+ Module::Address address,
+ Module::Address size) {
+ dwarf2reader::DIEHandler *func
+ = parent->FindChildHandler(0x11c70f94c6e87ccdLL,
+ dwarf2reader::DW_TAG_subprogram);
+ ASSERT_TRUE(func != NULL);
+ if (!name.empty()) {
+ func->ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ name);
+ }
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc,
+ dwarf2reader::DW_FORM_addr,
+ address);
+ func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
+ dwarf2reader::DW_FORM_addr,
+ address + size);
+ func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin,
+ dwarf2reader::DW_FORM_ref4,
+ origin);
+ ProcessStrangeAttributes(func);
+ EXPECT_TRUE(func->EndAttributes());
+ func->Finish();
+ delete func;
+}
+
+void CUFixtureBase::FillFunctions() {
+ if (functions_filled_)
+ return;
+ module_.GetFunctions(&functions_, functions_.end());
+ sort(functions_.begin(), functions_.end(),
+ Module::Function::CompareByAddress);
+ functions_filled_ = true;
+}
+
+void CUFixtureBase::TestFunctionCount(size_t expected) {
+ FillFunctions();
+ ASSERT_EQ(expected, functions_.size());
+}
+
+void CUFixtureBase::TestFunction(int i, const string &name,
+ Module::Address address,
+ Module::Address size) {
+ FillFunctions();
+ ASSERT_LT((size_t) i, functions_.size());
+
+ Module::Function *function = functions_[i];
+ EXPECT_EQ(name, function->name);
+ EXPECT_EQ(address, function->address);
+ EXPECT_EQ(size, function->size);
+ EXPECT_EQ(0U, function->parameter_size);
+}
+
+void CUFixtureBase::TestLineCount(int i, size_t expected) {
+ FillFunctions();
+ ASSERT_LT((size_t) i, functions_.size());
+
+ ASSERT_EQ(expected, functions_[i]->lines.size());
+}
+
+void CUFixtureBase::TestLine(int i, int j,
+ Module::Address address, Module::Address size,
+ const string &filename, int number) {
+ FillFunctions();
+ ASSERT_LT((size_t) i, functions_.size());
+ ASSERT_LT((size_t) j, functions_[i]->lines.size());
+
+ Module::Line *line = &functions_[i]->lines[j];
+ EXPECT_EQ(address, line->address);
+ EXPECT_EQ(size, line->size);
+ EXPECT_EQ(filename, line->file->name.c_str());
+ EXPECT_EQ(number, line->number);
+}
+
+// Include caller locations for our test subroutines.
+#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0)
+#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d)))
+#define SetLanguage(a) TRACE(SetLanguage(a))
+#define StartCU() TRACE(StartCU())
+#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e)))
+// (DefineFunction) instead of DefineFunction to avoid macro expansion.
+#define DefineFunction6(a,b,c,d,e,f) \
+ TRACE((DefineFunction)((a),(b),(c),(d),(e),(f)))
+#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e)))
+#define DefinitionDIE(a,b,c,d,e,f) \
+ TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f)))
+#define TestFunctionCount(a) TRACE(TestFunctionCount(a))
+#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d)))
+#define TestLineCount(a,b) TRACE(TestLineCount((a),(b)))
+#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f)))
+
+class SimpleCU: public CUFixtureBase, public Test {
+};
+
+TEST_F(SimpleCU, CompilationDir) {
+ compilation_dir_ = "/src/build/";
+
+ StartCU();
+ root_handler_.Finish();
+}
+
+TEST_F(SimpleCU, OneFunc) {
+ PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1",
+ 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file",
+ 246571772);
+}
+
+// As above, only DW_AT_high_pc is a length rather than an address.
+TEST_F(SimpleCU, OneFuncHighPcIsLength) {
+ PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
+
+ StartCU();
+ DefineFunction6(&root_handler_, "function1",
+ 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL,
+ dwarf2reader::DW_FORM_udata);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file",
+ 246571772);
+}
+
+TEST_F(SimpleCU, MangledName) {
+ PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1",
+ 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi");
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
+}
+
+TEST_F(SimpleCU, IrrelevantRootChildren) {
+ StartCU();
+ EXPECT_FALSE(root_handler_
+ .FindChildHandler(0x7db32bff4e2dcfb1ULL,
+ dwarf2reader::DW_TAG_lexical_block));
+}
+
+TEST_F(SimpleCU, IrrelevantNamedScopeChildren) {
+ StartCU();
+ DIEHandler *class_A_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
+ EXPECT_TRUE(class_A_handler != NULL);
+ EXPECT_FALSE(class_A_handler
+ ->FindChildHandler(0x02e55999b865e4e9ULL,
+ dwarf2reader::DW_TAG_lexical_block));
+ delete class_A_handler;
+}
+
+// Verify that FileContexts can safely be deleted unused.
+TEST_F(SimpleCU, UnusedFileContext) {
+ Module m("module-name", "module-os", "module-arch", "module-id");
+ DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
+
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+}
+
+TEST_F(SimpleCU, InlineFunction) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+TEST_F(SimpleCU, InlineFunctionSignedAttribute) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name",
+ dwarf2reader::DW_FORM_sdata);
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+// Any DIE with an DW_AT_inline attribute can be cited by
+// DW_AT_abstract_origin attributes --- even if the value of the
+// DW_AT_inline attribute is DW_INL_not_inlined.
+TEST_F(SimpleCU, AbstractOriginNotInlined) {
+ PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL,
+ dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance");
+ DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL,
+ 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "abstract-instance",
+ 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL);
+}
+
+TEST_F(SimpleCU, UnknownAbstractOrigin) {
+ EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return());
+ EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL))
+ .WillOnce(Return());
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0, "inline-name");
+ DefineInlineInstanceDIE(&root_handler_, "", 1ULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "<name omitted>",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+TEST_F(SimpleCU, UnnamedFunction) {
+ EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL))
+ .WillOnce(Return());
+ PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850);
+
+ StartCU();
+ DefineFunction(&root_handler_, "",
+ 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "<name omitted>",
+ 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL);
+}
+
+// An address range.
+struct Range {
+ Module::Address start, end;
+};
+
+// Test data for pairing functions and lines.
+struct Situation {
+ // Two function intervals, and two line intervals.
+ Range functions[2], lines[2];
+
+ // The number of lines we expect to be assigned to each of the
+ // functions, and the address ranges.
+ int paired_count[2];
+ Range paired[2][2];
+
+ // The number of functions that are not entirely covered by lines,
+ // and vice versa.
+ int uncovered_functions, uncovered_lines;
+};
+
+#define PAIRING(func1_start, func1_end, func2_start, func2_end, \
+ line1_start, line1_end, line2_start, line2_end, \
+ func1_num_lines, func2_num_lines, \
+ func1_line1_start, func1_line1_end, \
+ func1_line2_start, func1_line2_end, \
+ func2_line1_start, func2_line1_end, \
+ func2_line2_start, func2_line2_end, \
+ uncovered_functions, uncovered_lines) \
+ { { { func1_start, func1_end }, { func2_start, func2_end } }, \
+ { { line1_start, line1_end }, { line2_start, line2_end } }, \
+ { func1_num_lines, func2_num_lines }, \
+ { { { func1_line1_start, func1_line1_end }, \
+ { func1_line2_start, func1_line2_end } }, \
+ { { func2_line1_start, func2_line1_end }, \
+ { func2_line2_start, func2_line2_end } } }, \
+ uncovered_functions, uncovered_lines },
+
+Situation situations[] = {
+#include "common/testdata/func-line-pairing.h"
+};
+
+#undef PAIRING
+
+class FuncLinePairing: public CUFixtureBase,
+ public TestWithParam<Situation> { };
+
+INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing,
+ ValuesIn(situations));
+
+TEST_P(FuncLinePairing, Pairing) {
+ const Situation &s = GetParam();
+ PushLine(s.lines[0].start,
+ s.lines[0].end - s.lines[0].start,
+ "line-file", 67636963);
+ PushLine(s.lines[1].start,
+ s.lines[1].end - s.lines[1].start,
+ "line-file", 67636963);
+ if (s.uncovered_functions)
+ EXPECT_CALL(reporter_, UncoveredFunction(_))
+ .Times(s.uncovered_functions)
+ .WillRepeatedly(Return());
+ if (s.uncovered_lines)
+ EXPECT_CALL(reporter_, UncoveredLine(_))
+ .Times(s.uncovered_lines)
+ .WillRepeatedly(Return());
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1",
+ s.functions[0].start,
+ s.functions[0].end - s.functions[0].start, NULL);
+ DefineFunction(&root_handler_, "function2",
+ s.functions[1].start,
+ s.functions[1].end - s.functions[1].start, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "function1",
+ s.functions[0].start,
+ s.functions[0].end - s.functions[0].start);
+ TestLineCount(0, s.paired_count[0]);
+ for (int i = 0; i < s.paired_count[0]; i++)
+ TestLine(0, i, s.paired[0][i].start,
+ s.paired[0][i].end - s.paired[0][i].start,
+ "line-file", 67636963);
+ TestFunction(1, "function2",
+ s.functions[1].start,
+ s.functions[1].end - s.functions[1].start);
+ TestLineCount(1, s.paired_count[1]);
+ for (int i = 0; i < s.paired_count[1]; i++)
+ TestLine(1, i, s.paired[1][i].start,
+ s.paired[1][i].end - s.paired[1][i].start,
+ "line-file", 67636963);
+}
+
+TEST_F(FuncLinePairing, EmptyCU) {
+ StartCU();
+ root_handler_.Finish();
+
+ TestFunctionCount(0);
+}
+
+TEST_F(FuncLinePairing, LinesNoFuncs) {
+ PushLine(40, 2, "line-file", 82485646);
+ EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
+
+ StartCU();
+ root_handler_.Finish();
+
+ TestFunctionCount(0);
+}
+
+TEST_F(FuncLinePairing, FuncsNoLines) {
+ EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U,
+ NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U);
+}
+
+TEST_F(FuncLinePairing, GapThenFunction) {
+ PushLine(20, 2, "line-file-2", 174314698);
+ PushLine(10, 2, "line-file-1", 263008005);
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1", 10, 2, NULL);
+ DefineFunction(&root_handler_, "function2", 20, 2, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "function1", 10, 2);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 10, 2, "line-file-1", 263008005);
+ TestFunction(1, "function2", 20, 2);
+ TestLineCount(1, 1);
+ TestLine(1, 0, 20, 2, "line-file-2", 174314698);
+}
+
+// If GCC emits padding after one function to align the start of
+// the next, then it will attribute the padding instructions to
+// the last source line of function (to reduce the size of the
+// line number info), but omit it from the DW_AT_{low,high}_pc
+// range given in .debug_info (since it costs nothing to be
+// precise there). If we did use at least some of the line
+// we're about to skip, then assume this is what happened, and
+// don't warn.
+TEST_F(FuncLinePairing, GCCAlignmentStretch) {
+ PushLine(10, 10, "line-file", 63351048);
+ PushLine(20, 10, "line-file", 61661044);
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1", 10, 5, NULL);
+ // five-byte gap between functions, covered by line 63351048.
+ // This should not elicit a warning.
+ DefineFunction(&root_handler_, "function2", 20, 10, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "function1", 10, 5);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 10, 5, "line-file", 63351048);
+ TestFunction(1, "function2", 20, 10);
+ TestLineCount(1, 1);
+ TestLine(1, 0, 20, 10, "line-file", 61661044);
+}
+
+// Unfortunately, neither the DWARF parser's handler interface nor the
+// DIEHandler interface is capable of expressing a function that abuts
+// the end of the address space: the high_pc value looks like zero.
+
+TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) {
+ PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048);
+ EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL);
+ DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048);
+ TestFunction(1, "function2", 0xfffffffffffffffaULL, 5);
+ TestLineCount(1, 1);
+ TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048);
+}
+
+// A function with more than one uncovered area should only be warned
+// about once.
+TEST_F(FuncLinePairing, WarnOnceFunc) {
+ PushLine(20, 1, "line-file-2", 262951329);
+ PushLine(11, 1, "line-file-1", 219964021);
+ EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
+
+ StartCU();
+ DefineFunction(&root_handler_, "function", 10, 11, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "function", 10, 11);
+ TestLineCount(0, 2);
+ TestLine(0, 0, 11, 1, "line-file-1", 219964021);
+ TestLine(0, 1, 20, 1, "line-file-2", 262951329);
+}
+
+// A line with more than one uncovered area should only be warned
+// about once.
+TEST_F(FuncLinePairing, WarnOnceLine) {
+ PushLine(10, 20, "filename1", 118581871);
+ EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
+
+ StartCU();
+ DefineFunction(&root_handler_, "function1", 11, 1, NULL);
+ DefineFunction(&root_handler_, "function2", 13, 1, NULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "function1", 11, 1);
+ TestLineCount(0, 1);
+ TestLine(0, 0, 11, 1, "filename1", 118581871);
+ TestFunction(1, "function2", 13, 1);
+ TestLineCount(1, 1);
+ TestLine(1, 0, 13, 1, "filename1", 118581871);
+}
+
+class CXXQualifiedNames: public CUFixtureBase,
+ public TestWithParam<DwarfTag> { };
+
+INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames,
+ Values(dwarf2reader::DW_TAG_class_type,
+ dwarf2reader::DW_TAG_structure_type,
+ dwarf2reader::DW_TAG_union_type,
+ dwarf2reader::DW_TAG_namespace));
+
+TEST_P(CXXQualifiedNames, TwoFunctions) {
+ DwarfTag tag = GetParam();
+
+ SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ PushLine(10, 1, "filename1", 69819327);
+ PushLine(20, 1, "filename2", 95115701);
+
+ StartCU();
+ DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag,
+ "Enclosure");
+ EXPECT_TRUE(enclosure_handler != NULL);
+ DefineFunction(enclosure_handler, "func_B", 10, 1, NULL);
+ DefineFunction(enclosure_handler, "func_C", 20, 1, NULL);
+ enclosure_handler->Finish();
+ delete enclosure_handler;
+ root_handler_.Finish();
+
+ TestFunctionCount(2);
+ TestFunction(0, "Enclosure::func_B", 10, 1);
+ TestFunction(1, "Enclosure::func_C", 20, 1);
+}
+
+TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
+ DwarfTag tag = GetParam();
+
+ SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ PushLine(10, 1, "line-file", 69819327);
+
+ StartCU();
+ DIEHandler *namespace_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ "Namespace");
+ EXPECT_TRUE(namespace_handler != NULL);
+ DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag,
+ "Enclosure");
+ EXPECT_TRUE(enclosure_handler != NULL);
+ DefineFunction(enclosure_handler, "function", 10, 1, NULL);
+ enclosure_handler->Finish();
+ delete enclosure_handler;
+ namespace_handler->Finish();
+ delete namespace_handler;
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "Namespace::Enclosure::function", 10, 1);
+}
+
+TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
+ SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+ PushLine(10, 1, "filename1", 69819327);
+
+ StartCU();
+ DIEHandler *namespace_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ "namespace_A");
+ EXPECT_TRUE(namespace_handler != NULL);
+ DIEHandler *struct_handler
+ = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type,
+ "struct_B");
+ EXPECT_TRUE(struct_handler != NULL);
+ DIEHandler *class_handler
+ = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type,
+ "class_C");
+ DefineFunction(class_handler, "function_D", 10, 1, NULL);
+ class_handler->Finish();
+ delete class_handler;
+ struct_handler->Finish();
+ delete struct_handler;
+ namespace_handler->Finish();
+ delete namespace_handler;
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1);
+}
+
+struct LanguageAndQualifiedName {
+ dwarf2reader::DwarfLanguage language;
+ const char *name;
+};
+
+const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = {
+ { dwarf2reader::DW_LANG_none, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_C, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_C89, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_C99, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_Java, "class_A.function_B" },
+ { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" },
+ { dwarf2reader::DW_LANG_Mips_Assembler, NULL }
+};
+
+class QualifiedForLanguage
+ : public CUFixtureBase,
+ public TestWithParam<LanguageAndQualifiedName> { };
+
+INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage,
+ ValuesIn(LanguageAndQualifiedNameCases));
+
+TEST_P(QualifiedForLanguage, MemberFunction) {
+ const LanguageAndQualifiedName &param = GetParam();
+
+ PushLine(10, 1, "line-file", 212966758);
+ SetLanguage(param.language);
+
+ StartCU();
+ DIEHandler *class_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ "class_A");
+ DefineFunction(class_handler, "function_B", 10, 1, NULL);
+ class_handler->Finish();
+ delete class_handler;
+ root_handler_.Finish();
+
+ if (param.name) {
+ TestFunctionCount(1);
+ TestFunction(0, param.name, 10, 1);
+ } else {
+ TestFunctionCount(0);
+ }
+}
+
+TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) {
+ const LanguageAndQualifiedName &param = GetParam();
+
+ PushLine(10, 1, "line-file", 212966758);
+ SetLanguage(param.language);
+ SetLanguageSigned(true);
+
+ StartCU();
+ DIEHandler *class_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ "class_A");
+ DefineFunction(class_handler, "function_B", 10, 1, NULL);
+ class_handler->Finish();
+ delete class_handler;
+ root_handler_.Finish();
+
+ if (param.name) {
+ TestFunctionCount(1);
+ TestFunction(0, param.name, 10, 1);
+ } else {
+ TestFunctionCount(0);
+ }
+}
+
+class Specifications: public CUFixtureBase, public Test { };
+
+TEST_F(Specifications, Function) {
+ PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0xcd3c51b946fb1eeeLL, "",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "declaration-name",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+}
+
+TEST_F(Specifications, MangledName) {
+ // Language defaults to C++, so no need to set it here.
+ PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ "_ZN1C1fEi");
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0xcd3c51b946fb1eeeLL, "",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "C::f(int)",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+}
+
+TEST_F(Specifications, MangledNameSwift) {
+ // Swift mangled names should pass through untouched.
+ SetLanguage(dwarf2reader::DW_LANG_Swift);
+ PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
+ StartCU();
+ const string kName = "_TFC9swifttest5Shape17simpleDescriptionfS0_FT_Si";
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ kName);
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0xcd3c51b946fb1eeeLL, "",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, kName,
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+}
+
+TEST_F(Specifications, MangledNameRust) {
+ SetLanguage(dwarf2reader::DW_LANG_Rust);
+ PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
+
+ StartCU();
+ const string kName = "_ZN14rustc_demangle8demangle17h373defa94bffacdeE";
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name",
+ kName);
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0xcd3c51b946fb1eeeLL, "",
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0,
+#ifndef HAVE_RUST_DEMANGLE
+ // Rust mangled names should pass through untouched if not
+ // using rust-demangle.
+ kName,
+#else
+ // If rust-demangle is available this should be properly
+ // demangled.
+ "rustc_demangle::demangle",
+#endif
+ 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
+}
+
+TEST_F(Specifications, MemberFunction) {
+ PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
+
+ StartCU();
+ DIEHandler *class_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
+ DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ class_handler->Finish();
+ delete class_handler;
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0x7d83028c431406e8ULL, "",
+ 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "class_A::declaration-name",
+ 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL);
+}
+
+// This case should gather the name from both the definition and the
+// declaration's parent.
+TEST_F(Specifications, FunctionDeclarationParent) {
+ PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922);
+
+ StartCU();
+ {
+ DIEHandler *class_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ "class_A");
+ ASSERT_TRUE(class_handler != NULL);
+ DeclarationDIE(class_handler, 0x0e0e877c8404544aULL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ class_handler->Finish();
+ delete class_handler;
+ }
+
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0x0e0e877c8404544aULL, "definition-name",
+ 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
+
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "class_A::definition-name",
+ 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL);
+}
+
+// Named scopes should also gather enclosing name components from
+// their declarations.
+TEST_F(Specifications, NamedScopeDeclarationParent) {
+ PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604);
+
+ StartCU();
+ {
+ DIEHandler *space_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ "space_A");
+ ASSERT_TRUE(space_handler != NULL);
+ DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
+ dwarf2reader::DW_TAG_class_type, "class-declaration-name",
+ "");
+ space_handler->Finish();
+ delete space_handler;
+ }
+
+ {
+ DIEHandler *class_handler
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ 0x419bb1d12f9a73a2ULL, "class-definition-name");
+ ASSERT_TRUE(class_handler != NULL);
+ DefineFunction(class_handler, "function",
+ 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL);
+ class_handler->Finish();
+ delete class_handler;
+ }
+
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "space_A::class-definition-name::function",
+ 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
+}
+
+// This test recreates bug 364.
+TEST_F(Specifications, InlineFunction) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
+ dwarf2reader::DW_TAG_subprogram, "inline-name", "");
+ AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
+ DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "inline-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+// An inline function in a namespace should correctly derive its
+// name from its abstract origin, and not just the namespace name.
+TEST_F(Specifications, InlineFunctionInNamespace) {
+ PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118);
+
+ StartCU();
+ DIEHandler* space_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ "Namespace");
+ ASSERT_TRUE(space_handler != NULL);
+ AbstractInstanceDIE(space_handler, 0x1e8dac5d507ed7abULL,
+ dwarf2reader::DW_INL_inlined, 0LL, "func-name");
+ DefineInlineInstanceDIE(space_handler, "", 0x1e8dac5d507ed7abULL,
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+ space_handler->Finish();
+ delete space_handler;
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "Namespace::func-name",
+ 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL);
+}
+
+// Check name construction for a long chain containing each combination of:
+// - struct, union, class, namespace
+// - direct and definition
+TEST_F(Specifications, LongChain) {
+ PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926);
+ SetLanguage(dwarf2reader::DW_LANG_C_plus_plus);
+
+ StartCU();
+ // The structure we're building here is:
+ // space_A full definition
+ // space_B declaration
+ // space_B definition
+ // struct_C full definition
+ // struct_D declaration
+ // struct_D definition
+ // union_E full definition
+ // union_F declaration
+ // union_F definition
+ // class_G full definition
+ // class_H declaration
+ // class_H definition
+ // func_I declaration
+ // func_I definition
+ //
+ // So:
+ // - space_A, struct_C, union_E, and class_G don't use specifications;
+ // - space_B, struct_D, union_F, and class_H do.
+ // - func_I uses a specification.
+ //
+ // The full name for func_I is thus:
+ //
+ // space_A::space_B::struct_C::struct_D::union_E::union_F::
+ // class_G::class_H::func_I
+ {
+ DIEHandler *space_A_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ "space_A");
+ DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
+ dwarf2reader::DW_TAG_namespace, "space_B", "");
+ space_A_handler->Finish();
+ delete space_A_handler;
+ }
+
+ {
+ DIEHandler *space_B_handler
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
+ 0x2e111126496596e2ULL);
+ DIEHandler *struct_C_handler
+ = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
+ "struct_C");
+ DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
+ dwarf2reader::DW_TAG_structure_type, "struct_D", "");
+ struct_C_handler->Finish();
+ delete struct_C_handler;
+ space_B_handler->Finish();
+ delete space_B_handler;
+ }
+
+ {
+ DIEHandler *struct_D_handler
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type,
+ 0x20cd423bf2a25a4cULL);
+ DIEHandler *union_E_handler
+ = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
+ "union_E");
+ DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
+ dwarf2reader::DW_TAG_union_type, "union_F", "");
+ union_E_handler->Finish();
+ delete union_E_handler;
+ struct_D_handler->Finish();
+ delete struct_D_handler;
+ }
+
+ {
+ DIEHandler *union_F_handler
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type,
+ 0xe25c84805aa58c32ULL);
+ DIEHandler *class_G_handler
+ = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
+ "class_G");
+ DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
+ dwarf2reader::DW_TAG_class_type, "class_H", "");
+ class_G_handler->Finish();
+ delete class_G_handler;
+ union_F_handler->Finish();
+ delete union_F_handler;
+ }
+
+ {
+ DIEHandler *class_H_handler
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ 0xb70d960dcc173b6eULL);
+ DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
+ dwarf2reader::DW_TAG_subprogram, "func_I", "");
+ class_H_handler->Finish();
+ delete class_H_handler;
+ }
+
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0x27ff829e3bf69f37ULL, "",
+ 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F"
+ "::class_G::class_H::func_I",
+ 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL);
+}
+
+TEST_F(Specifications, InterCU) {
+ Module m("module-name", "module-os", "module-arch", "module-id");
+ DwarfCUToModule::FileContext fc("dwarf-filename", &m, true);
+ EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
+ MockLineToModuleHandler lr;
+ EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
+
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ // First CU. Declares class_A.
+ {
+ DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root1_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ProcessStrangeAttributes(&root1_handler);
+ ASSERT_TRUE(root1_handler.EndAttributes());
+ DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
+ dwarf2reader::DW_TAG_class_type, "class_A", "");
+ root1_handler.Finish();
+ }
+
+ // Second CU. Defines class_A, declares member_func_B.
+ {
+ DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root2_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ASSERT_TRUE(root2_handler.EndAttributes());
+ DIEHandler *class_A_handler
+ = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
+ 0xb8fbfdd5f0b26fceULL);
+ DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
+ dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
+ class_A_handler->Finish();
+ delete class_A_handler;
+ root2_handler.Finish();
+ }
+
+ // Third CU. Defines member_func_B.
+ {
+ DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root3_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ASSERT_TRUE(root3_handler.EndAttributes());
+ DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
+ 0xb01fef8b380bd1a2ULL, "",
+ 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
+ root3_handler.Finish();
+ }
+
+ vector<Module::Function *> functions;
+ m.GetFunctions(&functions, functions.end());
+ EXPECT_EQ(1U, functions.size());
+ EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str());
+}
+
+TEST_F(Specifications, UnhandledInterCU) {
+ Module m("module-name", "module-os", "module-arch", "module-id");
+ DwarfCUToModule::FileContext fc("dwarf-filename", &m, false);
+ EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
+ MockLineToModuleHandler lr;
+ EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0);
+
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ // First CU. Declares class_A.
+ {
+ DwarfCUToModule root1_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root1_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ProcessStrangeAttributes(&root1_handler);
+ ASSERT_TRUE(root1_handler.EndAttributes());
+ DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
+ dwarf2reader::DW_TAG_class_type, "class_A", "");
+ root1_handler.Finish();
+ }
+
+ // Second CU. Defines class_A, declares member_func_B.
+ {
+ DwarfCUToModule root2_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root2_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ASSERT_TRUE(root2_handler.EndAttributes());
+ EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
+ DIEHandler *class_A_handler
+ = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
+ 0xb8fbfdd5f0b26fceULL);
+ DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
+ dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
+ class_A_handler->Finish();
+ delete class_A_handler;
+ root2_handler.Finish();
+ }
+
+ // Third CU. Defines member_func_B.
+ {
+ DwarfCUToModule root3_handler(&fc, &lr, &reporter_);
+ ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3));
+ ASSERT_TRUE(root3_handler.StartRootDIE(1,
+ dwarf2reader::DW_TAG_compile_unit));
+ ASSERT_TRUE(root3_handler.EndAttributes());
+ EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1);
+ EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1);
+ DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram,
+ 0xb01fef8b380bd1a2ULL, "",
+ 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL);
+ root3_handler.Finish();
+ }
+}
+
+TEST_F(Specifications, BadOffset) {
+ PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272);
+ EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL))
+ .WillOnce(Return());
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL,
+ dwarf2reader::DW_TAG_subprogram, "", "");
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0x2be953efa6f9a996ULL, "function",
+ 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL);
+ root_handler_.Finish();
+}
+
+TEST_F(Specifications, FunctionDefinitionHasOwnName) {
+ PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL,
+ dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0xc34ff4786cae78bdULL, "definition-name",
+ 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "definition-name",
+ 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
+}
+
+TEST_F(Specifications, ClassDefinitionHasOwnName) {
+ PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241);
+
+ StartCU();
+ DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL,
+ dwarf2reader::DW_TAG_class_type, "class-declaration-name", "");
+
+ dwarf2reader::DIEHandler *class_definition
+ = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ 0xd0fe467ec2f1a58cULL, "class-definition-name");
+ ASSERT_TRUE(class_definition);
+ DeclarationDIE(class_definition, 0x6d028229c15623dbULL,
+ dwarf2reader::DW_TAG_subprogram,
+ "function-declaration-name", "");
+ class_definition->Finish();
+ delete class_definition;
+
+ DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
+ 0x6d028229c15623dbULL, "function-definition-name",
+ 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
+
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "class-definition-name::function-definition-name",
+ 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL);
+}
+
+// DIEs that cite a specification should prefer the specification's
+// parents over their own when choosing qualified names. In this test,
+// we take the name from our definition but the enclosing scope name
+// from our declaration. I don't see why they'd ever be different, but
+// we want to verify what DwarfCUToModule is looking at.
+TEST_F(Specifications, PreferSpecificationParents) {
+ PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694);
+
+ StartCU();
+ {
+ dwarf2reader::DIEHandler *declaration_class_handler =
+ StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ "declaration-class");
+ DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
+ dwarf2reader::DW_TAG_subprogram, "function-declaration",
+ "");
+ declaration_class_handler->Finish();
+ delete declaration_class_handler;
+ }
+ {
+ dwarf2reader::DIEHandler *definition_class_handler
+ = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
+ "definition-class");
+ DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram,
+ 0x9ddb35517455ef7aULL, "function-definition",
+ 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
+ definition_class_handler->Finish();
+ delete definition_class_handler;
+ }
+ root_handler_.Finish();
+
+ TestFunctionCount(1);
+ TestFunction(0, "declaration-class::function-definition",
+ 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL);
+}
+
+class CUErrors: public CUFixtureBase, public Test { };
+
+TEST_F(CUErrors, BadStmtList) {
+ EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1);
+
+ ASSERT_TRUE(root_handler_
+ .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd,
+ 0x2d7d19546cf6590cULL, 3));
+ ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL,
+ dwarf2reader::DW_TAG_compile_unit));
+ root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name,
+ dwarf2reader::DW_FORM_strp,
+ "compilation-unit-name");
+ root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list,
+ dwarf2reader::DW_FORM_ref4,
+ dummy_line_size_ + 10);
+ root_handler_.EndAttributes();
+ root_handler_.Finish();
+}
+
+TEST_F(CUErrors, NoLineSection) {
+ EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1);
+ PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290);
+ // Delete the entry for .debug_line added by the fixture class's constructor.
+ file_context_.ClearSectionMapForTest();
+
+ StartCU();
+ root_handler_.Finish();
+}
+
+TEST_F(CUErrors, BadDwarfVersion1) {
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ ASSERT_FALSE(root_handler_
+ .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
+ 0xc9de224ccb99ac3eULL, 1));
+}
+
+TEST_F(CUErrors, GoodDwarfVersion2) {
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ ASSERT_TRUE(root_handler_
+ .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
+ 0xc9de224ccb99ac3eULL, 2));
+}
+
+TEST_F(CUErrors, GoodDwarfVersion3) {
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ ASSERT_TRUE(root_handler_
+ .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
+ 0xc9de224ccb99ac3eULL, 3));
+}
+
+TEST_F(CUErrors, BadCURootDIETag) {
+ // Kludge: satisfy reporter_'s expectation.
+ reporter_.SetCUName("compilation-unit-name");
+
+ ASSERT_TRUE(root_handler_
+ .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90,
+ 0xc9de224ccb99ac3eULL, 3));
+
+ ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL,
+ dwarf2reader::DW_TAG_subprogram));
+}
+
+// Tests for DwarfCUToModule::Reporter. These just produce (or fail to
+// produce) output, so their results need to be checked by hand.
+struct Reporter: public Test {
+ Reporter()
+ : reporter("filename", 0x123456789abcdef0ULL),
+ function("function name", 0x19c45c30770c1eb0ULL),
+ file("source file name") {
+ reporter.SetCUName("compilation-unit-name");
+
+ function.size = 0x89808a5bdfa0a6a3ULL;
+ function.parameter_size = 0x6a329f18683dcd51ULL;
+
+ line.address = 0x3606ac6267aebeccULL;
+ line.size = 0x5de482229f32556aULL;
+ line.file = &file;
+ line.number = 93400201;
+ }
+
+ DwarfCUToModule::WarningReporter reporter;
+ Module::Function function;
+ Module::File file;
+ Module::Line line;
+};
+
+TEST_F(Reporter, UnknownSpecification) {
+ reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
+}
+
+TEST_F(Reporter, UnknownAbstractOrigin) {
+ reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL);
+}
+
+TEST_F(Reporter, MissingSection) {
+ reporter.MissingSection("section name");
+}
+
+TEST_F(Reporter, BadLineInfoOffset) {
+ reporter.BadLineInfoOffset(0x123456789abcdef1ULL);
+}
+
+TEST_F(Reporter, UncoveredFunctionDisabled) {
+ reporter.UncoveredFunction(function);
+ EXPECT_FALSE(reporter.uncovered_warnings_enabled());
+}
+
+TEST_F(Reporter, UncoveredFunctionEnabled) {
+ reporter.set_uncovered_warnings_enabled(true);
+ reporter.UncoveredFunction(function);
+ EXPECT_TRUE(reporter.uncovered_warnings_enabled());
+}
+
+TEST_F(Reporter, UncoveredLineDisabled) {
+ reporter.UncoveredLine(line);
+ EXPECT_FALSE(reporter.uncovered_warnings_enabled());
+}
+
+TEST_F(Reporter, UncoveredLineEnabled) {
+ reporter.set_uncovered_warnings_enabled(true);
+ reporter.UncoveredLine(line);
+ EXPECT_TRUE(reporter.uncovered_warnings_enabled());
+}
+
+TEST_F(Reporter, UnnamedFunction) {
+ reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL);
+}
+
+// Would be nice to also test:
+// - overlapping lines, functions
diff --git a/3rdParty/Breakpad/src/common/dwarf_line_to_module.cc b/3rdParty/Breakpad/src/common/dwarf_line_to_module.cc
index 962848d..258b0b6 100644
--- a/3rdParty/Breakpad/src/common/dwarf_line_to_module.cc
+++ b/3rdParty/Breakpad/src/common/dwarf_line_to_module.cc
@@ -48,13 +48,17 @@ static bool PathIsAbsolute(const string &path) {
return (path.size() >= 1 && path[0] == '/');
}
+static bool HasTrailingSlash(const string &path) {
+ return (path.size() >= 1 && path[path.size() - 1] == '/');
+}
+
// If PATH is an absolute path, return PATH. If PATH is a relative path,
// treat it as relative to BASE and return the combined path.
static string ExpandPath(const string &path,
const string &base) {
- if (PathIsAbsolute(path))
+ if (PathIsAbsolute(path) || base.empty())
return path;
- return base + "/" + path;
+ return base + (HasTrailingSlash(base) ? "" : "/") + path;
}
namespace google_breakpad {
@@ -63,7 +67,7 @@ void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) {
// Directory number zero is reserved to mean the compilation
// directory. Silently ignore attempts to redefine it.
if (dir_num != 0)
- directories_[dir_num] = name;
+ directories_[dir_num] = ExpandPath(name, compilation_dir_);
}
void DwarfLineToModule::DefineFile(const string &name, int32 file_num,
@@ -74,25 +78,26 @@ void DwarfLineToModule::DefineFile(const string &name, int32 file_num,
else if (file_num > highest_file_number_)
highest_file_number_ = file_num;
- string full_name;
- if (dir_num != 0) {
+ string dir_name;
+ if (dir_num == 0) {
+ // Directory number zero is the compilation directory, and is stored as
+ // an attribute on the compilation unit, rather than in the program table.
+ dir_name = compilation_dir_;
+ } else {
DirectoryTable::const_iterator directory_it = directories_.find(dir_num);
if (directory_it != directories_.end()) {
- full_name = ExpandPath(name, directory_it->second);
+ dir_name = directory_it->second;
} else {
if (!warned_bad_directory_number_) {
fprintf(stderr, "warning: DWARF line number data refers to undefined"
" directory numbers\n");
warned_bad_directory_number_ = true;
}
- full_name = name; // just treat name as relative
}
- } else {
- // Directory number zero is the compilation directory; we just report
- // relative paths in that case.
- full_name = name;
}
+ string full_name = ExpandPath(name, dir_name);
+
// Find a Module::File object of the given name, and add it to the
// file table.
files_[file_num] = module_->FindFile(full_name);
diff --git a/3rdParty/Breakpad/src/common/dwarf_line_to_module.h b/3rdParty/Breakpad/src/common/dwarf_line_to_module.h
index 9382e40..1fdd4cb 100644
--- a/3rdParty/Breakpad/src/common/dwarf_line_to_module.h
+++ b/3rdParty/Breakpad/src/common/dwarf_line_to_module.h
@@ -120,8 +120,10 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
// end of the address space, we clip it. It's up to our client to
// sort out which lines belong to which functions; we don't add them
// to any particular function in MODULE ourselves.
- DwarfLineToModule(Module *module, vector<Module::Line> *lines)
+ DwarfLineToModule(Module *module, const string& compilation_dir,
+ vector<Module::Line> *lines)
: module_(module),
+ compilation_dir_(compilation_dir),
lines_(lines),
highest_file_number_(-1),
omitted_line_end_(0),
@@ -146,6 +148,10 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
// client.
Module *module_;
+ // The compilation directory for the current compilation unit whose
+ // lines are being accumulated.
+ string compilation_dir_;
+
// The vector of lines we're accumulating. Owned by our client.
//
// In a Module, as in a breakpad symbol file, lines belong to
diff --git a/3rdParty/Breakpad/src/common/dwarf_line_to_module_unittest.cc b/3rdParty/Breakpad/src/common/dwarf_line_to_module_unittest.cc
new file mode 100644
index 0000000..7c0fcfd
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/dwarf_line_to_module_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule.
+
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/dwarf_line_to_module.h"
+
+using std::vector;
+
+using google_breakpad::DwarfLineToModule;
+using google_breakpad::Module;
+using google_breakpad::Module;
+
+TEST(SimpleModule, One) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("file1", 0x30bf0f27, 0, 0, 0);
+ h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
+ 0x4c090cbf, 0x1cf9fe0d);
+
+ vector<Module::File *> files;
+ m.GetFiles(&files);
+ EXPECT_EQ(1U, files.size());
+ EXPECT_STREQ("/file1", files[0]->name.c_str());
+
+ EXPECT_EQ(1U, lines.size());
+ EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address);
+ EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size);
+ EXPECT_TRUE(lines[0].file == files[0]);
+ EXPECT_EQ(0x4c090cbf, lines[0].number);
+}
+
+TEST(SimpleModule, Many) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory1", 0x838299ab);
+ h.DefineDir("directory2", 0xf85de023);
+ h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0);
+ h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0);
+ h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0);
+ h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0);
+ h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a,
+ 0x15b0f0a9U, 0x3ff5abd6U);
+ h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4,
+ 0x4d259ce9U, 0x41c5ee32U);
+ h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56,
+ 0x1ee9fa4fU, 0xbf70e46aU);
+ h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c,
+ 0x77fc280eU, 0x2c4a728cU);
+ h.DefineFile("file3", -1, 0, 0, 0);
+ h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5,
+ 0x75047044U, 0xb6a0016cU);
+
+ vector<Module::File *> files;
+ m.GetFiles(&files);
+ ASSERT_EQ(5U, files.size());
+ EXPECT_STREQ("/directory1/file1", files[0]->name.c_str());
+ EXPECT_STREQ("/directory1/file2", files[1]->name.c_str());
+ EXPECT_STREQ("/directory2/file1", files[2]->name.c_str());
+ EXPECT_STREQ("/directory2/file2", files[3]->name.c_str());
+ EXPECT_STREQ("/file3", files[4]->name.c_str());
+
+ ASSERT_EQ(5U, lines.size());
+
+ EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address);
+ EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size);
+ EXPECT_TRUE(lines[0].file == files[0]);
+ EXPECT_EQ(0x15b0f0a9, lines[0].number);
+
+ EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address);
+ EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size);
+ EXPECT_TRUE(lines[1].file == files[2]);
+ EXPECT_EQ(0x4d259ce9, lines[1].number);
+
+ EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address);
+ EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size);
+ EXPECT_TRUE(lines[2].file == files[1]);
+ EXPECT_EQ(0x1ee9fa4f, lines[2].number);
+
+ EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address);
+ EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size);
+ EXPECT_TRUE(lines[3].file == files[3]);
+ EXPECT_EQ(0x77fc280e, lines[3].number);
+
+ EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address);
+ EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size);
+ EXPECT_TRUE(lines[4].file == files[4]);
+ EXPECT_EQ(0x75047044, lines[4].number);
+}
+
+TEST(Filenames, Absolute) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory1", 1);
+ h.DefineFile("/absolute", 1, 1, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ vector<Module::File *> files;
+ m.GetFiles(&files);
+ ASSERT_EQ(1U, files.size());
+ EXPECT_STREQ("/absolute", files[0]->name.c_str());
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_TRUE(lines[0].file == files[0]);
+}
+
+TEST(Filenames, Relative) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory1", 1);
+ h.DefineFile("relative", 1, 1, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ vector<Module::File *> files;
+ m.GetFiles(&files);
+ ASSERT_EQ(1U, files.size());
+ EXPECT_STREQ("/directory1/relative", files[0]->name.c_str());
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_TRUE(lines[0].file == files[0]);
+}
+
+TEST(Filenames, StrangeFile) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory1", 1);
+ h.DefineFile("", 1, 1, 0, 0);
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("/directory1/", lines[0].file->name.c_str());
+}
+
+TEST(Filenames, StrangeDirectory) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("", 1);
+ h.DefineFile("file1", 1, 1, 0, 0);
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("/file1", lines[0].file->name.c_str());
+}
+
+TEST(Filenames, StrangeDirectoryAndFile) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("", 1);
+ h.DefineFile("", 1, 1, 0, 0);
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("/", lines[0].file->name.c_str());
+}
+
+// We should use the compilation directory when encountering a file for
+// directory number zero.
+TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "src/build", &lines);
+
+ h.DefineDir("Dir", 1);
+ h.DefineFile("File", 1, 0, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("src/build/File", lines[0].file->name.c_str());
+}
+
+// We should treat non-absolute directories as relative to the compilation
+// directory.
+TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "src/build", &lines);
+
+ h.DefineDir("Dir", 1);
+ h.DefineFile("File", 1, 1, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("src/build/Dir/File", lines[0].file->name.c_str());
+}
+
+// We should treat absolute directories as absolute, and not relative to
+// the compilation dir.
+TEST(Filenames, IncludeDirectoryAbsolute) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "src/build", &lines);
+
+ h.DefineDir("/Dir", 1);
+ h.DefineFile("File", 1, 1, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("/Dir/File", lines[0].file->name.c_str());
+}
+
+// We should silently ignore attempts to define directory number zero,
+// since that is always the compilation directory.
+TEST(ModuleErrors, DirectoryZero) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory0", 0); // should be ignored
+ h.DefineFile("relative", 1, 0, 0, 0);
+
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("/relative", lines[0].file->name.c_str());
+}
+
+// We should refuse to add lines with bogus file numbers. We should
+// produce only one warning, however.
+TEST(ModuleErrors, BadFileNumber) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("relative", 1, 0, 0, 0);
+ h.AddLine(1, 1, 2, 0, 0); // bad file number
+ h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning)
+
+ EXPECT_EQ(0U, lines.size());
+}
+
+// We should treat files with bogus directory numbers as relative to
+// the compilation unit.
+TEST(ModuleErrors, BadDirectoryNumber) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineDir("directory1", 1);
+ h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number
+ h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning)
+ h.AddLine(1, 1, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str());
+}
+
+// We promise not to report empty lines.
+TEST(ModuleErrors, EmptyLine) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(1, 0, 1, 0, 0);
+
+ ASSERT_EQ(0U, lines.size());
+}
+
+// We are supposed to clip lines that extend beyond the end of the
+// address space.
+TEST(ModuleErrors, BigLine) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0);
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_EQ(1U, lines[0].size);
+}
+
+// The 'Omitted' tests verify that we correctly omit line information
+// for code in sections that the linker has dropped. See "GNU
+// toolchain omitted sections support" at the top of the
+// DwarfLineToModule class.
+
+TEST(Omitted, DroppedThenGood) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(0, 10, 1, 83816211, 0); // should be omitted
+ h.AddLine(20, 10, 1, 13059195, 0); // should be recorded
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_EQ(13059195, lines[0].number);
+}
+
+TEST(Omitted, GoodThenDropped) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded
+ h.AddLine(0, 10, 1, 44793413, 0); // should be omitted
+
+ ASSERT_EQ(1U, lines.size());
+ EXPECT_EQ(41454594, lines[0].number);
+}
+
+TEST(Omitted, Mix1) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded
+ h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded
+ h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted
+ h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted
+ h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted
+ h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded
+ h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded
+
+ ASSERT_EQ(4U, lines.size());
+ EXPECT_EQ(58932642, lines[0].number);
+ EXPECT_EQ(39847385, lines[1].number);
+ EXPECT_EQ(91806582, lines[2].number);
+ EXPECT_EQ(56169221, lines[3].number);
+}
+
+TEST(Omitted, Mix2) {
+ Module m("name", "os", "architecture", "id");
+ vector<Module::Line> lines;
+ DwarfLineToModule h(&m, "/", &lines);
+
+ h.DefineFile("filename1", 1, 0, 0, 0);
+ h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted
+ h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted
+ h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted
+ h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded
+ h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded
+ h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted
+ h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted
+ h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted
+
+ ASSERT_EQ(2U, lines.size());
+ EXPECT_EQ(67355743, lines[0].number);
+ EXPECT_EQ(23365776, lines[1].number);
+}
diff --git a/3rdParty/Breakpad/src/common/language.cc b/3rdParty/Breakpad/src/common/language.cc
index c2fd81f..978fb85 100644
--- a/3rdParty/Breakpad/src/common/language.cc
+++ b/3rdParty/Breakpad/src/common/language.cc
@@ -34,18 +34,70 @@
#include "common/language.h"
+#include <stdlib.h>
+
+#if !defined(__ANDROID__)
+#include <cxxabi.h>
+#endif
+
+#if defined(HAVE_RUST_DEMANGLE)
+#include <rust_demangle.h>
+#endif
+
+#include <limits>
+
+namespace {
+
+string MakeQualifiedNameWithSeparator(const string& parent_name,
+ const char* separator,
+ const string& name) {
+ if (parent_name.empty()) {
+ return name;
+ }
+
+ return parent_name + separator + name;
+}
+
+} // namespace
+
namespace google_breakpad {
// C++ language-specific operations.
class CPPLanguage: public Language {
public:
CPPLanguage() {}
+
string MakeQualifiedName(const string &parent_name,
const string &name) const {
- if (parent_name.empty())
- return name;
- else
- return parent_name + "::" + name;
+ return MakeQualifiedNameWithSeparator(parent_name, "::", name);
+ }
+
+ virtual DemangleResult DemangleName(const string& mangled,
+ string* demangled) const {
+#if defined(__ANDROID__)
+ // Android NDK doesn't provide abi::__cxa_demangle.
+ demangled->clear();
+ return kDontDemangle;
+#else
+ int status;
+ char* demangled_c =
+ abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
+
+ DemangleResult result;
+ if (status == 0) {
+ result = kDemangleSuccess;
+ demangled->assign(demangled_c);
+ } else {
+ result = kDemangleFailure;
+ demangled->clear();
+ }
+
+ if (demangled_c) {
+ free(reinterpret_cast<void*>(demangled_c));
+ }
+
+ return result;
+#endif
}
};
@@ -54,19 +106,79 @@ CPPLanguage CPPLanguageSingleton;
// Java language-specific operations.
class JavaLanguage: public Language {
public:
+ JavaLanguage() {}
+
string MakeQualifiedName(const string &parent_name,
const string &name) const {
- if (parent_name.empty())
- return name;
- else
- return parent_name + "." + name;
+ return MakeQualifiedNameWithSeparator(parent_name, ".", name);
}
};
JavaLanguage JavaLanguageSingleton;
+// Swift language-specific operations.
+class SwiftLanguage: public Language {
+ public:
+ SwiftLanguage() {}
+
+ string MakeQualifiedName(const string &parent_name,
+ const string &name) const {
+ return MakeQualifiedNameWithSeparator(parent_name, ".", name);
+ }
+
+ virtual DemangleResult DemangleName(const string& mangled,
+ string* demangled) const {
+ // There is no programmatic interface to a Swift demangler. Pass through the
+ // mangled form because it encodes more information than the qualified name
+ // that would have been built by MakeQualifiedName(). The output can be
+ // post-processed by xcrun swift-demangle to transform mangled Swift names
+ // into something more readable.
+ demangled->assign(mangled);
+ return kDemangleSuccess;
+ }
+};
+
+SwiftLanguage SwiftLanguageSingleton;
+
+// Rust language-specific operations.
+class RustLanguage: public Language {
+ public:
+ RustLanguage() {}
+
+ string MakeQualifiedName(const string &parent_name,
+ const string &name) const {
+ return MakeQualifiedNameWithSeparator(parent_name, ".", name);
+ }
+
+ virtual DemangleResult DemangleName(const string& mangled,
+ string* demangled) const {
+ // Rust names use GCC C++ name mangling, but demangling them with
+ // abi_demangle doesn't produce stellar results due to them having
+ // another layer of encoding.
+ // If callers provide rustc-demangle, use that.
+#if defined(HAVE_RUST_DEMANGLE)
+ char* rust_demangled = rust_demangle(mangled.c_str());
+ if (rust_demangled == nullptr) {
+ return kDemangleFailure;
+ }
+ demangled->assign(rust_demangled);
+ free_rust_demangled_name(rust_demangled);
+#else
+ // Otherwise, pass through the mangled name so callers can demangle
+ // after the fact.
+ demangled->assign(mangled);
+#endif
+ return kDemangleSuccess;
+ }
+};
+
+RustLanguage RustLanguageSingleton;
+
// Assembler language-specific operations.
class AssemblerLanguage: public Language {
+ public:
+ AssemblerLanguage() {}
+
bool HasFunctions() const { return false; }
string MakeQualifiedName(const string &parent_name,
const string &name) const {
@@ -78,6 +190,8 @@ AssemblerLanguage AssemblerLanguageSingleton;
const Language * const Language::CPlusPlus = &CPPLanguageSingleton;
const Language * const Language::Java = &JavaLanguageSingleton;
+const Language * const Language::Swift = &SwiftLanguageSingleton;
+const Language * const Language::Rust = &RustLanguageSingleton;
const Language * const Language::Assembler = &AssemblerLanguageSingleton;
} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/language.h b/3rdParty/Breakpad/src/common/language.h
index bbe3033..2d2dbcd 100644
--- a/3rdParty/Breakpad/src/common/language.h
+++ b/3rdParty/Breakpad/src/common/language.h
@@ -77,9 +77,26 @@ class Language {
virtual string MakeQualifiedName (const string &parent_name,
const string &name) const = 0;
+ enum DemangleResult {
+ // Demangling was not performed because it’s not appropriate to attempt.
+ kDontDemangle = -1,
+
+ kDemangleSuccess,
+ kDemangleFailure,
+ };
+
+ // Wraps abi::__cxa_demangle() or similar for languages where appropriate.
+ virtual DemangleResult DemangleName(const string& mangled,
+ string* demangled) const {
+ demangled->clear();
+ return kDontDemangle;
+ }
+
// Instances for specific languages.
static const Language * const CPlusPlus,
* const Java,
+ * const Swift,
+ * const Rust,
* const Assembler;
};
diff --git a/3rdParty/Breakpad/src/common/linux/linux_libc_support.h b/3rdParty/Breakpad/src/common/linux/linux_libc_support.h
index b2f47af..ec5a8d6 100644
--- a/3rdParty/Breakpad/src/common/linux/linux_libc_support.h
+++ b/3rdParty/Breakpad/src/common/linux/linux_libc_support.h
@@ -52,17 +52,16 @@ extern int my_strncmp(const char* a, const char* b, size_t len);
// Return true iff successful.
extern bool my_strtoui(int* result, const char* s);
-// Return the length of the given, non-negative integer when expressed in base
-// 10.
-extern unsigned my_int_len(intmax_t i);
+// Return the length of the given unsigned integer when expressed in base 10.
+extern unsigned my_uint_len(uintmax_t i);
-// Convert a non-negative integer to a string
+// Convert an unsigned integer to a string
// output: (output) the resulting string is written here. This buffer must be
-// large enough to hold the resulting string. Call |my_int_len| to get the
+// large enough to hold the resulting string. Call |my_uint_len| to get the
// required length.
-// i: the non-negative integer to serialise.
-// i_len: the length of the integer in base 10 (see |my_int_len|).
-extern void my_itos(char* output, intmax_t i, unsigned i_len);
+// i: the unsigned integer to serialise.
+// i_len: the length of the integer in base 10 (see |my_uint_len|).
+extern void my_uitos(char* output, uintmax_t i, unsigned i_len);
extern const char* my_strchr(const char* haystack, char needle);
@@ -78,6 +77,8 @@ extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s);
extern void my_memset(void* ip, char c, size_t len);
+extern void* my_memchr(const void* src, int c, size_t len);
+
// The following are considered safe to use in a compromised environment.
// Besides, this gives the compiler an opportunity to optimize their calls.
#define my_memcpy memcpy
diff --git a/3rdParty/Breakpad/src/common/mac/Breakpad.xcconfig b/3rdParty/Breakpad/src/common/mac/Breakpad.xcconfig
new file mode 100644
index 0000000..f091369
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/Breakpad.xcconfig
@@ -0,0 +1,52 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+GCC_C_LANGUAGE_STANDARD = c99
+
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+// TODO(nealsid): Get the code so we can turn on the 64_TO_32 warning.
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+
+// Once https://bugs.chromium.org/p/google-breakpad/issues/detail?id=697
+// is fixed this should be reenabled.
+//GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
+GCC_WARN_UNDECLARED_SELECTOR = YES
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+
+ALWAYS_SEARCH_USER_PATHS = NO
diff --git a/3rdParty/Breakpad/src/common/mac/BreakpadDebug.xcconfig b/3rdParty/Breakpad/src/common/mac/BreakpadDebug.xcconfig
new file mode 100644
index 0000000..94cdd8c
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/BreakpadDebug.xcconfig
@@ -0,0 +1,32 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "Breakpad.xcconfig"
+
+GCC_OPTIMIZATION_LEVEL = 0
diff --git a/3rdParty/Breakpad/src/common/mac/BreakpadRelease.xcconfig b/3rdParty/Breakpad/src/common/mac/BreakpadRelease.xcconfig
new file mode 100644
index 0000000..920f277
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/BreakpadRelease.xcconfig
@@ -0,0 +1,34 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "Breakpad.xcconfig"
+
+GCC_OPTIMIZATION_LEVEL = s
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG
diff --git a/3rdParty/Breakpad/src/common/mac/GTMDefines.h b/3rdParty/Breakpad/src/common/mac/GTMDefines.h
new file mode 100644
index 0000000..04fcf6d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/GTMDefines.h
@@ -0,0 +1,456 @@
+//
+// GTMDefines.h
+//
+// Copyright 2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+// ============================================================================
+
+#include <AvailabilityMacros.h>
+#include <TargetConditionals.h>
+
+#ifdef __OBJC__
+#include <Foundation/NSObjCRuntime.h>
+#endif // __OBJC__
+
+#if TARGET_OS_IPHONE
+#include <Availability.h>
+#endif // TARGET_OS_IPHONE
+
+// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs
+#ifndef MAC_OS_X_VERSION_10_5
+ #define MAC_OS_X_VERSION_10_5 1050
+#endif
+#ifndef MAC_OS_X_VERSION_10_6
+ #define MAC_OS_X_VERSION_10_6 1060
+#endif
+#ifndef MAC_OS_X_VERSION_10_7
+ #define MAC_OS_X_VERSION_10_7 1070
+#endif
+
+// Not all __IPHONE_X macros defined in past SDKs
+#ifndef __IPHONE_3_0
+ #define __IPHONE_3_0 30000
+#endif
+#ifndef __IPHONE_3_1
+ #define __IPHONE_3_1 30100
+#endif
+#ifndef __IPHONE_3_2
+ #define __IPHONE_3_2 30200
+#endif
+#ifndef __IPHONE_4_0
+ #define __IPHONE_4_0 40000
+#endif
+#ifndef __IPHONE_4_3
+ #define __IPHONE_4_3 40300
+#endif
+#ifndef __IPHONE_5_0
+ #define __IPHONE_5_0 50000
+#endif
+
+// ----------------------------------------------------------------------------
+// CPP symbols that can be overridden in a prefix to control how the toolbox
+// is compiled.
+// ----------------------------------------------------------------------------
+
+
+// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and
+// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens
+// when a validation fails. If you implement your own validators, you may want
+// to control their internals using the same macros for consistency.
+#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT
+ #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0
+#endif
+
+// Give ourselves a consistent way to do inlines. Apple's macros even use
+// a few different actual definitions, so we're based off of the foundation
+// one.
+#if !defined(GTM_INLINE)
+ #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__)
+ #define GTM_INLINE static __inline__ __attribute__((always_inline))
+ #else
+ #define GTM_INLINE static __inline__
+ #endif
+#endif
+
+// Give ourselves a consistent way of doing externs that links up nicely
+// when mixing objc and objc++
+#if !defined (GTM_EXTERN)
+ #if defined __cplusplus
+ #define GTM_EXTERN extern "C"
+ #define GTM_EXTERN_C_BEGIN extern "C" {
+ #define GTM_EXTERN_C_END }
+ #else
+ #define GTM_EXTERN extern
+ #define GTM_EXTERN_C_BEGIN
+ #define GTM_EXTERN_C_END
+ #endif
+#endif
+
+// Give ourselves a consistent way of exporting things if we have visibility
+// set to hidden.
+#if !defined (GTM_EXPORT)
+ #define GTM_EXPORT __attribute__((visibility("default")))
+#endif
+
+// Give ourselves a consistent way of declaring something as unused. This
+// doesn't use __unused because that is only supported in gcc 4.2 and greater.
+#if !defined (GTM_UNUSED)
+#define GTM_UNUSED(x) ((void)(x))
+#endif
+
+// _GTMDevLog & _GTMDevAssert
+//
+// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for
+// developer level errors. This implementation simply macros to NSLog/NSAssert.
+// It is not intended to be a general logging/reporting system.
+//
+// Please see https://github.com/google/google-toolbox-for-mac/wiki/DevLogNAssert
+// for a little more background on the usage of these macros.
+//
+// _GTMDevLog log some error/problem in debug builds
+// _GTMDevAssert assert if conditon isn't met w/in a method/function
+// in all builds.
+//
+// To replace this system, just provide different macro definitions in your
+// prefix header. Remember, any implementation you provide *must* be thread
+// safe since this could be called by anything in what ever situtation it has
+// been placed in.
+//
+
+// We only define the simple macros if nothing else has defined this.
+#ifndef _GTMDevLog
+
+#ifdef DEBUG
+ #define _GTMDevLog(...) NSLog(__VA_ARGS__)
+#else
+ #define _GTMDevLog(...) do { } while (0)
+#endif
+
+#endif // _GTMDevLog
+
+#ifndef _GTMDevAssert
+// we directly invoke the NSAssert handler so we can pass on the varargs
+// (NSAssert doesn't have a macro we can use that takes varargs)
+#if !defined(NS_BLOCK_ASSERTIONS)
+ #define _GTMDevAssert(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ [[NSAssertionHandler currentHandler] \
+ handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \
+ file:[NSString stringWithUTF8String:__FILE__] \
+ lineNumber:__LINE__ \
+ description:__VA_ARGS__]; \
+ } \
+ } while(0)
+#else // !defined(NS_BLOCK_ASSERTIONS)
+ #define _GTMDevAssert(condition, ...) do { } while (0)
+#endif // !defined(NS_BLOCK_ASSERTIONS)
+
+#endif // _GTMDevAssert
+
+// _GTMCompileAssert
+// _GTMCompileAssert is an assert that is meant to fire at compile time if you
+// want to check things at compile instead of runtime. For example if you
+// want to check that a wchar is 4 bytes instead of 2 you would use
+// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X)
+// Note that the second "arg" is not in quotes, and must be a valid processor
+// symbol in it's own right (no spaces, punctuation etc).
+
+// Wrapping this in an #ifndef allows external groups to define their own
+// compile time assert scheme.
+#ifndef _GTMCompileAssert
+ // We got this technique from here:
+ // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html
+
+ #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg
+ #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg)
+ #define _GTMCompileAssert(test, msg) \
+ typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
+#endif // _GTMCompileAssert
+
+// ----------------------------------------------------------------------------
+// CPP symbols defined based on the project settings so the GTM code has
+// simple things to test against w/o scattering the knowledge of project
+// setting through all the code.
+// ----------------------------------------------------------------------------
+
+// Provide a single constant CPP symbol that all of GTM uses for ifdefing
+// iPhone code.
+#if TARGET_OS_IPHONE // iPhone SDK
+ // For iPhone specific stuff
+ #define GTM_IPHONE_SDK 1
+ #if TARGET_IPHONE_SIMULATOR
+ #define GTM_IPHONE_DEVICE 0
+ #define GTM_IPHONE_SIMULATOR 1
+ #else
+ #define GTM_IPHONE_DEVICE 1
+ #define GTM_IPHONE_SIMULATOR 0
+ #endif // TARGET_IPHONE_SIMULATOR
+ // By default, GTM has provided it's own unittesting support, define this
+ // to use the support provided by Xcode, especially for the Xcode4 support
+ // for unittesting.
+ #ifndef GTM_IPHONE_USE_SENTEST
+ #define GTM_IPHONE_USE_SENTEST 0
+ #endif
+ #define GTM_MACOS_SDK 0
+#else
+ // For MacOS specific stuff
+ #define GTM_MACOS_SDK 1
+ #define GTM_IPHONE_SDK 0
+ #define GTM_IPHONE_SIMULATOR 0
+ #define GTM_IPHONE_DEVICE 0
+ #define GTM_IPHONE_USE_SENTEST 0
+#endif
+
+// Some of our own availability macros
+#if GTM_MACOS_SDK
+#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE
+#define GTM_AVAILABLE_ONLY_ON_MACOS
+#else
+#define GTM_AVAILABLE_ONLY_ON_IPHONE
+#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE
+#endif
+
+// GC was dropped by Apple, define the old constant incase anyone still keys
+// off of it.
+#ifndef GTM_SUPPORT_GC
+ #define GTM_SUPPORT_GC 0
+#endif
+
+// To simplify support for 64bit (and Leopard in general), we provide the type
+// defines for non Leopard SDKs
+#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+ // NSInteger/NSUInteger and Max/Mins
+ #ifndef NSINTEGER_DEFINED
+ #if (defined(__LP64__) && __LP64__) || NS_BUILD_32_LIKE_64
+ typedef long NSInteger;
+ typedef unsigned long NSUInteger;
+ #else
+ typedef int NSInteger;
+ typedef unsigned int NSUInteger;
+ #endif
+ #define NSIntegerMax LONG_MAX
+ #define NSIntegerMin LONG_MIN
+ #define NSUIntegerMax ULONG_MAX
+ #define NSINTEGER_DEFINED 1
+ #endif // NSINTEGER_DEFINED
+ // CGFloat
+ #ifndef CGFLOAT_DEFINED
+ #if defined(__LP64__) && __LP64__
+ // This really is an untested path (64bit on Tiger?)
+ typedef double CGFloat;
+ #define CGFLOAT_MIN DBL_MIN
+ #define CGFLOAT_MAX DBL_MAX
+ #define CGFLOAT_IS_DOUBLE 1
+ #else /* !defined(__LP64__) || !__LP64__ */
+ typedef float CGFloat;
+ #define CGFLOAT_MIN FLT_MIN
+ #define CGFLOAT_MAX FLT_MAX
+ #define CGFLOAT_IS_DOUBLE 0
+ #endif /* !defined(__LP64__) || !__LP64__ */
+ #define CGFLOAT_DEFINED 1
+ #endif // CGFLOAT_DEFINED
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
+
+// Some support for advanced clang static analysis functionality
+// See http://clang-analyzer.llvm.org/annotations.html
+#ifndef __has_feature // Optional.
+ #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_RETURNS_RETAINED
+ #if __has_feature(attribute_ns_returns_retained)
+ #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+ #else
+ #define NS_RETURNS_RETAINED
+ #endif
+#endif
+
+#ifndef NS_RETURNS_NOT_RETAINED
+ #if __has_feature(attribute_ns_returns_not_retained)
+ #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+ #else
+ #define NS_RETURNS_NOT_RETAINED
+ #endif
+#endif
+
+#ifndef CF_RETURNS_RETAINED
+ #if __has_feature(attribute_cf_returns_retained)
+ #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+ #else
+ #define CF_RETURNS_RETAINED
+ #endif
+#endif
+
+#ifndef CF_RETURNS_NOT_RETAINED
+ #if __has_feature(attribute_cf_returns_not_retained)
+ #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+ #else
+ #define CF_RETURNS_NOT_RETAINED
+ #endif
+#endif
+
+#ifndef NS_CONSUMED
+ #if __has_feature(attribute_ns_consumed)
+ #define NS_CONSUMED __attribute__((ns_consumed))
+ #else
+ #define NS_CONSUMED
+ #endif
+#endif
+
+#ifndef CF_CONSUMED
+ #if __has_feature(attribute_cf_consumed)
+ #define CF_CONSUMED __attribute__((cf_consumed))
+ #else
+ #define CF_CONSUMED
+ #endif
+#endif
+
+#ifndef NS_CONSUMES_SELF
+ #if __has_feature(attribute_ns_consumes_self)
+ #define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+ #else
+ #define NS_CONSUMES_SELF
+ #endif
+#endif
+
+// Defined on 10.6 and above.
+#ifndef NS_FORMAT_ARGUMENT
+ #define NS_FORMAT_ARGUMENT(A)
+#endif
+
+// Defined on 10.6 and above.
+#ifndef NS_FORMAT_FUNCTION
+ #define NS_FORMAT_FUNCTION(F,A)
+#endif
+
+// Defined on 10.6 and above.
+#ifndef CF_FORMAT_ARGUMENT
+ #define CF_FORMAT_ARGUMENT(A)
+#endif
+
+// Defined on 10.6 and above.
+#ifndef CF_FORMAT_FUNCTION
+ #define CF_FORMAT_FUNCTION(F,A)
+#endif
+
+#ifndef GTM_NONNULL
+ #if defined(__has_attribute)
+ #if __has_attribute(nonnull)
+ #define GTM_NONNULL(x) __attribute__((nonnull x))
+ #else
+ #define GTM_NONNULL(x)
+ #endif
+ #else
+ #define GTM_NONNULL(x)
+ #endif
+#endif
+
+// Invalidates the initializer from which it's called.
+#ifndef GTMInvalidateInitializer
+ #if __has_feature(objc_arc)
+ #define GTMInvalidateInitializer() \
+ do { \
+ [self class]; /* Avoid warning of dead store to |self|. */ \
+ _GTMDevAssert(NO, @"Invalid initializer."); \
+ return nil; \
+ } while (0)
+ #else
+ #define GTMInvalidateInitializer() \
+ do { \
+ [self release]; \
+ _GTMDevAssert(NO, @"Invalid initializer."); \
+ return nil; \
+ } while (0)
+ #endif
+#endif
+
+#ifndef GTMCFAutorelease
+ #if __has_feature(objc_arc)
+ #define GTMCFAutorelease(x) CFBridgingRelease(x)
+ #else
+ #define GTMCFAutorelease(x) ([(id)x autorelease])
+ #endif
+#endif
+
+#ifdef __OBJC__
+
+// Declared here so that it can easily be used for logging tracking if
+// necessary. See GTMUnitTestDevLog.h for details.
+@class NSString;
+GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2);
+
+// Macro to allow you to create NSStrings out of other macros.
+// #define FOO foo
+// NSString *fooString = GTM_NSSTRINGIFY(FOO);
+#if !defined (GTM_NSSTRINGIFY)
+ #define GTM_NSSTRINGIFY_INNER(x) @#x
+ #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x)
+#endif
+
+// Macro to allow fast enumeration when building for 10.5 or later, and
+// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
+// does keys, so pick the right thing, nothing is done on the FastEnumeration
+// side to be sure you're getting what you wanted.
+#ifndef GTM_FOREACH_OBJECT
+ #if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
+ #define GTM_FOREACH_ENUMEREE(element, enumeration) \
+ for (element in enumeration)
+ #define GTM_FOREACH_OBJECT(element, collection) \
+ for (element in collection)
+ #define GTM_FOREACH_KEY(element, collection) \
+ for (element in collection)
+ #else
+ #define GTM_FOREACH_ENUMEREE(element, enumeration) \
+ for (NSEnumerator *_ ## element ## _enum = enumeration; \
+ (element = [_ ## element ## _enum nextObject]) != nil; )
+ #define GTM_FOREACH_OBJECT(element, collection) \
+ GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator])
+ #define GTM_FOREACH_KEY(element, collection) \
+ GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator])
+ #endif
+#endif
+
+// ============================================================================
+
+// To simplify support for both Leopard and Snow Leopard we declare
+// the Snow Leopard protocols that we need here.
+#if !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
+#define GTM_10_6_PROTOCOLS_DEFINED 1
+@protocol NSConnectionDelegate
+@end
+@protocol NSAnimationDelegate
+@end
+@protocol NSImageDelegate
+@end
+@protocol NSTabViewDelegate
+@end
+#endif // !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
+
+// GTM_SEL_STRING is for specifying selector (usually property) names to KVC
+// or KVO methods.
+// In debug it will generate warnings for undeclared selectors if
+// -Wunknown-selector is turned on.
+// In release it will have no runtime overhead.
+#ifndef GTM_SEL_STRING
+ #ifdef DEBUG
+ #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName))
+ #else
+ #define GTM_SEL_STRING(selName) @#selName
+ #endif // DEBUG
+#endif // GTM_SEL_STRING
+
+#endif // __OBJC__
diff --git a/3rdParty/Breakpad/src/common/mac/GTMLogger.h b/3rdParty/Breakpad/src/common/mac/GTMLogger.h
new file mode 100644
index 0000000..c4fd140
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/GTMLogger.h
@@ -0,0 +1,504 @@
+//
+// GTMLogger.h
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+// Key Abstractions
+// ----------------
+//
+// This file declares multiple classes and protocols that are used by the
+// GTMLogger logging system. The 4 main abstractions used in this file are the
+// following:
+//
+// * logger (GTMLogger) - The main logging class that users interact with. It
+// has methods for logging at different levels and uses a log writer, a log
+// formatter, and a log filter to get the job done.
+//
+// * log writer (GTMLogWriter) - Writes a given string to some log file, where
+// a "log file" can be a physical file on disk, a POST over HTTP to some URL,
+// or even some in-memory structure (e.g., a ring buffer).
+//
+// * log formatter (GTMLogFormatter) - Given a format string and arguments as
+// a va_list, returns a single formatted NSString. A "formatted string" could
+// be a string with the date prepended, a string with values in a CSV format,
+// or even a string of XML.
+//
+// * log filter (GTMLogFilter) - Given a formatted log message as an NSString
+// and the level at which the message is to be logged, this class will decide
+// whether the given message should be logged or not. This is a flexible way
+// to filter out messages logged at a certain level, messages that contain
+// certain text, or filter nothing out at all. This gives the caller the
+// flexibility to dynamically enable debug logging in Release builds.
+//
+// This file also declares some classes to handle the common log writer, log
+// formatter, and log filter cases. Callers can also create their own writers,
+// formatters, and filters and they can even build them on top of the ones
+// declared here. Keep in mind that your custom writer/formatter/filter may be
+// called from multiple threads, so it must be thread-safe.
+
+#import <Foundation/Foundation.h>
+#import "GTMDefines.h"
+
+// Predeclaration of used protocols that are declared later in this file.
+@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
+
+// GTMLogger
+//
+// GTMLogger is the primary user-facing class for an object-oriented logging
+// system. It is built on the concept of log formatters (GTMLogFormatter), log
+// writers (GTMLogWriter), and log filters (GTMLogFilter). When a message is
+// sent to a GTMLogger to log a message, the message is formatted using the log
+// formatter, then the log filter is consulted to see if the message should be
+// logged, and if so, the message is sent to the log writer to be written out.
+//
+// GTMLogger is intended to be a flexible and thread-safe logging solution. Its
+// flexibility comes from the fact that GTMLogger instances can be customized
+// with user defined formatters, filters, and writers. And these writers,
+// filters, and formatters can be combined, stacked, and customized in arbitrary
+// ways to suit the needs at hand. For example, multiple writers can be used at
+// the same time, and a GTMLogger instance can even be used as another
+// GTMLogger's writer. This allows for arbitrarily deep logging trees.
+//
+// A standard GTMLogger uses a writer that sends messages to standard out, a
+// formatter that smacks a timestamp and a few other bits of interesting
+// information on the message, and a filter that filters out debug messages from
+// release builds. Using the standard log settings, a log message will look like
+// the following:
+//
+// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] foo=<Foo: 0x123>
+//
+// The output contains the date and time of the log message, the name of the
+// process followed by its process ID/thread ID, the log level at which the
+// message was logged (in the previous example the level was 1:
+// kGTMLoggerLevelDebug), and finally, the user-specified log message itself (in
+// this case, the log message was @"foo=%@", foo).
+//
+// Multiple instances of GTMLogger can be created, each configured their own
+// way. Though GTMLogger is not a singleton (in the GoF sense), it does provide
+// access to a shared (i.e., globally accessible) GTMLogger instance. This makes
+// it convenient for all code in a process to use the same GTMLogger instance.
+// The shared GTMLogger instance can also be configured in an arbitrary, and
+// these configuration changes will affect all code that logs through the shared
+// instance.
+
+//
+// Log Levels
+// ----------
+// GTMLogger has 3 different log levels: Debug, Info, and Error. GTMLogger
+// doesn't take any special action based on the log level; it simply forwards
+// this information on to formatters, filters, and writers, each of which may
+// optionally take action based on the level. Since log level filtering is
+// performed at runtime, log messages are typically not filtered out at compile
+// time. The exception to this rule is that calls to the GTMLoggerDebug() macro
+// *ARE* filtered out of non-DEBUG builds. This is to be backwards compatible
+// with behavior that many developers are currently used to. Note that this
+// means that GTMLoggerDebug(@"hi") will be compiled out of Release builds, but
+// [[GTMLogger sharedLogger] logDebug:@"hi"] will NOT be compiled out.
+//
+// Standard loggers are created with the GTMLogLevelFilter log filter, which
+// filters out certain log messages based on log level, and some other settings.
+//
+// In addition to the -logDebug:, -logInfo:, and -logError: methods defined on
+// GTMLogger itself, there are also C macros that make usage of the shared
+// GTMLogger instance very convenient. These macros are:
+//
+// GTMLoggerDebug(...)
+// GTMLoggerInfo(...)
+// GTMLoggerError(...)
+//
+// Again, a notable feature of these macros is that GTMLogDebug() calls *will be
+// compiled out of non-DEBUG builds*.
+//
+// Standard Loggers
+// ----------------
+// GTMLogger has the concept of "standard loggers". A standard logger is simply
+// a logger that is pre-configured with some standard/common writer, formatter,
+// and filter combination. Standard loggers are created using the creation
+// methods beginning with "standard". The alternative to a standard logger is a
+// regular logger, which will send messages to stdout, with no special
+// formatting, and no filtering.
+//
+// How do I use GTMLogger?
+// ----------------------
+// The typical way you will want to use GTMLogger is to simply use the
+// GTMLogger*() macros for logging from code. That way we can easily make
+// changes to the GTMLogger class and simply update the macros accordingly. Only
+// your application startup code (perhaps, somewhere in main()) should use the
+// GTMLogger class directly in order to configure the shared logger, which all
+// of the code using the macros will be using. Again, this is just the typical
+// situation.
+//
+// To be complete, there are cases where you may want to use GTMLogger directly,
+// or even create separate GTMLogger instances for some reason. That's fine,
+// too.
+//
+// Examples
+// --------
+// The following show some common GTMLogger use cases.
+//
+// 1. You want to log something as simply as possible. Also, this call will only
+// appear in debug builds. In non-DEBUG builds it will be completely removed.
+//
+// GTMLoggerDebug(@"foo = %@", foo);
+//
+// 2. The previous example is similar to the following. The major difference is
+// that the previous call (example 1) will be compiled out of Release builds
+// but this statement will not be compiled out.
+//
+// [[GTMLogger sharedLogger] logDebug:@"foo = %@", foo];
+//
+// 3. Send all logging output from the shared logger to a file. We do this by
+// creating an NSFileHandle for writing associated with a file, and setting
+// that file handle as the logger's writer.
+//
+// NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log"
+// create:YES];
+// [[GTMLogger sharedLogger] setWriter:f];
+// GTMLoggerError(@"hi"); // This will be sent to /tmp/f.log
+//
+// 4. Create a new GTMLogger that will log to a file. This example differs from
+// the previous one because here we create a new GTMLogger that is different
+// from the shared logger.
+//
+// GTMLogger *logger = [GTMLogger standardLoggerWithPath:@"/tmp/temp.log"];
+// [logger logInfo:@"hi temp log file"];
+//
+// 5. Create a logger that writes to stdout and does NOT do any formatting to
+// the log message. This might be useful, for example, when writing a help
+// screen for a command-line tool to standard output.
+//
+// GTMLogger *logger = [GTMLogger logger];
+// [logger logInfo:@"%@ version 0.1 usage", progName];
+//
+// 6. Send log output to stdout AND to a log file. The trick here is that
+// NSArrays function as composite log writers, which means when an array is
+// set as the log writer, it forwards all logging messages to all of its
+// contained GTMLogWriters.
+//
+// // Create array of GTMLogWriters
+// NSArray *writers = [NSArray arrayWithObjects:
+// [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" create:YES],
+// [NSFileHandle fileHandleWithStandardOutput], nil];
+//
+// GTMLogger *logger = [GTMLogger standardLogger];
+// [logger setWriter:writers];
+// [logger logInfo:@"hi"]; // Output goes to stdout and /tmp/f.log
+//
+// For futher details on log writers, formatters, and filters, see the
+// documentation below.
+//
+// NOTE: GTMLogger is application level logging. By default it does nothing
+// with _GTMDevLog/_GTMDevAssert (see GTMDefines.h). An application can choose
+// to bridge _GTMDevLog/_GTMDevAssert to GTMLogger by providing macro
+// definitions in its prefix header (see GTMDefines.h for how one would do
+// that).
+//
+@interface GTMLogger : NSObject {
+ @private
+ id<GTMLogWriter> writer_;
+ id<GTMLogFormatter> formatter_;
+ id<GTMLogFilter> filter_;
+}
+
+//
+// Accessors for the shared logger instance
+//
+
+// Returns a shared/global standard GTMLogger instance. Callers should typically
+// use this method to get a GTMLogger instance, unless they explicitly want
+// their own instance to configure for their own needs. This is the only method
+// that returns a shared instance; all the rest return new GTMLogger instances.
++ (id)sharedLogger;
+
+// Sets the shared logger instance to |logger|. Future calls to +sharedLogger
+// will return |logger| instead.
++ (void)setSharedLogger:(GTMLogger *)logger;
+
+//
+// Creation methods
+//
+
+// Returns a new autoreleased GTMLogger instance that will log to stdout, using
+// the GTMLogStandardFormatter, and the GTMLogLevelFilter filter.
++ (id)standardLogger;
+
+// Same as +standardLogger, but logs to stderr.
++ (id)standardLoggerWithStderr;
+
+// Same as +standardLogger but levels >= kGTMLoggerLevelError are routed to
+// stderr, everything else goes to stdout.
++ (id)standardLoggerWithStdoutAndStderr;
+
+// Returns a new standard GTMLogger instance with a log writer that will
+// write to the file at |path|, and will use the GTMLogStandardFormatter and
+// GTMLogLevelFilter classes. If |path| does not exist, it will be created.
++ (id)standardLoggerWithPath:(NSString *)path;
+
+// Returns an autoreleased GTMLogger instance that will use the specified
+// |writer|, |formatter|, and |filter|.
++ (id)loggerWithWriter:(id<GTMLogWriter>)writer
+ formatter:(id<GTMLogFormatter>)formatter
+ filter:(id<GTMLogFilter>)filter;
+
+// Returns an autoreleased GTMLogger instance that logs to stdout, with the
+// basic formatter, and no filter. The returned logger differs from the logger
+// returned by +standardLogger because this one does not do any filtering and
+// does not do any special log formatting; this is the difference between a
+// "regular" logger and a "standard" logger.
++ (id)logger;
+
+// Designated initializer. This method returns a GTMLogger initialized with the
+// specified |writer|, |formatter|, and |filter|. See the setter methods below
+// for what values will be used if nil is passed for a parameter.
+- (id)initWithWriter:(id<GTMLogWriter>)writer
+ formatter:(id<GTMLogFormatter>)formatter
+ filter:(id<GTMLogFilter>)filter;
+
+//
+// Logging methods
+//
+
+// Logs a message at the debug level (kGTMLoggerLevelDebug).
+- (void)logDebug:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
+// Logs a message at the info level (kGTMLoggerLevelInfo).
+- (void)logInfo:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
+// Logs a message at the error level (kGTMLoggerLevelError).
+- (void)logError:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
+// Logs a message at the assert level (kGTMLoggerLevelAssert).
+- (void)logAssert:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
+
+
+//
+// Accessors
+//
+
+// Accessor methods for the log writer. If the log writer is set to nil,
+// [NSFileHandle fileHandleWithStandardOutput] is used.
+- (id<GTMLogWriter>)writer;
+- (void)setWriter:(id<GTMLogWriter>)writer;
+
+// Accessor methods for the log formatter. If the log formatter is set to nil,
+// GTMLogBasicFormatter is used. This formatter will format log messages in a
+// plain printf style.
+- (id<GTMLogFormatter>)formatter;
+- (void)setFormatter:(id<GTMLogFormatter>)formatter;
+
+// Accessor methods for the log filter. If the log filter is set to nil,
+// GTMLogNoFilter is used, which allows all log messages through.
+- (id<GTMLogFilter>)filter;
+- (void)setFilter:(id<GTMLogFilter>)filter;
+
+@end // GTMLogger
+
+
+// Helper functions that are used by the convenience GTMLogger*() macros that
+// enable the logging of function names.
+@interface GTMLogger (GTMLoggerMacroHelpers)
+- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ...
+ NS_FORMAT_FUNCTION(2, 3);
+- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
+ NS_FORMAT_FUNCTION(2, 3);
+- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
+ NS_FORMAT_FUNCTION(2, 3);
+- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
+ NS_FORMAT_FUNCTION(2, 3);
+@end // GTMLoggerMacroHelpers
+
+
+// The convenience macros are only defined if they haven't already been defined.
+#ifndef GTMLoggerInfo
+
+// Convenience macros that log to the shared GTMLogger instance. These macros
+// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug()
+// calls will be compiled out of non-Debug builds.
+#define GTMLoggerDebug(...) \
+ [[GTMLogger sharedLogger] logFuncDebug:__func__ msg:__VA_ARGS__]
+#define GTMLoggerInfo(...) \
+ [[GTMLogger sharedLogger] logFuncInfo:__func__ msg:__VA_ARGS__]
+#define GTMLoggerError(...) \
+ [[GTMLogger sharedLogger] logFuncError:__func__ msg:__VA_ARGS__]
+#define GTMLoggerAssert(...) \
+ [[GTMLogger sharedLogger] logFuncAssert:__func__ msg:__VA_ARGS__]
+
+// If we're not in a debug build, remove the GTMLoggerDebug statements. This
+// makes calls to GTMLoggerDebug "compile out" of Release builds
+#ifndef DEBUG
+#undef GTMLoggerDebug
+#define GTMLoggerDebug(...) do {} while(0)
+#endif
+
+#endif // !defined(GTMLoggerInfo)
+
+// Log levels.
+typedef enum {
+ kGTMLoggerLevelUnknown,
+ kGTMLoggerLevelDebug,
+ kGTMLoggerLevelInfo,
+ kGTMLoggerLevelError,
+ kGTMLoggerLevelAssert,
+} GTMLoggerLevel;
+
+
+//
+// Log Writers
+//
+
+// Protocol to be implemented by a GTMLogWriter instance.
+@protocol GTMLogWriter <NSObject>
+// Writes the given log message to where the log writer is configured to write.
+- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level;
+@end // GTMLogWriter
+
+
+// Simple category on NSFileHandle that makes NSFileHandles valid log writers.
+// This is convenient because something like, say, +fileHandleWithStandardError
+// now becomes a valid log writer. Log messages are written to the file handle
+// with a newline appended.
+@interface NSFileHandle (GTMFileHandleLogWriter) <GTMLogWriter>
+// Opens the file at |path| in append mode, and creates the file with |mode|
+// if it didn't previously exist.
++ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode;
+@end // NSFileHandle
+
+
+// This category makes NSArray a GTMLogWriter that can be composed of other
+// GTMLogWriters. This is the classic Composite GoF design pattern. When the
+// GTMLogWriter -logMessage:level: message is sent to the array, the array
+// forwards the message to all of its elements that implement the GTMLogWriter
+// protocol.
+//
+// This is useful in situations where you would like to send log output to
+// multiple log writers at the same time. Simply create an NSArray of the log
+// writers you wish to use, then set the array as the "writer" for your
+// GTMLogger instance.
+@interface NSArray (GTMArrayCompositeLogWriter) <GTMLogWriter>
+@end // GTMArrayCompositeLogWriter
+
+
+// This category adapts the GTMLogger interface so that it can be used as a log
+// writer; it's an "adapter" in the GoF Adapter pattern sense.
+//
+// This is useful when you want to configure a logger to log to a specific
+// writer with a specific formatter and/or filter. But you want to also compose
+// that with a different log writer that may have its own formatter and/or
+// filter.
+@interface GTMLogger (GTMLoggerLogWriter) <GTMLogWriter>
+@end // GTMLoggerLogWriter
+
+
+//
+// Log Formatters
+//
+
+// Protocol to be implemented by a GTMLogFormatter instance.
+@protocol GTMLogFormatter <NSObject>
+// Returns a formatted string using the format specified in |fmt| and the va
+// args specified in |args|.
+- (NSString *)stringForFunc:(NSString *)func
+ withFormat:(NSString *)fmt
+ valist:(va_list)args
+ level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0);
+@end // GTMLogFormatter
+
+
+// A basic log formatter that formats a string the same way that NSLog (or
+// printf) would. It does not do anything fancy, nor does it add any data of its
+// own.
+@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter>
+
+// Helper method for prettying C99 __func__ and GCC __PRETTY_FUNCTION__
+- (NSString *)prettyNameForFunc:(NSString *)func;
+
+@end // GTMLogBasicFormatter
+
+
+// A log formatter that formats the log string like the basic formatter, but
+// also prepends a timestamp and some basic process info to the message, as
+// shown in the following sample output.
+// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] log mesage here
+@interface GTMLogStandardFormatter : GTMLogBasicFormatter {
+ @private
+ NSDateFormatter *dateFormatter_; // yyyy-MM-dd HH:mm:ss.SSS
+ NSString *pname_;
+ pid_t pid_;
+}
+@end // GTMLogStandardFormatter
+
+
+//
+// Log Filters
+//
+
+// Protocol to be imlemented by a GTMLogFilter instance.
+@protocol GTMLogFilter <NSObject>
+// Returns YES if |msg| at |level| should be filtered out; NO otherwise.
+- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level;
+@end // GTMLogFilter
+
+
+// A log filter that filters messages at the kGTMLoggerLevelDebug level out of
+// non-debug builds. Messages at the kGTMLoggerLevelInfo level are also filtered
+// out of non-debug builds unless GTMVerboseLogging is set in the environment or
+// the processes's defaults. Messages at the kGTMLoggerLevelError level are
+// never filtered.
+@interface GTMLogLevelFilter : NSObject <GTMLogFilter>
+@end // GTMLogLevelFilter
+
+// A simple log filter that does NOT filter anything out;
+// -filterAllowsMessage:level will always return YES. This can be a convenient
+// way to enable debug-level logging in release builds (if you so desire).
+@interface GTMLogNoFilter : NSObject <GTMLogFilter>
+@end // GTMLogNoFilter
+
+
+// Base class for custom level filters. Not for direct use, use the minimum
+// or maximum level subclasses below.
+@interface GTMLogAllowedLevelFilter : NSObject <GTMLogFilter> {
+ @private
+ NSIndexSet *allowedLevels_;
+}
+@end
+
+// A log filter that allows you to set a minimum log level. Messages below this
+// level will be filtered.
+@interface GTMLogMininumLevelFilter : GTMLogAllowedLevelFilter
+
+// Designated initializer, logs at levels < |level| will be filtered.
+- (id)initWithMinimumLevel:(GTMLoggerLevel)level;
+
+@end
+
+// A log filter that allows you to set a maximum log level. Messages whose level
+// exceeds this level will be filtered. This is really only useful if you have
+// a composite GTMLogger that is sending the other messages elsewhere.
+@interface GTMLogMaximumLevelFilter : GTMLogAllowedLevelFilter
+
+// Designated initializer, logs at levels > |level| will be filtered.
+- (id)initWithMaximumLevel:(GTMLoggerLevel)level;
+
+@end
+
+
+// For subclasses only
+@interface GTMLogger (PrivateMethods)
+
+- (void)logInternalFunc:(const char *)func
+ format:(NSString *)fmt
+ valist:(va_list)args
+ level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0);
+
+@end
+
diff --git a/3rdParty/Breakpad/src/common/mac/GTMLogger.m b/3rdParty/Breakpad/src/common/mac/GTMLogger.m
new file mode 100644
index 0000000..ebc5836
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/GTMLogger.m
@@ -0,0 +1,611 @@
+//
+// GTMLogger.m
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMLogger.h"
+#import <fcntl.h>
+#import <unistd.h>
+#import <stdlib.h>
+#import <pthread.h>
+
+
+#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
+// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
+// -Wmissing-format-attribute
+// when the function is anything more complex than foo(NSString *fmt, ...).
+// You see the error inside the function when you turn ... into va_args and
+// attempt to call another function (like vsprintf for example).
+// So we just shut off the warning for this file. We reenable it at the end.
+#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
+#endif // !__clang__
+
+// Reference to the shared GTMLogger instance. This is not a singleton, it's
+// just an easy reference to one shared instance.
+static GTMLogger *gSharedLogger = nil;
+
+
+@implementation GTMLogger
+
+// Returns a pointer to the shared logger instance. If none exists, a standard
+// logger is created and returned.
++ (id)sharedLogger {
+ @synchronized(self) {
+ if (gSharedLogger == nil) {
+ gSharedLogger = [[self standardLogger] retain];
+ }
+ }
+ return [[gSharedLogger retain] autorelease];
+}
+
++ (void)setSharedLogger:(GTMLogger *)logger {
+ @synchronized(self) {
+ [gSharedLogger autorelease];
+ gSharedLogger = [logger retain];
+ }
+}
+
++ (id)standardLogger {
+ // Don't trust NSFileHandle not to throw
+ @try {
+ id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
+ id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init]
+ autorelease];
+ id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
+ return [[[self alloc] initWithWriter:writer
+ formatter:fr
+ filter:filter] autorelease];
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ return nil;
+}
+
++ (id)standardLoggerWithStderr {
+ // Don't trust NSFileHandle not to throw
+ @try {
+ id me = [self standardLogger];
+ [me setWriter:[NSFileHandle fileHandleWithStandardError]];
+ return me;
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ return nil;
+}
+
++ (id)standardLoggerWithStdoutAndStderr {
+ // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor
+ // and create a composite logger that an outer "standard" logger can use
+ // as a writer. Our inner loggers should apply no formatting since the main
+ // logger does that and we want the caller to be able to change formatters
+ // or add writers without knowing the inner structure of our composite.
+
+ // Don't trust NSFileHandle not to throw
+ @try {
+ GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init]
+ autorelease];
+ GTMLogger *stdoutLogger =
+ [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput]
+ formatter:formatter
+ filter:[[[GTMLogMaximumLevelFilter alloc]
+ initWithMaximumLevel:kGTMLoggerLevelInfo]
+ autorelease]];
+ GTMLogger *stderrLogger =
+ [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError]
+ formatter:formatter
+ filter:[[[GTMLogMininumLevelFilter alloc]
+ initWithMinimumLevel:kGTMLoggerLevelError]
+ autorelease]];
+ GTMLogger *compositeWriter =
+ [self loggerWithWriter:[NSArray arrayWithObjects:
+ stdoutLogger, stderrLogger, nil]
+ formatter:formatter
+ filter:[[[GTMLogNoFilter alloc] init] autorelease]];
+ GTMLogger *outerLogger = [self standardLogger];
+ [outerLogger setWriter:compositeWriter];
+ return outerLogger;
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ return nil;
+}
+
++ (id)standardLoggerWithPath:(NSString *)path {
+ @try {
+ NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
+ if (fh == nil) return nil;
+ id me = [self standardLogger];
+ [me setWriter:fh];
+ return me;
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ return nil;
+}
+
++ (id)loggerWithWriter:(id<GTMLogWriter>)writer
+ formatter:(id<GTMLogFormatter>)formatter
+ filter:(id<GTMLogFilter>)filter {
+ return [[[self alloc] initWithWriter:writer
+ formatter:formatter
+ filter:filter] autorelease];
+}
+
++ (id)logger {
+ return [[[self alloc] init] autorelease];
+}
+
+- (id)init {
+ return [self initWithWriter:nil formatter:nil filter:nil];
+}
+
+- (id)initWithWriter:(id<GTMLogWriter>)writer
+ formatter:(id<GTMLogFormatter>)formatter
+ filter:(id<GTMLogFilter>)filter {
+ if ((self = [super init])) {
+ [self setWriter:writer];
+ [self setFormatter:formatter];
+ [self setFilter:filter];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ // Unlikely, but |writer_| may be an NSFileHandle, which can throw
+ @try {
+ [formatter_ release];
+ [filter_ release];
+ [writer_ release];
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ [super dealloc];
+}
+
+- (id<GTMLogWriter>)writer {
+ return [[writer_ retain] autorelease];
+}
+
+- (void)setWriter:(id<GTMLogWriter>)writer {
+ @synchronized(self) {
+ [writer_ autorelease];
+ writer_ = nil;
+ if (writer == nil) {
+ // Try to use stdout, but don't trust NSFileHandle
+ @try {
+ writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
+ }
+ @catch (id e) {
+ // Leave |writer_| nil
+ }
+ } else {
+ writer_ = [writer retain];
+ }
+ }
+}
+
+- (id<GTMLogFormatter>)formatter {
+ return [[formatter_ retain] autorelease];
+}
+
+- (void)setFormatter:(id<GTMLogFormatter>)formatter {
+ @synchronized(self) {
+ [formatter_ autorelease];
+ formatter_ = nil;
+ if (formatter == nil) {
+ @try {
+ formatter_ = [[GTMLogBasicFormatter alloc] init];
+ }
+ @catch (id e) {
+ // Leave |formatter_| nil
+ }
+ } else {
+ formatter_ = [formatter retain];
+ }
+ }
+}
+
+- (id<GTMLogFilter>)filter {
+ return [[filter_ retain] autorelease];
+}
+
+- (void)setFilter:(id<GTMLogFilter>)filter {
+ @synchronized(self) {
+ [filter_ autorelease];
+ filter_ = nil;
+ if (filter == nil) {
+ @try {
+ filter_ = [[GTMLogNoFilter alloc] init];
+ }
+ @catch (id e) {
+ // Leave |filter_| nil
+ }
+ } else {
+ filter_ = [filter retain];
+ }
+ }
+}
+
+- (void)logDebug:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug];
+ va_end(args);
+}
+
+- (void)logInfo:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo];
+ va_end(args);
+}
+
+- (void)logError:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError];
+ va_end(args);
+}
+
+- (void)logAssert:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert];
+ va_end(args);
+}
+
+@end // GTMLogger
+
+@implementation GTMLogger (GTMLoggerMacroHelpers)
+
+- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug];
+ va_end(args);
+}
+
+- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo];
+ va_end(args);
+}
+
+- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError];
+ va_end(args);
+}
+
+- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... {
+ va_list args;
+ va_start(args, fmt);
+ [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert];
+ va_end(args);
+}
+
+@end // GTMLoggerMacroHelpers
+
+@implementation GTMLogger (PrivateMethods)
+
+- (void)logInternalFunc:(const char *)func
+ format:(NSString *)fmt
+ valist:(va_list)args
+ level:(GTMLoggerLevel)level {
+ // Primary point where logging happens, logging should never throw, catch
+ // everything.
+ @try {
+ NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
+ NSString *msg = [formatter_ stringForFunc:fname
+ withFormat:fmt
+ valist:args
+ level:level];
+ if (msg && [filter_ filterAllowsMessage:msg level:level])
+ [writer_ logMessage:msg level:level];
+ }
+ @catch (id e) {
+ // Ignored
+ }
+}
+
+@end // PrivateMethods
+
+
+@implementation NSFileHandle (GTMFileHandleLogWriter)
+
++ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode {
+ int fd = -1;
+ if (path) {
+ int flags = O_WRONLY | O_APPEND | O_CREAT;
+ fd = open([path fileSystemRepresentation], flags, mode);
+ }
+ if (fd == -1) return nil;
+ return [[[self alloc] initWithFileDescriptor:fd
+ closeOnDealloc:YES] autorelease];
+}
+
+- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+ @synchronized(self) {
+ // Closed pipes should not generate exceptions in our caller. Catch here
+ // as well [GTMLogger logInternalFunc:...] so that an exception in this
+ // writer does not prevent other writers from having a chance.
+ @try {
+ NSString *line = [NSString stringWithFormat:@"%@\n", msg];
+ [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ @catch (id e) {
+ // Ignored
+ }
+ }
+}
+
+@end // GTMFileHandleLogWriter
+
+
+@implementation NSArray (GTMArrayCompositeLogWriter)
+
+- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+ @synchronized(self) {
+ id<GTMLogWriter> child = nil;
+ GTM_FOREACH_OBJECT(child, self) {
+ if ([child conformsToProtocol:@protocol(GTMLogWriter)])
+ [child logMessage:msg level:level];
+ }
+ }
+}
+
+@end // GTMArrayCompositeLogWriter
+
+
+@implementation GTMLogger (GTMLoggerLogWriter)
+
+- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+ switch (level) {
+ case kGTMLoggerLevelDebug:
+ [self logDebug:@"%@", msg];
+ break;
+ case kGTMLoggerLevelInfo:
+ [self logInfo:@"%@", msg];
+ break;
+ case kGTMLoggerLevelError:
+ [self logError:@"%@", msg];
+ break;
+ case kGTMLoggerLevelAssert:
+ [self logAssert:@"%@", msg];
+ break;
+ default:
+ // Ignore the message.
+ break;
+ }
+}
+
+@end // GTMLoggerLogWriter
+
+
+@implementation GTMLogBasicFormatter
+
+- (NSString *)prettyNameForFunc:(NSString *)func {
+ NSString *name = [func stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ NSString *function = @"(unknown)";
+ if ([name length]) {
+ if (// Objective C __func__ and __PRETTY_FUNCTION__
+ [name hasPrefix:@"-["] || [name hasPrefix:@"+["] ||
+ // C++ __PRETTY_FUNCTION__ and other preadorned formats
+ [name hasSuffix:@")"]) {
+ function = name;
+ } else {
+ // Assume C99 __func__
+ function = [NSString stringWithFormat:@"%@()", name];
+ }
+ }
+ return function;
+}
+
+- (NSString *)stringForFunc:(NSString *)func
+ withFormat:(NSString *)fmt
+ valist:(va_list)args
+ level:(GTMLoggerLevel)level {
+ // Performance note: We may want to do a quick check here to see if |fmt|
+ // contains a '%', and if not, simply return 'fmt'.
+ if (!(fmt && args)) return nil;
+ return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease];
+}
+
+@end // GTMLogBasicFormatter
+
+
+@implementation GTMLogStandardFormatter
+
+- (id)init {
+ if ((self = [super init])) {
+ dateFormatter_ = [[NSDateFormatter alloc] init];
+ [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4];
+ [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
+ pname_ = [[[NSProcessInfo processInfo] processName] copy];
+ pid_ = [[NSProcessInfo processInfo] processIdentifier];
+ if (!(dateFormatter_ && pname_)) {
+ [self release];
+ return nil;
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [dateFormatter_ release];
+ [pname_ release];
+ [super dealloc];
+}
+
+- (NSString *)stringForFunc:(NSString *)func
+ withFormat:(NSString *)fmt
+ valist:(va_list)args
+ level:(GTMLoggerLevel)level {
+ NSString *tstamp = nil;
+ @synchronized (dateFormatter_) {
+ tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
+ }
+ return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
+ tstamp, pname_, pid_, pthread_self(),
+ level, [self prettyNameForFunc:func],
+ // |super| has guard for nil |fmt| and |args|
+ [super stringForFunc:func withFormat:fmt valist:args level:level]];
+}
+
+@end // GTMLogStandardFormatter
+
+
+@implementation GTMLogLevelFilter
+
+// Check the environment and the user preferences for the GTMVerboseLogging key
+// to see if verbose logging has been enabled. The environment variable will
+// override the defaults setting, so check the environment first.
+// COV_NF_START
+static BOOL IsVerboseLoggingEnabled(void) {
+ static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
+ NSString *value = [[[NSProcessInfo processInfo] environment]
+ objectForKey:kVerboseLoggingKey];
+ if (value) {
+ // Emulate [NSString boolValue] for pre-10.5
+ value = [value stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if ([[value uppercaseString] hasPrefix:@"Y"] ||
+ [[value uppercaseString] hasPrefix:@"T"] ||
+ [value intValue]) {
+ return YES;
+ } else {
+ return NO;
+ }
+ }
+ return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
+}
+// COV_NF_END
+
+// In DEBUG builds, log everything. If we're not in a debug build we'll assume
+// that we're in a Release build.
+- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+#if defined(DEBUG) && DEBUG
+ return YES;
+#endif
+
+ BOOL allow = YES;
+
+ switch (level) {
+ case kGTMLoggerLevelDebug:
+ allow = NO;
+ break;
+ case kGTMLoggerLevelInfo:
+ allow = IsVerboseLoggingEnabled();
+ break;
+ case kGTMLoggerLevelError:
+ allow = YES;
+ break;
+ case kGTMLoggerLevelAssert:
+ allow = YES;
+ break;
+ default:
+ allow = YES;
+ break;
+ }
+
+ return allow;
+}
+
+@end // GTMLogLevelFilter
+
+
+@implementation GTMLogNoFilter
+
+- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+ return YES; // Allow everything through
+}
+
+@end // GTMLogNoFilter
+
+
+@implementation GTMLogAllowedLevelFilter
+
+// Private designated initializer
+- (id)initWithAllowedLevels:(NSIndexSet *)levels {
+ self = [super init];
+ if (self != nil) {
+ allowedLevels_ = [levels retain];
+ // Cap min/max level
+ if (!allowedLevels_ ||
+ // NSIndexSet is unsigned so only check the high bound, but need to
+ // check both first and last index because NSIndexSet appears to allow
+ // wraparound.
+ ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) ||
+ ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) {
+ [self release];
+ return nil;
+ }
+ }
+ return self;
+}
+
+- (id)init {
+ // Allow all levels in default init
+ return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
+ NSMakeRange(kGTMLoggerLevelUnknown,
+ (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]];
+}
+
+- (void)dealloc {
+ [allowedLevels_ release];
+ [super dealloc];
+}
+
+- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
+ return [allowedLevels_ containsIndex:level];
+}
+
+@end // GTMLogAllowedLevelFilter
+
+
+@implementation GTMLogMininumLevelFilter
+
+- (id)initWithMinimumLevel:(GTMLoggerLevel)level {
+ return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
+ NSMakeRange(level,
+ (kGTMLoggerLevelAssert - level + 1))]];
+}
+
+@end // GTMLogMininumLevelFilter
+
+
+@implementation GTMLogMaximumLevelFilter
+
+- (id)initWithMaximumLevel:(GTMLoggerLevel)level {
+ return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
+ NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]];
+}
+
+@end // GTMLogMaximumLevelFilter
+
+#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
+// See comment at top of file.
+#pragma GCC diagnostic error "-Wmissing-format-attribute"
+#endif // !__clang__
+
diff --git a/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.h b/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.h
new file mode 100644
index 0000000..42e8fed
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// HTTPMultipartUpload: A multipart/form-data HTTP uploader.
+// Each parameter pair is sent as a boundary
+// Each file is sent with a name field in addition to the filename and data
+// The data will be sent synchronously.
+
+#import <Foundation/Foundation.h>
+
+@interface HTTPMultipartUpload : NSObject {
+ @protected
+ NSURL *url_; // The destination URL (STRONG)
+ NSDictionary *parameters_; // The key/value pairs for sending data (STRONG)
+ NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG)
+ NSString *boundary_; // The boundary string (STRONG)
+ NSHTTPURLResponse *response_; // The response from the send (STRONG)
+}
+
+- (id)initWithURL:(NSURL *)url;
+
+- (NSURL *)URL;
+
+- (void)setParameters:(NSDictionary *)parameters;
+- (NSDictionary *)parameters;
+
+- (void)addFileAtPath:(NSString *)path name:(NSString *)name;
+- (void)addFileContents:(NSData *)data name:(NSString *)name;
+- (NSDictionary *)files;
+
+// Set the data and return the response
+- (NSData *)send:(NSError **)error;
+- (NSHTTPURLResponse *)response;
+
+@end
diff --git a/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.m b/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.m
new file mode 100644
index 0000000..f6d081e
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/HTTPMultipartUpload.m
@@ -0,0 +1,267 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "HTTPMultipartUpload.h"
+#import "GTMDefines.h"
+
+// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been
+// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it
+// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when
+// using those SDKs.
+static NSString *PercentEncodeNSString(NSString *key) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ return [key stringByAddingPercentEncodingWithAllowedCharacters:
+ [NSCharacterSet URLQueryAllowedCharacterSet]];
+#else
+ return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+#endif
+}
+
+// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has
+// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements
+// it using -[NSURLSession dataTaskWithRequest:completionHandler:] which is
+// available on iOS 7+.
+static NSData *SendSynchronousNSURLRequest(NSURLRequest *req,
+ NSURLResponse **out_response,
+ NSError **out_error) {
+#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_7_0) && \
+ __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) || \
+ (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \
+ defined(MAC_OS_X_VERSION_10_11) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11)
+ __block NSData* result = nil;
+ __block NSError* error = nil;
+ __block NSURLResponse* response = nil;
+ dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0);
+ [[[NSURLSession sharedSession]
+ dataTaskWithRequest:req
+ completionHandler:^(NSData *data,
+ NSURLResponse *resp,
+ NSError *err) {
+ if (out_error)
+ error = [err retain];
+ if (out_response)
+ response = [resp retain];
+ if (err == nil)
+ result = [data retain];
+ dispatch_semaphore_signal(wait_semaphone);
+ }] resume];
+ dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER);
+ dispatch_release(wait_semaphone);
+ if (out_error)
+ *out_error = [error autorelease];
+ if (out_response)
+ *out_response = [response autorelease];
+ return [result autorelease];
+#else
+ return [NSURLConnection sendSynchronousRequest:req
+ returningResponse:out_response
+ error:out_error];
+#endif
+}
+@interface HTTPMultipartUpload(PrivateMethods)
+- (NSString *)multipartBoundary;
+// Each of the following methods will append the starting multipart boundary,
+// but not the ending one.
+- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
+- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
+- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
+@end
+
+@implementation HTTPMultipartUpload
+//=============================================================================
+#pragma mark -
+#pragma mark || Private ||
+//=============================================================================
+- (NSString *)multipartBoundary {
+ // The boundary has 27 '-' characters followed by 16 hex digits
+ return [NSString stringWithFormat:@"---------------------------%08X%08X",
+ rand(), rand()];
+}
+
+//=============================================================================
+- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value {
+ NSString *escaped = PercentEncodeNSString(key);
+ NSString *fmt =
+ @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n";
+ NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value];
+
+ return [form dataUsingEncoding:NSUTF8StringEncoding];
+}
+
+//=============================================================================
+- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name {
+ NSMutableData *data = [NSMutableData data];
+ NSString *escaped = PercentEncodeNSString(name);
+ NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
+ "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
+ NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
+
+ [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
+ [data appendData:contents];
+
+ return data;
+}
+
+//=============================================================================
+- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name {
+ NSData *contents = [NSData dataWithContentsOfFile:file];
+
+ return [self formDataForFileContents:contents name:name];
+}
+
+//=============================================================================
+#pragma mark -
+#pragma mark || Public ||
+//=============================================================================
+- (id)initWithURL:(NSURL *)url {
+ if ((self = [super init])) {
+ url_ = [url copy];
+ boundary_ = [[self multipartBoundary] retain];
+ files_ = [[NSMutableDictionary alloc] init];
+ }
+
+ return self;
+}
+
+//=============================================================================
+- (void)dealloc {
+ [url_ release];
+ [parameters_ release];
+ [files_ release];
+ [boundary_ release];
+ [response_ release];
+
+ [super dealloc];
+}
+
+//=============================================================================
+- (NSURL *)URL {
+ return url_;
+}
+
+//=============================================================================
+- (void)setParameters:(NSDictionary *)parameters {
+ if (parameters != parameters_) {
+ [parameters_ release];
+ parameters_ = [parameters copy];
+ }
+}
+
+//=============================================================================
+- (NSDictionary *)parameters {
+ return parameters_;
+}
+
+//=============================================================================
+- (void)addFileAtPath:(NSString *)path name:(NSString *)name {
+ [files_ setObject:path forKey:name];
+}
+
+//=============================================================================
+- (void)addFileContents:(NSData *)data name:(NSString *)name {
+ [files_ setObject:data forKey:name];
+}
+
+//=============================================================================
+- (NSDictionary *)files {
+ return files_;
+}
+
+//=============================================================================
+- (NSData *)send:(NSError **)error {
+ NSMutableURLRequest *req =
+ [[NSMutableURLRequest alloc]
+ initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:10.0 ];
+
+ NSMutableData *postBody = [NSMutableData data];
+
+ [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",
+ boundary_] forHTTPHeaderField:@"Content-type"];
+
+ // Add any parameters to the message
+ NSArray *parameterKeys = [parameters_ allKeys];
+ NSString *key;
+
+ NSInteger count = [parameterKeys count];
+ for (NSInteger i = 0; i < count; ++i) {
+ key = [parameterKeys objectAtIndex:i];
+ [postBody appendData:[self formDataForKey:key
+ value:[parameters_ objectForKey:key]]];
+ }
+
+ // Add any files to the message
+ NSArray *fileNames = [files_ allKeys];
+ for (NSString *name in fileNames) {
+ id fileOrData = [files_ objectForKey:name];
+ NSData *fileData;
+
+ // The object can be either the path to a file (NSString) or the contents
+ // of the file (NSData).
+ if ([fileOrData isKindOfClass:[NSData class]])
+ fileData = [self formDataForFileContents:fileOrData name:name];
+ else
+ fileData = [self formDataForFile:fileOrData name:name];
+
+ [postBody appendData:fileData];
+ }
+
+ NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
+ [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
+
+ [req setHTTPBody:postBody];
+ [req setHTTPMethod:@"POST"];
+
+ [response_ release];
+ response_ = nil;
+
+ NSData *data = nil;
+ if ([[req URL] isFileURL]) {
+ [[req HTTPBody] writeToURL:[req URL] options:0 error:error];
+ } else {
+ NSURLResponse *response = nil;
+ data = SendSynchronousNSURLRequest(req, &response, error);
+ response_ = (NSHTTPURLResponse *)[response retain];
+ }
+ [req release];
+
+ return data;
+}
+
+//=============================================================================
+- (NSHTTPURLResponse *)response {
+ return response_;
+}
+
+@end
diff --git a/3rdParty/Breakpad/src/common/mac/MachIPC.h b/3rdParty/Breakpad/src/common/mac/MachIPC.h
index 52bed59..8df9165 100644
--- a/3rdParty/Breakpad/src/common/mac/MachIPC.h
+++ b/3rdParty/Breakpad/src/common/mac/MachIPC.h
@@ -164,11 +164,11 @@ class MachMessage {
public:
// The receiver of the message can retrieve the raw data this way
- u_int8_t *GetData() {
+ uint8_t *GetData() {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
- u_int32_t GetDataLength() {
+ uint32_t GetDataLength() {
return EndianU32_LtoN(GetDataPacket()->data_length);
}
@@ -210,7 +210,7 @@ class MachMessage {
struct MessageDataPacket {
int32_t id; // little-endian
int32_t data_length; // little-endian
- u_int8_t data[1]; // actual size limited by sizeof(MachMessage)
+ uint8_t data[1]; // actual size limited by sizeof(MachMessage)
};
MessageDataPacket* GetDataPacket();
@@ -223,7 +223,7 @@ class MachMessage {
mach_msg_header_t head;
mach_msg_body_t body;
- u_int8_t padding[1024]; // descriptors and data may be embedded here
+ uint8_t padding[1024]; // descriptors and data may be embedded here
};
//==============================================================================
diff --git a/3rdParty/Breakpad/src/common/mac/arch_utilities.cc b/3rdParty/Breakpad/src/common/mac/arch_utilities.cc
new file mode 100644
index 0000000..c9225e0
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/arch_utilities.cc
@@ -0,0 +1,231 @@
+// Copyright (c) 2012, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/mac/arch_utilities.h"
+
+#include <mach-o/arch.h>
+#include <mach-o/fat.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef CPU_SUBTYPE_ARM_V7S
+#define CPU_SUBTYPE_ARM_V7S (static_cast<cpu_subtype_t>(11))
+#endif // CPU_SUBTYPE_ARM_V7S
+
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
+#endif // CPU_TYPE_ARM64
+
+#ifndef CPU_SUBTYPE_ARM64_ALL
+#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_subtype_t>(0))
+#endif // CPU_SUBTYPE_ARM64_ALL
+
+namespace {
+
+const NXArchInfo* ArchInfo_arm64() {
+ NXArchInfo* arm64 = new NXArchInfo;
+ *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
+ CPU_SUBTYPE_ARM_V7);
+ arm64->name = "arm64";
+ arm64->cputype = CPU_TYPE_ARM64;
+ arm64->cpusubtype = CPU_SUBTYPE_ARM64_ALL;
+ arm64->description = "arm 64";
+ return arm64;
+}
+
+const NXArchInfo* ArchInfo_armv7s() {
+ NXArchInfo* armv7s = new NXArchInfo;
+ *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
+ CPU_SUBTYPE_ARM_V7);
+ armv7s->name = "armv7s";
+ armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S;
+ armv7s->description = "arm v7s";
+ return armv7s;
+}
+
+} // namespace
+
+namespace google_breakpad {
+
+const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) {
+ // TODO: Remove this when the OS knows about arm64.
+ if (!strcmp("arm64", arch_name))
+ return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64,
+ CPU_SUBTYPE_ARM64_ALL);
+
+ // TODO: Remove this when the OS knows about armv7s.
+ if (!strcmp("armv7s", arch_name))
+ return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S);
+
+ return NXGetArchInfoFromName(arch_name);
+}
+
+const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype) {
+ // TODO: Remove this when the OS knows about arm64.
+ if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) {
+ static const NXArchInfo* arm64 = ArchInfo_arm64();
+ return arm64;
+ }
+
+ // TODO: Remove this when the OS knows about armv7s.
+ if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) {
+ static const NXArchInfo* armv7s = ArchInfo_armv7s();
+ return armv7s;
+ }
+
+ return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
+}
+
+} // namespace google_breakpad
+
+#ifndef __APPLE__
+namespace {
+
+enum Architecture {
+ kArch_i386 = 0,
+ kArch_x86_64,
+ kArch_x86_64h,
+ kArch_arm,
+ kArch_arm64,
+ kArch_ppc,
+ // This must be last.
+ kNumArchitectures
+};
+
+// enum Architecture above and kKnownArchitectures below
+// must be kept in sync.
+const NXArchInfo kKnownArchitectures[] = {
+ {
+ "i386",
+ CPU_TYPE_I386,
+ CPU_SUBTYPE_I386_ALL,
+ NX_LittleEndian,
+ "Intel 80x86"
+ },
+ {
+ "x86_64",
+ CPU_TYPE_X86_64,
+ CPU_SUBTYPE_X86_64_ALL,
+ NX_LittleEndian,
+ "Intel x86-64"
+ },
+ {
+ "x86_64h",
+ CPU_TYPE_X86_64,
+ CPU_SUBTYPE_X86_64_H,
+ NX_LittleEndian,
+ "Intel x86-64h Haswell"
+ },
+ {
+ "arm",
+ CPU_TYPE_ARM,
+ CPU_SUBTYPE_ARM_ALL,
+ NX_LittleEndian,
+ "ARM"
+ },
+ {
+ "arm64",
+ CPU_TYPE_ARM64,
+ CPU_SUBTYPE_ARM64_ALL,
+ NX_LittleEndian,
+ "ARM64"
+ },
+ {
+ "ppc",
+ CPU_TYPE_POWERPC,
+ CPU_SUBTYPE_POWERPC_ALL,
+ NX_BigEndian,
+ "PowerPC"
+ }
+};
+
+} // namespace
+
+const NXArchInfo *NXGetLocalArchInfo(void) {
+ Architecture arch;
+#if defined(__i386__)
+ arch = kArch_i386;
+#elif defined(__x86_64__)
+ arch = kArch_x86_64;
+#elif defined(__arm64)
+ arch = kArch_arm64;
+#elif defined(__arm__)
+ arch = kArch_arm;
+#elif defined(__powerpc__)
+ arch = kArch_ppc;
+#else
+ #error "Unsupported CPU architecture"
+#endif
+ return &kKnownArchitectures[arch];
+}
+
+const NXArchInfo *NXGetArchInfoFromName(const char *name) {
+ for (int arch = 0; arch < kNumArchitectures; ++arch) {
+ if (!strcmp(name, kKnownArchitectures[arch].name)) {
+ return &kKnownArchitectures[arch];
+ }
+ }
+ return NULL;
+}
+
+const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype,
+ cpu_subtype_t cpusubtype) {
+ const NXArchInfo *candidate = NULL;
+ for (int arch = 0; arch < kNumArchitectures; ++arch) {
+ if (kKnownArchitectures[arch].cputype == cputype) {
+ if (kKnownArchitectures[arch].cpusubtype == cpusubtype) {
+ return &kKnownArchitectures[arch];
+ }
+ if (!candidate) {
+ candidate = &kKnownArchitectures[arch];
+ }
+ }
+ }
+ return candidate;
+}
+
+struct fat_arch *NXFindBestFatArch(cpu_type_t cputype,
+ cpu_subtype_t cpusubtype,
+ struct fat_arch *fat_archs,
+ uint32_t nfat_archs) {
+ struct fat_arch *candidate = NULL;
+ for (uint32_t f = 0; f < nfat_archs; ++f) {
+ if (fat_archs[f].cputype == cputype) {
+ if (fat_archs[f].cpusubtype == cpusubtype) {
+ return &fat_archs[f];
+ }
+ if (!candidate) {
+ candidate = &fat_archs[f];
+ }
+ }
+ }
+ return candidate;
+}
+#endif // !__APPLE__
diff --git a/3rdParty/Breakpad/src/common/mac/arch_utilities.h b/3rdParty/Breakpad/src/common/mac/arch_utilities.h
new file mode 100644
index 0000000..397c1f5
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/arch_utilities.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// arch_utilities.h: Utilities for architecture introspection for Mac platform.
+
+#ifndef COMMON_MAC_ARCH_UTILITIES_H__
+#define COMMON_MAC_ARCH_UTILITIES_H__
+
+#include <mach-o/arch.h>
+
+namespace google_breakpad {
+
+// Custom implementation of |NXGetArchInfoFromName| and
+// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes.
+const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name);
+const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype);
+
+} // namespace google_breakpad
+
+#endif // COMMON_MAC_ARCH_UTILITIES_H__
diff --git a/3rdParty/Breakpad/src/common/mac/byteswap.h b/3rdParty/Breakpad/src/common/mac/byteswap.h
index a5d745b..b7bbc0b 100644
--- a/3rdParty/Breakpad/src/common/mac/byteswap.h
+++ b/3rdParty/Breakpad/src/common/mac/byteswap.h
@@ -36,6 +36,7 @@
#ifndef COMMON_MAC_BYTESWAP_H_
#define COMMON_MAC_BYTESWAP_H_
+#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); }
@@ -45,4 +46,28 @@ static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); }
static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); }
static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); }
+#elif defined(__linux__)
+// For NXByteOrder
+#include <architecture/byte_order.h>
+#include <stdint.h>
+#include <endian.h>
+#include_next <byteswap.h>
+
+static inline uint16_t ByteSwap(uint16_t v) { return bswap_16(v); }
+static inline uint32_t ByteSwap(uint32_t v) { return bswap_32(v); }
+static inline uint64_t ByteSwap(uint64_t v) { return bswap_64(v); }
+static inline int16_t ByteSwap(int16_t v) { return bswap_16(v); }
+static inline int32_t ByteSwap(int32_t v) { return bswap_32(v); }
+static inline int64_t ByteSwap(int64_t v) { return bswap_64(v); }
+
+static inline NXByteOrder NXHostByteOrder() {
+#ifdef __LITTLE_ENDIAN
+ return NX_LittleEndian;
+#else
+ return NX_BigEndian;
+#endif
+}
+
+#endif // __APPLE__
+
#endif // COMMON_MAC_BYTESWAP_H_
diff --git a/3rdParty/Breakpad/src/common/mac/dump_syms.mm b/3rdParty/Breakpad/src/common/mac/dump_syms.cc
index 9783514..eb92729 100644
--- a/3rdParty/Breakpad/src/common/mac/dump_syms.mm
+++ b/3rdParty/Breakpad/src/common/mac/dump_syms.cc
@@ -31,14 +31,21 @@
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
-// dump_syms.mm: Create a symbol file for use with minidumps
+// dump_syms.cc: Create a symbol file for use with minidumps
#include "common/mac/dump_syms.h"
-#include <Foundation/Foundation.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libgen.h>
#include <mach-o/arch.h>
#include <mach-o/fat.h>
+#include <stdint.h>
#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <ostream>
#include <string>
@@ -50,15 +57,22 @@
#include "common/dwarf_cu_to_module.h"
#include "common/dwarf_line_to_module.h"
#include "common/mac/file_id.h"
+#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
+#include "common/scoped_ptr.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
+#include "common/symbol_data.h"
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
#endif // CPU_TYPE_ARM
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228))
+#endif // CPU_TYPE_ARM64
+
using dwarf2reader::ByteReader;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
@@ -69,109 +83,126 @@ using google_breakpad::mach_o::Segment;
using google_breakpad::Module;
using google_breakpad::StabsReader;
using google_breakpad::StabsToModule;
+using google_breakpad::scoped_ptr;
using std::make_pair;
using std::pair;
using std::string;
using std::vector;
+namespace {
+// Return a vector<string> with absolute paths to all the entries
+// in directory (excluding . and ..).
+vector<string> list_directory(const string& directory) {
+ vector<string> entries;
+ DIR* dir = opendir(directory.c_str());
+ if (!dir) {
+ return entries;
+ }
+
+ string path = directory;
+ if (path[path.length() - 1] != '/') {
+ path += '/';
+ }
+
+ struct dirent* entry = NULL;
+ while ((entry = readdir(dir))) {
+ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
+ entries.push_back(path + entry->d_name);
+ }
+ }
+
+ closedir(dir);
+ return entries;
+}
+}
+
namespace google_breakpad {
-bool DumpSymbols::Read(NSString *filename) {
- if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
- fprintf(stderr, "Object file does not exist: %s\n",
- [filename fileSystemRepresentation]);
+bool DumpSymbols::Read(const string &filename) {
+ struct stat st;
+ if (stat(filename.c_str(), &st) == -1) {
+ fprintf(stderr, "Could not access object file %s: %s\n",
+ filename.c_str(), strerror(errno));
return false;
}
- input_pathname_ = [filename retain];
+ input_pathname_ = filename;
// Does this filename refer to a dSYM bundle?
- NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_];
-
- if (bundle) {
- // Filenames referring to bundles usually have names of the form
- // "<basename>.dSYM"; however, if the user has specified a wrapper
- // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
- // then the name may have the form "<basename>.<extension>.dSYM". In
- // either case, the resource name for the file containing the DWARF
- // info within the bundle is <basename>.
- //
- // Since there's no way to tell how much to strip off, remove one
- // extension at a time, and use the first one that
- // pathForResource:ofType:inDirectory likes.
- NSString *base_name = [input_pathname_ lastPathComponent];
- NSString *dwarf_resource;
-
- do {
- NSString *new_base_name = [base_name stringByDeletingPathExtension];
-
- // If stringByDeletingPathExtension returned the name unchanged, then
- // there's nothing more for us to strip off --- lose.
- if ([new_base_name isEqualToString:base_name]) {
- fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
- [input_pathname_ fileSystemRepresentation]);
- return false;
- }
-
- // Take the shortened result as our new base_name.
- base_name = new_base_name;
-
- // Try to find a DWARF resource in the bundle under the new base_name.
- dwarf_resource = [bundle pathForResource:base_name
- ofType:nil inDirectory:@"DWARF"];
- } while (!dwarf_resource);
+ string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
+ if (S_ISDIR(st.st_mode) &&
+ access(contents_path.c_str(), F_OK) == 0) {
+ // If there's one file under Contents/Resources/DWARF then use that,
+ // otherwise bail out.
+ const vector<string> entries = list_directory(contents_path);
+ if (entries.size() == 0) {
+ fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
+ input_pathname_.c_str());
+ return false;
+ }
+ if (entries.size() > 1) {
+ fprintf(stderr, "Too many DWARF files in bundle: %s\n",
+ input_pathname_.c_str());
+ return false;
+ }
- object_filename_ = [dwarf_resource retain];
+ object_filename_ = entries[0];
} else {
- object_filename_ = [input_pathname_ retain];
+ object_filename_ = input_pathname_;
}
// Read the file's contents into memory.
- //
- // The documentation for dataWithContentsOfMappedFile says:
- //
- // Because of file mapping restrictions, this method should only be
- // used if the file is guaranteed to exist for the duration of the
- // data object’s existence. It is generally safer to use the
- // dataWithContentsOfFile: method.
- //
- // I gather this means that OS X doesn't have (or at least, that method
- // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the
- // process appears to get its own copy of the data, and changes to the
- // file don't affect memory and vice versa).
- NSError *error;
- contents_ = [NSData dataWithContentsOfFile:object_filename_
- options:0
- error:&error];
- if (!contents_) {
+ bool read_ok = true;
+ string error;
+ if (stat(object_filename_.c_str(), &st) != -1) {
+ FILE* f = fopen(object_filename_.c_str(), "rb");
+ if (f) {
+ contents_.reset(new uint8_t[st.st_size]);
+ off_t total = 0;
+ while (total < st.st_size && !feof(f)) {
+ size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f);
+ if (read == 0) {
+ if (ferror(f)) {
+ read_ok = false;
+ error = strerror(errno);
+ }
+ break;
+ }
+ total += read;
+ }
+ fclose(f);
+ } else {
+ error = strerror(errno);
+ }
+ }
+
+ if (!read_ok) {
fprintf(stderr, "Error reading object file: %s: %s\n",
- [object_filename_ fileSystemRepresentation],
- [[error localizedDescription] UTF8String]);
+ object_filename_.c_str(),
+ error.c_str());
return false;
}
- [contents_ retain];
// Get the list of object files present in the file.
- FatReader::Reporter fat_reporter([object_filename_
- fileSystemRepresentation]);
+ FatReader::Reporter fat_reporter(object_filename_);
FatReader fat_reader(&fat_reporter);
- if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
- [contents_ length])) {
+ if (!fat_reader.Read(&contents_[0],
+ st.st_size)) {
return false;
}
// Get our own copy of fat_reader's object file list.
size_t object_files_count;
- const struct fat_arch *object_files =
+ const SuperFatArch *object_files =
fat_reader.object_files(&object_files_count);
if (object_files_count == 0) {
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
- [object_filename_ fileSystemRepresentation]);
+ object_filename_.c_str());
return false;
}
object_files_.resize(object_files_count);
memcpy(&object_files_[0], object_files,
- sizeof(struct fat_arch) * object_files_count);
+ sizeof(SuperFatArch) * object_files_count);
return true;
}
@@ -179,9 +210,8 @@ bool DumpSymbols::Read(NSString *filename) {
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype) {
// Find the best match for the architecture the user requested.
- const struct fat_arch *best_match
- = NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
- static_cast<uint32_t>(object_files_.size()));
+ const SuperFatArch *best_match = FindBestMatchForArchitecture(
+ cpu_type, cpu_subtype);
if (!best_match) return false;
// Record the selected object file.
@@ -191,20 +221,73 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
bool arch_set = false;
- const NXArchInfo *arch_info = NXGetArchInfoFromName(arch_name.c_str());
+ const NXArchInfo *arch_info =
+ google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
if (arch_info) {
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
}
return arch_set;
}
+SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
+ cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
+ // Check if all the object files can be converted to struct fat_arch.
+ bool can_convert_to_fat_arch = true;
+ vector<struct fat_arch> fat_arch_vector;
+ for (vector<SuperFatArch>::const_iterator it = object_files_.begin();
+ it != object_files_.end();
+ ++it) {
+ struct fat_arch arch;
+ bool success = it->ConvertToFatArch(&arch);
+ if (!success) {
+ can_convert_to_fat_arch = false;
+ break;
+ }
+ fat_arch_vector.push_back(arch);
+ }
+
+ // If all the object files can be converted to struct fat_arch, use
+ // NXFindBestFatArch.
+ if (can_convert_to_fat_arch) {
+ const struct fat_arch *best_match
+ = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
+ static_cast<uint32_t>(fat_arch_vector.size()));
+
+ for (size_t i = 0; i < fat_arch_vector.size(); ++i) {
+ if (best_match == &fat_arch_vector[i])
+ return &object_files_[i];
+ }
+ assert(best_match == NULL);
+ return NULL;
+ }
+
+ // Check for an exact match with cpu_type and cpu_subtype.
+ for (vector<SuperFatArch>::iterator it = object_files_.begin();
+ it != object_files_.end();
+ ++it) {
+ if (static_cast<cpu_type_t>(it->cputype) == cpu_type &&
+ static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype)
+ return &*it;
+ }
+
+ // No exact match found.
+ // TODO(erikchen): If it becomes necessary, we can copy the implementation of
+ // NXFindBestFatArch, located at
+ // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
+ fprintf(stderr, "Failed to find an exact match for an object file with cpu "
+ "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
+ "larger than 2**32.\n", cpu_type, cpu_subtype);
+ return NULL;
+}
+
string DumpSymbols::Identifier() {
- FileID file_id([object_filename_ fileSystemRepresentation]);
+ FileID file_id(object_filename_.c_str());
unsigned char identifier_bytes[16];
cpu_type_t cpu_type = selected_object_file_->cputype;
- if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
+ cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
+ if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
- [object_filename_ fileSystemRepresentation]);
+ object_filename_.c_str());
return "";
}
@@ -224,24 +307,90 @@ string DumpSymbols::Identifier() {
// dwarf2reader::LineInfo and populates a Module and a line vector
// with the results.
class DumpSymbols::DumperLineToModule:
- public DwarfCUToModule::LineToModuleFunctor {
+ public DwarfCUToModule::LineToModuleHandler {
public:
// Create a line-to-module converter using BYTE_READER.
DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
: byte_reader_(byte_reader) { }
- void operator()(const char *program, uint64 length,
- Module *module, vector<Module::Line> *lines) {
- DwarfLineToModule handler(module, lines);
+
+ void StartCompilationUnit(const string& compilation_dir) {
+ compilation_dir_ = compilation_dir;
+ }
+
+ void ReadProgram(const uint8_t *program, uint64 length,
+ Module *module, vector<Module::Line> *lines) {
+ DwarfLineToModule handler(module, compilation_dir_, lines);
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
parser.Start();
}
private:
+ string compilation_dir_;
dwarf2reader::ByteReader *byte_reader_; // WEAK
};
+bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) {
+ // Select an object file, if SetArchitecture hasn't been called to set one
+ // explicitly.
+ if (!selected_object_file_) {
+ // If there's only one architecture, that's the one.
+ if (object_files_.size() == 1)
+ selected_object_file_ = &object_files_[0];
+ else {
+ // Look for an object file whose architecture matches our own.
+ const NXArchInfo *local_arch = NXGetLocalArchInfo();
+ if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
+ fprintf(stderr, "%s: object file contains more than one"
+ " architecture, none of which match the current"
+ " architecture; specify an architecture explicitly"
+ " with '-a ARCH' to resolve the ambiguity\n",
+ object_filename_.c_str());
+ return false;
+ }
+ }
+ }
+
+ assert(selected_object_file_);
+
+ // Find the name of the selected file's architecture, to appear in
+ // the MODULE record and in error messages.
+ const NXArchInfo *selected_arch_info =
+ google_breakpad::BreakpadGetArchInfoFromCpuType(
+ selected_object_file_->cputype, selected_object_file_->cpusubtype);
+
+ const char *selected_arch_name = selected_arch_info->name;
+ if (strcmp(selected_arch_name, "i386") == 0)
+ selected_arch_name = "x86";
+
+ // Produce a name to use in error messages that includes the
+ // filename, and the architecture, if there is more than one.
+ selected_object_name_ = object_filename_;
+ if (object_files_.size() > 1) {
+ selected_object_name_ += ", architecture ";
+ selected_object_name_ + selected_arch_name;
+ }
+
+ // Compute a module name, to appear in the MODULE record.
+ string module_name = object_filename_;
+ module_name = basename(&module_name[0]);
+
+ // Choose an identifier string, to appear in the MODULE record.
+ string identifier = Identifier();
+ if (identifier.empty())
+ return false;
+ identifier += "0";
+
+ // Create a module to hold the debugging information.
+ module.reset(new Module(module_name,
+ "mac",
+ selected_arch_name,
+ identifier));
+ return true;
+}
+
bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections) const {
+ const mach_o::SectionMap &dwarf_sections,
+ bool handle_inter_cu_refs) const {
// Build a byte reader of the appropriate endianness.
ByteReader byte_reader(macho_reader.big_endian()
? dwarf2reader::ENDIANNESS_BIG
@@ -249,19 +398,24 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
// Construct a context for this file.
DwarfCUToModule::FileContext file_context(selected_object_name_,
- module);
+ module,
+ handle_inter_cu_refs);
// Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
- it != dwarf_sections.end(); it++) {
- file_context.section_map[it->first] =
- make_pair(reinterpret_cast<const char *>(it->second.contents.start),
- it->second.contents.Size());
+ it != dwarf_sections.end(); ++it) {
+ file_context.AddSectionToSectionMap(
+ it->first,
+ it->second.contents.start,
+ it->second.contents.Size());
}
// Find the __debug_info section.
- std::pair<const char *, uint64> debug_info_section
- = file_context.section_map["__debug_info"];
+ dwarf2reader::SectionMap::const_iterator debug_info_entry =
+ file_context.section_map().find("__debug_info");
+ assert(debug_info_entry != file_context.section_map().end());
+ const std::pair<const uint8_t *, uint64>& debug_info_section =
+ debug_info_entry->second;
// There had better be a __debug_info section!
if (!debug_info_section.first) {
fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
@@ -283,7 +437,8 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
// Make a Dwarf2Handler that drives our DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.
- dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map,
+ dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_,
+ file_context.section_map(),
offset,
&byte_reader,
&die_dispatcher);
@@ -311,10 +466,12 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
case CPU_TYPE_ARM:
register_names = DwarfCFIToModule::RegisterNames::ARM();
break;
+ case CPU_TYPE_ARM64:
+ register_names = DwarfCFIToModule::RegisterNames::ARM64();
+ break;
default: {
- const NXArchInfo *arch =
- NXGetArchInfoFromCpuType(macho_reader.cpu_type(),
- macho_reader.cpu_subtype());
+ const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
+ macho_reader.cpu_type(), macho_reader.cpu_subtype());
fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
selected_object_name_.c_str());
if (arch)
@@ -328,7 +485,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
}
// Find the call frame information and its size.
- const char *cfi = reinterpret_cast<const char *>(section.contents.start);
+ const uint8_t *cfi = section.contents.start;
size_t cfi_size = section.contents.Size();
// Plug together the parser, handler, and their entourages.
@@ -362,8 +519,14 @@ class DumpSymbols::LoadCommandDumper:
// file, and adding data to MODULE.
LoadCommandDumper(const DumpSymbols &dumper,
google_breakpad::Module *module,
- const mach_o::Reader &reader)
- : dumper_(dumper), module_(module), reader_(reader) { }
+ const mach_o::Reader &reader,
+ SymbolData symbol_data,
+ bool handle_inter_cu_refs)
+ : dumper_(dumper),
+ module_(module),
+ reader_(reader),
+ symbol_data_(symbol_data),
+ handle_inter_cu_refs_(handle_inter_cu_refs) { }
bool SegmentCommand(const mach_o::Segment &segment);
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
@@ -372,6 +535,8 @@ class DumpSymbols::LoadCommandDumper:
const DumpSymbols &dumper_;
google_breakpad::Module *module_; // WEAK
const mach_o::Reader &reader_;
+ const SymbolData symbol_data_;
+ const bool handle_inter_cu_refs_;
};
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
@@ -381,23 +546,31 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
if (segment.name == "__TEXT") {
module_->SetLoadAddress(segment.vmaddr);
- mach_o::SectionMap::const_iterator eh_frame =
- section_map.find("__eh_frame");
- if (eh_frame != section_map.end()) {
- // If there is a problem reading this, don't treat it as a fatal error.
- dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
+ if (symbol_data_ != NO_CFI) {
+ mach_o::SectionMap::const_iterator eh_frame =
+ section_map.find("__eh_frame");
+ if (eh_frame != section_map.end()) {
+ // If there is a problem reading this, don't treat it as a fatal error.
+ dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
+ }
}
return true;
}
if (segment.name == "__DWARF") {
- if (!dumper_.ReadDwarf(module_, reader_, section_map))
- return false;
- mach_o::SectionMap::const_iterator debug_frame
- = section_map.find("__debug_frame");
- if (debug_frame != section_map.end()) {
- // If there is a problem reading this, don't treat it as a fatal error.
- dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
+ if (symbol_data_ != ONLY_CFI) {
+ if (!dumper_.ReadDwarf(module_, reader_, section_map,
+ handle_inter_cu_refs_)) {
+ return false;
+ }
+ }
+ if (symbol_data_ != NO_CFI) {
+ mach_o::SectionMap::const_iterator debug_frame
+ = section_map.find("__debug_frame");
+ if (debug_frame != section_map.end()) {
+ // If there is a problem reading this, don't treat it as a fatal error.
+ dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
+ }
}
}
@@ -421,64 +594,15 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
return true;
}
-bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
- // Select an object file, if SetArchitecture hasn't been called to set one
- // explicitly.
- if (!selected_object_file_) {
- // If there's only one architecture, that's the one.
- if (object_files_.size() == 1)
- selected_object_file_ = &object_files_[0];
- else {
- // Look for an object file whose architecture matches our own.
- const NXArchInfo *local_arch = NXGetLocalArchInfo();
- if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
- fprintf(stderr, "%s: object file contains more than one"
- " architecture, none of which match the current"
- " architecture; specify an architecture explicitly"
- " with '-a ARCH' to resolve the ambiguity\n",
- [object_filename_ fileSystemRepresentation]);
- return false;
- }
- }
- }
-
- assert(selected_object_file_);
-
- // Find the name of the selected file's architecture, to appear in
- // the MODULE record and in error messages.
- const NXArchInfo *selected_arch_info
- = NXGetArchInfoFromCpuType(selected_object_file_->cputype,
- selected_object_file_->cpusubtype);
-
- const char *selected_arch_name = selected_arch_info->name;
- if (strcmp(selected_arch_name, "i386") == 0)
- selected_arch_name = "x86";
-
- // Produce a name to use in error messages that includes the
- // filename, and the architecture, if there is more than one.
- selected_object_name_ = [object_filename_ UTF8String];
- if (object_files_.size() > 1) {
- selected_object_name_ += ", architecture ";
- selected_object_name_ + selected_arch_name;
- }
-
- // Compute a module name, to appear in the MODULE record.
- NSString *module_name = [object_filename_ lastPathComponent];
-
- // Choose an identifier string, to appear in the MODULE record.
- string identifier = Identifier();
- if (identifier.empty())
+bool DumpSymbols::ReadSymbolData(Module** out_module) {
+ scoped_ptr<Module> module;
+ if (!CreateEmptyModule(module))
return false;
- identifier += "0";
-
- // Create a module to hold the debugging information.
- Module module([module_name UTF8String], "mac", selected_arch_name,
- identifier);
// Parse the selected object file.
mach_o::Reader::Reporter reporter(selected_object_name_);
mach_o::Reader reader(&reporter);
- if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
+ if (!reader.Read(&contents_[0]
+ selected_object_file_->offset,
selected_object_file_->size,
selected_object_file_->cputype,
@@ -486,11 +610,37 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
return false;
// Walk its load commands, and deal with whatever is there.
- LoadCommandDumper load_command_dumper(*this, &module, reader);
+ LoadCommandDumper load_command_dumper(*this, module.get(), reader,
+ symbol_data_, handle_inter_cu_refs_);
if (!reader.WalkLoadCommands(&load_command_dumper))
return false;
- return module.Write(stream, cfi);
+ *out_module = module.release();
+
+ return true;
+}
+
+bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
+ Module* module = NULL;
+
+ if (ReadSymbolData(&module) && module) {
+ bool res = module->Write(stream, symbol_data_);
+ delete module;
+ return res;
+ }
+
+ return false;
+}
+
+// Read the selected object file's debugging information, and write out the
+// header only to |stream|. Return true on success; if an error occurs, report
+// it and return false.
+bool DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) {
+ scoped_ptr<Module> module;
+ if (!CreateEmptyModule(module))
+ return false;
+
+ return module->Write(stream, symbol_data_);
}
} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/mac/dump_syms.h b/3rdParty/Breakpad/src/common/mac/dump_syms.h
index 0e2f464..9463f7d 100644
--- a/3rdParty/Breakpad/src/common/mac/dump_syms.h
+++ b/3rdParty/Breakpad/src/common/mac/dump_syms.h
@@ -35,7 +35,6 @@
// reading debugging information from Mach-O files and writing it out as a
// Breakpad symbol file.
-#include <Foundation/Foundation.h>
#include <mach-o/loader.h>
#include <stdio.h>
#include <stdlib.h>
@@ -46,33 +45,32 @@
#include "common/byte_cursor.h"
#include "common/mac/macho_reader.h"
+#include "common/mac/super_fat_arch.h"
#include "common/module.h"
+#include "common/scoped_ptr.h"
+#include "common/symbol_data.h"
namespace google_breakpad {
class DumpSymbols {
public:
- DumpSymbols()
- : input_pathname_(),
+ DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs)
+ : symbol_data_(symbol_data),
+ handle_inter_cu_refs_(handle_inter_cu_refs),
+ input_pathname_(),
object_filename_(),
contents_(),
+ object_files_(),
selected_object_file_(),
selected_object_name_() { }
~DumpSymbols() {
- [input_pathname_ release];
- [object_filename_ release];
- [contents_ release];
}
// Prepare to read debugging information from |filename|. |filename| may be
// the name of a universal binary, a Mach-O file, or a dSYM bundle
// containing either of the above. On success, return true; if there is a
// problem reading |filename|, report it and return false.
- //
- // (This class uses NSString for filenames and related values,
- // because the Mac Foundation framework seems to support
- // filename-related operations more fully on NSString values.)
- bool Read(NSString *filename);
+ bool Read(const std::string &filename);
// If this dumper's file includes an object file for |cpu_type| and
// |cpu_subtype|, then select that object file for dumping, and return
@@ -95,14 +93,14 @@ class DumpSymbols {
// architecture matches that of this dumper program.
bool SetArchitecture(const std::string &arch_name);
- // Return a pointer to an array of 'struct fat_arch' structures,
- // describing the object files contained in this dumper's file. Set
- // *|count| to the number of elements in the array. The returned array is
- // owned by this DumpSymbols instance.
+ // Return a pointer to an array of SuperFatArch structures describing the
+ // object files contained in this dumper's file. Set *|count| to the number
+ // of elements in the array. The returned array is owned by this DumpSymbols
+ // instance.
//
// If there are no available architectures, this function
// may return NULL.
- const struct fat_arch *AvailableArchitectures(size_t *count) {
+ const SuperFatArch* AvailableArchitectures(size_t *count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -110,24 +108,44 @@ class DumpSymbols {
}
// Read the selected object file's debugging information, and write it out to
- // |stream|. Write the CFI section if |cfi| is true. Return true on success;
- // if an error occurs, report it and return false.
- bool WriteSymbolFile(std::ostream &stream, bool cfi);
+ // |stream|. Return true on success; if an error occurs, report it and
+ // return false.
+ bool WriteSymbolFile(std::ostream &stream);
+
+ // Read the selected object file's debugging information, and write out the
+ // header only to |stream|. Return true on success; if an error occurs, report
+ // it and return false.
+ bool WriteSymbolFileHeader(std::ostream &stream);
+
+ // As above, but simply return the debugging information in module
+ // instead of writing it to a stream. The caller owns the resulting
+ // module object and must delete it when finished.
+ bool ReadSymbolData(Module** module);
private:
// Used internally.
class DumperLineToModule;
class LoadCommandDumper;
+ // This method behaves similarly to NXFindBestFatArch, but it supports
+ // SuperFatArch.
+ SuperFatArch* FindBestMatchForArchitecture(
+ cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
+
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
+
+ // Creates an empty module object.
+ bool CreateEmptyModule(scoped_ptr<Module>& module);
+
// Read debugging information from |dwarf_sections|, which was taken from
// |macho_reader|, and add it to |module|. On success, return true;
// on failure, report the problem and return false.
bool ReadDwarf(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
- const mach_o::SectionMap &dwarf_sections) const;
+ const mach_o::SectionMap &dwarf_sections,
+ bool handle_inter_cu_refs) const;
// Read DWARF CFI or .eh_frame data from |section|, belonging to
// |macho_reader|, and record it in |module|. If |eh_frame| is true,
@@ -139,28 +157,34 @@ class DumpSymbols {
const mach_o::Section &section,
bool eh_frame) const;
+ // The selection of what type of symbol data to read/write.
+ const SymbolData symbol_data_;
+
+ // Whether to handle references between compilation units.
+ const bool handle_inter_cu_refs_;
+
// The name of the file or bundle whose symbols this will dump.
// This is the path given to Read, for use in error messages.
- NSString *input_pathname_;
+ std::string input_pathname_;
// The name of the file this DumpSymbols will actually read debugging
// information from. Normally, this is the same as input_pathname_, but if
// filename refers to a dSYM bundle, then this is the resource file
// within that bundle.
- NSString *object_filename_;
+ std::string object_filename_;
// The complete contents of object_filename_, mapped into memory.
- NSData *contents_;
+ scoped_array<uint8_t> contents_;
- // A vector of fat_arch structures describing the object files
+ // A vector of SuperFatArch structures describing the object files
// object_filename_ contains. If object_filename_ refers to a fat binary,
// this may have more than one element; if it refers to a Mach-O file, this
// has exactly one element.
- vector<struct fat_arch> object_files_;
+ vector<SuperFatArch> object_files_;
// The object file in object_files_ selected to dump, or NULL if
// SetArchitecture hasn't been called yet.
- const struct fat_arch *selected_object_file_;
+ const SuperFatArch *selected_object_file_;
// A string that identifies the selected object file, for use in error
// messages. This is usually object_filename_, but if that refers to a
diff --git a/3rdParty/Breakpad/src/common/mac/file_id.cc b/3rdParty/Breakpad/src/common/mac/file_id.cc
index 50502e4..4661d5d 100644
--- a/3rdParty/Breakpad/src/common/mac/file_id.cc
+++ b/3rdParty/Breakpad/src/common/mac/file_id.cc
@@ -34,6 +34,7 @@
// Author: Dan Waylonis
#include <fcntl.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -45,7 +46,7 @@ using MacFileUtilities::MachoID;
namespace google_breakpad {
FileID::FileID(const char *path) {
- strlcpy(path_, path, sizeof(path_));
+ snprintf(path_, sizeof(path_), "%s", path);
}
bool FileID::FileIdentifier(unsigned char identifier[16]) {
@@ -61,7 +62,7 @@ bool FileID::FileIdentifier(unsigned char identifier[16]) {
unsigned char buffer[4096 * 2];
size_t buffer_size = sizeof(buffer);
while ((buffer_size = read(fd, buffer, buffer_size) > 0)) {
- MD5Update(&md5, buffer, buffer_size);
+ MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size));
}
close(fd);
@@ -70,13 +71,15 @@ bool FileID::FileIdentifier(unsigned char identifier[16]) {
return true;
}
-bool FileID::MachoIdentifier(int cpu_type, unsigned char identifier[16]) {
+bool FileID::MachoIdentifier(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]) {
MachoID macho(path_);
- if (macho.UUIDCommand(cpu_type, identifier))
+ if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
return true;
- return macho.MD5(cpu_type, identifier);
+ return macho.MD5(cpu_type, cpu_subtype, identifier);
}
// static
@@ -90,8 +93,10 @@ void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
buffer[buffer_idx++] = '-';
- buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
- buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
+ buffer[buffer_idx++] =
+ static_cast<char>((hi >= 10) ? ('A' + hi - 10) : ('0' + hi));
+ buffer[buffer_idx++] =
+ static_cast<char>((lo >= 10) ? ('A' + lo - 10) : ('0' + lo));
}
// NULL terminate
diff --git a/3rdParty/Breakpad/src/common/mac/file_id.h b/3rdParty/Breakpad/src/common/mac/file_id.h
index eb06b0d..1d6dfde 100644
--- a/3rdParty/Breakpad/src/common/mac/file_id.h
+++ b/3rdParty/Breakpad/src/common/mac/file_id.h
@@ -35,6 +35,7 @@
#define COMMON_MAC_FILE_ID_H__
#include <limits.h>
+#include <mach/machine.h>
namespace google_breakpad {
@@ -50,15 +51,18 @@ class FileID {
bool FileIdentifier(unsigned char identifier[16]);
// Treat the file as a mach-o file that will contain one or more archicture.
- // Accepted values for |cpu_type| (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC)
- // are listed in /usr/include/mach/machine.h.
- // If |cpu_type| is 0, then the native cpu type is used.
- // Returns false if opening the file failed or if the |cpu_type| is not
- // present in the file.
+ // Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or
+ // CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h.
+ // If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is
+ // CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|.
+ // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
+ // is not present in the file.
// Return the unique identifier in |identifier|.
// The current implementation will look for the (in order of priority):
// LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|.
- bool MachoIdentifier(int cpu_type, unsigned char identifier[16]);
+ bool MachoIdentifier(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]);
// Convert the |identifier| data to a NULL terminated string. The string will
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
@@ -75,4 +79,3 @@ class FileID {
} // namespace google_breakpad
#endif // COMMON_MAC_FILE_ID_H__
-
diff --git a/3rdParty/Breakpad/src/common/mac/launch_reporter.cc b/3rdParty/Breakpad/src/common/mac/launch_reporter.cc
new file mode 100644
index 0000000..245be82
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/launch_reporter.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace google_breakpad {
+
+void LaunchReporter(const char *reporter_executable_path,
+ const char *config_file_path) {
+ const char* argv[] = { reporter_executable_path, config_file_path, NULL };
+
+ // Launch the reporter
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ perror("fork");
+ fprintf(stderr, "Failed to fork reporter process\n");
+ return;
+ }
+
+ // If we're in the child, load in our new executable and run.
+ // The parent will not wait for the child to complete.
+ if (pid == 0) {
+ execv(argv[0], (char* const*)argv);
+ perror("exec");
+ fprintf(stderr,
+ "Failed to launch reporter process from path %s\n",
+ reporter_executable_path);
+ unlink(config_file_path); // launch failed - get rid of config file
+ _exit(1);
+ }
+
+ // Wait until the Reporter child process exits.
+ //
+
+ // We'll use a timeout of one minute.
+ int timeout_count = 60; // 60 seconds
+
+ while (timeout_count-- > 0) {
+ int status;
+ pid_t result = waitpid(pid, &status, WNOHANG);
+
+ if (result == 0) {
+ // The child has not yet finished.
+ sleep(1);
+ } else if (result == -1) {
+ // error occurred.
+ break;
+ } else {
+ // child has finished
+ break;
+ }
+ }
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/mac/launch_reporter.h b/3rdParty/Breakpad/src/common/mac/launch_reporter.h
new file mode 100644
index 0000000..4531123
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/launch_reporter.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_MAC_LAUNCH_REPORTER_H__
+#define COMMON_MAC_LAUNCH_REPORTER_H__
+
+namespace google_breakpad {
+
+// Launch the crash dump sender app.
+// |reporter_executable_path| is the path to the sender executable.
+// |config_file_path| is the path to the config file.
+void LaunchReporter(const char *reporter_executable_path,
+ const char *config_file_path);
+
+} // namespace google_breakpad
+
+#endif // COMMON_MAC_LAUNCH_REPORTER_H__
diff --git a/3rdParty/Breakpad/src/common/mac/macho_id.cc b/3rdParty/Breakpad/src/common/mac/macho_id.cc
index abe1fab..c396ad8 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_id.cc
+++ b/3rdParty/Breakpad/src/common/mac/macho_id.cc
@@ -33,17 +33,15 @@
//
// Author: Dan Waylonis
-extern "C" { // necessary for Leopard
- #include <fcntl.h>
- #include <mach-o/loader.h>
- #include <mach-o/swap.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <unistd.h>
-}
+
+#include <fcntl.h>
+#include <mach-o/loader.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "common/mac/macho_id.h"
#include "common/mac/macho_walker.h"
@@ -61,7 +59,7 @@ MachoID::MachoID(const char *path)
crc_(0),
md5_context_(),
update_function_(NULL) {
- strlcpy(path_, path, sizeof(path_));
+ snprintf(path_, sizeof(path_), "%s", path);
}
MachoID::MachoID(const char *path, void *memory, size_t size)
@@ -70,7 +68,7 @@ MachoID::MachoID(const char *path, void *memory, size_t size)
crc_(0),
md5_context_(),
update_function_(NULL) {
- strlcpy(path_, path, sizeof(path_));
+ snprintf(path_, sizeof(path_), "%s", path);
}
MachoID::~MachoID() {
@@ -125,7 +123,7 @@ void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
}
void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
- MD5Update(&md5_context_, bytes, size);
+ MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
}
void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
@@ -153,10 +151,12 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
}
}
-bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
+bool MachoID::UUIDCommand(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char bytes[16]) {
struct breakpad_uuid_command uuid_cmd;
uuid_cmd.cmd = 0;
- if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd))
+ if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
return false;
// If we found the command, we'll have initialized the uuid_command
@@ -169,10 +169,12 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
return false;
}
-bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
+bool MachoID::IDCommand(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]) {
struct dylib_command dylib_cmd;
dylib_cmd.cmd = 0;
- if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd))
+ if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
return false;
// If we found the command, we'll have initialized the dylib_command
@@ -210,37 +212,38 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
return false;
}
-uint32_t MachoID::Adler32(int cpu_type) {
+uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
update_function_ = &MachoID::UpdateCRC;
crc_ = 0;
- if (!WalkHeader(cpu_type, WalkerCB, this))
+ if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return 0;
return crc_;
}
-bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
+bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
update_function_ = &MachoID::UpdateMD5;
MD5Init(&md5_context_);
- if (!WalkHeader(cpu_type, WalkerCB, this))
+ if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return false;
MD5Final(identifier, &md5_context_);
return true;
}
-bool MachoID::WalkHeader(int cpu_type,
+bool MachoID::WalkHeader(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback,
void *context) {
if (memory_) {
MachoWalker walker(memory_, memory_size_, callback, context);
- return walker.WalkHeader(cpu_type);
+ return walker.WalkHeader(cpu_type, cpu_subtype);
} else {
MachoWalker walker(path_, callback, context);
- return walker.WalkHeader(cpu_type);
+ return walker.WalkHeader(cpu_type, cpu_subtype);
}
}
@@ -256,7 +259,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- swap_segment_command(&seg, NXHostByteOrder());
+ breakpad_swap_segment_command(&seg);
struct mach_header_64 header;
off_t header_offset;
@@ -273,7 +276,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- swap_section(&sec, 1, NXHostByteOrder());
+ breakpad_swap_section(&sec, 1);
// sections of type S_ZEROFILL are "virtual" and contain no data
// in the file itself
@@ -289,7 +292,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
+ breakpad_swap_segment_command_64(&seg64);
struct mach_header_64 header;
off_t header_offset;
@@ -306,7 +309,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
+ breakpad_swap_section_64(&sec64, 1);
// sections of type S_ZEROFILL are "virtual" and contain no data
// in the file itself
@@ -335,7 +338,7 @@ bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
+ breakpad_swap_uuid_command(uuid_cmd);
return false;
}
@@ -354,7 +357,7 @@ bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
return false;
if (swap)
- swap_dylib_command(dylib_cmd, NXHostByteOrder());
+ breakpad_swap_dylib_command(dylib_cmd);
return false;
}
diff --git a/3rdParty/Breakpad/src/common/mac/macho_id.h b/3rdParty/Breakpad/src/common/mac/macho_id.h
index ccb126d..1037549 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_id.h
+++ b/3rdParty/Breakpad/src/common/mac/macho_id.h
@@ -35,6 +35,7 @@
#define COMMON_MAC_MACHO_ID_H__
#include <limits.h>
+#include <mach/machine.h>
#include <mach-o/loader.h>
#include "common/mac/macho_walker.h"
@@ -48,22 +49,32 @@ class MachoID {
MachoID(const char *path, void *memory, size_t size);
~MachoID();
- // For the given |cpu_type|, return a UUID from the LC_UUID command.
+ // For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID
+ // command.
// Return false if there isn't a LC_UUID command.
- bool UUIDCommand(int cpu_type, unsigned char identifier[16]);
+ bool UUIDCommand(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]);
- // For the given |cpu_type|, return a UUID from the LC_ID_DYLIB command.
+ // For the given |cpu_type| and |cpu_subtype|, return a UUID from the
+ // LC_ID_DYLIB command.
// Return false if there isn't a LC_ID_DYLIB command.
- bool IDCommand(int cpu_type, unsigned char identifier[16]);
+ bool IDCommand(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]);
- // For the given |cpu_type|, return the Adler32 CRC for the mach-o data
- // segment(s).
+ // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the
+ // mach-o data segment(s).
// Return 0 on error (e.g., if the file is not a mach-o file)
- uint32_t Adler32(int cpu_type);
+ uint32_t Adler32(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype);
- // For the given |cpu_type|, return the MD5 for the mach-o data segment(s).
+ // For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o
+ // data segment(s).
// Return true on success, false otherwise
- bool MD5(int cpu_type, unsigned char identifier[16]);
+ bool MD5(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ unsigned char identifier[16]);
private:
// Signature of class member function to be called with data read from file
@@ -81,8 +92,8 @@ class MachoID {
void Update(MachoWalker *walker, off_t offset, size_t size);
// Factory for the MachoWalker
- bool WalkHeader(int cpu_type, MachoWalker::LoadCommandCallback callback,
- void *context);
+ bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,
+ MachoWalker::LoadCommandCallback callback, void *context);
// The callback from the MachoWalker for CRC and MD5
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
diff --git a/3rdParty/Breakpad/src/common/mac/macho_reader.cc b/3rdParty/Breakpad/src/common/mac/macho_reader.cc
index f1f0a17..52f3c41 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_reader.cc
+++ b/3rdParty/Breakpad/src/common/mac/macho_reader.cc
@@ -43,6 +43,10 @@
#define CPU_TYPE_ARM 12
#endif
+#if !defined(CPU_TYPE_ARM_64)
+#define CPU_TYPE_ARM_64 16777228
+#endif
+
namespace google_breakpad {
namespace mach_o {
@@ -97,22 +101,26 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
// Read the list of object files.
object_files_.resize(object_files_count);
for (size_t i = 0; i < object_files_count; i++) {
- struct fat_arch *objfile = &object_files_[i];
+ struct fat_arch objfile;
// Read this object file entry, byte-swapping as appropriate.
- cursor >> objfile->cputype
- >> objfile->cpusubtype
- >> objfile->offset
- >> objfile->size
- >> objfile->align;
+ cursor >> objfile.cputype
+ >> objfile.cpusubtype
+ >> objfile.offset
+ >> objfile.size
+ >> objfile.align;
+
+ SuperFatArch super_fat_arch(objfile);
+ object_files_[i] = super_fat_arch;
+
if (!cursor) {
reporter_->TooShort();
return false;
}
// Does the file actually have the bytes this entry refers to?
size_t fat_size = buffer_.Size();
- if (objfile->offset > fat_size ||
- objfile->size > fat_size - objfile->offset) {
+ if (objfile.offset > fat_size ||
+ objfile.size > fat_size - objfile.offset) {
reporter_->MisplacedObjectFile();
return false;
}
@@ -135,16 +143,14 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
}
object_files_[0].offset = 0;
- object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
+ object_files_[0].size = static_cast<uint64_t>(buffer_.Size());
// This alignment is correct for 32 and 64-bit x86 and ppc.
// See get_align in the lipo source for other architectures:
// http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
object_files_[0].align = 12; // 2^12 == 4096
-
return true;
}
}
-
reporter_->BadHeader();
return false;
}
@@ -175,15 +181,15 @@ void Reader::Reporter::LoadCommandRegionTruncated() {
void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
LoadCommandType type) {
- fprintf(stderr, "%s: file's header claims there are %ld"
- " load commands, but load command #%ld",
+ fprintf(stderr, "%s: file's header claims there are %zu"
+ " load commands, but load command #%zu",
filename_.c_str(), claimed, i);
if (type) fprintf(stderr, ", of type %d,", type);
fprintf(stderr, " extends beyond the end of the load command region\n");
}
void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
- fprintf(stderr, "%s: the contents of load command #%ld, of type %d,"
+ fprintf(stderr, "%s: the contents of load command #%zu, of type %d,"
" extend beyond the size given in the load command's header\n",
filename_.c_str(), i, type);
}
@@ -242,6 +248,7 @@ bool Reader::Read(const uint8_t *buffer,
case CPU_TYPE_POWERPC:
expected_magic = MH_MAGIC;
break;
+ case CPU_TYPE_ARM_64:
case CPU_TYPE_X86_64:
expected_magic = MH_CIGAM_64;
break;
@@ -310,7 +317,7 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
// remainder of the load command series.
ByteBuffer command(list_cursor.here(), list_cursor.Available());
ByteCursor cursor(&command, big_endian_);
-
+
// Read the command type and size --- fields common to all commands.
uint32_t type, size;
if (!(cursor >> type)) {
@@ -395,7 +402,7 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
return false;
break;
}
-
+
default: {
if (!handler->UnknownCommand(type, command))
return false;
@@ -414,7 +421,7 @@ class Reader::SegmentFinder : public LoadCommandHandler {
public:
// Create a load command handler that looks for a segment named NAME,
// and sets SEGMENT to describe it if found.
- SegmentFinder(const string &name, Segment *segment)
+ SegmentFinder(const string &name, Segment *segment)
: name_(name), segment_(segment), found_() { }
// Return true if the traversal found the segment, false otherwise.
@@ -474,10 +481,12 @@ bool Reader::WalkSegmentSections(const Segment &segment,
reporter_->SectionsMissing(segment.name);
return false;
}
- if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
+ const uint32_t section_type = section.flags & SECTION_TYPE;
+ if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL ||
+ section_type == S_GB_ZEROFILL) {
// Zero-fill sections have a size, but no contents.
section.contents.start = section.contents.end = NULL;
- } else if (segment.contents.start == NULL &&
+ } else if (segment.contents.start == NULL &&
segment.contents.end == NULL) {
// Mach-O files in .dSYM bundles have the contents of the loaded
// segments removed, and their file offsets and file sizes zeroed
diff --git a/3rdParty/Breakpad/src/common/mac/macho_reader.h b/3rdParty/Breakpad/src/common/mac/macho_reader.h
index 7537648..30db742 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_reader.h
+++ b/3rdParty/Breakpad/src/common/mac/macho_reader.h
@@ -47,6 +47,7 @@
#include <vector>
#include "common/byte_cursor.h"
+#include "common/mac/super_fat_arch.h"
namespace google_breakpad {
namespace mach_o {
@@ -93,7 +94,7 @@ class FatReader {
// complete header, or the header implies that contents are present
// beyond the actual end of the file.
virtual void TooShort();
-
+
private:
// The filename to which the reader should attribute problems.
string filename_;
@@ -101,7 +102,7 @@ class FatReader {
// Create a fat binary file reader that uses |reporter| to report problems.
explicit FatReader(Reporter *reporter) : reporter_(reporter) { }
-
+
// Read the |size| bytes at |buffer| as a fat binary file. On success,
// return true; on failure, report the problem to reporter_ and return
// false.
@@ -111,13 +112,13 @@ class FatReader {
// single object file is the Mach-O file.
bool Read(const uint8_t *buffer, size_t size);
- // Return an array of 'struct fat_arch' structures describing the
+ // Return an array of 'SuperFatArch' structures describing the
// object files present in this fat binary file. Set |size| to the
// number of elements in the array.
//
- // Assuming Read returned true, the entries are validated: it is
- // safe to assume that the offsets and sizes in each 'struct
- // fat_arch' refer to subranges of the bytes passed to Read.
+ // Assuming Read returned true, the entries are validated: it is safe to
+ // assume that the offsets and sizes in each SuperFatArch refer to subranges
+ // of the bytes passed to Read.
//
// If there are no object files in this fat binary, then this
// function can return NULL.
@@ -129,7 +130,7 @@ class FatReader {
// possible to use the result with OS X functions like NXFindBestFatArch,
// so that the symbol dumper will behave consistently with other OS X
// utilities that work with fat binaries.
- const struct fat_arch *object_files(size_t *count) const {
+ const SuperFatArch* object_files(size_t *count) const {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -149,7 +150,7 @@ class FatReader {
// The list of object files in this binary.
// object_files_.size() == fat_header.nfat_arch
- vector<struct fat_arch> object_files_;
+ vector<SuperFatArch> object_files_;
};
// A segment in a Mach-O file. All these fields have been byte-swapped as
@@ -177,7 +178,7 @@ struct Segment {
// The maximum and initial VM protection of this segment's contents.
uint32_t maxprot;
uint32_t initprot;
-
+
// The number of sections in section_list.
uint32_t nsects;
@@ -376,7 +377,7 @@ class Reader {
return Read(buffer.start,
buffer.Size(),
expected_cpu_type,
- expected_cpu_subtype);
+ expected_cpu_subtype);
}
// Return this file's characteristics, as found in the Mach-O header.
diff --git a/3rdParty/Breakpad/src/common/mac/macho_reader_unittest.cc b/3rdParty/Breakpad/src/common/mac/macho_reader_unittest.cc
new file mode 100644
index 0000000..d8459d8
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/macho_reader_unittest.cc
@@ -0,0 +1,1902 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader
+// and google_breakpad::Mach_O::Reader.
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/mac/macho_reader.h"
+#include "common/test_assembler.h"
+
+namespace mach_o = google_breakpad::mach_o;
+namespace test_assembler = google_breakpad::test_assembler;
+
+using mach_o::FatReader;
+using mach_o::FileFlags;
+using mach_o::FileType;
+using mach_o::LoadCommandType;
+using mach_o::Reader;
+using mach_o::Section;
+using mach_o::SectionMap;
+using mach_o::Segment;
+using test_assembler::Endianness;
+using test_assembler::Label;
+using test_assembler::kBigEndian;
+using test_assembler::kLittleEndian;
+using test_assembler::kUnsetEndian;
+using google_breakpad::ByteBuffer;
+using std::map;
+using std::string;
+using std::vector;
+using testing::AllOf;
+using testing::DoAll;
+using testing::Field;
+using testing::InSequence;
+using testing::Matcher;
+using testing::Return;
+using testing::SaveArg;
+using testing::Test;
+using testing::_;
+
+
+// Mock classes for the reader's various reporters and handlers.
+
+class MockFatReaderReporter: public FatReader::Reporter {
+ public:
+ MockFatReaderReporter(const string &filename)
+ : FatReader::Reporter(filename) { }
+ MOCK_METHOD0(BadHeader, void());
+ MOCK_METHOD0(MisplacedObjectFile, void());
+ MOCK_METHOD0(TooShort, void());
+};
+
+class MockReaderReporter: public Reader::Reporter {
+ public:
+ MockReaderReporter(const string &filename) : Reader::Reporter(filename) { }
+ MOCK_METHOD0(BadHeader, void());
+ MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ cpu_type_t expected_cpu_type,
+ cpu_subtype_t expected_cpu_subtype));
+ MOCK_METHOD0(HeaderTruncated, void());
+ MOCK_METHOD0(LoadCommandRegionTruncated, void());
+ MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i,
+ LoadCommandType type));
+ MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type));
+ MOCK_METHOD1(SectionsMissing, void(const string &name));
+ MOCK_METHOD1(MisplacedSegmentData, void(const string &name));
+ MOCK_METHOD2(MisplacedSectionData, void(const string &section,
+ const string &segment));
+ MOCK_METHOD0(MisplacedSymbolTable, void());
+ MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type));
+};
+
+class MockLoadCommandHandler: public Reader::LoadCommandHandler {
+ public:
+ MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &));
+ MOCK_METHOD1(SegmentCommand, bool(const Segment &));
+ MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &));
+};
+
+class MockSectionHandler: public Reader::SectionHandler {
+ public:
+ MOCK_METHOD1(HandleSection, bool(const Section &section));
+};
+
+
+// Tests for mach_o::FatReader.
+
+// Since the effect of these functions is to write to stderr, the
+// results of these tests must be inspected by hand.
+TEST(FatReaderReporter, BadHeader) {
+ FatReader::Reporter reporter("filename");
+ reporter.BadHeader();
+}
+
+TEST(FatReaderReporter, MisplacedObjectFile) {
+ FatReader::Reporter reporter("filename");
+ reporter.MisplacedObjectFile();
+}
+
+TEST(FatReaderReporter, TooShort) {
+ FatReader::Reporter reporter("filename");
+ reporter.TooShort();
+}
+
+TEST(MachOReaderReporter, BadHeader) {
+ Reader::Reporter reporter("filename");
+ reporter.BadHeader();
+}
+
+TEST(MachOReaderReporter, CPUTypeMismatch) {
+ Reader::Reporter reporter("filename");
+ reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
+ CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
+}
+
+TEST(MachOReaderReporter, HeaderTruncated) {
+ Reader::Reporter reporter("filename");
+ reporter.HeaderTruncated();
+}
+
+TEST(MachOReaderReporter, LoadCommandRegionTruncated) {
+ Reader::Reporter reporter("filename");
+ reporter.LoadCommandRegionTruncated();
+}
+
+TEST(MachOReaderReporter, LoadCommandsOverrun) {
+ Reader::Reporter reporter("filename");
+ reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB);
+ reporter.LoadCommandsOverrun(10, 9, 0);
+}
+
+TEST(MachOReaderReporter, LoadCommandTooShort) {
+ Reader::Reporter reporter("filename");
+ reporter.LoadCommandTooShort(11, LC_SYMTAB);
+}
+
+TEST(MachOReaderReporter, SectionsMissing) {
+ Reader::Reporter reporter("filename");
+ reporter.SectionsMissing("segment name");
+}
+
+TEST(MachOReaderReporter, MisplacedSegmentData) {
+ Reader::Reporter reporter("filename");
+ reporter.MisplacedSegmentData("segment name");
+}
+
+TEST(MachOReaderReporter, MisplacedSectionData) {
+ Reader::Reporter reporter("filename");
+ reporter.MisplacedSectionData("section name", "segment name");
+}
+
+TEST(MachOReaderReporter, MisplacedSymbolTable) {
+ Reader::Reporter reporter("filename");
+ reporter.MisplacedSymbolTable();
+}
+
+TEST(MachOReaderReporter, UnsupportedCPUType) {
+ Reader::Reporter reporter("filename");
+ reporter.UnsupportedCPUType(CPU_TYPE_HPPA);
+}
+
+struct FatReaderFixture {
+ FatReaderFixture()
+ : fat(kBigEndian),
+ reporter("reporter filename"),
+ reader(&reporter), object_files() {
+ EXPECT_CALL(reporter, BadHeader()).Times(0);
+ EXPECT_CALL(reporter, TooShort()).Times(0);
+
+ // here, start, and Mark are file offsets in 'fat'.
+ fat.start() = 0;
+ }
+ // Append a 'fat_arch' entry to 'fat', with the given field values.
+ void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype,
+ Label offset, Label size, uint32_t align) {
+ fat
+ .B32(type)
+ .B32(subtype)
+ .B32(offset)
+ .B32(size)
+ .B32(align);
+ }
+ // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and
+ // subtype have unrealistic values.
+ void AppendDummyArchEntries(int n) {
+ for (int i = 0; i < n; i++)
+ AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1);
+ }
+ void ReadFat(bool expect_parse_success = true) {
+ ASSERT_TRUE(fat.GetContents(&contents));
+ fat_bytes = reinterpret_cast<const uint8_t *>(contents.data());
+ if (expect_parse_success) {
+ EXPECT_TRUE(reader.Read(fat_bytes, contents.size()));
+ size_t fat_files_count;
+ const SuperFatArch* fat_files = reader.object_files(&fat_files_count);
+ object_files.resize(fat_files_count);
+ for (size_t i = 0; i < fat_files_count; ++i) {
+ EXPECT_TRUE(fat_files[i].ConvertToFatArch(&object_files[i]));
+ }
+ }
+ else
+ EXPECT_FALSE(reader.Read(fat_bytes, contents.size()));
+ }
+ test_assembler::Section fat;
+ MockFatReaderReporter reporter;
+ FatReader reader;
+ string contents;
+ const uint8_t *fat_bytes;
+ vector<struct fat_arch> object_files;
+};
+
+class FatReaderTest: public FatReaderFixture, public Test { };
+
+TEST_F(FatReaderTest, BadMagic) {
+ EXPECT_CALL(reporter, BadHeader()).Times(1);
+ fat
+ .B32(0xcafed00d) // magic number (incorrect)
+ .B32(10); // number of architectures
+ AppendDummyArchEntries(10);
+ ReadFat(false);
+}
+
+TEST_F(FatReaderTest, HeaderTooShort) {
+ EXPECT_CALL(reporter, TooShort()).Times(1);
+ fat
+ .B32(0xcafebabe); // magic number
+ ReadFat(false);
+}
+
+TEST_F(FatReaderTest, ObjectListTooShort) {
+ EXPECT_CALL(reporter, TooShort()).Times(1);
+ fat
+ .B32(0xcafebabe) // magic number
+ .B32(10); // number of architectures
+ AppendDummyArchEntries(9); // nine dummy architecture entries...
+ fat // and a tenth, missing a byte at the end
+ .B32(0x3d46c8fc) // cpu type
+ .B32(0x8a7bfb01) // cpu subtype
+ .B32(0) // offset
+ .B32(0) // size
+ .Append(3, '*'); // one byte short of a four-byte alignment
+ ReadFat(false);
+}
+
+TEST_F(FatReaderTest, DataTooShort) {
+ EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1);
+ Label arch_data;
+ fat
+ .B32(0xcafebabe) // magic number
+ .B32(1); // number of architectures
+ AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0);
+ fat
+ .Mark(&arch_data) // file data begins here
+ .Append(30, '*'); // only 30 bytes, not 40 as header claims
+ ReadFat(false);
+}
+
+TEST_F(FatReaderTest, NoObjectFiles) {
+ fat
+ .B32(0xcafebabe) // magic number
+ .B32(0); // number of architectures
+ ReadFat();
+ EXPECT_EQ(0U, object_files.size());
+}
+
+TEST_F(FatReaderTest, OneObjectFile) {
+ Label obj1_offset;
+ fat
+ .B32(0xcafebabe) // magic number
+ .B32(1); // number of architectures
+ // First object file list entry
+ AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2);
+ // First object file data
+ fat
+ .Mark(&obj1_offset)
+ .Append(0x42, '*'); // dummy contents
+ ReadFat();
+ ASSERT_EQ(1U, object_files.size());
+ EXPECT_EQ(0x5e3a6e91, object_files[0].cputype);
+ EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype);
+ EXPECT_EQ(obj1_offset.Value(), object_files[0].offset);
+ EXPECT_EQ(0x42U, object_files[0].size);
+ EXPECT_EQ(0x355b15b2U, object_files[0].align);
+}
+
+TEST_F(FatReaderTest, ThreeObjectFiles) {
+ Label obj1, obj2, obj3;
+ fat
+ .B32(0xcafebabe) // magic number
+ .B32(3); // number of architectures
+ // Three object file list entries.
+ AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8);
+ AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd);
+ AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7);
+ fat
+ // First object file data
+ .Mark(&obj1)
+ .Append(0xfb4, '*') // dummy contents
+ // Second object file data
+ .Mark(&obj2)
+ .Append(0xc31, '%') // dummy contents
+ // Third object file data
+ .Mark(&obj3)
+ .Append(0x4b3, '^'); // dummy contents
+
+ ReadFat();
+
+ ASSERT_EQ(3U, object_files.size());
+
+ // First object file.
+ EXPECT_EQ(0x0cb92c30, object_files[0].cputype);
+ EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype);
+ EXPECT_EQ(obj1.Value(), object_files[0].offset);
+ EXPECT_EQ(0xfb4U, object_files[0].size);
+ EXPECT_EQ(0x2615dbe8U, object_files[0].align);
+
+ // Second object file.
+ EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype);
+ EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype);
+ EXPECT_EQ(obj2.Value(), object_files[1].offset);
+ EXPECT_EQ(0xc31U, object_files[1].size);
+ EXPECT_EQ(0x83af6ffdU, object_files[1].align);
+
+ // Third object file.
+ EXPECT_EQ(0x3717276d, object_files[2].cputype);
+ EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype);
+ EXPECT_EQ(obj3.Value(), object_files[2].offset);
+ EXPECT_EQ(0x4b3U, object_files[2].size);
+ EXPECT_EQ(0x035267d7U, object_files[2].align);
+}
+
+TEST_F(FatReaderTest, BigEndianMachO32) {
+ fat.set_endianness(kBigEndian);
+ fat
+ .D32(0xfeedface) // Mach-O file magic number
+ .D32(0x1a9d0518) // cpu type
+ .D32(0x1b779357) // cpu subtype
+ .D32(0x009df67e) // file type
+ .D32(0) // no load commands
+ .D32(0) // the load commands occupy no bytes
+ .D32(0x21987a99); // flags
+
+ ReadFat();
+
+ // FatReader should treat a Mach-O file as if it were a fat binary file
+ // containing one object file --- the whole thing.
+ ASSERT_EQ(1U, object_files.size());
+ EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
+ EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
+ EXPECT_EQ(0U, object_files[0].offset);
+ EXPECT_EQ(contents.size(), object_files[0].size);
+}
+
+TEST_F(FatReaderTest, BigEndianMachO64) {
+ fat.set_endianness(kBigEndian);
+ fat
+ .D32(0xfeedfacf) // Mach-O 64-bit file magic number
+ .D32(0x5aff8487) // cpu type
+ .D32(0x4c6a57f7) // cpu subtype
+ .D32(0x4392d2c8) // file type
+ .D32(0) // no load commands
+ .D32(0) // the load commands occupy no bytes
+ .D32(0x1b033eea); // flags
+
+ ReadFat();
+
+ // FatReader should treat a Mach-O file as if it were a fat binary file
+ // containing one object file --- the whole thing.
+ ASSERT_EQ(1U, object_files.size());
+ EXPECT_EQ(0x5aff8487, object_files[0].cputype);
+ EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
+ EXPECT_EQ(0U, object_files[0].offset);
+ EXPECT_EQ(contents.size(), object_files[0].size);
+}
+
+TEST_F(FatReaderTest, LittleEndianMachO32) {
+ fat.set_endianness(kLittleEndian);
+ fat
+ .D32(0xfeedface) // Mach-O file magic number
+ .D32(0x1a9d0518) // cpu type
+ .D32(0x1b779357) // cpu subtype
+ .D32(0x009df67e) // file type
+ .D32(0) // no load commands
+ .D32(0) // the load commands occupy no bytes
+ .D32(0x21987a99); // flags
+
+ ReadFat();
+
+ // FatReader should treat a Mach-O file as if it were a fat binary file
+ // containing one object file --- the whole thing.
+ ASSERT_EQ(1U, object_files.size());
+ EXPECT_EQ(0x1a9d0518, object_files[0].cputype);
+ EXPECT_EQ(0x1b779357, object_files[0].cpusubtype);
+ EXPECT_EQ(0U, object_files[0].offset);
+ EXPECT_EQ(contents.size(), object_files[0].size);
+}
+
+TEST_F(FatReaderTest, LittleEndianMachO64) {
+ fat.set_endianness(kLittleEndian);
+ fat
+ .D32(0xfeedfacf) // Mach-O 64-bit file magic number
+ .D32(0x5aff8487) // cpu type
+ .D32(0x4c6a57f7) // cpu subtype
+ .D32(0x4392d2c8) // file type
+ .D32(0) // no load commands
+ .D32(0) // the load commands occupy no bytes
+ .D32(0x1b033eea); // flags
+
+ ReadFat();
+
+ // FatReader should treat a Mach-O file as if it were a fat binary file
+ // containing one object file --- the whole thing.
+ ASSERT_EQ(1U, object_files.size());
+ EXPECT_EQ(0x5aff8487, object_files[0].cputype);
+ EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype);
+ EXPECT_EQ(0U, object_files[0].offset);
+ EXPECT_EQ(contents.size(), object_files[0].size);
+}
+
+TEST_F(FatReaderTest, IncompleteMach) {
+ fat.set_endianness(kLittleEndian);
+ fat
+ .D32(0xfeedfacf) // Mach-O 64-bit file magic number
+ .D32(0x5aff8487); // cpu type
+ // Truncated!
+
+ EXPECT_CALL(reporter, TooShort()).WillOnce(Return());
+
+ ReadFat(false);
+}
+
+
+// General mach_o::Reader tests.
+
+// Dynamically scoped configuration data.
+class WithConfiguration {
+ public:
+ // Establish the given parameters as the default for SizedSections
+ // created within the dynamic scope of this instance.
+ WithConfiguration(Endianness endianness, size_t word_size)
+ : endianness_(endianness), word_size_(word_size), saved_(current_) {
+ current_ = this;
+ }
+ ~WithConfiguration() { current_ = saved_; }
+ static Endianness endianness() {
+ assert(current_);
+ return current_->endianness_;
+ }
+ static size_t word_size() {
+ assert(current_);
+ return current_->word_size_;
+ }
+
+ private:
+ // The innermost WithConfiguration in whose dynamic scope we are
+ // currently executing.
+ static WithConfiguration *current_;
+
+ // The innermost WithConfiguration whose dynamic scope encloses this
+ // WithConfiguration.
+ Endianness endianness_;
+ size_t word_size_;
+ WithConfiguration *saved_;
+};
+
+WithConfiguration *WithConfiguration::current_ = NULL;
+
+// A test_assembler::Section with a size that we can cite. The start(),
+// Here() and Mark() member functions of a SizedSection always represent
+// offsets within the overall file.
+class SizedSection: public test_assembler::Section {
+ public:
+ // Construct a section of the given endianness and word size.
+ explicit SizedSection(Endianness endianness, size_t word_size)
+ : test_assembler::Section(endianness), word_size_(word_size) {
+ assert(word_size_ == 32 || word_size_ == 64);
+ }
+ SizedSection()
+ : test_assembler::Section(WithConfiguration::endianness()),
+ word_size_(WithConfiguration::word_size()) {
+ assert(word_size_ == 32 || word_size_ == 64);
+ }
+
+ // Access/set this section's word size.
+ size_t word_size() const { return word_size_; }
+ void set_word_size(size_t word_size) {
+ assert(word_size_ == 32 || word_size_ == 64);
+ word_size_ = word_size;
+ }
+
+ // Return a label representing the size this section will have when it
+ // is Placed in some containing section.
+ Label final_size() const { return final_size_; }
+
+ // Append SECTION to the end of this section, and call its Finish member.
+ // Return a reference to this section.
+ SizedSection &Place(SizedSection *section) {
+ assert(section->endianness() == endianness());
+ section->Finish();
+ section->start() = Here();
+ test_assembler::Section::Append(*section);
+ return *this;
+ }
+
+ protected:
+ // Mark this section's contents as complete. For plain SizedSections, we
+ // set SECTION's start to its position in this section, and its final_size
+ // label to its current size. Derived classes can extend this as needed
+ // for their additional semantics.
+ virtual void Finish() {
+ final_size_ = Size();
+ }
+
+ // The word size for this data: either 32 or 64.
+ size_t word_size_;
+
+ private:
+ // This section's final size, set when we are placed in some other
+ // SizedSection.
+ Label final_size_;
+};
+
+// A SizedSection that is loaded into memory at a particular address.
+class LoadedSection: public SizedSection {
+ public:
+ explicit LoadedSection(Label address = Label()) : address_(address) { }
+
+ // Return a label representing this section's address.
+ Label address() const { return address_; }
+
+ // Placing a loaded section within a loaded section sets the relationship
+ // between their addresses.
+ LoadedSection &Place(LoadedSection *section) {
+ section->address() = address() + Size();
+ SizedSection::Place(section);
+ return *this;
+ }
+
+ protected:
+ // The address at which this section's contents will be loaded.
+ Label address_;
+};
+
+// A SizedSection representing a segment load command.
+class SegmentLoadCommand: public SizedSection {
+ public:
+ SegmentLoadCommand() : section_count_(0) { }
+
+ // Append a segment load command header with the given characteristics.
+ // The load command will refer to CONTENTS, which must be Placed in the
+ // file separately, at the desired position. Return a reference to this
+ // section.
+ SegmentLoadCommand &Header(const string &name, const LoadedSection &contents,
+ uint32_t maxprot, uint32_t initprot,
+ uint32_t flags) {
+ assert(contents.word_size() == word_size());
+ D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64);
+ D32(final_size());
+ AppendCString(name, 16);
+ Append(endianness(), word_size() / 8, contents.address());
+ Append(endianness(), word_size() / 8, vmsize_);
+ Append(endianness(), word_size() / 8, contents.start());
+ Append(endianness(), word_size() / 8, contents.final_size());
+ D32(maxprot);
+ D32(initprot);
+ D32(final_section_count_);
+ D32(flags);
+
+ content_final_size_ = contents.final_size();
+
+ return *this;
+ }
+
+ // Return a label representing the size of this segment when loaded into
+ // memory. If this label is still undefined by the time we place this
+ // segment, it defaults to the final size of the segment's in-file
+ // contents. Return a reference to this load command.
+ Label &vmsize() { return vmsize_; }
+
+ // Add a section entry with the given characteristics to this segment
+ // load command. Return a reference to this. The section entry will refer
+ // to CONTENTS, which must be Placed in the segment's contents
+ // separately, at the desired position.
+ SegmentLoadCommand &AppendSectionEntry(const string &section_name,
+ const string &segment_name,
+ uint32_t alignment, uint32_t flags,
+ const LoadedSection &contents) {
+ AppendCString(section_name, 16);
+ AppendCString(segment_name, 16);
+ Append(endianness(), word_size() / 8, contents.address());
+ Append(endianness(), word_size() / 8, contents.final_size());
+ D32(contents.start());
+ D32(alignment);
+ D32(0); // relocations start
+ D32(0); // relocations size
+ D32(flags);
+ D32(0x93656b95); // reserved1
+ D32(0xc35a2473); // reserved2
+ if (word_size() == 64)
+ D32(0x70284b95); // reserved3
+
+ section_count_++;
+
+ return *this;
+ }
+
+ protected:
+ void Finish() {
+ final_section_count_ = section_count_;
+ if (!vmsize_.IsKnownConstant())
+ vmsize_ = content_final_size_;
+ SizedSection::Finish();
+ }
+
+ private:
+ // The number of sections that have been added to this segment so far.
+ size_t section_count_;
+
+ // A label representing the final number of sections this segment will hold.
+ Label final_section_count_;
+
+ // The size of the contents for this segment present in the file.
+ Label content_final_size_;
+
+ // A label representing the size of this segment when loaded; this can be
+ // larger than the size of its file contents, the difference being
+ // zero-filled. If not set explicitly by calling set_vmsize, this is set
+ // equal to the size of the contents.
+ Label vmsize_;
+};
+
+// A SizedSection holding a list of Mach-O load commands.
+class LoadCommands: public SizedSection {
+ public:
+ LoadCommands() : command_count_(0) { }
+
+ // Return a label representing the final load command count.
+ Label final_command_count() const { return final_command_count_; }
+
+ // Increment the command count; return a reference to this section.
+ LoadCommands &CountCommand() {
+ command_count_++;
+ return *this;
+ }
+
+ // Place COMMAND, containing a load command, at the end of this section.
+ // Return a reference to this section.
+ LoadCommands &Place(SizedSection *section) {
+ SizedSection::Place(section);
+ CountCommand();
+ return *this;
+ }
+
+ protected:
+ // Mark this load command list as complete.
+ void Finish() {
+ SizedSection::Finish();
+ final_command_count_ = command_count_;
+ }
+
+ private:
+ // The number of load commands we have added to this file so far.
+ size_t command_count_;
+
+ // A label representing the final command count.
+ Label final_command_count_;
+};
+
+// A SizedSection holding the contents of a Mach-O file. Within a
+// MachOFile, the start, Here, and Mark members refer to file offsets.
+class MachOFile: public SizedSection {
+ public:
+ MachOFile() {
+ start() = 0;
+ }
+
+ // Create a Mach-O file header using the given characteristics and load
+ // command list. This Places COMMANDS immediately after the header.
+ // Return a reference to this section.
+ MachOFile &Header(LoadCommands *commands,
+ cpu_type_t cpu_type = CPU_TYPE_X86,
+ cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL,
+ FileType file_type = MH_EXECUTE,
+ uint32_t file_flags = (MH_TWOLEVEL |
+ MH_DYLDLINK |
+ MH_NOUNDEFS)) {
+ D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf); // magic number
+ D32(cpu_type); // cpu type
+ D32(cpu_subtype); // cpu subtype
+ D32(file_type); // file type
+ D32(commands->final_command_count()); // number of load commands
+ D32(commands->final_size()); // their size in bytes
+ D32(file_flags); // flags
+ if (word_size() == 64)
+ D32(0x55638b90); // reserved
+ Place(commands);
+ return *this;
+ }
+};
+
+
+struct ReaderFixture {
+ ReaderFixture()
+ : reporter("reporter filename"),
+ reader(&reporter) {
+ EXPECT_CALL(reporter, BadHeader()).Times(0);
+ EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0);
+ EXPECT_CALL(reporter, HeaderTruncated()).Times(0);
+ EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0);
+ EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0);
+ EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0);
+ EXPECT_CALL(reporter, SectionsMissing(_)).Times(0);
+ EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0);
+ EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0);
+ EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0);
+ EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0);
+
+ EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0);
+ EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0);
+ }
+
+ void ReadFile(MachOFile *file,
+ bool expect_parse_success,
+ cpu_type_t expected_cpu_type,
+ cpu_subtype_t expected_cpu_subtype) {
+ ASSERT_TRUE(file->GetContents(&file_contents));
+ file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data());
+ if (expect_parse_success) {
+ EXPECT_TRUE(reader.Read(file_bytes,
+ file_contents.size(),
+ expected_cpu_type,
+ expected_cpu_subtype));
+ } else {
+ EXPECT_FALSE(reader.Read(file_bytes,
+ file_contents.size(),
+ expected_cpu_type,
+ expected_cpu_subtype));
+ }
+ }
+
+ string file_contents;
+ const uint8_t *file_bytes;
+ MockReaderReporter reporter;
+ Reader reader;
+ MockLoadCommandHandler load_command_handler;
+ MockSectionHandler section_handler;
+};
+
+class ReaderTest: public ReaderFixture, public Test { };
+
+TEST_F(ReaderTest, BadMagic) {
+ WithConfiguration config(kLittleEndian, 32);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0x67bdebe1) // Not a proper magic number.
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
+ ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
+}
+
+TEST_F(ReaderTest, MismatchedMagic) {
+ WithConfiguration config(kLittleEndian, 32);
+ const cpu_type_t kCPUType = CPU_TYPE_I386;
+ const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
+ MachOFile file;
+ file
+ .D32(MH_CIGAM) // Right magic, but winds up wrong
+ // due to bitswapping
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ EXPECT_CALL(reporter, BadHeader()).WillOnce(Return());
+ ReadFile(&file, false, kCPUType, kCPUSubType);
+}
+
+TEST_F(ReaderTest, ShortMagic) {
+ WithConfiguration config(kBigEndian, 32);
+ MachOFile file;
+ file
+ .D16(0xfeed); // magic number
+ // truncated!
+ EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
+ ReadFile(&file, false, CPU_TYPE_ANY, 0);
+}
+
+TEST_F(ReaderTest, ShortHeader) {
+ WithConfiguration config(kBigEndian, 32);
+ const cpu_type_t kCPUType = CPU_TYPE_ANY;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedface) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0); // they occupy no bytes
+ EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return());
+ ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
+}
+
+TEST_F(ReaderTest, MismatchedCPU) {
+ WithConfiguration config(kBigEndian, 32);
+ const cpu_type_t kCPUType = CPU_TYPE_I386;
+ const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL;
+ MachOFile file;
+ file
+ .D32(MH_MAGIC) // Right magic for PPC (once bitswapped)
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ EXPECT_CALL(reporter,
+ CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL,
+ CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL))
+ .WillOnce(Return());
+ ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL);
+}
+
+TEST_F(ReaderTest, LittleEndian32Bit) {
+ WithConfiguration config(kLittleEndian, 32);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedface) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
+ EXPECT_FALSE(reader.bits_64());
+ EXPECT_FALSE(reader.big_endian());
+ EXPECT_EQ(kCPUType, reader.cpu_type());
+ EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
+ EXPECT_EQ(FileType(0x149fc717), reader.file_type());
+ EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
+}
+
+TEST_F(ReaderTest, LittleEndian64Bit) {
+ WithConfiguration config(kLittleEndian, 64);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedfacf) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
+ EXPECT_TRUE(reader.bits_64());
+ EXPECT_FALSE(reader.big_endian());
+ EXPECT_EQ(kCPUType, reader.cpu_type());
+ EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
+ EXPECT_EQ(FileType(0x149fc717), reader.file_type());
+ EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
+}
+
+TEST_F(ReaderTest, BigEndian32Bit) {
+ WithConfiguration config(kBigEndian, 32);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedface) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
+ EXPECT_FALSE(reader.bits_64());
+ EXPECT_TRUE(reader.big_endian());
+ EXPECT_EQ(kCPUType, reader.cpu_type());
+ EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
+ EXPECT_EQ(FileType(0x149fc717), reader.file_type());
+ EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
+}
+
+TEST_F(ReaderTest, BigEndian64Bit) {
+ WithConfiguration config(kBigEndian, 64);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedfacf) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(0) // no load commands
+ .D32(0) // they occupy no bytes
+ .D32(0x80e71d64) // flags
+ .D32(0); // reserved
+ ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType);
+ EXPECT_TRUE(reader.bits_64());
+ EXPECT_TRUE(reader.big_endian());
+ EXPECT_EQ(kCPUType, reader.cpu_type());
+ EXPECT_EQ(kCPUSubType, reader.cpu_subtype());
+ EXPECT_EQ(FileType(0x149fc717), reader.file_type());
+ EXPECT_EQ(FileFlags(0x80e71d64), reader.flags());
+}
+
+
+// Load command tests.
+
+class LoadCommand: public ReaderFixture, public Test { };
+
+TEST_F(LoadCommand, RegionTruncated) {
+ WithConfiguration config(kBigEndian, 64);
+ const cpu_type_t kCPUType = 0x46b760df;
+ const cpu_subtype_t kCPUSubType = 0x76a0e7f7;
+ MachOFile file;
+ file
+ .D32(0xfeedfacf) // magic number
+ .D32(kCPUType) // cpu type
+ .D32(kCPUSubType) // cpu subtype
+ .D32(0x149fc717) // file type
+ .D32(1) // one load command
+ .D32(40) // occupying 40 bytes
+ .D32(0x80e71d64) // flags
+ .D32(0) // reserved
+ .Append(20, 0); // load command region, not as long as
+ // Mach-O header promised
+
+ EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return());
+
+ ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType);
+}
+
+TEST_F(LoadCommand, None) {
+ WithConfiguration config(kLittleEndian, 32);
+ LoadCommands load_commands;
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL);
+
+ EXPECT_FALSE(reader.bits_64());
+ EXPECT_FALSE(reader.big_endian());
+ EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type());
+ EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
+ EXPECT_EQ(FileFlags(MH_TWOLEVEL |
+ MH_DYLDLINK |
+ MH_NOUNDEFS),
+ FileFlags(reader.flags()));
+
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, Unknown) {
+ WithConfiguration config(kBigEndian, 32);
+ LoadCommands load_commands;
+ load_commands
+ .CountCommand()
+ .D32(0x33293d4a) // unknown load command
+ .D32(40) // total size in bytes
+ .Append(32, '*'); // dummy data
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_FALSE(reader.bits_64());
+ EXPECT_TRUE(reader.big_endian());
+ EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type());
+ EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type());
+ EXPECT_EQ(FileFlags(MH_TWOLEVEL |
+ MH_DYLDLINK |
+ MH_NOUNDEFS),
+ reader.flags());
+
+ ByteBuffer expected;
+ expected.start = file_bytes + load_commands.start().Value();
+ expected.end = expected.start + load_commands.final_size().Value();
+ EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a,
+ expected))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, TypeIncomplete) {
+ WithConfiguration config(kLittleEndian, 32);
+ LoadCommands load_commands;
+ load_commands
+ .CountCommand()
+ .Append(3, 0); // load command type, incomplete
+
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, LengthIncomplete) {
+ WithConfiguration config(kBigEndian, 64);
+ LoadCommands load_commands;
+ load_commands
+ .CountCommand()
+ .D32(LC_SEGMENT); // load command
+ // no length
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, ContentIncomplete) {
+ WithConfiguration config(kLittleEndian, 64);
+ LoadCommands load_commands;
+ load_commands
+ .CountCommand()
+ .D32(LC_SEGMENT) // load command
+ .D32(40) // total size in bytes
+ .Append(28, '*'); // not enough dummy data
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, SegmentBE32) {
+ WithConfiguration config(kBigEndian, 32);
+ LoadedSection segment;
+ segment.address() = 0x1891139c;
+ segment.Append(42, '*'); // segment contents
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd);
+ segment_command.vmsize() = 0xcb76584fU;
+ LoadCommands load_commands;
+ load_commands.Place(&segment_command);
+ MachOFile file;
+ file
+ .Header(&load_commands)
+ .Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_CALL(load_command_handler, SegmentCommand(_))
+ .WillOnce(DoAll(SaveArg<0>(&actual_segment),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_FALSE(actual_segment.bits_64);
+ EXPECT_EQ("froon", actual_segment.name);
+ EXPECT_EQ(0x1891139cU, actual_segment.vmaddr);
+ EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);
+ EXPECT_EQ(0x94d6dd22U, actual_segment.maxprot);
+ EXPECT_EQ(0x8bdbc319U, actual_segment.initprot);
+ EXPECT_EQ(0x990a16ddU, actual_segment.flags);
+ EXPECT_EQ(0U, actual_segment.nsects);
+ EXPECT_EQ(0U, actual_segment.section_list.Size());
+ EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
+}
+
+TEST_F(LoadCommand, SegmentLE32) {
+ WithConfiguration config(kLittleEndian, 32);
+ LoadedSection segment;
+ segment.address() = 0x4b877866;
+ segment.Append(42, '*'); // segment contents
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("sixteenprecisely", segment,
+ 0x350759ed, 0x6cf5a62e, 0x990a16dd);
+ segment_command.vmsize() = 0xcb76584fU;
+ LoadCommands load_commands;
+ load_commands.Place(&segment_command);
+ MachOFile file;
+ file
+ .Header(&load_commands)
+ .Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_CALL(load_command_handler, SegmentCommand(_))
+ .WillOnce(DoAll(SaveArg<0>(&actual_segment),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_FALSE(actual_segment.bits_64);
+ EXPECT_EQ("sixteenprecisely", actual_segment.name);
+ EXPECT_EQ(0x4b877866U, actual_segment.vmaddr);
+ EXPECT_EQ(0xcb76584fU, actual_segment.vmsize);
+ EXPECT_EQ(0x350759edU, actual_segment.maxprot);
+ EXPECT_EQ(0x6cf5a62eU, actual_segment.initprot);
+ EXPECT_EQ(0x990a16ddU, actual_segment.flags);
+ EXPECT_EQ(0U, actual_segment.nsects);
+ EXPECT_EQ(0U, actual_segment.section_list.Size());
+ EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
+}
+
+TEST_F(LoadCommand, SegmentBE64) {
+ WithConfiguration config(kBigEndian, 64);
+ LoadedSection segment;
+ segment.address() = 0x79f484f77009e511ULL;
+ segment.Append(42, '*'); // segment contents
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220);
+ segment_command.vmsize() = 0x8d92397ce6248abaULL;
+ LoadCommands load_commands;
+ load_commands.Place(&segment_command);
+ MachOFile file;
+ file
+ .Header(&load_commands)
+ .Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_CALL(load_command_handler, SegmentCommand(_))
+ .WillOnce(DoAll(SaveArg<0>(&actual_segment),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_EQ(true, actual_segment.bits_64);
+ EXPECT_EQ("froon", actual_segment.name);
+ EXPECT_EQ(0x79f484f77009e511ULL, actual_segment.vmaddr);
+ EXPECT_EQ(0x8d92397ce6248abaULL, actual_segment.vmsize);
+ EXPECT_EQ(0x42b45da5U, actual_segment.maxprot);
+ EXPECT_EQ(0x8bdbc319U, actual_segment.initprot);
+ EXPECT_EQ(0xb2335220U, actual_segment.flags);
+ EXPECT_EQ(0U, actual_segment.nsects);
+ EXPECT_EQ(0U, actual_segment.section_list.Size());
+ EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
+}
+
+TEST_F(LoadCommand, SegmentLE64) {
+ WithConfiguration config(kLittleEndian, 64);
+ LoadedSection segment;
+ segment.address() = 0x50c0501dc5922d35ULL;
+ segment.Append(42, '*'); // segment contents
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("sixteenprecisely", segment,
+ 0x917c339d, 0xdbc446fa, 0xb650b563);
+ segment_command.vmsize() = 0x84ae73e7c75469bfULL;
+ LoadCommands load_commands;
+ load_commands.Place(&segment_command);
+ MachOFile file;
+ file
+ .Header(&load_commands)
+ .Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_CALL(load_command_handler, SegmentCommand(_))
+ .WillOnce(DoAll(SaveArg<0>(&actual_segment),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_EQ(true, actual_segment.bits_64);
+ EXPECT_EQ("sixteenprecisely", actual_segment.name);
+ EXPECT_EQ(0x50c0501dc5922d35ULL, actual_segment.vmaddr);
+ EXPECT_EQ(0x84ae73e7c75469bfULL, actual_segment.vmsize);
+ EXPECT_EQ(0x917c339dU, actual_segment.maxprot);
+ EXPECT_EQ(0xdbc446faU, actual_segment.initprot);
+ EXPECT_EQ(0xb650b563U, actual_segment.flags);
+ EXPECT_EQ(0U, actual_segment.nsects);
+ EXPECT_EQ(0U, actual_segment.section_list.Size());
+ EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size());
+}
+
+TEST_F(LoadCommand, SegmentCommandTruncated) {
+ WithConfiguration config(kBigEndian, 32);
+ LoadedSection segment_contents;
+ segment_contents.Append(20, '*'); // lah di dah
+ SizedSection command;
+ command
+ .D32(LC_SEGMENT) // command type
+ .D32(command.final_size()) // command size
+ .AppendCString("too-short", 16) // segment name
+ .D32(0x9c759211) // vmaddr
+ .D32(segment_contents.final_size()) // vmsize
+ .D32(segment_contents.start()) // file offset
+ .D32(segment_contents.final_size()) // file size
+ .D32(0x56f28446) // max protection
+ .D32(0xe7910dcb) // initial protection
+ .D32(0) // no sections
+ .Append(3, 0); // flags (one byte short!)
+ LoadCommands load_commands;
+ load_commands.Place(&command);
+ MachOFile file;
+ file
+ .Header(&load_commands)
+ .Place(&segment_contents);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT))
+ .WillOnce(Return());
+
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, SegmentBadContentOffset) {
+ WithConfiguration config(kLittleEndian, 32);
+ // Instead of letting a Place call set the segment's file offset and size,
+ // set them ourselves, to check that the parser catches invalid offsets
+ // instead of handing us bogus pointers.
+ LoadedSection segment;
+ segment.address() = 0x4db5489c;
+ segment.start() = 0x7e189e76; // beyond end of file
+ segment.final_size() = 0x98b9c3ab;
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f);
+ LoadCommands load_commands;
+ load_commands.Place(&segment_command);
+ MachOFile file;
+ file.Header(&load_commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen"))
+ .WillOnce(Return());
+
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(LoadCommand, ThreeLoadCommands) {
+ WithConfiguration config(kBigEndian, 32);
+ LoadedSection seg1, seg2, seg3;
+ SegmentLoadCommand cmd1, cmd2, cmd3;
+
+ seg1.Append(128, '@');
+ seg1.address() = 0xa7f61ef6;
+ cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87);
+ // Include some dummy data at the end of the load command. Since we
+ // didn't claim to have any sections, the reader should ignore this. But
+ // making sure the commands have different lengths ensures that we're
+ // using the right command's length to advance the LoadCommandIterator.
+ cmd1.Append(128, '!');
+
+ seg2.Append(42, '*');
+ seg2.address() = 0xc70fc909;
+ cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30);
+ // More dummy data at the end of the load command.
+ cmd2.Append(32, '^');
+
+ seg3.Append(42, '%');
+ seg3.address() = 0x46b3ab05;
+ cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b);
+ // More dummy data at the end of the load command.
+ cmd3.Append(64, '&');
+
+ LoadCommands load_commands;
+ load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
+
+ MachOFile file;
+ file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ {
+ InSequence s;
+ EXPECT_CALL(load_command_handler,
+ SegmentCommand(Field(&Segment::name, "head")))
+ .WillOnce(Return(true));
+ EXPECT_CALL(load_command_handler,
+ SegmentCommand(Field(&Segment::name, "thorax")))
+ .WillOnce(Return(true));
+ EXPECT_CALL(load_command_handler,
+ SegmentCommand(Field(&Segment::name, "abdomen")))
+ .WillOnce(Return(true));
+ }
+
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+static inline Matcher<const Section &> MatchSection(
+ Matcher<bool> bits_64,
+ Matcher<const string &> section_name,
+ Matcher<const string &> segment_name,
+ Matcher<uint64_t> address,
+ Matcher<uint32_t> alignment,
+ Matcher<uint32_t> flags,
+ Matcher<const ByteBuffer &> contents) {
+ return AllOf(AllOf(Field(&Section::bits_64, bits_64),
+ Field(&Section::section_name, section_name),
+ Field(&Section::segment_name, segment_name),
+ Field(&Section::address, address)),
+ AllOf(Field(&Section::align, alignment),
+ Field(&Section::flags, flags),
+ Field(&Section::contents, contents)));
+}
+
+static inline Matcher<const Section &> MatchSection(
+ Matcher<bool> bits_64,
+ Matcher<const string &> section_name,
+ Matcher<const string &> segment_name,
+ Matcher<uint64_t> address) {
+ return AllOf(Field(&Section::bits_64, bits_64),
+ Field(&Section::section_name, section_name),
+ Field(&Section::segment_name, segment_name),
+ Field(&Section::address, address));
+}
+
+TEST_F(LoadCommand, OneSegmentTwoSections) {
+ WithConfiguration config(kBigEndian, 64);
+
+ // Create some sections with some data.
+ LoadedSection section1, section2;
+ section1.Append("buddha's hand");
+ section2.Append("kumquat");
+
+ // Create a segment to hold them.
+ LoadedSection segment;
+ segment.address() = 0xe1d0eeec;
+ segment.Place(&section2).Place(&section1);
+
+ SegmentLoadCommand segment_command;
+ segment_command
+ .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2)
+ .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1)
+ .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2);
+
+ LoadCommands commands;
+ commands.Place(&segment_command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_CALL(load_command_handler, SegmentCommand(_))
+ .WillOnce(DoAll(SaveArg<0>(&actual_segment),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ {
+ InSequence s;
+ ByteBuffer contents1;
+ contents1.start = file_bytes + section1.start().Value();
+ contents1.end = contents1.start + section1.final_size().Value();
+ EXPECT_EQ("buddha's hand",
+ string(reinterpret_cast<const char *>(contents1.start),
+ contents1.Size()));
+ EXPECT_CALL(section_handler,
+ HandleSection(MatchSection(true, "mandarin", "kishu",
+ section1.address().Value(), 12,
+ 0x8cd4604bU, contents1)))
+ .WillOnce(Return(true));
+
+ ByteBuffer contents2;
+ contents2.start = file_bytes + section2.start().Value();
+ contents2.end = contents2.start + section2.final_size().Value();
+ EXPECT_EQ("kumquat",
+ string(reinterpret_cast<const char *>(contents2.start),
+ contents2.Size()));
+ EXPECT_CALL(section_handler,
+ HandleSection(MatchSection(true, "bergamot", "cara cara",
+ section2.address().Value(), 12,
+ 0x98746efaU, contents2)))
+ .WillOnce(Return(true));
+ }
+
+ EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MisplacedSectionBefore) {
+ WithConfiguration config(kLittleEndian, 64);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.Append(10, '0');
+
+ // The contents of the following sections don't matter, because
+ // we're not really going to Place them in segment; we're just going
+ // to set all their labels by hand to get the (impossible)
+ // configurations we want.
+
+ // A section whose starting offset is before that of its section.
+ LoadedSection before;
+ before.Append(10, '1');
+ before.start() = segment.start() - 1;
+ before.address() = segment.address() - 1;
+ before.final_size() = before.Size();
+
+ SegmentLoadCommand command;
+ command
+ .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
+ .AppendSectionEntry("before", "segment", 0, 0x686c6921, before);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
+
+ EXPECT_CALL(reporter, MisplacedSectionData("before", "segment"))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MisplacedSectionAfter) {
+ WithConfiguration config(kLittleEndian, 64);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.Append(10, '0');
+
+ // The contents of the following sections don't matter, because
+ // we're not really going to Place them in segment; we're just going
+ // to set all their labels by hand to get the (impossible)
+ // configurations we want.
+
+ // A section whose starting offset is after the end of its section.
+ LoadedSection after;
+ after.Append(10, '2');
+ after.start() = segment.start() + 11;
+ after.address() = segment.address() + 11;
+ after.final_size() = after.Size();
+
+ SegmentLoadCommand command;
+ command
+ .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
+ .AppendSectionEntry("after", "segment", 0, 0x2ee50124, after);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
+
+ EXPECT_CALL(reporter, MisplacedSectionData("after", "segment"))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MisplacedSectionTooBig) {
+ WithConfiguration config(kLittleEndian, 64);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.Append(10, '0');
+
+ // The contents of the following sections don't matter, because
+ // we're not really going to Place them in segment; we're just going
+ // to set all their labels by hand to get the (impossible)
+ // configurations we want.
+
+ // A section that extends beyond the end of its section.
+ LoadedSection too_big;
+ too_big.Append(10, '3');
+ too_big.start() = segment.start() + 1;
+ too_big.address() = segment.address() + 1;
+ too_big.final_size() = too_big.Size();
+
+ SegmentLoadCommand command;
+ command
+ .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057)
+ .AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("segment", &actual_segment));
+
+ EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment"))
+ .WillOnce(Return());
+ EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+
+// The segments in a .dSYM bundle's Mach-O file have their file offset
+// and size set to zero, but the sections don't. The reader shouldn't
+// report an error in this case.
+TEST_F(LoadCommand, ZappedSegment) {
+ WithConfiguration config(kBigEndian, 32);
+
+ // The segment.
+ LoadedSection segment;
+ segment.address() = 0x696d83cc;
+ segment.start() = 0;
+ segment.final_size() = 0;
+
+ // The section.
+ LoadedSection section;
+ section.address() = segment.address();
+ section.start() = 0;
+ section.final_size() = 1000; // extends beyond its segment
+
+ SegmentLoadCommand command;
+ command
+ .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c)
+ .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section);
+
+ LoadCommands commands;
+ commands.Place(&command);
+
+ MachOFile file;
+ file.Header(&commands);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+ EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment));
+
+ ByteBuffer zapped_extent(NULL, 0);
+ EXPECT_CALL(section_handler,
+ HandleSection(MatchSection(false, "twitching", "zapped",
+ 0x696d83cc, 0, 0x93b3bd42,
+ zapped_extent)))
+ .WillOnce(Return(true));
+
+ EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, &section_handler));
+}
+
+TEST_F(LoadCommand, MapSegmentSections) {
+ WithConfiguration config(kLittleEndian, 32);
+
+ // Create some sections with some data.
+ LoadedSection section1, section2, section3, section4;
+ section1.Append("buddha's hand");
+ section2.start() = 0; // Section 2 is an S_ZEROFILL section.
+ section2.final_size() = 0;
+ section3.Append("shasta gold");
+ section4.Append("satsuma");
+
+ // Create two segments to hold them.
+ LoadedSection segment1, segment2;
+ segment1.address() = 0x13e6c8a9;
+ segment1.Place(&section3).Place(&section1);
+ segment2.set_word_size(64);
+ segment2.address() = 0x04d462e2;
+ segment2.Place(&section4);
+ section2.address() = segment2.address() + segment2.Size();
+
+ SegmentLoadCommand segment_command1, segment_command2;
+ segment_command1
+ .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64)
+ .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1)
+ .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3);
+ segment_command2.set_word_size(64);
+ segment_command2
+ .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33)
+ .AppendSectionEntry("sixteenprecisely", "thorax",
+ 12, S_ZEROFILL, section2)
+ .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4);
+
+ LoadCommands commands;
+ commands.Place(&segment_command1).Place(&segment_command2);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment1).Place(&segment2);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment segment;
+ SectionMap section_map;
+
+ EXPECT_FALSE(reader.FindSegment("smoot", &segment));
+
+ ASSERT_TRUE(reader.FindSegment("thorax", &segment));
+ ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
+
+ EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome")
+ != section_map.end());
+ EXPECT_FALSE(section_map.find("mandarin") != section_map.end());
+ ASSERT_TRUE(section_map.find("cara cara") != section_map.end());
+ EXPECT_THAT(section_map["cara cara"],
+ MatchSection(true, "cara cara", "thorax", 0x04d462e2));
+ ASSERT_TRUE(section_map.find("sixteenprecisely")
+ != section_map.end());
+ ByteBuffer sixteenprecisely_contents(NULL, 0);
+ EXPECT_THAT(section_map["sixteenprecisely"],
+ MatchSection(true, "sixteenprecisely", "thorax",
+ 0x04d462e2 + 7, 12, S_ZEROFILL,
+ sixteenprecisely_contents));
+
+ ASSERT_TRUE(reader.FindSegment("head", &segment));
+ ASSERT_TRUE(reader.MapSegmentSections(segment, &section_map));
+
+ ASSERT_TRUE(section_map.find("mandarin") != section_map.end());
+ EXPECT_THAT(section_map["mandarin"],
+ MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11));
+ ASSERT_TRUE(section_map.find("bergamot") != section_map.end());
+ EXPECT_THAT(section_map["bergamot"],
+ MatchSection(false, "bergamot", "head", 0x13e6c8a9));
+}
+
+TEST_F(LoadCommand, FindSegment) {
+ WithConfiguration config(kBigEndian, 32);
+
+ LoadedSection segment1, segment2, segment3;
+ segment1.address() = 0xb8ae5752;
+ segment1.Append("Some contents!");
+ segment2.address() = 0xd6b0ce83;
+ segment2.Append("Different stuff.");
+ segment3.address() = 0x7374fd2a;
+ segment3.Append("Further materials.");
+
+ SegmentLoadCommand cmd1, cmd2, cmd3;
+ cmd1.Header("first", segment1, 0xfadb6932, 0x175bf529, 0x0de790ad);
+ cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef);
+ cmd3.Header("third", segment3, 0xe172b39e, 0x86012f07, 0x080ac94d);
+
+ LoadCommands commands;
+ commands.Place(&cmd1).Place(&cmd2).Place(&cmd3);
+
+ MachOFile file;
+ file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ Segment actual_segment;
+
+ EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment));
+
+ EXPECT_TRUE(reader.FindSegment("second", &actual_segment));
+ EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr);
+}
+
+
+// Symtab tests.
+
+// A StringAssembler is a class for generating .stabstr sections to present
+// as input to the STABS parser.
+class StringAssembler: public SizedSection {
+ public:
+ // Add the string S to this StringAssembler, and return the string's
+ // offset within this compilation unit's strings.
+ size_t Add(const string &s) {
+ size_t offset = Size();
+ AppendCString(s);
+ return offset;
+ }
+};
+
+// A SymbolAssembler is a class for generating .stab sections to present as
+// test input for the STABS parser.
+class SymbolAssembler: public SizedSection {
+ public:
+ // Create a SymbolAssembler that uses StringAssembler for its strings.
+ explicit SymbolAssembler(StringAssembler *string_assembler)
+ : string_assembler_(string_assembler),
+ entry_count_(0) { }
+
+ // Append a STAB entry to the end of this section with the given
+ // characteristics. NAME is the offset of this entry's name string within
+ // its compilation unit's portion of the .stabstr section; this can be a
+ // value generated by a StringAssembler. Return a reference to this
+ // SymbolAssembler.
+ SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
+ Label value, Label name) {
+ D32(name);
+ D8(type);
+ D8(other);
+ D16(descriptor);
+ Append(endianness(), word_size_ / 8, value);
+ entry_count_++;
+ return *this;
+ }
+
+ // As above, but automatically add NAME to our StringAssembler.
+ SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor,
+ Label value, const string &name) {
+ return Symbol(type, other, descriptor, value, string_assembler_->Add(name));
+ }
+
+ private:
+ // The strings for our STABS entries.
+ StringAssembler *string_assembler_;
+
+ // The number of entries in this compilation unit so far.
+ size_t entry_count_;
+};
+
+class Symtab: public ReaderFixture, public Test { };
+
+TEST_F(Symtab, Symtab32) {
+ WithConfiguration config(kLittleEndian, 32);
+
+ StringAssembler strings;
+ SymbolAssembler symbols(&strings);
+ symbols
+ .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu")
+ .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith");
+
+ SizedSection symtab_command;
+ symtab_command
+ .D32(LC_SYMTAB) // command
+ .D32(symtab_command.final_size()) // size
+ .D32(symbols.start()) // file offset of symbols
+ .D32(2) // symbol count
+ .D32(strings.start()) // file offset of strings
+ .D32(strings.final_size()); // strings size
+
+ LoadCommands load_commands;
+ load_commands.Place(&symtab_command);
+
+ MachOFile file;
+ file.Header(&load_commands).Place(&symbols).Place(&strings);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ ByteBuffer symbols_found, strings_found;
+ EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&symbols_found),
+ SaveArg<1>(&strings_found),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_EQ(24U, symbols_found.Size());
+ EXPECT_EQ(14U, strings_found.Size());
+}
+
+TEST_F(Symtab, Symtab64) {
+ WithConfiguration config(kBigEndian, 64);
+
+ StringAssembler strings;
+ SymbolAssembler symbols(&strings);
+ symbols
+ .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
+ .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
+
+ SizedSection symtab_command;
+ symtab_command
+ .D32(LC_SYMTAB) // command
+ .D32(symtab_command.final_size()) // size
+ .D32(symbols.start()) // file offset of symbols
+ .D32(2) // symbol count
+ .D32(strings.start()) // file offset of strings
+ .D32(strings.final_size()); // strings size
+
+ LoadCommands load_commands;
+ load_commands.Place(&symtab_command);
+
+ MachOFile file;
+ file.Header(&load_commands).Place(&symbols).Place(&strings);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ ByteBuffer symbols_found, strings_found;
+ EXPECT_CALL(load_command_handler, SymtabCommand(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&symbols_found),
+ SaveArg<1>(&strings_found),
+ Return(true)));
+ EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler));
+
+ EXPECT_EQ(32U, symbols_found.Size());
+ EXPECT_EQ(8U, strings_found.Size());
+}
+
+TEST_F(Symtab, SymtabMisplacedSymbols) {
+ WithConfiguration config(kBigEndian, 32);
+
+ StringAssembler strings;
+ SymbolAssembler symbols(&strings);
+ symbols
+ .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
+ .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
+
+ SizedSection symtab_command;
+ symtab_command
+ .D32(LC_SYMTAB) // command
+ .D32(symtab_command.final_size()) // size
+ .D32(symbols.start()) // file offset of symbols
+ .D32(3) // symbol count (too many)
+ .D32(strings.start()) // file offset of strings
+ .D32(strings.final_size()); // strings size
+
+ LoadCommands load_commands;
+ load_commands.Place(&symtab_command);
+
+ MachOFile file;
+ // Put symbols at end, so the excessive length will be noticed.
+ file.Header(&load_commands).Place(&strings).Place(&symbols);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
+TEST_F(Symtab, SymtabMisplacedStrings) {
+ WithConfiguration config(kLittleEndian, 32);
+
+ StringAssembler strings;
+ SymbolAssembler symbols(&strings);
+ symbols
+ .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo")
+ .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar");
+
+ SizedSection symtab_command;
+ symtab_command
+ .D32(LC_SYMTAB) // command
+ .D32(symtab_command.final_size()) // size
+ .D32(symbols.start()) // file offset of symbols
+ .D32(2) // symbol count
+ .D32(strings.start()) // file offset of strings
+ .D32(strings.final_size() + 1); // strings size (too long)
+
+ LoadCommands load_commands;
+ load_commands.Place(&symtab_command);
+
+ MachOFile file;
+ // Put strings at end, so the excessive length will be noticed.
+ file.Header(&load_commands).Place(&symbols).Place(&strings);
+
+ ReadFile(&file, true, CPU_TYPE_ANY, 0);
+
+ EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1);
+ EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler));
+}
+
diff --git a/3rdParty/Breakpad/src/common/mac/macho_utilities.cc b/3rdParty/Breakpad/src/common/mac/macho_utilities.cc
index 89f9e77..f56fe76 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_utilities.cc
+++ b/3rdParty/Breakpad/src/common/mac/macho_utilities.cc
@@ -34,16 +34,44 @@
#include "common/mac/byteswap.h"
#include "common/mac/macho_utilities.h"
-void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
- enum NXByteOrder target_byte_order)
-{
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc) {
uc->cmd = ByteSwap(uc->cmd);
uc->cmdsize = ByteSwap(uc->cmdsize);
}
-void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
- enum NXByteOrder target_byte_order)
-{
+void breakpad_swap_load_command(struct load_command *lc) {
+ lc->cmd = ByteSwap(lc->cmd);
+ lc->cmdsize = ByteSwap(lc->cmdsize);
+}
+
+void breakpad_swap_dylib_command(struct dylib_command *dc) {
+ dc->cmd = ByteSwap(dc->cmd);
+ dc->cmdsize = ByteSwap(dc->cmdsize);
+
+ dc->dylib.name.offset = ByteSwap(dc->dylib.name.offset);
+ dc->dylib.timestamp = ByteSwap(dc->dylib.timestamp);
+ dc->dylib.current_version = ByteSwap(dc->dylib.current_version);
+ dc->dylib.compatibility_version = ByteSwap(dc->dylib.compatibility_version);
+}
+
+void breakpad_swap_segment_command(struct segment_command *sc) {
+ sc->cmd = ByteSwap(sc->cmd);
+ sc->cmdsize = ByteSwap(sc->cmdsize);
+
+ sc->vmaddr = ByteSwap(sc->vmaddr);
+ sc->vmsize = ByteSwap(sc->vmsize);
+ sc->fileoff = ByteSwap(sc->fileoff);
+ sc->filesize = ByteSwap(sc->filesize);
+ sc->maxprot = ByteSwap(sc->maxprot);
+ sc->initprot = ByteSwap(sc->initprot);
+ sc->nsects = ByteSwap(sc->nsects);
+ sc->flags = ByteSwap(sc->flags);
+}
+
+void breakpad_swap_segment_command_64(struct segment_command_64 *sg) {
sg->cmd = ByteSwap(sg->cmd);
sg->cmdsize = ByteSwap(sg->cmdsize);
@@ -58,9 +86,32 @@ void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
sg->flags = ByteSwap(sg->flags);
}
-void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
- enum NXByteOrder target_byte_order)
-{
+void breakpad_swap_fat_header(struct fat_header *fh) {
+ fh->magic = ByteSwap(fh->magic);
+ fh->nfat_arch = ByteSwap(fh->nfat_arch);
+}
+
+void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs) {
+ for (uint32_t i = 0; i < narchs; ++i) {
+ fa[i].cputype = ByteSwap(fa[i].cputype);
+ fa[i].cpusubtype = ByteSwap(fa[i].cpusubtype);
+ fa[i].offset = ByteSwap(fa[i].offset);
+ fa[i].size = ByteSwap(fa[i].size);
+ fa[i].align = ByteSwap(fa[i].align);
+ }
+}
+
+void breakpad_swap_mach_header(struct mach_header *mh) {
+ mh->magic = ByteSwap(mh->magic);
+ mh->cputype = ByteSwap(mh->cputype);
+ mh->cpusubtype = ByteSwap(mh->cpusubtype);
+ mh->filetype = ByteSwap(mh->filetype);
+ mh->ncmds = ByteSwap(mh->ncmds);
+ mh->sizeofcmds = ByteSwap(mh->sizeofcmds);
+ mh->flags = ByteSwap(mh->flags);
+}
+
+void breakpad_swap_mach_header_64(struct mach_header_64 *mh) {
mh->magic = ByteSwap(mh->magic);
mh->cputype = ByteSwap(mh->cputype);
mh->cpusubtype = ByteSwap(mh->cpusubtype);
@@ -71,10 +122,24 @@ void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
mh->reserved = ByteSwap(mh->reserved);
}
+void breakpad_swap_section(struct section *s,
+ uint32_t nsects) {
+ for (uint32_t i = 0; i < nsects; i++) {
+ s[i].addr = ByteSwap(s[i].addr);
+ s[i].size = ByteSwap(s[i].size);
+
+ s[i].offset = ByteSwap(s[i].offset);
+ s[i].align = ByteSwap(s[i].align);
+ s[i].reloff = ByteSwap(s[i].reloff);
+ s[i].nreloc = ByteSwap(s[i].nreloc);
+ s[i].flags = ByteSwap(s[i].flags);
+ s[i].reserved1 = ByteSwap(s[i].reserved1);
+ s[i].reserved2 = ByteSwap(s[i].reserved2);
+ }
+}
+
void breakpad_swap_section_64(struct section_64 *s,
- uint32_t nsects,
- enum NXByteOrder target_byte_order)
-{
+ uint32_t nsects) {
for (uint32_t i = 0; i < nsects; i++) {
s[i].addr = ByteSwap(s[i].addr);
s[i].size = ByteSwap(s[i].size);
diff --git a/3rdParty/Breakpad/src/common/mac/macho_utilities.h b/3rdParty/Breakpad/src/common/mac/macho_utilities.h
index a07945f..00563a7 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_utilities.h
+++ b/3rdParty/Breakpad/src/common/mac/macho_utilities.h
@@ -54,14 +54,6 @@
# define LC_UUID 0x1b /* the uuid */
#endif
-#if TARGET_CPU_X86
-# define BREAKPAD_MACHINE_THREAD_STATE i386_THREAD_STATE
-#elif TARGET_CPU_X86_64
-# define BREAKPAD_MACHINE_THREAD_STATE x86_THREAD_STATE64
-#else
-# define BREAKPAD_MACHINE_THREAD_STATE MACHINE_THREAD_STATE
-#endif
-
// The uuid_command struct/swap routines were added during the 10.4 series.
// Their presence isn't guaranteed.
struct breakpad_uuid_command {
@@ -70,23 +62,34 @@ struct breakpad_uuid_command {
uint8_t uuid[16]; /* the 128-bit uuid */
};
-void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
- enum NXByteOrder target_byte_order);
+void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc);
+
+void breakpad_swap_load_command(struct load_command *lc);
+
+void breakpad_swap_dylib_command(struct dylib_command *dc);
// Older SDKs defines thread_state_data_t as an int[] instead
// of the natural_t[] it should be.
typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX];
+void breakpad_swap_segment_command(struct segment_command *sc);
+
// The 64-bit swap routines were added during the 10.4 series, their
// presence isn't guaranteed.
-void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
- enum NXByteOrder target_byte_order);
+void breakpad_swap_segment_command_64(struct segment_command_64 *sg);
+
+void breakpad_swap_fat_header(struct fat_header *fh);
+
+void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs);
+
+void breakpad_swap_mach_header(struct mach_header *mh);
+
+void breakpad_swap_mach_header_64(struct mach_header_64 *mh);
-void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
- enum NXByteOrder target_byte_order);
+void breakpad_swap_section(struct section *s,
+ uint32_t nsects);
void breakpad_swap_section_64(struct section_64 *s,
- uint32_t nsects,
- enum NXByteOrder target_byte_order);
+ uint32_t nsects);
#endif
diff --git a/3rdParty/Breakpad/src/common/mac/macho_walker.cc b/3rdParty/Breakpad/src/common/mac/macho_walker.cc
index 92da7b1..1acd866 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_walker.cc
+++ b/3rdParty/Breakpad/src/common/mac/macho_walker.cc
@@ -33,15 +33,13 @@
//
// Author: Dan Waylonis
-extern "C" { // necessary for Leopard
- #include <assert.h>
- #include <fcntl.h>
- #include <mach-o/arch.h>
- #include <mach-o/loader.h>
- #include <mach-o/swap.h>
- #include <string.h>
- #include <unistd.h>
-}
+#include <assert.h>
+#include <fcntl.h>
+#include <mach-o/arch.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include <string.h>
+#include <unistd.h>
#include "common/mac/byteswap.h"
#include "common/mac/macho_walker.h"
@@ -51,7 +49,7 @@ namespace MacFileUtilities {
MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
void *context)
- : file_(0),
+ : file_(-1),
memory_(NULL),
memory_size_(0),
callback_(callback),
@@ -64,7 +62,7 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
MachoWalker::MachoWalker(void *memory, size_t size,
LoadCommandCallback callback, void *context)
- : file_(0),
+ : file_(-1),
memory_(memory),
memory_size_(size),
callback_(callback),
@@ -79,21 +77,18 @@ MachoWalker::~MachoWalker() {
close(file_);
}
-int MachoWalker::ValidateCPUType(int cpu_type) {
- // If the user didn't specify, use the local architecture.
+bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
+ cpu_type_t valid_cpu_type = cpu_type;
+ cpu_subtype_t valid_cpu_subtype = cpu_subtype;
+ // if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
const NXArchInfo *arch = NXGetLocalArchInfo();
assert(arch);
- cpu_type = arch->cputype;
+ valid_cpu_type = arch->cputype;
+ valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
}
-
- return cpu_type;
-}
-
-bool MachoWalker::WalkHeader(int cpu_type) {
- int valid_cpu_type = ValidateCPUType(cpu_type);
off_t offset;
- if (FindHeader(valid_cpu_type, offset)) {
+ if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) {
if (cpu_type & CPU_ARCH_ABI64)
return WalkHeader64AtOffset(offset);
@@ -111,7 +106,7 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
if (offset + size > memory_size_) {
if (static_cast<size_t>(offset) >= memory_size_)
return false;
- size = memory_size_ - offset;
+ size = memory_size_ - static_cast<size_t>(offset);
result = false;
}
memcpy(buffer, static_cast<char *>(memory_) + offset, size);
@@ -131,8 +126,9 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
return false;
}
-bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
- int valid_cpu_type = ValidateCPUType(cpu_type);
+bool MachoWalker::FindHeader(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ off_t &offset) {
// Read the magic bytes that's common amongst all mach-o files
uint32_t magic;
if (!ReadBytes(&magic, sizeof(magic), 0))
@@ -153,15 +149,18 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
if (!is_fat) {
// If we don't have a fat header, check if the cpu type matches the single
// header
- cpu_type_t header_cpu_type;
- if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
+ struct mach_header header;
+ if (!ReadBytes(&header, sizeof(header), 0))
return false;
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
- header_cpu_type = ByteSwap(header_cpu_type);
+ breakpad_swap_mach_header(&header);
- if (valid_cpu_type != header_cpu_type)
+ if (cpu_type != header.cputype ||
+ (cpu_subtype != CPU_SUBTYPE_MULTIPLE &&
+ cpu_subtype != header.cpusubtype)) {
return false;
+ }
offset = 0;
return true;
@@ -173,7 +172,7 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
return false;
if (NXHostByteOrder() != NX_BigEndian)
- swap_fat_header(&fat, NXHostByteOrder());
+ breakpad_swap_fat_header(&fat);
offset += sizeof(fat);
@@ -184,9 +183,11 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
return false;
if (NXHostByteOrder() != NX_BigEndian)
- swap_fat_arch(&arch, 1, NXHostByteOrder());
+ breakpad_swap_fat_arch(&arch, 1);
- if (arch.cputype == valid_cpu_type) {
+ if (arch.cputype == cpu_type &&
+ (cpu_subtype == CPU_SUBTYPE_MULTIPLE ||
+ arch.cpusubtype == cpu_subtype)) {
offset = arch.offset;
return true;
}
@@ -205,7 +206,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
bool swap = (header.magic == MH_CIGAM);
if (swap)
- swap_mach_header(&header, NXHostByteOrder());
+ breakpad_swap_mach_header(&header);
// Copy the data into the mach_header_64 structure. Since the 32-bit and
// 64-bit only differ in the last field (reserved), this is safe to do.
@@ -231,7 +232,7 @@ bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
bool swap = (header.magic == MH_CIGAM_64);
if (swap)
- breakpad_swap_mach_header_64(&header, NXHostByteOrder());
+ breakpad_swap_mach_header_64(&header);
current_header_ = &header;
current_header_size_ = sizeof(header);
@@ -252,7 +253,7 @@ bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
return false;
if (swap)
- swap_load_command(&cmd, NXHostByteOrder());
+ breakpad_swap_load_command(&cmd);
// Call the user callback
if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
diff --git a/3rdParty/Breakpad/src/common/mac/macho_walker.h b/3rdParty/Breakpad/src/common/mac/macho_walker.h
index cee3eb8..dd53581 100644
--- a/3rdParty/Breakpad/src/common/mac/macho_walker.h
+++ b/3rdParty/Breakpad/src/common/mac/macho_walker.h
@@ -34,6 +34,7 @@
#ifndef COMMON_MAC_MACHO_WALKER_H__
#define COMMON_MAC_MACHO_WALKER_H__
+#include <mach/machine.h>
#include <mach-o/loader.h>
#include <sys/types.h>
@@ -56,16 +57,14 @@ class MachoWalker {
void *context);
~MachoWalker();
- // Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the
- // native cpu type is used. Otherwise, accepted values are listed in
- // /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC).
- // Returns false if opening the file failed or if the |cpu_type| is not
- // present in the file.
- bool WalkHeader(int cpu_type);
-
- // Locate (if any) the header offset for |cpu_type| and return in |offset|.
- // Return true if found, false otherwise.
- bool FindHeader(int cpu_type, off_t &offset);
+ // Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type|
+ // is 0, then the native cpu type is used. Otherwise, accepted values are
+ // listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or
+ // CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is
+ // only done on |cpu_type|.
+ // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
+ // is not present in the file.
+ bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
// Read |size| bytes from the opened file at |offset| into |buffer|
bool ReadBytes(void *buffer, size_t size, off_t offset);
@@ -74,8 +73,11 @@ class MachoWalker {
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
private:
- // Validate the |cpu_type|
- int ValidateCPUType(int cpu_type);
+ // Locate (if any) the header offset for |cpu_type| and return in |offset|.
+ // Return true if found, false otherwise.
+ bool FindHeader(cpu_type_t cpu_type,
+ cpu_subtype_t cpu_subtype,
+ off_t &offset);
// Process an individual header starting at |offset| from the start of the
// file. Return true if successful, false otherwise.
diff --git a/3rdParty/Breakpad/src/common/mac/string_utilities.cc b/3rdParty/Breakpad/src/common/mac/string_utilities.cc
index e1f63a9..07c0f42 100644
--- a/3rdParty/Breakpad/src/common/mac/string_utilities.cc
+++ b/3rdParty/Breakpad/src/common/mac/string_utilities.cc
@@ -27,7 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include "processor/scoped_ptr.h"
+#include "common/scoped_ptr.h"
#include "common/mac/string_utilities.h"
namespace MacStringUtils {
diff --git a/3rdParty/Breakpad/src/common/mac/super_fat_arch.h b/3rdParty/Breakpad/src/common/mac/super_fat_arch.h
new file mode 100644
index 0000000..501c865
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/mac/super_fat_arch.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Erik Chen <erikchen@chromium.org>
+
+// super_fat_arch.h: A class to handle 64-bit object files. Has conversions to
+// and from struct fat_arch.
+
+#ifndef BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
+#define BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
+
+#include <limits>
+#include <mach-o/fat.h>
+#include <stdint.h>
+
+// Similar to struct fat_arch, except size-related parameters support
+// 64-bits.
+class SuperFatArch {
+ public:
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t align;
+
+ SuperFatArch() :
+ cputype(0),
+ cpusubtype(0),
+ offset(0),
+ size(0),
+ align(0) {
+ }
+
+ explicit SuperFatArch(const struct fat_arch &arch) :
+ cputype(arch.cputype),
+ cpusubtype(arch.cpusubtype),
+ offset(arch.offset),
+ size(arch.size),
+ align(arch.align) {
+ }
+
+ // Returns false if the conversion cannot be made.
+ // If the conversion succeeds, the result is placed in |output_arch|.
+ bool ConvertToFatArch(struct fat_arch* output_arch) const {
+ if (offset > std::numeric_limits<uint32_t>::max())
+ return false;
+ if (size > std::numeric_limits<uint32_t>::max())
+ return false;
+ if (align > std::numeric_limits<uint32_t>::max())
+ return false;
+ struct fat_arch arch;
+ arch.cputype = cputype;
+ arch.cpusubtype = cpusubtype;
+ arch.offset = offset;
+ arch.size = size;
+ arch.align = align;
+ *output_arch = arch;
+ return true;
+ }
+};
+
+#endif // BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
diff --git a/3rdParty/Breakpad/src/common/md5.cc b/3rdParty/Breakpad/src/common/md5.cc
index bccf61c..4f1ac8c 100644
--- a/3rdParty/Breakpad/src/common/md5.cc
+++ b/3rdParty/Breakpad/src/common/md5.cc
@@ -58,7 +58,7 @@ void MD5Init(struct MD5Context *ctx)
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
-void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len)
{
u32 t;
@@ -138,8 +138,8 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
byteReverse(ctx->in, 14);
/* Append length in bits and transform */
- ((u32 *) ctx->in)[14] = ctx->bits[0];
- ((u32 *) ctx->in)[15] = ctx->bits[1];
+ memcpy(&ctx->in[14], &ctx->bits[0], sizeof(u32));
+ memcpy(&ctx->in[15], &ctx->bits[1], sizeof(u32));
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
@@ -166,7 +166,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
*/
static void MD5Transform(u32 buf[4], u32 const in[16])
{
- register u32 a, b, c, d;
+ u32 a, b, c, d;
a = buf[0];
b = buf[1];
diff --git a/3rdParty/Breakpad/src/common/md5.h b/3rdParty/Breakpad/src/common/md5.h
index e96521e..2ab0ab9 100644
--- a/3rdParty/Breakpad/src/common/md5.h
+++ b/3rdParty/Breakpad/src/common/md5.h
@@ -18,7 +18,7 @@ struct MD5Context {
void MD5Init(struct MD5Context *ctx);
-void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len);
void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
diff --git a/3rdParty/Breakpad/src/common/memory.h b/3rdParty/Breakpad/src/common/memory.h
index e90bd52..9158b50 100644
--- a/3rdParty/Breakpad/src/common/memory.h
+++ b/3rdParty/Breakpad/src/common/memory.h
@@ -35,9 +35,15 @@
#include <unistd.h>
#include <sys/mman.h>
+#include <memory>
+#include <vector>
+
+#if defined(MEMORY_SANITIZER)
+#include <sanitizer/msan_interface.h>
+#endif
+
#ifdef __APPLE__
#define sys_mmap mmap
-#define sys_mmap2 mmap
#define sys_munmap munmap
#define MAP_ANONYMOUS MAP_ANON
#else
@@ -57,14 +63,15 @@ class PageAllocator {
: page_size_(getpagesize()),
last_(NULL),
current_page_(NULL),
- page_offset_(0) {
+ page_offset_(0),
+ pages_allocated_(0) {
}
~PageAllocator() {
FreeAll();
}
- void *Alloc(unsigned bytes) {
+ void *Alloc(size_t bytes) {
if (!bytes)
return NULL;
@@ -79,35 +86,54 @@ class PageAllocator {
return ret;
}
- const unsigned pages =
+ const size_t pages =
(bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_;
uint8_t *const ret = GetNPages(pages);
if (!ret)
return NULL;
- page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % page_size_;
+ page_offset_ =
+ (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) %
+ page_size_;
current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL;
return ret + sizeof(PageHeader);
}
+ // Checks whether the page allocator owns the passed-in pointer.
+ // This method exists for testing pursposes only.
+ bool OwnsPointer(const void* p) {
+ for (PageHeader* header = last_; header; header = header->next) {
+ const char* current = reinterpret_cast<char*>(header);
+ if ((p >= current) && (p < current + header->num_pages * page_size_))
+ return true;
+ }
+
+ return false;
+ }
+
+ unsigned long pages_allocated() { return pages_allocated_; }
+
private:
- uint8_t *GetNPages(unsigned num_pages) {
-#ifdef __x86_64
+ uint8_t *GetNPages(size_t num_pages) {
void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
- void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#endif
if (a == MAP_FAILED)
return NULL;
+#if defined(MEMORY_SANITIZER)
+ // We need to indicate to MSan that memory allocated through sys_mmap is
+ // initialized, since linux_syscall_support.h doesn't have MSan hooks.
+ __msan_unpoison(a, page_size_ * num_pages);
+#endif
+
struct PageHeader *header = reinterpret_cast<PageHeader*>(a);
header->next = last_;
header->num_pages = num_pages;
last_ = header;
+ pages_allocated_ += num_pages;
+
return reinterpret_cast<uint8_t*>(a);
}
@@ -122,97 +148,102 @@ class PageAllocator {
struct PageHeader {
PageHeader *next; // pointer to the start of the next set of pages.
- unsigned num_pages; // the number of pages in this set.
+ size_t num_pages; // the number of pages in this set.
};
- const unsigned page_size_;
+ const size_t page_size_;
PageHeader *last_;
uint8_t *current_page_;
- unsigned page_offset_;
+ size_t page_offset_;
+ unsigned long pages_allocated_;
};
-// A wasteful vector is like a normal std::vector, except that it's very much
-// simplier and it allocates memory from a PageAllocator. It's wasteful
-// because, when resizing, it always allocates a whole new array since the
-// PageAllocator doesn't support realloc.
-template<class T>
-class wasteful_vector {
- public:
- wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16)
- : allocator_(allocator),
- a_((T*) allocator->Alloc(sizeof(T) * size_hint)),
- allocated_(size_hint),
- used_(0) {
- }
-
- T& back() {
- return a_[used_ - 1];
- }
-
- const T& back() const {
- return a_[used_ - 1];
- }
-
- bool empty() const {
- return used_ == 0;
- }
-
- void push_back(const T& new_element) {
- if (used_ == allocated_)
- Realloc(allocated_ * 2);
- a_[used_++] = new_element;
- }
-
- size_t size() const {
- return used_;
- }
-
- void resize(unsigned sz, T c = T()) {
- // No need to test "sz >= 0", as "sz" is unsigned.
- if (sz <= used_) {
- used_ = sz;
- } else {
- unsigned a = allocated_;
- if (sz > a) {
- while (sz > a) {
- a *= 2;
- }
- Realloc(a);
- }
- while (sz > used_) {
- a_[used_++] = c;
- }
+// Wrapper to use with STL containers
+template <typename T>
+struct PageStdAllocator : public std::allocator<T> {
+ typedef typename std::allocator<T>::pointer pointer;
+ typedef typename std::allocator<T>::size_type size_type;
+
+ explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator),
+ stackdata_(NULL),
+ stackdata_size_(0)
+ {}
+
+ template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other)
+ : allocator_(other.allocator_),
+ stackdata_(nullptr),
+ stackdata_size_(0)
+ {}
+
+ explicit PageStdAllocator(PageAllocator& allocator,
+ pointer stackdata,
+ size_type stackdata_size) : allocator_(allocator),
+ stackdata_(stackdata),
+ stackdata_size_(stackdata_size)
+ {}
+
+ inline pointer allocate(size_type n, const void* = 0) {
+ const size_type size = sizeof(T) * n;
+ if (size <= stackdata_size_) {
+ return stackdata_;
}
+ return static_cast<pointer>(allocator_.Alloc(size));
}
- T& operator[](size_t index) {
- return a_[index];
+ inline void deallocate(pointer, size_type) {
+ // The PageAllocator doesn't free.
}
- const T& operator[](size_t index) const {
- return a_[index];
- }
+ template <typename U> struct rebind {
+ typedef PageStdAllocator<U> other;
+ };
private:
- void Realloc(unsigned new_size) {
- T *new_array =
- reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size));
- memcpy(new_array, a_, used_ * sizeof(T));
- a_ = new_array;
- allocated_ = new_size;
+ // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will
+ // otherwise complain that `other.allocator_` is private in the constructor
+ // code.
+ template<typename Other> friend struct PageStdAllocator;
+
+ PageAllocator& allocator_;
+ pointer stackdata_;
+ size_type stackdata_size_;
+};
+
+// A wasteful vector is a std::vector, except that it allocates memory from a
+// PageAllocator. It's wasteful because, when resizing, it always allocates a
+// whole new array since the PageAllocator doesn't support realloc.
+template<class T>
+class wasteful_vector : public std::vector<T, PageStdAllocator<T> > {
+ public:
+ wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16)
+ : std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
+ std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
}
+ protected:
+ wasteful_vector(PageStdAllocator<T> allocator)
+ : std::vector<T, PageStdAllocator<T> >(allocator) {}
+};
- PageAllocator *const allocator_;
- T *a_; // pointer to an array of |allocated_| elements.
- unsigned allocated_; // size of |a_|, in elements.
- unsigned used_; // number of used slots in |a_|.
+// auto_wasteful_vector allocates space on the stack for N entries to avoid
+// using the PageAllocator for small data, while still allowing for larger data.
+template<class T, unsigned int N>
+class auto_wasteful_vector : public wasteful_vector<T> {
+ T stackdata_[N];
+ public:
+ auto_wasteful_vector(PageAllocator* allocator)
+ : wasteful_vector<T>(
+ PageStdAllocator<T>(*allocator,
+ &stackdata_[0],
+ sizeof(stackdata_))) {
+ std::vector<T, PageStdAllocator<T> >::reserve(N);
+ }
};
} // namespace google_breakpad
inline void* operator new(size_t nbytes,
google_breakpad::PageAllocator& allocator) {
- return allocator.Alloc(nbytes);
+ return allocator.Alloc(nbytes);
}
#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_
diff --git a/3rdParty/Breakpad/src/common/memory_range.h b/3rdParty/Breakpad/src/common/memory_range.h
new file mode 100644
index 0000000..41dd2da
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/memory_range.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// memory_range.h: Define the google_breakpad::MemoryRange class, which
+// is a lightweight wrapper with a pointer and a length to encapsulate
+// a contiguous range of memory.
+
+#ifndef COMMON_MEMORY_RANGE_H_
+#define COMMON_MEMORY_RANGE_H_
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+namespace google_breakpad {
+
+// A lightweight wrapper with a pointer and a length to encapsulate a
+// contiguous range of memory. It provides helper methods for checked
+// access of a subrange of the memory. Its implemementation does not
+// allocate memory or call into libc functions, and is thus safer to use
+// in a crashed environment.
+class MemoryRange {
+ public:
+ MemoryRange() : data_(NULL), length_(0) {}
+
+ MemoryRange(const void* data, size_t length) {
+ Set(data, length);
+ }
+
+ // Returns true if this memory range contains no data.
+ bool IsEmpty() const {
+ // Set() guarantees that |length_| is zero if |data_| is NULL.
+ return length_ == 0;
+ }
+
+ // Resets to an empty range.
+ void Reset() {
+ data_ = NULL;
+ length_ = 0;
+ }
+
+ // Sets this memory range to point to |data| and its length to |length|.
+ void Set(const void* data, size_t length) {
+ data_ = reinterpret_cast<const uint8_t*>(data);
+ // Always set |length_| to zero if |data_| is NULL.
+ length_ = data ? length : 0;
+ }
+
+ // Returns true if this range covers a subrange of |sub_length| bytes
+ // at |sub_offset| bytes of this memory range, or false otherwise.
+ bool Covers(size_t sub_offset, size_t sub_length) const {
+ // The following checks verify that:
+ // 1. sub_offset is within [ 0 .. length_ - 1 ]
+ // 2. sub_offset + sub_length is within
+ // [ sub_offset .. length_ ]
+ return sub_offset < length_ &&
+ sub_offset + sub_length >= sub_offset &&
+ sub_offset + sub_length <= length_;
+ }
+
+ // Returns a raw data pointer to a subrange of |sub_length| bytes at
+ // |sub_offset| bytes of this memory range, or NULL if the subrange
+ // is out of bounds.
+ const void* GetData(size_t sub_offset, size_t sub_length) const {
+ return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL;
+ }
+
+ // Same as the two-argument version of GetData() but uses sizeof(DataType)
+ // as the subrange length and returns an |DataType| pointer for convenience.
+ template <typename DataType>
+ const DataType* GetData(size_t sub_offset) const {
+ return reinterpret_cast<const DataType*>(
+ GetData(sub_offset, sizeof(DataType)));
+ }
+
+ // Returns a raw pointer to the |element_index|-th element of an array
+ // of elements of length |element_size| starting at |sub_offset| bytes
+ // of this memory range, or NULL if the element is out of bounds.
+ const void* GetArrayElement(size_t element_offset,
+ size_t element_size,
+ unsigned element_index) const {
+ size_t sub_offset = element_offset + element_index * element_size;
+ return GetData(sub_offset, element_size);
+ }
+
+ // Same as the three-argument version of GetArrayElement() but deduces
+ // the element size using sizeof(ElementType) and returns an |ElementType|
+ // pointer for convenience.
+ template <typename ElementType>
+ const ElementType* GetArrayElement(size_t element_offset,
+ unsigned element_index) const {
+ return reinterpret_cast<const ElementType*>(
+ GetArrayElement(element_offset, sizeof(ElementType), element_index));
+ }
+
+ // Returns a subrange of |sub_length| bytes at |sub_offset| bytes of
+ // this memory range, or an empty range if the subrange is out of bounds.
+ MemoryRange Subrange(size_t sub_offset, size_t sub_length) const {
+ return Covers(sub_offset, sub_length) ?
+ MemoryRange(data_ + sub_offset, sub_length) : MemoryRange();
+ }
+
+ // Returns a pointer to the beginning of this memory range.
+ const uint8_t* data() const { return data_; }
+
+ // Returns the length, in bytes, of this memory range.
+ size_t length() const { return length_; }
+
+ private:
+ // Pointer to the beginning of this memory range.
+ const uint8_t* data_;
+
+ // Length, in bytes, of this memory range.
+ size_t length_;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_MEMORY_RANGE_H_
diff --git a/3rdParty/Breakpad/src/common/memory_range_unittest.cc b/3rdParty/Breakpad/src/common/memory_range_unittest.cc
new file mode 100644
index 0000000..f6cf8c8
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/memory_range_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// memory_range_unittest.cc: Unit tests for google_breakpad::MemoryRange.
+
+#include "breakpad_googletest_includes.h"
+#include "common/memory_range.h"
+
+using google_breakpad::MemoryRange;
+using testing::Message;
+
+namespace {
+
+const uint32_t kBuffer[10] = { 0 };
+const size_t kBufferSize = sizeof(kBuffer);
+const uint8_t* kBufferPointer = reinterpret_cast<const uint8_t*>(kBuffer);
+
+// Test vectors for verifying Covers, GetData, and Subrange.
+const struct {
+ bool valid;
+ size_t offset;
+ size_t length;
+} kSubranges[] = {
+ { true, 0, 0 },
+ { true, 0, 2 },
+ { true, 0, kBufferSize },
+ { true, 2, 0 },
+ { true, 2, 4 },
+ { true, 2, kBufferSize - 2 },
+ { true, kBufferSize - 1, 1 },
+ { false, kBufferSize, 0 },
+ { false, kBufferSize, static_cast<size_t>(-1) },
+ { false, kBufferSize + 1, 0 },
+ { false, static_cast<size_t>(-1), 2 },
+ { false, 1, kBufferSize },
+ { false, kBufferSize - 1, 2 },
+ { false, 0, static_cast<size_t>(-1) },
+ { false, 1, static_cast<size_t>(-1) },
+};
+const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]);
+
+// Test vectors for verifying GetArrayElement.
+const struct {
+ size_t offset;
+ size_t size;
+ size_t index;
+ const void* const pointer;
+} kElements[] = {
+ // Valid array elemenets
+ { 0, 1, 0, kBufferPointer },
+ { 0, 1, 1, kBufferPointer + 1 },
+ { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 },
+ { 0, 2, 1, kBufferPointer + 2 },
+ { 0, 4, 2, kBufferPointer + 8 },
+ { 0, 4, 9, kBufferPointer + 36 },
+ { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 },
+ // Invalid array elemenets
+ { 0, 1, kBufferSize, NULL },
+ { 0, 4, 10, NULL },
+ { kBufferSize - 1, 1, 1, NULL },
+ { kBufferSize - 1, 2, 0, NULL },
+ { kBufferSize, 1, 0, NULL },
+};
+const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]);
+
+} // namespace
+
+TEST(MemoryRangeTest, DefaultConstructor) {
+ MemoryRange range;
+ EXPECT_EQ(NULL, range.data());
+ EXPECT_EQ(0U, range.length());
+}
+
+TEST(MemoryRangeTest, ConstructorWithDataAndLength) {
+ MemoryRange range(kBuffer, kBufferSize);
+ EXPECT_EQ(kBufferPointer, range.data());
+ EXPECT_EQ(kBufferSize, range.length());
+}
+
+TEST(MemoryRangeTest, Reset) {
+ MemoryRange range;
+ range.Reset();
+ EXPECT_EQ(NULL, range.data());
+ EXPECT_EQ(0U, range.length());
+
+ range.Set(kBuffer, kBufferSize);
+ EXPECT_EQ(kBufferPointer, range.data());
+ EXPECT_EQ(kBufferSize, range.length());
+
+ range.Reset();
+ EXPECT_EQ(NULL, range.data());
+ EXPECT_EQ(0U, range.length());
+}
+
+TEST(MemoryRangeTest, Set) {
+ MemoryRange range;
+ range.Set(kBuffer, kBufferSize);
+ EXPECT_EQ(kBufferPointer, range.data());
+ EXPECT_EQ(kBufferSize, range.length());
+
+ range.Set(NULL, 0);
+ EXPECT_EQ(NULL, range.data());
+ EXPECT_EQ(0U, range.length());
+}
+
+TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) {
+ MemoryRange range;
+ MemoryRange subrange = range.Subrange(0, 10);
+ EXPECT_EQ(NULL, subrange.data());
+ EXPECT_EQ(0U, subrange.length());
+}
+
+TEST(MemoryRangeTest, SubrangeAndGetData) {
+ MemoryRange range(kBuffer, kBufferSize);
+ for (size_t i = 0; i < kNumSubranges; ++i) {
+ bool valid = kSubranges[i].valid;
+ size_t sub_offset = kSubranges[i].offset;
+ size_t sub_length = kSubranges[i].length;
+ SCOPED_TRACE(Message() << "offset=" << sub_offset
+ << ", length=" << sub_length);
+
+ MemoryRange subrange = range.Subrange(sub_offset, sub_length);
+ if (valid) {
+ EXPECT_TRUE(range.Covers(sub_offset, sub_length));
+ EXPECT_EQ(kBufferPointer + sub_offset,
+ range.GetData(sub_offset, sub_length));
+ EXPECT_EQ(kBufferPointer + sub_offset, subrange.data());
+ EXPECT_EQ(sub_length, subrange.length());
+ } else {
+ EXPECT_FALSE(range.Covers(sub_offset, sub_length));
+ EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length));
+ EXPECT_EQ(NULL, subrange.data());
+ EXPECT_EQ(0U, subrange.length());
+ }
+ }
+}
+
+TEST(MemoryRangeTest, GetDataWithTemplateType) {
+ MemoryRange range(kBuffer, kBufferSize);
+ const char* char_pointer = range.GetData<char>(0);
+ EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
+ const int* int_pointer = range.GetData<int>(0);
+ EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
+}
+
+TEST(MemoryRangeTest, GetArrayElement) {
+ MemoryRange range(kBuffer, kBufferSize);
+ for (size_t i = 0; i < kNumElements; ++i) {
+ size_t element_offset = kElements[i].offset;
+ size_t element_size = kElements[i].size;
+ unsigned element_index = kElements[i].index;
+ const void* const element_pointer = kElements[i].pointer;
+ SCOPED_TRACE(Message() << "offset=" << element_offset
+ << ", size=" << element_size
+ << ", index=" << element_index);
+ EXPECT_EQ(element_pointer, range.GetArrayElement(
+ element_offset, element_size, element_index));
+ }
+}
+
+TEST(MemoryRangeTest, GetArrayElmentWithTemplateType) {
+ MemoryRange range(kBuffer, kBufferSize);
+ const char* char_pointer = range.GetArrayElement<char>(0, 0);
+ EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
+ const int* int_pointer = range.GetArrayElement<int>(0, 0);
+ EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
+}
diff --git a/3rdParty/Breakpad/src/common/memory_unittest.cc b/3rdParty/Breakpad/src/common/memory_unittest.cc
new file mode 100644
index 0000000..8d2494c
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/memory_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "breakpad_googletest_includes.h"
+#include "common/memory.h"
+
+using namespace google_breakpad;
+
+namespace {
+typedef testing::Test PageAllocatorTest;
+}
+
+TEST(PageAllocatorTest, Setup) {
+ PageAllocator allocator;
+ EXPECT_EQ(0U, allocator.pages_allocated());
+}
+
+TEST(PageAllocatorTest, SmallObjects) {
+ PageAllocator allocator;
+
+ EXPECT_EQ(0U, allocator.pages_allocated());
+ for (unsigned i = 1; i < 1024; ++i) {
+ uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
+ ASSERT_FALSE(p == NULL);
+ memset(p, 0, i);
+ }
+}
+
+TEST(PageAllocatorTest, LargeObject) {
+ PageAllocator allocator;
+
+ EXPECT_EQ(0U, allocator.pages_allocated());
+ uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
+ ASSERT_FALSE(p == NULL);
+ EXPECT_EQ(3U, allocator.pages_allocated());
+ for (unsigned i = 1; i < 10; ++i) {
+ uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
+ ASSERT_FALSE(p == NULL);
+ memset(p, 0, i);
+ }
+}
+
+namespace {
+typedef testing::Test WastefulVectorTest;
+}
+
+TEST(WastefulVectorTest, Setup) {
+ PageAllocator allocator_;
+ wasteful_vector<int> v(&allocator_);
+ ASSERT_TRUE(v.empty());
+ ASSERT_EQ(v.size(), 0u);
+}
+
+TEST(WastefulVectorTest, Simple) {
+ PageAllocator allocator_;
+ EXPECT_EQ(0U, allocator_.pages_allocated());
+ wasteful_vector<unsigned> v(&allocator_);
+
+ for (unsigned i = 0; i < 256; ++i) {
+ v.push_back(i);
+ ASSERT_EQ(i, v.back());
+ ASSERT_EQ(&v.back(), &v[i]);
+ }
+ ASSERT_FALSE(v.empty());
+ ASSERT_EQ(v.size(), 256u);
+ EXPECT_EQ(1U, allocator_.pages_allocated());
+ for (unsigned i = 0; i < 256; ++i)
+ ASSERT_EQ(v[i], i);
+}
+
+TEST(WastefulVectorTest, UsesPageAllocator) {
+ PageAllocator allocator_;
+ wasteful_vector<unsigned> v(&allocator_);
+ EXPECT_EQ(1U, allocator_.pages_allocated());
+
+ v.push_back(1);
+ ASSERT_TRUE(allocator_.OwnsPointer(&v[0]));
+}
+
+TEST(WastefulVectorTest, AutoWastefulVector) {
+ PageAllocator allocator_;
+ EXPECT_EQ(0U, allocator_.pages_allocated());
+
+ auto_wasteful_vector<unsigned, 4> v(&allocator_);
+ EXPECT_EQ(0U, allocator_.pages_allocated());
+
+ v.push_back(1);
+ EXPECT_EQ(0U, allocator_.pages_allocated());
+ EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
+
+ v.resize(4);
+ EXPECT_EQ(0U, allocator_.pages_allocated());
+ EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
+
+ v.resize(10);
+ EXPECT_EQ(1U, allocator_.pages_allocated());
+ EXPECT_TRUE(allocator_.OwnsPointer(&v[0]));
+}
diff --git a/3rdParty/Breakpad/src/common/minidump_type_helper.h b/3rdParty/Breakpad/src/common/minidump_type_helper.h
new file mode 100644
index 0000000..5a7d5a6
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/minidump_type_helper.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2014, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
+
+#include <stdint.h>
+
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+template <size_t>
+struct MDTypeHelper;
+
+template <>
+struct MDTypeHelper<sizeof(uint32_t)> {
+ typedef MDRawDebug32 MDRawDebug;
+ typedef MDRawLinkMap32 MDRawLinkMap;
+};
+
+template <>
+struct MDTypeHelper<sizeof(uint64_t)> {
+ typedef MDRawDebug64 MDRawDebug;
+ typedef MDRawLinkMap64 MDRawLinkMap;
+};
+
+} // namespace google_breakpad
+
+#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_
diff --git a/3rdParty/Breakpad/src/common/module.cc b/3rdParty/Breakpad/src/common/module.cc
index 4e257d1..b5fcb62 100644
--- a/3rdParty/Breakpad/src/common/module.cc
+++ b/3rdParty/Breakpad/src/common/module.cc
@@ -49,11 +49,13 @@ using std::hex;
Module::Module(const string &name, const string &os,
- const string &architecture, const string &id) :
+ const string &architecture, const string &id,
+ const string &code_id /* = "" */) :
name_(name),
os_(os),
architecture_(architecture),
id_(id),
+ code_id_(code_id),
load_address_(0) { }
Module::~Module() {
@@ -79,8 +81,34 @@ void Module::AddFunction(Function *function) {
// FUNC lines must not hold an empty name, so catch the problem early if
// callers try to add one.
assert(!function->name.empty());
+
+ // FUNCs are better than PUBLICs as they come with sizes, so remove an extern
+ // with the same address if present.
+ Extern ext(function->address);
+ ExternSet::iterator it_ext = externs_.find(&ext);
+ if (it_ext == externs_.end() &&
+ architecture_ == "arm" &&
+ (function->address & 0x1) == 0) {
+ // ARM THUMB functions have bit 0 set. ARM64 does not have THUMB.
+ Extern arm_thumb_ext(function->address | 0x1);
+ it_ext = externs_.find(&arm_thumb_ext);
+ }
+ if (it_ext != externs_.end()) {
+ delete *it_ext;
+ externs_.erase(it_ext);
+ }
+#if _DEBUG
+ {
+ // There should be no other PUBLIC symbols that overlap with the function.
+ Extern debug_ext(function->address);
+ ExternSet::iterator it_debug = externs_.lower_bound(&ext);
+ assert(it_debug == externs_.end() ||
+ (*it_debug)->address >= function->address + function->size);
+ }
+#endif
+
std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
- if (!ret.second) {
+ if (!ret.second && (*ret.first != function)) {
// Free the duplicate that was not inserted because this Module
// now owns it.
delete function;
@@ -130,8 +158,7 @@ Module::File *Module::FindFile(const string &name) {
FileByNameMap::iterator destiny = files_.lower_bound(&name);
if (destiny == files_.end()
|| *destiny->first != name) { // Repeated string comparison, boo hoo.
- File *file = new File;
- file->name = name;
+ File *file = new File(name);
file->source_id = -1;
destiny = files_.insert(destiny,
FileByNameMap::value_type(&file->name, file));
@@ -155,7 +182,7 @@ void Module::GetFiles(vector<File *> *vec) {
vec->push_back(it->second);
}
-void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
+void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
*vec = stack_frame_entries_;
}
@@ -204,62 +231,66 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
return stream.good();
}
-bool Module::Write(std::ostream &stream, bool cfi) {
+bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
stream << "MODULE " << os_ << " " << architecture_ << " "
<< id_ << " " << name_ << endl;
if (!stream.good())
return ReportError();
- AssignSourceIds();
+ if (!code_id_.empty()) {
+ stream << "INFO CODE_ID " << code_id_ << endl;
+ }
- // Write out files.
- for (FileByNameMap::iterator file_it = files_.begin();
- file_it != files_.end(); ++file_it) {
- File *file = file_it->second;
- if (file->source_id >= 0) {
- stream << "FILE " << file->source_id << " " << file->name << endl;
- if (!stream.good())
- return ReportError();
+ if (symbol_data != ONLY_CFI) {
+ AssignSourceIds();
+
+ // Write out files.
+ for (FileByNameMap::iterator file_it = files_.begin();
+ file_it != files_.end(); ++file_it) {
+ File *file = file_it->second;
+ if (file->source_id >= 0) {
+ stream << "FILE " << file->source_id << " " << file->name << endl;
+ if (!stream.good())
+ return ReportError();
+ }
}
- }
- // Write out functions and their lines.
- for (FunctionSet::const_iterator func_it = functions_.begin();
- func_it != functions_.end(); ++func_it) {
- Function *func = *func_it;
- stream << "FUNC " << hex
- << (func->address - load_address_) << " "
- << func->size << " "
- << func->parameter_size << " "
- << func->name << dec << endl;
-
- if (!stream.good())
- return ReportError();
- for (vector<Line>::iterator line_it = func->lines.begin();
- line_it != func->lines.end(); ++line_it) {
- stream << hex
- << (line_it->address - load_address_) << " "
- << line_it->size << " "
- << dec
- << line_it->number << " "
- << line_it->file->source_id << endl;
+ // Write out functions and their lines.
+ for (FunctionSet::const_iterator func_it = functions_.begin();
+ func_it != functions_.end(); ++func_it) {
+ Function *func = *func_it;
+ stream << "FUNC " << hex
+ << (func->address - load_address_) << " "
+ << func->size << " "
+ << func->parameter_size << " "
+ << func->name << dec << endl;
if (!stream.good())
return ReportError();
+
+ for (vector<Line>::iterator line_it = func->lines.begin();
+ line_it != func->lines.end(); ++line_it) {
+ stream << hex
+ << (line_it->address - load_address_) << " "
+ << line_it->size << " "
+ << dec
+ << line_it->number << " "
+ << line_it->file->source_id << endl;
+ if (!stream.good())
+ return ReportError();
+ }
}
- }
- // Write out 'PUBLIC' records.
- for (ExternSet::const_iterator extern_it = externs_.begin();
- extern_it != externs_.end(); ++extern_it) {
- Extern *ext = *extern_it;
- stream << "PUBLIC " << hex
- << (ext->address - load_address_) << " 0 "
- << ext->name << dec << endl;
- if (!stream.good())
- return ReportError();
+ // Write out 'PUBLIC' records.
+ for (ExternSet::const_iterator extern_it = externs_.begin();
+ extern_it != externs_.end(); ++extern_it) {
+ Extern *ext = *extern_it;
+ stream << "PUBLIC " << hex
+ << (ext->address - load_address_) << " 0 "
+ << ext->name << dec << endl;
+ }
}
- if (cfi) {
+ if (symbol_data != NO_CFI) {
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
vector<StackFrameEntry *>::const_iterator frame_it;
for (frame_it = stack_frame_entries_.begin();
diff --git a/3rdParty/Breakpad/src/common/module.h b/3rdParty/Breakpad/src/common/module.h
index cc89bba..6c2bb27 100644
--- a/3rdParty/Breakpad/src/common/module.h
+++ b/3rdParty/Breakpad/src/common/module.h
@@ -44,6 +44,7 @@
#include <string>
#include <vector>
+#include "common/symbol_data.h"
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
@@ -60,7 +61,7 @@ using std::map;
class Module {
public:
// The type of addresses and sizes in a symbol table.
- typedef u_int64_t Address;
+ typedef uint64_t Address;
struct File;
struct Function;
struct Line;
@@ -73,8 +74,10 @@ class Module {
// A source file.
struct File {
+ explicit File(const string &name_input) : name(name_input), source_id(0) {}
+
// The name of the source file.
- string name;
+ const string name;
// The file's source id. The Write member function clears this
// field and assigns source ids a fresh, so any value placed here
@@ -84,6 +87,9 @@ class Module {
// A function.
struct Function {
+ Function(const string &name_input, const Address &address_input) :
+ name(name_input), address(address_input), size(0), parameter_size(0) {}
+
// For sorting by address. (Not style-guide compliant, but it's
// stupid not to put this in the struct.)
static bool CompareByAddress(const Function *x, const Function *y) {
@@ -91,10 +97,11 @@ class Module {
}
// The function's name.
- string name;
+ const string name;
// The start address and length of the function's code.
- Address address, size;
+ const Address address;
+ Address size;
// The function's parameter size.
Address parameter_size;
@@ -119,7 +126,8 @@ class Module {
// An exported symbol.
struct Extern {
- Address address;
+ explicit Extern(const Address &address_input) : address(address_input) {}
+ const Address address;
string name;
};
@@ -171,7 +179,7 @@ class Module {
// Create a new module with the given name, operating system,
// architecture, and ID string.
Module(const string &name, const string &os, const string &architecture,
- const string &id);
+ const string &id, const string &code_id = "");
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
@@ -246,7 +254,7 @@ class Module {
// effectively a copy of the stack frame entry list, this is mostly
// useful for testing; other uses should probably get
// a more appropriate interface.)
- void GetStackFrameEntries(vector<StackFrameEntry *> *vec);
+ void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const;
// Find those files in this module that are actually referred to by
// functions' line number data, and assign them source id numbers.
@@ -259,13 +267,21 @@ class Module {
// breakpad symbol format. Return true if all goes well, or false if
// an error occurs. This method writes out:
// - a header based on the values given to the constructor,
+ // If symbol_data is not ONLY_CFI then:
// - the source files added via FindFile,
// - the functions added via AddFunctions, each with its lines,
// - all public records,
- // - and if CFI is true, all CFI records.
+ // If symbol_data is not NO_CFI then:
+ // - all CFI records.
// Addresses in the output are all relative to the load address
// established by SetLoadAddress.
- bool Write(std::ostream &stream, bool cfi);
+ bool Write(std::ostream &stream, SymbolData symbol_data);
+
+ string name() const { return name_; }
+ string os() const { return os_; }
+ string architecture() const { return architecture_; }
+ string identifier() const { return id_; }
+ string code_identifier() const { return code_id_; }
private:
// Report an error that has occurred writing the symbol file, using
@@ -278,7 +294,7 @@ class Module {
static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream);
// Module header entries.
- string name_, os_, architecture_, id_;
+ string name_, os_, architecture_, id_, code_id_;
// The module's nominal load address. Addresses for functions and
// lines are absolute, assuming the module is loaded at this
@@ -288,7 +304,7 @@ class Module {
// Relation for maps whose keys are strings shared with some other
// structure.
struct CompareStringPtrs {
- bool operator()(const string *x, const string *y) { return *x < *y; }
+ bool operator()(const string *x, const string *y) const { return *x < *y; }
};
// A map from filenames to File structures. The map's keys are
diff --git a/3rdParty/Breakpad/src/common/module_unittest.cc b/3rdParty/Breakpad/src/common/module_unittest.cc
new file mode 100644
index 0000000..78406e3
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/module_unittest.cc
@@ -0,0 +1,557 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// module_unittest.cc: Unit tests for google_breakpad::Module.
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+
+#include "breakpad_googletest_includes.h"
+#include "common/module.h"
+#include "common/using_std_string.h"
+
+using google_breakpad::Module;
+using std::stringstream;
+using std::vector;
+using testing::ContainerEq;
+
+static Module::Function *generate_duplicate_function(const string &name) {
+ const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL;
+ const Module::Address DUP_SIZE = 0x200b26e605f99071LL;
+ const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL;
+
+ Module::Function *function = new Module::Function(name, DUP_ADDRESS);
+ function->size = DUP_SIZE;
+ function->parameter_size = DUP_PARAMETER_SIZE;
+ return function;
+}
+
+#define MODULE_NAME "name with spaces"
+#define MODULE_OS "os-name"
+#define MODULE_ARCH "architecture"
+#define MODULE_ID "id-string"
+#define MODULE_CODE_ID "code-id-string"
+
+TEST(Write, Header) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
+ contents.c_str());
+}
+
+TEST(Write, HeaderCodeId) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID);
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "INFO CODE_ID code-id-string\n",
+ contents.c_str());
+}
+
+TEST(Write, OneLineFunc) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ Module::File *file = m.FindFile("file_name.cc");
+ Module::Function *function = new Module::Function(
+ "function_name", 0xe165bf8023b9d9abLL);
+ function->size = 0x1e4bb0eb1cbf5b09LL;
+ function->parameter_size = 0x772beee89114358aLL;
+ Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
+ file, 67519080 };
+ function->lines.push_back(line);
+ m.AddFunction(function);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FILE 0 file_name.cc\n"
+ "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a"
+ " function_name\n"
+ "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n",
+ contents.c_str());
+}
+
+TEST(Write, RelativeLoadAddress) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Some source files. We will expect to see them in lexicographic order.
+ Module::File *file1 = m.FindFile("filename-b.cc");
+ Module::File *file2 = m.FindFile("filename-a.cc");
+
+ // A function.
+ Module::Function *function = new Module::Function(
+ "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
+ function->size = 0x2922088f98d3f6fcLL;
+ function->parameter_size = 0xe5e9aa008bd5f0d0LL;
+
+ // Some source lines. The module should not sort these.
+ Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
+ file1, 41676901 };
+ Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL,
+ file2, 67519080 };
+ function->lines.push_back(line2);
+ function->lines.push_back(line1);
+
+ m.AddFunction(function);
+
+ // Some stack information.
+ Module::StackFrameEntry *entry = new Module::StackFrameEntry();
+ entry->address = 0x30f9e5c83323973dULL;
+ entry->size = 0x49fc9ca7c7c13dc2ULL;
+ entry->initial_rules[".cfa"] = "he was a handsome man";
+ entry->initial_rules["and"] = "what i want to know is";
+ entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
+ "do you like your blueeyed boy";
+ entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
+ m.AddStackFrameEntry(entry);
+
+ // Set the load address. Doing this after adding all the data to
+ // the module must work fine.
+ m.SetLoadAddress(0x2ab698b0b6407073LL);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FILE 0 filename-a.cc\n"
+ "FILE 1 filename-b.cc\n"
+ "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
+ " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
+ "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n"
+ "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n"
+ "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2"
+ " .cfa: he was a handsome man"
+ " and: what i want to know is\n"
+ "STACK CFI 6434d177ce326cb"
+ " Mister: Death"
+ " how: do you like your blueeyed boy\n",
+ contents.c_str());
+}
+
+TEST(Write, OmitUnusedFiles) {
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Create some source files.
+ Module::File *file1 = m.FindFile("filename1");
+ m.FindFile("filename2"); // not used by any line
+ Module::File *file3 = m.FindFile("filename3");
+
+ // Create a function.
+ Module::Function *function = new Module::Function(
+ "function_name", 0x9b926d464f0b9384LL);
+ function->size = 0x4f524a4ba795e6a6LL;
+ function->parameter_size = 0xbbe8133a6641c9b7LL;
+
+ // Source files that refer to some files, but not others.
+ Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL,
+ file1, 137850127 };
+ Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL,
+ file3, 28113549 };
+ function->lines.push_back(line1);
+ function->lines.push_back(line2);
+ m.AddFunction(function);
+
+ m.AssignSourceIds();
+
+ vector<Module::File *> vec;
+ m.GetFiles(&vec);
+ EXPECT_EQ((size_t) 3, vec.size());
+ EXPECT_STREQ("filename1", vec[0]->name.c_str());
+ EXPECT_NE(-1, vec[0]->source_id);
+ // Expect filename2 not to be used.
+ EXPECT_STREQ("filename2", vec[1]->name.c_str());
+ EXPECT_EQ(-1, vec[1]->source_id);
+ EXPECT_STREQ("filename3", vec[2]->name.c_str());
+ EXPECT_NE(-1, vec[2]->source_id);
+
+ stringstream s;
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FILE 0 filename1\n"
+ "FILE 1 filename3\n"
+ "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7"
+ " function_name\n"
+ "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n"
+ "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n",
+ contents.c_str());
+}
+
+TEST(Write, NoCFI) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Some source files. We will expect to see them in lexicographic order.
+ Module::File *file1 = m.FindFile("filename.cc");
+
+ // A function.
+ Module::Function *function = new Module::Function(
+ "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL);
+ function->size = 0x2922088f98d3f6fcLL;
+ function->parameter_size = 0xe5e9aa008bd5f0d0LL;
+
+ // Some source lines. The module should not sort these.
+ Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
+ file1, 41676901 };
+ function->lines.push_back(line1);
+
+ m.AddFunction(function);
+
+ // Some stack information.
+ Module::StackFrameEntry *entry = new Module::StackFrameEntry();
+ entry->address = 0x30f9e5c83323973dULL;
+ entry->size = 0x49fc9ca7c7c13dc2ULL;
+ entry->initial_rules[".cfa"] = "he was a handsome man";
+ entry->initial_rules["and"] = "what i want to know is";
+ entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
+ "do you like your blueeyed boy";
+ entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
+ m.AddStackFrameEntry(entry);
+
+ // Set the load address. Doing this after adding all the data to
+ // the module must work fine.
+ m.SetLoadAddress(0x2ab698b0b6407073LL);
+
+ m.Write(s, NO_CFI);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FILE 0 filename.cc\n"
+ "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
+ " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
+ "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n",
+ contents.c_str());
+}
+
+TEST(Construct, AddFunctions) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two functions.
+ Module::Function *function1 = new Module::Function(
+ "_without_form", 0xd35024aa7ca7da5cLL);
+ function1->size = 0x200b26e605f99071LL;
+ function1->parameter_size = 0xf14ac4fed48c4a99LL;
+
+ Module::Function *function2 = new Module::Function(
+ "_and_void", 0x2987743d0b35b13fLL);
+ function2->size = 0xb369db048deb3010LL;
+ function2->parameter_size = 0x938e556cb5a79988LL;
+
+ // Put them in a vector.
+ vector<Module::Function *> vec;
+ vec.push_back(function1);
+ vec.push_back(function2);
+
+ m.AddFunctions(vec.begin(), vec.end());
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
+ " _and_void\n"
+ "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99"
+ " _without_form\n",
+ contents.c_str());
+
+ // Check that m.GetFunctions returns the functions we expect.
+ vec.clear();
+ m.GetFunctions(&vec, vec.end());
+ EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1));
+ EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2));
+ EXPECT_EQ((size_t) 2, vec.size());
+}
+
+TEST(Construct, AddFrames) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // First STACK CFI entry, with no initial rules or deltas.
+ Module::StackFrameEntry *entry1 = new Module::StackFrameEntry();
+ entry1->address = 0xddb5f41285aa7757ULL;
+ entry1->size = 0x1486493370dc5073ULL;
+ m.AddStackFrameEntry(entry1);
+
+ // Second STACK CFI entry, with initial rules but no deltas.
+ Module::StackFrameEntry *entry2 = new Module::StackFrameEntry();
+ entry2->address = 0x8064f3af5e067e38ULL;
+ entry2->size = 0x0de2a5ee55509407ULL;
+ entry2->initial_rules[".cfa"] = "I think that I shall never see";
+ entry2->initial_rules["stromboli"] = "a poem lovely as a tree";
+ entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest";
+ m.AddStackFrameEntry(entry2);
+
+ // Third STACK CFI entry, with initial rules and deltas.
+ Module::StackFrameEntry *entry3 = new Module::StackFrameEntry();
+ entry3->address = 0x5e8d0db0a7075c6cULL;
+ entry3->size = 0x1c7edb12a7aea229ULL;
+ entry3->initial_rules[".cfa"] = "Whose woods are these";
+ entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] =
+ "the village though";
+ entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
+ "he will not see me stopping here";
+ entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] =
+ "his house is in";
+ entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
+ "I think I know";
+ m.AddStackFrameEntry(entry3);
+
+ // Check that Write writes STACK CFI records properly.
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
+ "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407"
+ " .cfa: I think that I shall never see"
+ " cannoli: a tree whose hungry mouth is prest"
+ " stromboli: a poem lovely as a tree\n"
+ "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229"
+ " .cfa: Whose woods are these\n"
+ "STACK CFI 36682fad3763ffff"
+ " .cfa: I think I know"
+ " stromboli: his house is in\n"
+ "STACK CFI 47ceb0f63c269d7f"
+ " calzone: the village though"
+ " cannoli: he will not see me stopping here\n",
+ contents.c_str());
+
+ // Check that GetStackFrameEntries works.
+ vector<Module::StackFrameEntry *> entries;
+ m.GetStackFrameEntries(&entries);
+ ASSERT_EQ(3U, entries.size());
+ // Check first entry.
+ EXPECT_EQ(0xddb5f41285aa7757ULL, entries[0]->address);
+ EXPECT_EQ(0x1486493370dc5073ULL, entries[0]->size);
+ ASSERT_EQ(0U, entries[0]->initial_rules.size());
+ ASSERT_EQ(0U, entries[0]->rule_changes.size());
+ // Check second entry.
+ EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address);
+ EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size);
+ ASSERT_EQ(3U, entries[1]->initial_rules.size());
+ Module::RuleMap entry2_initial;
+ entry2_initial[".cfa"] = "I think that I shall never see";
+ entry2_initial["stromboli"] = "a poem lovely as a tree";
+ entry2_initial["cannoli"] = "a tree whose hungry mouth is prest";
+ EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
+ ASSERT_EQ(0U, entries[1]->rule_changes.size());
+ // Check third entry.
+ EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[2]->address);
+ EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[2]->size);
+ Module::RuleMap entry3_initial;
+ entry3_initial[".cfa"] = "Whose woods are these";
+ EXPECT_THAT(entries[2]->initial_rules, ContainerEq(entry3_initial));
+ Module::RuleChangeMap entry3_changes;
+ entry3_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know";
+ entry3_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in";
+ entry3_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though";
+ entry3_changes[0x47ceb0f63c269d7fULL]["cannoli"] =
+ "he will not see me stopping here";
+ EXPECT_THAT(entries[2]->rule_changes, ContainerEq(entry3_changes));
+}
+
+TEST(Construct, UniqueFiles) {
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+ Module::File *file1 = m.FindFile("foo");
+ Module::File *file2 = m.FindFile(string("bar"));
+ Module::File *file3 = m.FindFile(string("foo"));
+ Module::File *file4 = m.FindFile("bar");
+ EXPECT_NE(file1, file2);
+ EXPECT_EQ(file1, file3);
+ EXPECT_EQ(file2, file4);
+ EXPECT_EQ(file1, m.FindExistingFile("foo"));
+ EXPECT_TRUE(m.FindExistingFile("baz") == NULL);
+}
+
+TEST(Construct, DuplicateFunctions) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two functions.
+ Module::Function *function1 = generate_duplicate_function("_without_form");
+ Module::Function *function2 = generate_duplicate_function("_without_form");
+
+ m.AddFunction(function1);
+ m.AddFunction(function2);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
+ " _without_form\n",
+ contents.c_str());
+}
+
+TEST(Construct, FunctionsWithSameAddress) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two functions.
+ Module::Function *function1 = generate_duplicate_function("_without_form");
+ Module::Function *function2 = generate_duplicate_function("_and_void");
+
+ m.AddFunction(function1);
+ m.AddFunction(function2);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+ EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
+ "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
+ " _and_void\n"
+ "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
+ " _without_form\n",
+ contents.c_str());
+}
+
+// Externs should be written out as PUBLIC records, sorted by
+// address.
+TEST(Construct, Externs) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two externs.
+ Module::Extern *extern1 = new Module::Extern(0xffff);
+ extern1->name = "_abc";
+ Module::Extern *extern2 = new Module::Extern(0xaaaa);
+ extern2->name = "_xyz";
+
+ m.AddExtern(extern1);
+ m.AddExtern(extern2);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
+ MODULE_ID " " MODULE_NAME "\n"
+ "PUBLIC aaaa 0 _xyz\n"
+ "PUBLIC ffff 0 _abc\n",
+ contents.c_str());
+}
+
+// Externs with the same address should only keep the first entry
+// added.
+TEST(Construct, DuplicateExterns) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two externs.
+ Module::Extern *extern1 = new Module::Extern(0xffff);
+ extern1->name = "_xyz";
+ Module::Extern *extern2 = new Module::Extern(0xffff);
+ extern2->name = "_abc";
+
+ m.AddExtern(extern1);
+ m.AddExtern(extern2);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
+ MODULE_ID " " MODULE_NAME "\n"
+ "PUBLIC ffff 0 _xyz\n",
+ contents.c_str());
+}
+
+// If there exists an extern and a function at the same address, only write
+// out the FUNC entry.
+TEST(Construct, FunctionsAndExternsWithSameAddress) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
+
+ // Two externs.
+ Module::Extern* extern1 = new Module::Extern(0xabc0);
+ extern1->name = "abc";
+ Module::Extern* extern2 = new Module::Extern(0xfff0);
+ extern2->name = "xyz";
+
+ m.AddExtern(extern1);
+ m.AddExtern(extern2);
+
+ Module::Function* function = new Module::Function("_xyz", 0xfff0);
+ function->size = 0x10;
+ function->parameter_size = 0;
+ m.AddFunction(function);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
+ MODULE_ID " " MODULE_NAME "\n"
+ "FUNC fff0 10 0 _xyz\n"
+ "PUBLIC abc0 0 abc\n",
+ contents.c_str());
+}
+
+// If there exists an extern and a function at the same address, only write
+// out the FUNC entry. For ARM THUMB, the extern that comes from the ELF
+// symbol section has bit 0 set.
+TEST(Construct, FunctionsAndThumbExternsWithSameAddress) {
+ stringstream s;
+ Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID);
+
+ // Two THUMB externs.
+ Module::Extern* thumb_extern1 = new Module::Extern(0xabc1);
+ thumb_extern1->name = "thumb_abc";
+ Module::Extern* thumb_extern2 = new Module::Extern(0xfff1);
+ thumb_extern2->name = "thumb_xyz";
+
+ Module::Extern* arm_extern1 = new Module::Extern(0xcc00);
+ arm_extern1->name = "arm_func";
+
+ m.AddExtern(thumb_extern1);
+ m.AddExtern(thumb_extern2);
+ m.AddExtern(arm_extern1);
+
+ // The corresponding function from the DWARF debug data have the actual
+ // address.
+ Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0);
+ function->size = 0x10;
+ function->parameter_size = 0;
+ m.AddFunction(function);
+
+ m.Write(s, ALL_SYMBOL_DATA);
+ string contents = s.str();
+
+ EXPECT_STREQ("MODULE " MODULE_OS " arm "
+ MODULE_ID " " MODULE_NAME "\n"
+ "FUNC fff0 10 0 _thumb_xyz\n"
+ "PUBLIC abc1 0 thumb_abc\n"
+ "PUBLIC cc00 0 arm_func\n",
+ contents.c_str());
+}
diff --git a/3rdParty/Breakpad/src/common/scoped_ptr.h b/3rdParty/Breakpad/src/common/scoped_ptr.h
new file mode 100644
index 0000000..d137c18
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/scoped_ptr.h
@@ -0,0 +1,404 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Scopers help you manage ownership of a pointer, helping you easily manage the
+// a pointer within a scope, and automatically destroying the pointer at the
+// end of a scope. There are two main classes you will use, which correspond
+// to the operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr):
+// {
+// scoped_ptr<Foo> foo(new Foo("wee"));
+// } // foo goes out of scope, releasing the pointer with it.
+//
+// {
+// scoped_ptr<Foo> foo; // No pointer managed.
+// foo.reset(new Foo("wee")); // Now a pointer is managed.
+// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
+// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
+// foo->Method(); // Foo::Method() called.
+// foo.get()->Method(); // Foo::Method() called.
+// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
+// // manages a pointer.
+// foo.reset(new Foo("wee4")); // foo manages a pointer again.
+// foo.reset(); // Foo("wee4") destroyed, foo no longer
+// // manages a pointer.
+// } // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_array):
+// {
+// scoped_array<Foo> foo(new Foo[100]);
+// foo.get()->Method(); // Foo::Method on the 0th element.
+// foo[10].Method(); // Foo::Method on the 10th element.
+// }
+
+#ifndef COMMON_SCOPED_PTR_H_
+#define COMMON_SCOPED_PTR_H_
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class, and its closely-related brethren,
+// scoped_array, scoped_ptr_malloc.
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+namespace google_breakpad {
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the threadsafety guarantees of T.
+//
+// The size of a scoped_ptr is small:
+// sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to initializing with NULL.
+ // There is no way to create an uninitialized scoped_ptr.
+ // The input parameter must be allocated with new.
+ explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_ptr() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != ptr_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ ptr_ = p;
+ }
+ }
+
+ // Accessors to get the owned object.
+ // operator* and operator-> will assert() if there is no current object.
+ C& operator*() const {
+ assert(ptr_ != NULL);
+ return *ptr_;
+ }
+ C* operator->() const {
+ assert(ptr_ != NULL);
+ return ptr_;
+ }
+ C* get() const { return ptr_; }
+
+ // Comparison operators.
+ // These return whether two scoped_ptr refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(C* p) const { return ptr_ == p; }
+ bool operator!=(C* p) const { return ptr_ != p; }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr& p2) {
+ C* tmp = ptr_;
+ ptr_ = p2.ptr_;
+ p2.ptr_ = tmp;
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = ptr_;
+ ptr_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* ptr_;
+
+ // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
+ // make sense, and if C2 == C, it still doesn't make sense because you should
+ // never have the same object owned by two different scoped_ptrs.
+ template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_ptr(const scoped_ptr&);
+ void operator=(const scoped_ptr&);
+};
+
+// Free functions
+template <class C>
+void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_ptr<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_ptr<C>& p2) {
+ return p1 != p2.get();
+}
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL. A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the threadsafety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_array.
+ // The input parameter must be allocated with new [].
+ explicit scoped_array(C* p = NULL) : array_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_array() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != array_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ array_ = p;
+ }
+ }
+
+ // Get one element of the current object.
+ // Will assert() if there is no current object, or index i is negative.
+ C& operator[](ptrdiff_t i) const {
+ assert(i >= 0);
+ assert(array_ != NULL);
+ return array_[i];
+ }
+
+ // Get a pointer to the zeroth element of the current object.
+ // If there is no current object, return NULL.
+ C* get() const {
+ return array_;
+ }
+
+ // Comparison operators.
+ // These return whether two scoped_array refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(C* p) const { return array_ == p; }
+ bool operator!=(C* p) const { return array_ != p; }
+
+ // Swap two scoped arrays.
+ void swap(scoped_array& p2) {
+ C* tmp = array_;
+ array_ = p2.array_;
+ p2.array_ = tmp;
+ }
+
+ // Release an array.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = array_;
+ array_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* array_;
+
+ // Forbid comparison of different scoped_array types.
+ template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_array(const scoped_array&);
+ void operator=(const scoped_array&);
+};
+
+// Free functions
+template <class C>
+void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_array<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_array<C>& p2) {
+ return p1 != p2.get();
+}
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+ inline void operator()(void* x) const {
+ free(x);
+ }
+};
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the functor used to free the object.
+
+template<class C, class FreeProc = ScopedPtrMallocFree>
+class scoped_ptr_malloc {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to initializing with NULL.
+ // There is no way to create an uninitialized scoped_ptr.
+ // The input parameter must be allocated with an allocator that matches the
+ // Free functor. For the default Free functor, this is malloc, calloc, or
+ // realloc.
+ explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}
+
+ // Destructor. If there is a C object, call the Free functor.
+ ~scoped_ptr_malloc() {
+ reset();
+ }
+
+ // Reset. Calls the Free functor on the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (ptr_ != p) {
+ FreeProc free_proc;
+ free_proc(ptr_);
+ ptr_ = p;
+ }
+ }
+
+ // Get the current object.
+ // operator* and operator-> will cause an assert() failure if there is
+ // no current object.
+ C& operator*() const {
+ assert(ptr_ != NULL);
+ return *ptr_;
+ }
+
+ C* operator->() const {
+ assert(ptr_ != NULL);
+ return ptr_;
+ }
+
+ C* get() const {
+ return ptr_;
+ }
+
+ // Comparison operators.
+ // These return whether a scoped_ptr_malloc and a plain pointer refer
+ // to the same object, not just to two different but equal objects.
+ // For compatibility with the boost-derived implementation, these
+ // take non-const arguments.
+ bool operator==(C* p) const {
+ return ptr_ == p;
+ }
+
+ bool operator!=(C* p) const {
+ return ptr_ != p;
+ }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr_malloc & b) {
+ C* tmp = b.ptr_;
+ b.ptr_ = ptr_;
+ ptr_ = tmp;
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* tmp = ptr_;
+ ptr_ = NULL;
+ return tmp;
+ }
+
+ private:
+ C* ptr_;
+
+ // no reason to use these: each scoped_ptr_malloc should have its own object
+ template <class C2, class GP>
+ bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;
+ template <class C2, class GP>
+ bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
+
+ // Disallow evil constructors
+ scoped_ptr_malloc(const scoped_ptr_malloc&);
+ void operator=(const scoped_ptr_malloc&);
+};
+
+template<class C, class FP> inline
+void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
+ a.swap(b);
+}
+
+template<class C, class FP> inline
+bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {
+ return p == b.get();
+}
+
+template<class C, class FP> inline
+bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {
+ return p != b.get();
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_SCOPED_PTR_H_
diff --git a/3rdParty/Breakpad/src/common/simple_string_dictionary.cc b/3rdParty/Breakpad/src/common/simple_string_dictionary.cc
new file mode 100644
index 0000000..e0a74ce
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/simple_string_dictionary.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/simple_string_dictionary.h"
+
+namespace google_breakpad {
+
+namespace {
+
+// In C++98 (ISO 14882), section 9.5.1 says that a union cannot have a member
+// with a non-trivial ctor, copy ctor, dtor, or assignment operator. Use this
+// property to ensure that Entry remains POD.
+union Compile_Assert {
+ NonAllocatingMap<1, 1, 1>::Entry Compile_Assert__entry_must_be_pod;
+};
+
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/simple_string_dictionary.h b/3rdParty/Breakpad/src/common/simple_string_dictionary.h
new file mode 100644
index 0000000..d2ab17f
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/simple_string_dictionary.h
@@ -0,0 +1,260 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_SIMPLE_STRING_DICTIONARY_H_
+#define COMMON_SIMPLE_STRING_DICTIONARY_H_
+
+#include <assert.h>
+#include <string.h>
+
+#include "common/basictypes.h"
+
+namespace google_breakpad {
+
+// Opaque type for the serialized representation of a NonAllocatingMap. One is
+// created in NonAllocatingMap::Serialize and can be deserialized using one of
+// the constructors.
+struct SerializedNonAllocatingMap;
+
+// NonAllocatingMap is an implementation of a map/dictionary collection that
+// uses a fixed amount of storage, so that it does not perform any dynamic
+// allocations for its operations.
+//
+// The actual map storage (the Entry) is guaranteed to be POD, so that it can
+// be transmitted over various IPC mechanisms.
+//
+// The template parameters control the amount of storage used for the key,
+// value, and map. The KeySize and ValueSize are measured in bytes, not glyphs,
+// and includes space for a \0 byte. This gives space for KeySize-1 and
+// ValueSize-1 characters in an entry. NumEntries is the total number of
+// entries that will fit in the map.
+template <size_t KeySize, size_t ValueSize, size_t NumEntries>
+class NonAllocatingMap {
+ public:
+ // Constant and publicly accessible versions of the template parameters.
+ static const size_t key_size = KeySize;
+ static const size_t value_size = ValueSize;
+ static const size_t num_entries = NumEntries;
+
+ // An Entry object is a single entry in the map. If the key is a 0-length
+ // NUL-terminated string, the entry is empty.
+ struct Entry {
+ char key[KeySize];
+ char value[ValueSize];
+
+ bool is_active() const {
+ return key[0] != '\0';
+ }
+ };
+
+ // An Iterator can be used to iterate over all the active entries in a
+ // NonAllocatingMap.
+ class Iterator {
+ public:
+ explicit Iterator(const NonAllocatingMap& map)
+ : map_(map),
+ current_(0) {
+ }
+
+ // Returns the next entry in the map, or NULL if at the end of the
+ // collection.
+ const Entry* Next() {
+ while (current_ < map_.num_entries) {
+ const Entry* entry = &map_.entries_[current_++];
+ if (entry->is_active()) {
+ return entry;
+ }
+ }
+ return NULL;
+ }
+
+ private:
+ const NonAllocatingMap& map_;
+ size_t current_;
+
+ DISALLOW_COPY_AND_ASSIGN(Iterator);
+ };
+
+ NonAllocatingMap() : entries_() {
+ }
+
+ NonAllocatingMap(const NonAllocatingMap& other) {
+ *this = other;
+ }
+
+ NonAllocatingMap& operator=(const NonAllocatingMap& other) {
+ assert(other.key_size == key_size);
+ assert(other.value_size == value_size);
+ assert(other.num_entries == num_entries);
+ if (other.key_size == key_size && other.value_size == value_size &&
+ other.num_entries == num_entries) {
+ memcpy(entries_, other.entries_, sizeof(entries_));
+ }
+ return *this;
+ }
+
+ // Constructs a map from its serialized form. |map| should be the out
+ // parameter from Serialize() and |size| should be its return value.
+ NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) {
+ assert(size == sizeof(entries_));
+ if (size == sizeof(entries_)) {
+ memcpy(entries_, map, size);
+ }
+ }
+
+ // Returns the number of active key/value pairs. The upper limit for this
+ // is NumEntries.
+ size_t GetCount() const {
+ size_t count = 0;
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (entries_[i].is_active()) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ // Given |key|, returns its corresponding |value|. |key| must not be NULL. If
+ // the key is not found, NULL is returned.
+ const char* GetValueForKey(const char* key) const {
+ assert(key);
+ if (!key)
+ return NULL;
+
+ const Entry* entry = GetConstEntryForKey(key);
+ if (!entry)
+ return NULL;
+
+ return entry->value;
+ }
+
+ // Stores |value| into |key|, replacing the existing value if |key| is
+ // already present. |key| must not be NULL. If |value| is NULL, the key is
+ // removed from the map. If there is no more space in the map, then the
+ // operation silently fails.
+ void SetKeyValue(const char* key, const char* value) {
+ if (!value) {
+ RemoveKey(key);
+ return;
+ }
+
+ assert(key);
+ if (!key)
+ return;
+
+ // Key must not be an empty string.
+ assert(key[0] != '\0');
+ if (key[0] == '\0')
+ return;
+
+ Entry* entry = GetEntryForKey(key);
+
+ // If it does not yet exist, attempt to insert it.
+ if (!entry) {
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (!entries_[i].is_active()) {
+ entry = &entries_[i];
+
+ strncpy(entry->key, key, key_size);
+ entry->key[key_size - 1] = '\0';
+
+ break;
+ }
+ }
+ }
+
+ // If the map is out of space, entry will be NULL.
+ if (!entry)
+ return;
+
+#ifndef NDEBUG
+ // Sanity check that the key only appears once.
+ int count = 0;
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (strncmp(entries_[i].key, key, key_size) == 0)
+ ++count;
+ }
+ assert(count == 1);
+#endif
+
+ strncpy(entry->value, value, value_size);
+ entry->value[value_size - 1] = '\0';
+ }
+
+ // Given |key|, removes any associated value. |key| must not be NULL. If
+ // the key is not found, this is a noop.
+ void RemoveKey(const char* key) {
+ assert(key);
+ if (!key)
+ return;
+
+ Entry* entry = GetEntryForKey(key);
+ if (entry) {
+ entry->key[0] = '\0';
+ entry->value[0] = '\0';
+ }
+
+#ifndef NDEBUG
+ assert(GetEntryForKey(key) == NULL);
+#endif
+ }
+
+ // Places a serialized version of the map into |map| and returns the size.
+ // Both of these should be passed to the deserializing constructor. Note that
+ // the serialized |map| is scoped to the lifetime of the non-serialized
+ // instance of this class. The |map| can be copied across IPC boundaries.
+ size_t Serialize(const SerializedNonAllocatingMap** map) const {
+ *map = reinterpret_cast<const SerializedNonAllocatingMap*>(entries_);
+ return sizeof(entries_);
+ }
+
+ private:
+ const Entry* GetConstEntryForKey(const char* key) const {
+ for (size_t i = 0; i < num_entries; ++i) {
+ if (strncmp(key, entries_[i].key, key_size) == 0) {
+ return &entries_[i];
+ }
+ }
+ return NULL;
+ }
+
+ Entry* GetEntryForKey(const char* key) {
+ return const_cast<Entry*>(GetConstEntryForKey(key));
+ }
+
+ Entry entries_[NumEntries];
+};
+
+// For historical reasons this specialized version is available with the same
+// size factors as a previous implementation.
+typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary;
+
+} // namespace google_breakpad
+
+#endif // COMMON_SIMPLE_STRING_DICTIONARY_H_
diff --git a/3rdParty/Breakpad/src/common/simple_string_dictionary_unittest.cc b/3rdParty/Breakpad/src/common/simple_string_dictionary_unittest.cc
new file mode 100644
index 0000000..34f4b9e
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/simple_string_dictionary_unittest.cc
@@ -0,0 +1,308 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "breakpad_googletest_includes.h"
+#include "common/simple_string_dictionary.h"
+
+namespace google_breakpad {
+
+TEST(NonAllocatingMapTest, Entry) {
+ typedef NonAllocatingMap<5, 9, 15> TestMap;
+ TestMap map;
+
+ const TestMap::Entry* entry = TestMap::Iterator(map).Next();
+ EXPECT_FALSE(entry);
+
+ // Try setting a key/value and then verify.
+ map.SetKeyValue("key1", "value1");
+ entry = TestMap::Iterator(map).Next();
+ ASSERT_TRUE(entry);
+ EXPECT_STREQ(entry->key, "key1");
+ EXPECT_STREQ(entry->value, "value1");
+
+ // Try setting a new value.
+ map.SetKeyValue("key1", "value3");
+ EXPECT_STREQ(entry->value, "value3");
+
+ // Make sure the key didn't change.
+ EXPECT_STREQ(entry->key, "key1");
+
+ // Clear the entry and verify the key and value are empty strings.
+ map.RemoveKey("key1");
+ EXPECT_FALSE(entry->is_active());
+ EXPECT_EQ(strlen(entry->key), 0u);
+ EXPECT_EQ(strlen(entry->value), 0u);
+}
+
+TEST(NonAllocatingMapTest, SimpleStringDictionary) {
+ // Make a new dictionary
+ SimpleStringDictionary dict;
+
+ // Set three distinct values on three keys
+ dict.SetKeyValue("key1", "value1");
+ dict.SetKeyValue("key2", "value2");
+ dict.SetKeyValue("key3", "value3");
+
+ EXPECT_NE(dict.GetValueForKey("key1"), "value1");
+ EXPECT_NE(dict.GetValueForKey("key2"), "value2");
+ EXPECT_NE(dict.GetValueForKey("key3"), "value3");
+ EXPECT_EQ(dict.GetCount(), 3u);
+ // try an unknown key
+ EXPECT_FALSE(dict.GetValueForKey("key4"));
+
+ // Remove a key
+ dict.RemoveKey("key3");
+
+ // Now make sure it's not there anymore
+ EXPECT_FALSE(dict.GetValueForKey("key3"));
+
+ // Remove by setting value to NULL
+ dict.SetKeyValue("key2", NULL);
+
+ // Now make sure it's not there anymore
+ EXPECT_FALSE(dict.GetValueForKey("key2"));
+}
+
+TEST(NonAllocatingMapTest, CopyAndAssign) {
+ NonAllocatingMap<10, 10, 10> map;
+ map.SetKeyValue("one", "a");
+ map.SetKeyValue("two", "b");
+ map.SetKeyValue("three", "c");
+ map.RemoveKey("two");
+ EXPECT_EQ(2u, map.GetCount());
+
+ // Test copy.
+ NonAllocatingMap<10, 10, 10> map_copy(map);
+ EXPECT_EQ(2u, map_copy.GetCount());
+ EXPECT_STREQ("a", map_copy.GetValueForKey("one"));
+ EXPECT_STREQ("c", map_copy.GetValueForKey("three"));
+ map_copy.SetKeyValue("four", "d");
+ EXPECT_STREQ("d", map_copy.GetValueForKey("four"));
+ EXPECT_FALSE(map.GetValueForKey("four"));
+
+ // Test assign.
+ NonAllocatingMap<10, 10, 10> map_assign;
+ map_assign = map;
+ EXPECT_EQ(2u, map_assign.GetCount());
+ EXPECT_STREQ("a", map_assign.GetValueForKey("one"));
+ EXPECT_STREQ("c", map_assign.GetValueForKey("three"));
+ map_assign.SetKeyValue("four", "d");
+ EXPECT_STREQ("d", map_assign.GetValueForKey("four"));
+ EXPECT_FALSE(map.GetValueForKey("four"));
+
+ map.RemoveKey("one");
+ EXPECT_FALSE(map.GetValueForKey("one"));
+ EXPECT_STREQ("a", map_copy.GetValueForKey("one"));
+ EXPECT_STREQ("a", map_assign.GetValueForKey("one"));
+}
+
+// Add a bunch of values to the dictionary, remove some entries in the middle,
+// and then add more.
+TEST(NonAllocatingMapTest, Iterator) {
+ SimpleStringDictionary* dict = new SimpleStringDictionary();
+ ASSERT_TRUE(dict);
+
+ char key[SimpleStringDictionary::key_size];
+ char value[SimpleStringDictionary::value_size];
+
+ const int kDictionaryCapacity = SimpleStringDictionary::num_entries;
+ const int kPartitionIndex = kDictionaryCapacity - 5;
+
+ // We assume at least this size in the tests below
+ ASSERT_GE(kDictionaryCapacity, 64);
+
+ // We'll keep track of the number of key/value pairs we think should
+ // be in the dictionary
+ int expectedDictionarySize = 0;
+
+ // Set a bunch of key/value pairs like key0/value0, key1/value1, ...
+ for (int i = 0; i < kPartitionIndex; ++i) {
+ sprintf(key, "key%d", i);
+ sprintf(value, "value%d", i);
+ dict->SetKeyValue(key, value);
+ }
+ expectedDictionarySize = kPartitionIndex;
+
+ // set a couple of the keys twice (with the same value) - should be nop
+ dict->SetKeyValue("key2", "value2");
+ dict->SetKeyValue("key4", "value4");
+ dict->SetKeyValue("key15", "value15");
+
+ // Remove some random elements in the middle
+ dict->RemoveKey("key7");
+ dict->RemoveKey("key18");
+ dict->RemoveKey("key23");
+ dict->RemoveKey("key31");
+ expectedDictionarySize -= 4; // we just removed four key/value pairs
+
+ // Set some more key/value pairs like key59/value59, key60/value60, ...
+ for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) {
+ sprintf(key, "key%d", i);
+ sprintf(value, "value%d", i);
+ dict->SetKeyValue(key, value);
+ }
+ expectedDictionarySize += kDictionaryCapacity - kPartitionIndex;
+
+ // Now create an iterator on the dictionary
+ SimpleStringDictionary::Iterator iter(*dict);
+
+ // We then verify that it iterates through exactly the number of
+ // key/value pairs we expect, and that they match one-for-one with what we
+ // would expect. The ordering of the iteration does not matter...
+
+ // used to keep track of number of occurrences found for key/value pairs
+ int count[kDictionaryCapacity];
+ memset(count, 0, sizeof(count));
+
+ int totalCount = 0;
+
+ const SimpleStringDictionary::Entry* entry;
+ while ((entry = iter.Next())) {
+ totalCount++;
+
+ // Extract keyNumber from a string of the form key<keyNumber>
+ int keyNumber;
+ sscanf(entry->key, "key%d", &keyNumber);
+
+ // Extract valueNumber from a string of the form value<valueNumber>
+ int valueNumber;
+ sscanf(entry->value, "value%d", &valueNumber);
+
+ // The value number should equal the key number since that's how we set them
+ EXPECT_EQ(keyNumber, valueNumber);
+
+ // Key and value numbers should be in proper range:
+ // 0 <= keyNumber < kDictionaryCapacity
+ bool isKeyInGoodRange =
+ (keyNumber >= 0 && keyNumber < kDictionaryCapacity);
+ bool isValueInGoodRange =
+ (valueNumber >= 0 && valueNumber < kDictionaryCapacity);
+ EXPECT_TRUE(isKeyInGoodRange);
+ EXPECT_TRUE(isValueInGoodRange);
+
+ if (isKeyInGoodRange && isValueInGoodRange) {
+ ++count[keyNumber];
+ }
+ }
+
+ // Make sure each of the key/value pairs showed up exactly one time, except
+ // for the ones which we removed.
+ for (size_t i = 0; i < kDictionaryCapacity; ++i) {
+ // Skip over key7, key18, key23, and key31, since we removed them
+ if (!(i == 7 || i == 18 || i == 23 || i == 31)) {
+ EXPECT_EQ(count[i], 1);
+ }
+ }
+
+ // Make sure the number of iterations matches the expected dictionary size.
+ EXPECT_EQ(totalCount, expectedDictionarySize);
+}
+
+
+TEST(NonAllocatingMapTest, AddRemove) {
+ NonAllocatingMap<5, 7, 6> map;
+ map.SetKeyValue("rob", "ert");
+ map.SetKeyValue("mike", "pink");
+ map.SetKeyValue("mark", "allays");
+
+ EXPECT_EQ(3u, map.GetCount());
+ EXPECT_STREQ("ert", map.GetValueForKey("rob"));
+ EXPECT_STREQ("pink", map.GetValueForKey("mike"));
+ EXPECT_STREQ("allays", map.GetValueForKey("mark"));
+
+ map.RemoveKey("mike");
+
+ EXPECT_EQ(2u, map.GetCount());
+ EXPECT_FALSE(map.GetValueForKey("mike"));
+
+ map.SetKeyValue("mark", "mal");
+ EXPECT_EQ(2u, map.GetCount());
+ EXPECT_STREQ("mal", map.GetValueForKey("mark"));
+
+ map.RemoveKey("mark");
+ EXPECT_EQ(1u, map.GetCount());
+ EXPECT_FALSE(map.GetValueForKey("mark"));
+}
+
+TEST(NonAllocatingMapTest, Serialize) {
+ typedef NonAllocatingMap<4, 5, 7> TestMap;
+ TestMap map;
+ map.SetKeyValue("one", "abc");
+ map.SetKeyValue("two", "def");
+ map.SetKeyValue("tre", "hig");
+
+ EXPECT_STREQ("abc", map.GetValueForKey("one"));
+ EXPECT_STREQ("def", map.GetValueForKey("two"));
+ EXPECT_STREQ("hig", map.GetValueForKey("tre"));
+
+ const SerializedNonAllocatingMap* serialized;
+ size_t size = map.Serialize(&serialized);
+
+ SerializedNonAllocatingMap* serialized_copy =
+ reinterpret_cast<SerializedNonAllocatingMap*>(malloc(size));
+ ASSERT_TRUE(serialized_copy);
+ memcpy(serialized_copy, serialized, size);
+
+ TestMap deserialized(serialized_copy, size);
+ free(serialized_copy);
+
+ EXPECT_EQ(3u, deserialized.GetCount());
+ EXPECT_STREQ("abc", deserialized.GetValueForKey("one"));
+ EXPECT_STREQ("def", deserialized.GetValueForKey("two"));
+ EXPECT_STREQ("hig", deserialized.GetValueForKey("tre"));
+}
+
+// Running out of space shouldn't crash.
+TEST(NonAllocatingMapTest, OutOfSpace) {
+ NonAllocatingMap<3, 2, 2> map;
+ map.SetKeyValue("a", "1");
+ map.SetKeyValue("b", "2");
+ map.SetKeyValue("c", "3");
+ EXPECT_EQ(2u, map.GetCount());
+ EXPECT_FALSE(map.GetValueForKey("c"));
+}
+
+#ifndef NDEBUG
+
+TEST(NonAllocatingMapTest, NullKey) {
+ NonAllocatingMap<4, 6, 6> map;
+ ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), "");
+
+ map.SetKeyValue("hi", "there");
+ ASSERT_DEATH(map.GetValueForKey(NULL), "");
+ EXPECT_STREQ("there", map.GetValueForKey("hi"));
+
+ ASSERT_DEATH(map.GetValueForKey(NULL), "");
+ map.RemoveKey("hi");
+ EXPECT_EQ(0u, map.GetCount());
+}
+
+#endif // !NDEBUG
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/stabs_reader.h b/3rdParty/Breakpad/src/common/stabs_reader.h
index d89afc0..98ee2dd 100644
--- a/3rdParty/Breakpad/src/common/stabs_reader.h
+++ b/3rdParty/Breakpad/src/common/stabs_reader.h
@@ -53,11 +53,10 @@
#include <config.h>
#endif
-#ifdef HAVE_A_OUT_H
-#include <a.out.h>
-#endif
#ifdef HAVE_MACH_O_NLIST_H
#include <mach-o/nlist.h>
+#elif defined(HAVE_A_OUT_H)
+#include <a.out.h>
#endif
#include <string>
diff --git a/3rdParty/Breakpad/src/common/stabs_reader_unittest.cc b/3rdParty/Breakpad/src/common/stabs_reader_unittest.cc
new file mode 100644
index 0000000..a84da1c
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/stabs_reader_unittest.cc
@@ -0,0 +1,611 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader.
+
+#include <assert.h>
+#include <errno.h>
+#include <stab.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "breakpad_googletest_includes.h"
+#include "common/stabs_reader.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+
+using ::testing::Eq;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::_;
+using google_breakpad::StabsHandler;
+using google_breakpad::StabsReader;
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+using std::map;
+
+namespace {
+
+// A StringAssembler is a class for generating .stabstr sections to present
+// as input to the STABS parser.
+class StringAssembler: public Section {
+ public:
+ StringAssembler() : in_cu_(false) { StartCU(); }
+
+ // Add the string S to this StringAssembler, and return the string's
+ // offset within this compilation unit's strings. If S has been added
+ // already, this returns the offset of its first instance.
+ size_t Add(const string &s) {
+ map<string, size_t>::iterator it = added_.find(s);
+ if (it != added_.end())
+ return it->second;
+ size_t offset = Size() - cu_start_;
+ AppendCString(s);
+ added_[s] = offset;
+ return offset;
+ }
+
+ // Start a fresh compilation unit string collection.
+ void StartCU() {
+ // Ignore duplicate calls to StartCU. Our test data don't always call
+ // StartCU at all, meaning that our constructor has to take care of it,
+ // meaning that tests that *do* call StartCU call it twice at the
+ // beginning. This is not worth smoothing out.
+ if (in_cu_) return;
+
+ added_.clear();
+ cu_start_ = Size();
+
+ // Each compilation unit's strings start with an empty string.
+ AppendCString("");
+ added_[""] = 0;
+
+ in_cu_ = true;
+ }
+
+ // Finish off the current CU's strings.
+ size_t EndCU() {
+ assert(in_cu_);
+ in_cu_ = false;
+ return Size() - cu_start_;
+ }
+
+ private:
+ // The offset of the start of this compilation unit's strings.
+ size_t cu_start_;
+
+ // True if we're in a CU.
+ bool in_cu_;
+
+ // A map from the strings that have been added to this section to
+ // their starting indices within their compilation unit.
+ map<string, size_t> added_;
+};
+
+// A StabsAssembler is a class for generating .stab sections to present as
+// test input for the STABS parser.
+class StabsAssembler: public Section {
+ public:
+ // Create a StabsAssembler that uses StringAssembler for its strings.
+ StabsAssembler(StringAssembler *string_assembler)
+ : Section(string_assembler->endianness()),
+ string_assembler_(string_assembler),
+ value_size_(0),
+ entry_count_(0),
+ cu_header_(NULL) { }
+ ~StabsAssembler() { assert(!cu_header_); }
+
+ // Accessor and setter for value_size_.
+ size_t value_size() const { return value_size_; }
+ StabsAssembler &set_value_size(size_t value_size) {
+ value_size_ = value_size;
+ return *this;
+ }
+
+ // Append a STAB entry to the end of this section with the given
+ // characteristics. NAME is the offset of this entry's name string within
+ // its compilation unit's portion of the .stabstr section; this can be a
+ // value generated by a StringAssembler. Return a reference to this
+ // StabsAssembler.
+ StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
+ Label value, Label name) {
+ D32(name);
+ D8(type);
+ D8(other);
+ D16(descriptor);
+ Append(endianness(), value_size_, value);
+ entry_count_++;
+ return *this;
+ }
+
+ // As above, but automatically add NAME to our StringAssembler.
+ StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor,
+ Label value, const string &name) {
+ return Stab(type, other, descriptor, value, string_assembler_->Add(name));
+ }
+
+ // Start a compilation unit named NAME, with an N_UNDF symbol to start
+ // it, and its own portion of the string section. Return a reference to
+ // this StabsAssembler.
+ StabsAssembler &StartCU(const string &name) {
+ assert(!cu_header_);
+ cu_header_ = new CUHeader;
+ string_assembler_->StartCU();
+ entry_count_ = 0;
+ return Stab(N_UNDF, 0,
+ cu_header_->final_entry_count,
+ cu_header_->final_string_size,
+ string_assembler_->Add(name));
+ }
+
+ // Close off the current compilation unit. Return a reference to this
+ // StabsAssembler.
+ StabsAssembler &EndCU() {
+ assert(cu_header_);
+ cu_header_->final_entry_count = entry_count_;
+ cu_header_->final_string_size = string_assembler_->EndCU();
+ delete cu_header_;
+ cu_header_ = NULL;
+ return *this;
+ }
+
+ private:
+ // Data used in a compilation unit header STAB that we won't know until
+ // we've finished the compilation unit.
+ struct CUHeader {
+ // The final number of entries this compilation unit will hold.
+ Label final_entry_count;
+
+ // The final size of this compilation unit's strings.
+ Label final_string_size;
+ };
+
+ // The strings for our STABS entries.
+ StringAssembler *string_assembler_;
+
+ // The size of the 'value' field of stabs entries in this section.
+ size_t value_size_;
+
+ // The number of entries in this compilation unit so far.
+ size_t entry_count_;
+
+ // Header labels for this compilation unit, if we've started one but not
+ // finished it.
+ CUHeader *cu_header_;
+};
+
+class MockStabsReaderHandler: public StabsHandler {
+ public:
+ MOCK_METHOD3(StartCompilationUnit,
+ bool(const char *, uint64_t, const char *));
+ MOCK_METHOD1(EndCompilationUnit, bool(uint64_t));
+ MOCK_METHOD2(StartFunction, bool(const string &, uint64_t));
+ MOCK_METHOD1(EndFunction, bool(uint64_t));
+ MOCK_METHOD3(Line, bool(uint64_t, const char *, int));
+ MOCK_METHOD2(Extern, bool(const string &, uint64_t));
+ void Warning(const char *format, ...) { MockWarning(format); }
+ MOCK_METHOD1(MockWarning, void(const char *));
+};
+
+struct StabsFixture {
+ StabsFixture() : stabs(&strings), unitized(true) { }
+
+ // Create a StabsReader to parse the mock stabs data in stabs and
+ // strings, and pass the parsed information to mock_handler. Use the
+ // endianness and value size of stabs to parse the data. If all goes
+ // well, return the result of calling the reader's Process member
+ // function. Otherwise, return false.
+ bool ApplyHandlerToMockStabsData() {
+ string stabs_contents, stabstr_contents;
+ if (!stabs.GetContents(&stabs_contents) ||
+ !strings.GetContents(&stabstr_contents))
+ return false;
+
+ // Run the parser on the test input, passing whatever we find to HANDLER.
+ StabsReader reader(
+ reinterpret_cast<const uint8_t *>(stabs_contents.data()),
+ stabs_contents.size(),
+ reinterpret_cast<const uint8_t *>(stabstr_contents.data()),
+ stabstr_contents.size(),
+ stabs.endianness() == kBigEndian, stabs.value_size(), unitized,
+ &mock_handler);
+ return reader.Process();
+ }
+
+ StringAssembler strings;
+ StabsAssembler stabs;
+ bool unitized;
+ MockStabsReaderHandler mock_handler;
+};
+
+class Stabs: public StabsFixture, public Test { };
+
+TEST_F(Stabs, MockStabsInput) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(4);
+ stabs
+ .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/")
+ .Stab(N_FUN, 83, 50010, 0x91a5353fU,
+ "not the SO with source file name we expected ")
+ .Stab(N_SO, 165, 24791, 0xfe69d23cU, "")
+ .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/")
+ .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c")
+ .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for")
+ .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1")
+ .Stab(N_BINCL, 150, 15694, 0xef65c659U,
+ "something to ignore in a FUN body")
+ .Stab(N_SLINE, 147, 4967, 0xd904b3f, "")
+ .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h")
+ .Stab(N_SLINE, 130, 24610, 0x90f145b, "")
+ .Stab(N_FUN, 45, 32441, 0xbf27cf93U,
+ "fun2:some stabs type info here:to trim from the name")
+ .Stab(N_SLINE, 138, 39002, 0x8148b87, "")
+ .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c")
+ .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "")
+ .Stab(N_SO, 167, 4647, 0xd04b7448U, "")
+ .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "")
+ .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c")
+ .Stab(N_SO, 218, 12447, 0x11cfe4b5U, "");
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U,
+ StrEq("builddir1/")))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"),
+ 0x11759f10U, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, AbruptCU) {
+ stabs.set_endianness(kBigEndian);
+ stabs.set_value_size(4);
+ stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c");
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, AbruptFunction) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(8);
+ stabs
+ .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c")
+ .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1");
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, NoCU) {
+ stabs.set_endianness(kBigEndian);
+ stabs.set_value_size(8);
+ stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/");
+
+ EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _))
+ .Times(0);
+ EXPECT_CALL(mock_handler, StartFunction(_, _))
+ .Times(0);
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, NoCUEnd) {
+ stabs.set_endianness(kBigEndian);
+ stabs.set_value_size(8);
+ stabs
+ .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c")
+ .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c");
+
+ {
+ InSequence s;
+
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+// On systems that store STABS in sections, string offsets are relative to
+// the beginning of that compilation unit's strings, marked with N_UNDF
+// symbols; see the comments for StabsReader::StabsReader.
+TEST_F(Stabs, Unitized) {
+ stabs.set_endianness(kBigEndian);
+ stabs.set_value_size(4);
+ stabs
+ .StartCU("antimony")
+ .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony")
+ .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic")
+ .Stab(N_SO, 124, 37175, 0x80b0014cU, "")
+ .EndCU()
+ .StartCU("aluminum")
+ .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum")
+ .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium")
+ .Stab(N_SO, 178, 56949, 0xbffff983U, "")
+ .EndCU();
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xbffff983U))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+// On systems that store STABS entries in the real symbol table, the N_UNDF
+// entries have no special meaning, and shouldn't mess up the string
+// indices.
+TEST_F(Stabs, NonUnitized) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(4);
+ unitized = false;
+ stabs
+ .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "")
+ .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "")
+ .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania")
+ .Stab(N_SO, 221, 41976, 0x21a97352, "");
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("Tanzania"),
+ 0x11a97352, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, FunctionEnd) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(8);
+ stabs
+ .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit")
+ // This function is terminated by the start of the next function.
+ .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1")
+ // This function is terminated by an explicit end-of-function stab,
+ // whose value is a size in bytes.
+ .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2")
+ .Stab(N_FUN, 14, 36749, 0xc1ab, "")
+ // This function is terminated by the end of the compilation unit.
+ .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3")
+ .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, "");
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("compilation unit"),
+ 0x52a830d644cd6942ULL, NULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+// On Mac OS X, SLINE records can appear before the FUN stab to which they
+// belong, and their values are absolute addresses, not offsets.
+TEST_F(Stabs, LeadingLine) {
+ stabs.set_endianness(kBigEndian);
+ stabs.set_value_size(4);
+ stabs
+ .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/")
+ .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit")
+ .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name")
+ .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "")
+ .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "")
+ .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga")
+ .Stab(N_FUN, 218, 16113, 0x5798, "")
+ .Stab(N_SO, 52, 53058, 0xd4af4415, "");
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ StartCompilationUnit(StrEq("compilation unit"),
+ 0x4c7e3bf4, StrEq("build directory/")))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ StartFunction(Eq("rutabaga"), 0xce1b98fa))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0x4cb3d7e0, StrEq("source file name"), 20015))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Line(0x4cba8b88, StrEq("source file name"), 43802))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415))
+ .WillOnce(Return(true));
+ }
+
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+
+#if defined(HAVE_MACH_O_NLIST_H)
+// These tests have no meaning on non-Mach-O-based systems, as
+// only Mach-O uses N_SECT to represent public symbols.
+TEST_F(Stabs, OnePublicSymbol) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(4);
+
+ const uint32_t kExpectedAddress = 0x9000;
+ const string kExpectedFunctionName("public_function");
+ stabs
+ .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName);
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ Extern(StrEq(kExpectedFunctionName),
+ kExpectedAddress))
+ .WillOnce(Return(true));
+ }
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+TEST_F(Stabs, TwoPublicSymbols) {
+ stabs.set_endianness(kLittleEndian);
+ stabs.set_value_size(4);
+
+ const uint32_t kExpectedAddress1 = 0xB0B0B0B0;
+ const string kExpectedFunctionName1("public_function");
+ const uint32_t kExpectedAddress2 = 0xF0F0F0F0;
+ const string kExpectedFunctionName2("something else");
+ stabs
+ .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1)
+ .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2);
+
+ {
+ InSequence s;
+ EXPECT_CALL(mock_handler,
+ Extern(StrEq(kExpectedFunctionName1),
+ kExpectedAddress1))
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_handler,
+ Extern(StrEq(kExpectedFunctionName2),
+ kExpectedAddress2))
+ .WillOnce(Return(true));
+ }
+ ASSERT_TRUE(ApplyHandlerToMockStabsData());
+}
+
+#endif
+
+} // anonymous namespace
diff --git a/3rdParty/Breakpad/src/common/stabs_to_module.cc b/3rdParty/Breakpad/src/common/stabs_to_module.cc
index e59aebd..0a83cf2 100644
--- a/3rdParty/Breakpad/src/common/stabs_to_module.cc
+++ b/3rdParty/Breakpad/src/common/stabs_to_module.cc
@@ -90,9 +90,7 @@ bool StabsToModule::EndCompilationUnit(uint64_t address) {
bool StabsToModule::StartFunction(const string &name,
uint64_t address) {
assert(!current_function_);
- Module::Function *f = new Module::Function;
- f->name = Demangle(name);
- f->address = address;
+ Module::Function *f = new Module::Function(Demangle(name), address);
f->size = 0; // We compute this in StabsToModule::Finalize().
f->parameter_size = 0; // We don't provide this information.
current_function_ = f;
@@ -133,7 +131,7 @@ bool StabsToModule::Line(uint64_t address, const char *name, int number) {
}
bool StabsToModule::Extern(const string &name, uint64_t address) {
- Module::Extern *ext = new Module::Extern;
+ Module::Extern *ext = new Module::Extern(address);
// Older libstdc++ demangle implementations can crash on unexpected
// input, so be careful about what gets passed in.
if (name.compare(0, 3, "__Z") == 0) {
@@ -143,7 +141,6 @@ bool StabsToModule::Extern(const string &name, uint64_t address) {
} else {
ext->name = name;
}
- ext->address = address;
module_->AddExtern(ext);
return true;
}
diff --git a/3rdParty/Breakpad/src/common/stabs_to_module_unittest.cc b/3rdParty/Breakpad/src/common/stabs_to_module_unittest.cc
new file mode 100644
index 0000000..d445d1d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/stabs_to_module_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// dump_stabs_unittest.cc: Unit tests for StabsToModule.
+
+#include <vector>
+
+#include "breakpad_googletest_includes.h"
+#include "common/stabs_to_module.h"
+
+using google_breakpad::Module;
+using google_breakpad::StabsToModule;
+using std::vector;
+
+TEST(StabsToModule, SimpleCU) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // Feed in a simple compilation unit that defines a function with
+ // one line.
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0x9f4d1271e50db93bLL,
+ "build-directory"));
+ EXPECT_TRUE(h.StartFunction("function", 0xfde4abbed390c394LL));
+ EXPECT_TRUE(h.Line(0xfde4abbed390c394LL, "source-file-name", 174823314));
+ EXPECT_TRUE(h.EndFunction(0xfde4abbed390c3a4LL));
+ EXPECT_TRUE(h.EndCompilationUnit(0xfee4abbed390c3a4LL));
+ h.Finalize();
+
+ // Now check to see what has been added to the Module.
+ Module::File *file = m.FindExistingFile("source-file-name");
+ ASSERT_TRUE(file != NULL);
+
+ vector<Module::Function *> functions;
+ m.GetFunctions(&functions, functions.end());
+ ASSERT_EQ((size_t) 1, functions.size());
+ Module::Function *function = functions[0];
+ EXPECT_STREQ("function", function->name.c_str());
+ EXPECT_EQ(0xfde4abbed390c394LL, function->address);
+ EXPECT_EQ(0x10U, function->size);
+ EXPECT_EQ(0U, function->parameter_size);
+ ASSERT_EQ((size_t) 1, function->lines.size());
+ Module::Line *line = &function->lines[0];
+ EXPECT_EQ(0xfde4abbed390c394LL, line->address);
+ EXPECT_EQ(0x10U, line->size); // derived from EndFunction
+ EXPECT_TRUE(line->file == file);
+ EXPECT_EQ(174823314, line->number);
+}
+
+#ifdef __GNUC__
+// Function name mangling can vary by compiler, so only run mangled-name
+// tests on GCC for simplicity's sake.
+TEST(StabsToModule, Externs) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // Feed in a few Extern symbols.
+ EXPECT_TRUE(h.Extern("_foo", 0xffff));
+ EXPECT_TRUE(h.Extern("__Z21dyldGlobalLockAcquirev", 0xaaaa));
+ EXPECT_TRUE(h.Extern("_MorphTableGetNextMorphChain", 0x1111));
+ h.Finalize();
+
+ // Now check to see what has been added to the Module.
+ vector<Module::Extern *> externs;
+ m.GetExterns(&externs, externs.end());
+ ASSERT_EQ((size_t) 3, externs.size());
+ Module::Extern *extern1 = externs[0];
+ EXPECT_STREQ("MorphTableGetNextMorphChain", extern1->name.c_str());
+ EXPECT_EQ((Module::Address)0x1111, extern1->address);
+ Module::Extern *extern2 = externs[1];
+ EXPECT_STREQ("dyldGlobalLockAcquire()", extern2->name.c_str());
+ EXPECT_EQ((Module::Address)0xaaaa, extern2->address);
+ Module::Extern *extern3 = externs[2];
+ EXPECT_STREQ("foo", extern3->name.c_str());
+ EXPECT_EQ((Module::Address)0xffff, extern3->address);
+}
+#endif // __GNUC__
+
+TEST(StabsToModule, DuplicateFunctionNames) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // Compilation unit with one function, mangled name.
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda36ecf7f46cLL,
+ "build-directory"));
+ EXPECT_TRUE(h.StartFunction("funcfoo",
+ 0xf2cfda36ecf7f46dLL));
+ EXPECT_TRUE(h.EndFunction(0));
+ EXPECT_TRUE(h.StartFunction("funcfoo",
+ 0xf2cfda36ecf7f46dLL));
+ EXPECT_TRUE(h.EndFunction(0));
+ EXPECT_TRUE(h.EndCompilationUnit(0));
+
+ h.Finalize();
+
+ // Now check to see what has been added to the Module.
+ Module::File *file = m.FindExistingFile("compilation-unit");
+ ASSERT_TRUE(file != NULL);
+
+ vector<Module::Function *> functions;
+ m.GetFunctions(&functions, functions.end());
+ ASSERT_EQ(1U, functions.size());
+
+ Module::Function *function = functions[0];
+ EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address);
+ EXPECT_LT(0U, function->size); // should have used dummy size
+ EXPECT_EQ(0U, function->parameter_size);
+ ASSERT_EQ(0U, function->lines.size());
+}
+
+TEST(InferSizes, LineSize) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // Feed in a simple compilation unit that defines a function with
+ // one line.
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xb4513962eff94e92LL,
+ "build-directory"));
+ EXPECT_TRUE(h.StartFunction("function", 0xb4513962eff94e92LL));
+ EXPECT_TRUE(h.Line(0xb4513962eff94e92LL, "source-file-name-1", 77396614));
+ EXPECT_TRUE(h.Line(0xb4513963eff94e92LL, "source-file-name-2", 87660088));
+ EXPECT_TRUE(h.EndFunction(0)); // unknown function end address
+ EXPECT_TRUE(h.EndCompilationUnit(0)); // unknown CU end address
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit-2", 0xb4523963eff94e92LL,
+ "build-directory-2")); // next boundary
+ EXPECT_TRUE(h.EndCompilationUnit(0));
+ h.Finalize();
+
+ // Now check to see what has been added to the Module.
+ Module::File *file1 = m.FindExistingFile("source-file-name-1");
+ ASSERT_TRUE(file1 != NULL);
+ Module::File *file2 = m.FindExistingFile("source-file-name-2");
+ ASSERT_TRUE(file2 != NULL);
+
+ vector<Module::Function *> functions;
+ m.GetFunctions(&functions, functions.end());
+ ASSERT_EQ((size_t) 1, functions.size());
+
+ Module::Function *function = functions[0];
+ EXPECT_STREQ("function", function->name.c_str());
+ EXPECT_EQ(0xb4513962eff94e92LL, function->address);
+ EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end
+ EXPECT_EQ(0U, function->parameter_size);
+ ASSERT_EQ((size_t) 2, function->lines.size());
+
+ Module::Line *line1 = &function->lines[0];
+ EXPECT_EQ(0xb4513962eff94e92LL, line1->address);
+ EXPECT_EQ(0x100000000ULL, line1->size); // derived from EndFunction
+ EXPECT_TRUE(line1->file == file1);
+ EXPECT_EQ(77396614, line1->number);
+
+ Module::Line *line2 = &function->lines[1];
+ EXPECT_EQ(0xb4513963eff94e92LL, line2->address);
+ EXPECT_EQ(0x1000000000000ULL, line2->size); // derived from EndFunction
+ EXPECT_TRUE(line2->file == file2);
+ EXPECT_EQ(87660088, line2->number);
+}
+
+#ifdef __GNUC__
+// Function name mangling can vary by compiler, so only run mangled-name
+// tests on GCC for simplicity's sake.
+TEST(FunctionNames, Mangled) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // Compilation unit with one function, mangled name.
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda63cef7f46cLL,
+ "build-directory"));
+ EXPECT_TRUE(h.StartFunction("_ZNSt6vectorIySaIyEE9push_backERKy",
+ 0xf2cfda63cef7f46dLL));
+ EXPECT_TRUE(h.EndFunction(0));
+ EXPECT_TRUE(h.EndCompilationUnit(0));
+
+ h.Finalize();
+
+ // Now check to see what has been added to the Module.
+ Module::File *file = m.FindExistingFile("compilation-unit");
+ ASSERT_TRUE(file != NULL);
+
+ vector<Module::Function *> functions;
+ m.GetFunctions(&functions, functions.end());
+ ASSERT_EQ(1U, functions.size());
+
+ Module::Function *function = functions[0];
+ // This is GCC-specific, but we shouldn't be seeing STABS data anywhere
+ // but Linux.
+ EXPECT_STREQ("std::vector<unsigned long long, "
+ "std::allocator<unsigned long long> >::"
+ "push_back(unsigned long long const&)",
+ function->name.c_str());
+ EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address);
+ EXPECT_LT(0U, function->size); // should have used dummy size
+ EXPECT_EQ(0U, function->parameter_size);
+ ASSERT_EQ(0U, function->lines.size());
+}
+#endif // __GNUC__
+
+// The GNU toolchain can omit functions that are not used; however,
+// when it does so, it doesn't clean up the debugging information that
+// refers to them. In STABS, this results in compilation units whose
+// SO addresses are zero.
+TEST(Omitted, Function) {
+ Module m("name", "os", "arch", "id");
+ StabsToModule h(&m);
+
+ // The StartCompilationUnit and EndCompilationUnit calls may both have an
+ // address of zero if the compilation unit has had sections removed.
+ EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0, "build-directory"));
+ EXPECT_TRUE(h.StartFunction("function", 0x2a133596));
+ EXPECT_TRUE(h.EndFunction(0));
+ EXPECT_TRUE(h.EndCompilationUnit(0));
+}
+
+// TODO --- if we actually cared about STABS. Even without these we've
+// got full coverage of non-failure source lines in dump_stabs.cc.
+
+// Line size from next line
+// Line size from function end
+// Line size from next function start
+// line size from cu end
+// line size from next cu start
+// fallback size is something plausible
+
+// function size from function end
+// function size from next function start
+// function size from cu end
+// function size from next cu start
+// fallback size is something plausible
+
+// omitting functions outside the compilation unit's address range
+// zero-line, one-line, many-line functions
diff --git a/3rdParty/Breakpad/src/common/stdio_wrapper.h b/3rdParty/Breakpad/src/common/stdio_wrapper.h
new file mode 100644
index 0000000..a3dd50a
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/stdio_wrapper.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H
+#define GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H
+
+#include <stdio.h>
+
+#if defined(_MSC_VER) && MSC_VER < 1900
+#include <basetsd.h>
+
+#define snprintf _snprintf
+typedef SSIZE_T ssize_t;
+#endif
+
+
+#endif // GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H
diff --git a/3rdParty/Breakpad/src/common/string_conversion.cc b/3rdParty/Breakpad/src/common/string_conversion.cc
index 27fb8cd..040d3e8 100644
--- a/3rdParty/Breakpad/src/common/string_conversion.cc
+++ b/3rdParty/Breakpad/src/common/string_conversion.cc
@@ -30,23 +30,23 @@
#include <string.h>
#include "common/convert_UTF.h"
+#include "common/scoped_ptr.h"
#include "common/string_conversion.h"
#include "common/using_std_string.h"
-#include "processor/scoped_ptr.h"
namespace google_breakpad {
using std::vector;
-void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
+void UTF8ToUTF16(const char *in, vector<uint16_t> *out) {
size_t source_length = strlen(in);
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
const UTF8 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
- u_int16_t *target_ptr = &(*out)[0];
- u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
+ uint16_t *target_ptr = &(*out)[0];
+ uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t);
ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
@@ -55,11 +55,11 @@ void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
-int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]) {
+int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) {
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
- const UTF8 *source_end_ptr = source_ptr + sizeof(char);
- u_int16_t *target_ptr = out;
- u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
+ const UTF8 *source_end_ptr = source_ptr + 1;
+ uint16_t *target_ptr = out;
+ uint16_t *target_end_ptr = target_ptr + 2;
out[0] = out[1] = 0;
// Process one character at a time
@@ -82,15 +82,15 @@ int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]) {
return 0;
}
-void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
+void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) {
size_t source_length = wcslen(in);
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
const UTF32 *source_end_ptr = source_ptr + source_length;
// Erase the contents and zero fill to the expected size
out->clear();
out->insert(out->begin(), source_length, 0);
- u_int16_t *target_ptr = &(*out)[0];
- u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
+ uint16_t *target_ptr = &(*out)[0];
+ uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t);
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
@@ -99,11 +99,11 @@ void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}
-void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
+void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) {
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
const UTF32 *source_end_ptr = source_ptr + 1;
- u_int16_t *target_ptr = out;
- u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
+ uint16_t *target_ptr = out;
+ uint16_t *target_end_ptr = target_ptr + 2;
out[0] = out[1] = 0;
ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
@@ -114,20 +114,20 @@ void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
}
}
-static inline u_int16_t Swap(u_int16_t value) {
- return (value >> 8) | (value << 8);
+static inline uint16_t Swap(uint16_t value) {
+ return (value >> 8) | static_cast<uint16_t>(value << 8);
}
-string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {
+string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) {
const UTF16 *source_ptr = &in[0];
- scoped_ptr<u_int16_t> source_buffer;
+ scoped_array<uint16_t> source_buffer;
// If we're to swap, we need to make a local copy and swap each byte pair
if (swap) {
int idx = 0;
- source_buffer.reset(new u_int16_t[in.size()]);
+ source_buffer.reset(new uint16_t[in.size()]);
UTF16 *source_buffer_ptr = source_buffer.get();
- for (vector<u_int16_t>::const_iterator it = in.begin();
+ for (vector<uint16_t>::const_iterator it = in.begin();
it != in.end(); ++it, ++idx)
source_buffer_ptr[idx] = Swap(*it);
@@ -140,7 +140,7 @@ string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {
scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
UTF8 *target_ptr = target_buffer.get();
UTF8 *target_end_ptr = target_ptr + target_capacity;
- ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
+ ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
&target_ptr, target_end_ptr,
strictConversion);
diff --git a/3rdParty/Breakpad/src/common/string_conversion.h b/3rdParty/Breakpad/src/common/string_conversion.h
index eeed4d2..b9ba96a 100644
--- a/3rdParty/Breakpad/src/common/string_conversion.h
+++ b/3rdParty/Breakpad/src/common/string_conversion.h
@@ -44,24 +44,24 @@ using std::vector;
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
-void UTF8ToUTF16(const char *in, vector<u_int16_t> *out);
+void UTF8ToUTF16(const char *in, vector<uint16_t> *out);
// Convert at least one character (up to a maximum of |in_length|) from |in|
// to UTF-16 into |out|. Return the number of characters consumed from |in|.
// Any unused characters in |out| will be initialized to 0. No memory will
// be allocated by this routine.
-int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]);
+int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]);
// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the
// conversion failed, |out| will be zero length.
-void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out);
+void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out);
// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be
// initialized to 0. No memory will be allocated by this routine.
-void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]);
+void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]);
// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting.
-string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap);
+string UTF16ToUTF8(const vector<uint16_t> &in, bool swap);
} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/symbol_data.h b/3rdParty/Breakpad/src/common/symbol_data.h
new file mode 100644
index 0000000..2cf15a8
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/symbol_data.h
@@ -0,0 +1,42 @@
+// -*- mode: c++ -*-
+
+// Copyright (c) 2013 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef COMMON_SYMBOL_DATA_H_
+#define COMMON_SYMBOL_DATA_H_
+
+// Control what data is used from the symbol file.
+enum SymbolData {
+ ALL_SYMBOL_DATA,
+ NO_CFI,
+ ONLY_CFI
+};
+
+#endif // COMMON_SYMBOL_DATA_H_
diff --git a/3rdParty/Breakpad/src/common/test_assembler.cc b/3rdParty/Breakpad/src/common/test_assembler.cc
new file mode 100644
index 0000000..1e783b4
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/test_assembler.cc
@@ -0,0 +1,359 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test_assembler.cc: Implementation of google_breakpad::TestAssembler.
+// See test_assembler.h for details.
+
+#include "common/test_assembler.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <iterator>
+
+namespace google_breakpad {
+namespace test_assembler {
+
+using std::back_insert_iterator;
+
+Label::Label() : value_(new Binding()) { }
+Label::Label(uint64_t value) : value_(new Binding(value)) { }
+Label::Label(const Label &label) {
+ value_ = label.value_;
+ value_->Acquire();
+}
+Label::~Label() {
+ if (value_->Release()) delete value_;
+}
+
+Label &Label::operator=(uint64_t value) {
+ value_->Set(NULL, value);
+ return *this;
+}
+
+Label &Label::operator=(const Label &label) {
+ value_->Set(label.value_, 0);
+ return *this;
+}
+
+Label Label::operator+(uint64_t addend) const {
+ Label l;
+ l.value_->Set(this->value_, addend);
+ return l;
+}
+
+Label Label::operator-(uint64_t subtrahend) const {
+ Label l;
+ l.value_->Set(this->value_, -subtrahend);
+ return l;
+}
+
+// When NDEBUG is #defined, assert doesn't evaluate its argument. This
+// means you can't simply use assert to check the return value of a
+// function with necessary side effects.
+//
+// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
+// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
+// that x is true.
+#ifdef NDEBUG
+#define ALWAYS_EVALUATE_AND_ASSERT(x) x
+#else
+#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
+#endif
+
+uint64_t Label::operator-(const Label &label) const {
+ uint64_t offset;
+ ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
+ return offset;
+}
+
+uint64_t Label::Value() const {
+ uint64_t v = 0;
+ ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
+ return v;
+};
+
+bool Label::IsKnownConstant(uint64_t *value_p) const {
+ Binding *base;
+ uint64_t addend;
+ value_->Get(&base, &addend);
+ if (base != NULL) return false;
+ if (value_p) *value_p = addend;
+ return true;
+}
+
+bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const
+{
+ Binding *label_base, *this_base;
+ uint64_t label_addend, this_addend;
+ label.value_->Get(&label_base, &label_addend);
+ value_->Get(&this_base, &this_addend);
+ // If this and label are related, Get will find their final
+ // common ancestor, regardless of how indirect the relation is. This
+ // comparison also handles the constant vs. constant case.
+ if (this_base != label_base) return false;
+ if (offset_p) *offset_p = this_addend - label_addend;
+ return true;
+}
+
+Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { }
+
+Label::Binding::Binding(uint64_t addend)
+ : base_(NULL), addend_(addend), reference_count_(1) { }
+
+Label::Binding::~Binding() {
+ assert(reference_count_ == 0);
+ if (base_ && base_ != this && base_->Release())
+ delete base_;
+}
+
+void Label::Binding::Set(Binding *binding, uint64_t addend) {
+ if (!base_ && !binding) {
+ // We're equating two constants. This could be okay.
+ assert(addend_ == addend);
+ } else if (!base_) {
+ // We are a known constant, but BINDING may not be, so turn the
+ // tables and try to set BINDING's value instead.
+ binding->Set(NULL, addend_ - addend);
+ } else {
+ if (binding) {
+ // Find binding's final value. Since the final value is always either
+ // completely unconstrained or a constant, never a reference to
+ // another variable (otherwise, it wouldn't be final), this
+ // guarantees we won't create cycles here, even for code like this:
+ // l = m, m = n, n = l;
+ uint64_t binding_addend;
+ binding->Get(&binding, &binding_addend);
+ addend += binding_addend;
+ }
+
+ // It seems likely that setting a binding to itself is a bug
+ // (although I can imagine this might turn out to be helpful to
+ // permit).
+ assert(binding != this);
+
+ if (base_ != this) {
+ // Set the other bindings on our chain as well. Note that this
+ // is sufficient even though binding relationships form trees:
+ // All binding operations traverse their chains to the end, and
+ // all bindings related to us share some tail of our chain, so
+ // they will see the changes we make here.
+ base_->Set(binding, addend - addend_);
+ // We're not going to use base_ any more.
+ if (base_->Release()) delete base_;
+ }
+
+ // Adopt BINDING as our base. Note that it should be correct to
+ // acquire here, after the release above, even though the usual
+ // reference-counting rules call for acquiring first, and then
+ // releasing: the self-reference assertion above should have
+ // complained if BINDING were 'this' or anywhere along our chain,
+ // so we didn't release BINDING.
+ if (binding) binding->Acquire();
+ base_ = binding;
+ addend_ = addend;
+ }
+}
+
+void Label::Binding::Get(Binding **base, uint64_t *addend) {
+ if (base_ && base_ != this) {
+ // Recurse to find the end of our reference chain (the root of our
+ // tree), and then rewrite every binding along the chain to refer
+ // to it directly, adjusting addends appropriately. (This is why
+ // this member function isn't this-const.)
+ Binding *final_base;
+ uint64_t final_addend;
+ base_->Get(&final_base, &final_addend);
+ if (final_base) final_base->Acquire();
+ if (base_->Release()) delete base_;
+ base_ = final_base;
+ addend_ += final_addend;
+ }
+ *base = base_;
+ *addend = addend_;
+}
+
+template<typename Inserter>
+static inline void InsertEndian(test_assembler::Endianness endianness,
+ size_t size, uint64_t number, Inserter dest) {
+ assert(size > 0);
+ if (endianness == kLittleEndian) {
+ for (size_t i = 0; i < size; i++) {
+ *dest++ = (char) (number & 0xff);
+ number >>= 8;
+ }
+ } else {
+ assert(endianness == kBigEndian);
+ // The loop condition is odd, but it's correct for size_t.
+ for (size_t i = size - 1; i < size; i--)
+ *dest++ = (char) ((number >> (i * 8)) & 0xff);
+ }
+}
+
+Section &Section::Append(Endianness endianness, size_t size, uint64_t number) {
+ InsertEndian(endianness, size, number,
+ back_insert_iterator<string>(contents_));
+ return *this;
+}
+
+Section &Section::Append(Endianness endianness, size_t size,
+ const Label &label) {
+ // If this label's value is known, there's no reason to waste an
+ // entry in references_ on it.
+ uint64_t value;
+ if (label.IsKnownConstant(&value))
+ return Append(endianness, size, value);
+
+ // This will get caught when the references are resolved, but it's
+ // nicer to find out earlier.
+ assert(endianness != kUnsetEndian);
+
+ references_.push_back(Reference(contents_.size(), endianness, size, label));
+ contents_.append(size, 0);
+ return *this;
+}
+
+#define ENDIANNESS_L kLittleEndian
+#define ENDIANNESS_B kBigEndian
+#define ENDIANNESS(e) ENDIANNESS_ ## e
+
+#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
+ Section &Section::e ## bits(uint ## bits ## _t v) { \
+ InsertEndian(ENDIANNESS(e), bits / 8, v, \
+ back_insert_iterator<string>(contents_)); \
+ return *this; \
+ }
+
+#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
+ Section &Section::e ## bits(const Label &v) { \
+ return Append(ENDIANNESS(e), bits / 8, v); \
+ }
+
+// Define L16, B32, and friends.
+#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
+ DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
+ DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
+
+DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
+DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
+DEFINE_SHORT_APPEND_ENDIAN(L, 16);
+DEFINE_SHORT_APPEND_ENDIAN(L, 32);
+DEFINE_SHORT_APPEND_ENDIAN(L, 64);
+DEFINE_SHORT_APPEND_ENDIAN(B, 16);
+DEFINE_SHORT_APPEND_ENDIAN(B, 32);
+DEFINE_SHORT_APPEND_ENDIAN(B, 64);
+
+#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
+ Section &Section::D ## bits(uint ## bits ## _t v) { \
+ InsertEndian(endianness_, bits / 8, v, \
+ back_insert_iterator<string>(contents_)); \
+ return *this; \
+ }
+#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
+ Section &Section::D ## bits(const Label &v) { \
+ return Append(endianness_, bits / 8, v); \
+ }
+#define DEFINE_SHORT_APPEND_DEFAULT(bits) \
+ DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
+ DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
+
+DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
+DEFINE_SHORT_APPEND_DEFAULT(16);
+DEFINE_SHORT_APPEND_DEFAULT(32);
+DEFINE_SHORT_APPEND_DEFAULT(64);
+
+Section &Section::Append(const Section &section) {
+ size_t base = contents_.size();
+ contents_.append(section.contents_);
+ for (vector<Reference>::const_iterator it = section.references_.begin();
+ it != section.references_.end(); it++)
+ references_.push_back(Reference(base + it->offset, it->endianness,
+ it->size, it->label));
+ return *this;
+}
+
+Section &Section::LEB128(long long value) {
+ while (value < -0x40 || 0x3f < value) {
+ contents_ += (value & 0x7f) | 0x80;
+ if (value < 0)
+ value = (value >> 7) | ~(((unsigned long long) -1) >> 7);
+ else
+ value = (value >> 7);
+ }
+ contents_ += value & 0x7f;
+ return *this;
+}
+
+Section &Section::ULEB128(uint64_t value) {
+ while (value > 0x7f) {
+ contents_ += (value & 0x7f) | 0x80;
+ value = (value >> 7);
+ }
+ contents_ += value;
+ return *this;
+}
+
+Section &Section::Align(size_t alignment, uint8_t pad_byte) {
+ // ALIGNMENT must be a power of two.
+ assert(((alignment - 1) & alignment) == 0);
+ size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
+ contents_.append(new_size - contents_.size(), pad_byte);
+ assert((contents_.size() & (alignment - 1)) == 0);
+ return *this;
+}
+
+void Section::Clear() {
+ contents_.clear();
+ references_.clear();
+}
+
+bool Section::GetContents(string *contents) {
+ // For each label reference, find the label's value, and patch it into
+ // the section's contents.
+ for (size_t i = 0; i < references_.size(); i++) {
+ Reference &r = references_[i];
+ uint64_t value;
+ if (!r.label.IsKnownConstant(&value)) {
+ fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
+ return false;
+ }
+ assert(r.offset < contents_.size());
+ assert(contents_.size() - r.offset >= r.size);
+ InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
+ }
+ contents->clear();
+ std::swap(contents_, *contents);
+ references_.clear();
+ return true;
+}
+
+} // namespace test_assembler
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/test_assembler.h b/3rdParty/Breakpad/src/common/test_assembler.h
new file mode 100644
index 0000000..373dbeb
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/test_assembler.h
@@ -0,0 +1,484 @@
+// -*- mode: C++ -*-
+
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test-assembler.h: interface to class for building complex binary streams.
+
+// To test the Breakpad symbol dumper and processor thoroughly, for
+// all combinations of host system and minidump processor
+// architecture, we need to be able to easily generate complex test
+// data like debugging information and minidump files.
+//
+// For example, if we want our unit tests to provide full code
+// coverage for stack walking, it may be difficult to persuade the
+// compiler to generate every possible sort of stack walking
+// information that we want to support; there are probably DWARF CFI
+// opcodes that GCC never emits. Similarly, if we want to test our
+// error handling, we will need to generate damaged minidumps or
+// debugging information that (we hope) the client or compiler will
+// never produce on its own.
+//
+// google_breakpad::TestAssembler provides a predictable and
+// (relatively) simple way to generate complex formatted data streams
+// like minidumps and CFI. Furthermore, because TestAssembler is
+// portable, developers without access to (say) Visual Studio or a
+// SPARC assembler can still work on test data for those targets.
+
+#ifndef PROCESSOR_TEST_ASSEMBLER_H_
+#define PROCESSOR_TEST_ASSEMBLER_H_
+
+#include <list>
+#include <vector>
+#include <string>
+
+#include "common/using_std_string.h"
+#include "google_breakpad/common/breakpad_types.h"
+
+namespace google_breakpad {
+
+using std::list;
+using std::vector;
+
+namespace test_assembler {
+
+// A Label represents a value not yet known that we need to store in a
+// section. As long as all the labels a section refers to are defined
+// by the time we retrieve its contents as bytes, we can use undefined
+// labels freely in that section's construction.
+//
+// A label can be in one of three states:
+// - undefined,
+// - defined as the sum of some other label and a constant, or
+// - a constant.
+//
+// A label's value never changes, but it can accumulate constraints.
+// Adding labels and integers is permitted, and yields a label.
+// Subtracting a constant from a label is permitted, and also yields a
+// label. Subtracting two labels that have some relationship to each
+// other is permitted, and yields a constant.
+//
+// For example:
+//
+// Label a; // a's value is undefined
+// Label b; // b's value is undefined
+// {
+// Label c = a + 4; // okay, even though a's value is unknown
+// b = c + 4; // also okay; b is now a+8
+// }
+// Label d = b - 2; // okay; d == a+6, even though c is gone
+// d.Value(); // error: d's value is not yet known
+// d - a; // is 6, even though their values are not known
+// a = 12; // now b == 20, and d == 18
+// d.Value(); // 18: no longer an error
+// b.Value(); // 20
+// d = 10; // error: d is already defined.
+//
+// Label objects' lifetimes are unconstrained: notice that, in the
+// above example, even though a and b are only related through c, and
+// c goes out of scope, the assignment to a sets b's value as well. In
+// particular, it's not necessary to ensure that a Label lives beyond
+// Sections that refer to it.
+class Label {
+ public:
+ Label(); // An undefined label.
+ Label(uint64_t value); // A label with a fixed value
+ Label(const Label &value); // A label equal to another.
+ ~Label();
+
+ // Return this label's value; it must be known.
+ //
+ // Providing this as a cast operator is nifty, but the conversions
+ // happen in unexpected places. In particular, ISO C++ says that
+ // Label + size_t becomes ambigious, because it can't decide whether
+ // to convert the Label to a uint64_t and then to a size_t, or use
+ // the overloaded operator that returns a new label, even though the
+ // former could fail if the label is not yet defined and the latter won't.
+ uint64_t Value() const;
+
+ Label &operator=(uint64_t value);
+ Label &operator=(const Label &value);
+ Label operator+(uint64_t addend) const;
+ Label operator-(uint64_t subtrahend) const;
+ uint64_t operator-(const Label &subtrahend) const;
+
+ // We could also provide == and != that work on undefined, but
+ // related, labels.
+
+ // Return true if this label's value is known. If VALUE_P is given,
+ // set *VALUE_P to the known value if returning true.
+ bool IsKnownConstant(uint64_t *value_p = NULL) const;
+
+ // Return true if the offset from LABEL to this label is known. If
+ // OFFSET_P is given, set *OFFSET_P to the offset when returning true.
+ //
+ // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m',
+ // except that it also returns a value indicating whether the
+ // subtraction is possible given what we currently know of l and m.
+ // It can be possible even if we don't know l and m's values. For
+ // example:
+ //
+ // Label l, m;
+ // m = l + 10;
+ // l.IsKnownConstant(); // false
+ // m.IsKnownConstant(); // false
+ // uint64_t d;
+ // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10.
+ // l-m // -10
+ // m-l // 10
+ // m.Value() // error: m's value is not known
+ bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const;
+
+ private:
+ // A label's value, or if that is not yet known, how the value is
+ // related to other labels' values. A binding may be:
+ // - a known constant,
+ // - constrained to be equal to some other binding plus a constant, or
+ // - unconstrained, and free to take on any value.
+ //
+ // Many labels may point to a single binding, and each binding may
+ // refer to another, so bindings and labels form trees whose leaves
+ // are labels, whose interior nodes (and roots) are bindings, and
+ // where links point from children to parents. Bindings are
+ // reference counted, allowing labels to be lightweight, copyable,
+ // assignable, placed in containers, and so on.
+ class Binding {
+ public:
+ Binding();
+ Binding(uint64_t addend);
+ ~Binding();
+
+ // Increment our reference count.
+ void Acquire() { reference_count_++; };
+ // Decrement our reference count, and return true if it is zero.
+ bool Release() { return --reference_count_ == 0; }
+
+ // Set this binding to be equal to BINDING + ADDEND. If BINDING is
+ // NULL, then set this binding to the known constant ADDEND.
+ // Update every binding on this binding's chain to point directly
+ // to BINDING, or to be a constant, with addends adjusted
+ // appropriately.
+ void Set(Binding *binding, uint64_t value);
+
+ // Return what we know about the value of this binding.
+ // - If this binding's value is a known constant, set BASE to
+ // NULL, and set ADDEND to its value.
+ // - If this binding is not a known constant but related to other
+ // bindings, set BASE to the binding at the end of the relation
+ // chain (which will always be unconstrained), and set ADDEND to the
+ // value to add to that binding's value to get this binding's
+ // value.
+ // - If this binding is unconstrained, set BASE to this, and leave
+ // ADDEND unchanged.
+ void Get(Binding **base, uint64_t *addend);
+
+ private:
+ // There are three cases:
+ //
+ // - A binding representing a known constant value has base_ NULL,
+ // and addend_ equal to the value.
+ //
+ // - A binding representing a completely unconstrained value has
+ // base_ pointing to this; addend_ is unused.
+ //
+ // - A binding whose value is related to some other binding's
+ // value has base_ pointing to that other binding, and addend_
+ // set to the amount to add to that binding's value to get this
+ // binding's value. We only represent relationships of the form
+ // x = y+c.
+ //
+ // Thus, the bind_ links form a chain terminating in either a
+ // known constant value or a completely unconstrained value. Most
+ // operations on bindings do path compression: they change every
+ // binding on the chain to point directly to the final value,
+ // adjusting addends as appropriate.
+ Binding *base_;
+ uint64_t addend_;
+
+ // The number of Labels and Bindings pointing to this binding.
+ // (When a binding points to itself, indicating a completely
+ // unconstrained binding, that doesn't count as a reference.)
+ int reference_count_;
+ };
+
+ // This label's value.
+ Binding *value_;
+};
+
+inline Label operator+(uint64_t a, const Label &l) { return l + a; }
+// Note that int-Label isn't defined, as negating a Label is not an
+// operation we support.
+
+// Conventions for representing larger numbers as sequences of bytes.
+enum Endianness {
+ kBigEndian, // Big-endian: the most significant byte comes first.
+ kLittleEndian, // Little-endian: the least significant byte comes first.
+ kUnsetEndian, // used internally
+};
+
+// A section is a sequence of bytes, constructed by appending bytes
+// to the end. Sections have a convenient and flexible set of member
+// functions for appending data in various formats: big-endian and
+// little-endian signed and unsigned values of different sizes;
+// LEB128 and ULEB128 values (see below), and raw blocks of bytes.
+//
+// If you need to append a value to a section that is not convenient
+// to compute immediately, you can create a label, append the
+// label's value to the section, and then set the label's value
+// later, when it's convenient to do so. Once a label's value is
+// known, the section class takes care of updating all previously
+// appended references to it.
+//
+// Once all the labels to which a section refers have had their
+// values determined, you can get a copy of the section's contents
+// as a string.
+//
+// Note that there is no specified "start of section" label. This is
+// because there are typically several different meanings for "the
+// start of a section": the offset of the section within an object
+// file, the address in memory at which the section's content appear,
+// and so on. It's up to the code that uses the Section class to
+// keep track of these explicitly, as they depend on the application.
+class Section {
+ public:
+ Section(Endianness endianness = kUnsetEndian)
+ : endianness_(endianness) { };
+
+ // A base class destructor should be either public and virtual,
+ // or protected and nonvirtual.
+ virtual ~Section() { };
+
+ // Set the default endianness of this section to ENDIANNESS. This
+ // sets the behavior of the D<N> appending functions. If the
+ // assembler's default endianness was set, this is the
+ void set_endianness(Endianness endianness) {
+ endianness_ = endianness;
+ }
+
+ // Return the default endianness of this section.
+ Endianness endianness() const { return endianness_; }
+
+ // Append the SIZE bytes at DATA or the contents of STRING to the
+ // end of this section. Return a reference to this section.
+ Section &Append(const uint8_t *data, size_t size) {
+ contents_.append(reinterpret_cast<const char *>(data), size);
+ return *this;
+ };
+ Section &Append(const string &data) {
+ contents_.append(data);
+ return *this;
+ };
+
+ // Append SIZE copies of BYTE to the end of this section. Return a
+ // reference to this section.
+ Section &Append(size_t size, uint8_t byte) {
+ contents_.append(size, (char) byte);
+ return *this;
+ }
+
+ // Append NUMBER to this section. ENDIANNESS is the endianness to
+ // use to write the number. SIZE is the length of the number in
+ // bytes. Return a reference to this section.
+ Section &Append(Endianness endianness, size_t size, uint64_t number);
+ Section &Append(Endianness endianness, size_t size, const Label &label);
+
+ // Append SECTION to the end of this section. The labels SECTION
+ // refers to need not be defined yet.
+ //
+ // Note that this has no effect on any Labels' values, or on
+ // SECTION. If placing SECTION within 'this' provides new
+ // constraints on existing labels' values, then it's up to the
+ // caller to fiddle with those labels as needed.
+ Section &Append(const Section &section);
+
+ // Append the contents of DATA as a series of bytes terminated by
+ // a NULL character.
+ Section &AppendCString(const string &data) {
+ Append(data);
+ contents_ += '\0';
+ return *this;
+ }
+
+ // Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes
+ // long, pad with '\0' characters.
+ Section &AppendCString(const string &data, size_t size) {
+ contents_.append(data, 0, size);
+ if (data.size() < size)
+ Append(size - data.size(), 0);
+ return *this;
+ }
+
+ // Append VALUE or LABEL to this section, with the given bit width and
+ // endianness. Return a reference to this section.
+ //
+ // The names of these functions have the form <ENDIANNESS><BITWIDTH>:
+ // <ENDIANNESS> is either 'L' (little-endian, least significant byte first),
+ // 'B' (big-endian, most significant byte first), or
+ // 'D' (default, the section's default endianness)
+ // <BITWIDTH> is 8, 16, 32, or 64.
+ //
+ // Since endianness doesn't matter for a single byte, all the
+ // <BITWIDTH>=8 functions are equivalent.
+ //
+ // These can be used to write both signed and unsigned values, as
+ // the compiler will properly sign-extend a signed value before
+ // passing it to the function, at which point the function's
+ // behavior is the same either way.
+ Section &L8(uint8_t value) { contents_ += value; return *this; }
+ Section &B8(uint8_t value) { contents_ += value; return *this; }
+ Section &D8(uint8_t value) { contents_ += value; return *this; }
+ Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t),
+ &B16(uint16_t), &B32(uint32_t), &B64(uint64_t),
+ &D16(uint16_t), &D32(uint32_t), &D64(uint64_t);
+ Section &L8(const Label &label), &L16(const Label &label),
+ &L32(const Label &label), &L64(const Label &label),
+ &B8(const Label &label), &B16(const Label &label),
+ &B32(const Label &label), &B64(const Label &label),
+ &D8(const Label &label), &D16(const Label &label),
+ &D32(const Label &label), &D64(const Label &label);
+
+ // Append VALUE in a signed LEB128 (Little-Endian Base 128) form.
+ //
+ // The signed LEB128 representation of an integer N is a variable
+ // number of bytes:
+ //
+ // - If N is between -0x40 and 0x3f, then its signed LEB128
+ // representation is a single byte whose value is N.
+ //
+ // - Otherwise, its signed LEB128 representation is (N & 0x7f) |
+ // 0x80, followed by the signed LEB128 representation of N / 128,
+ // rounded towards negative infinity.
+ //
+ // In other words, we break VALUE into groups of seven bits, put
+ // them in little-endian order, and then write them as eight-bit
+ // bytes with the high bit on all but the last.
+ //
+ // Note that VALUE cannot be a Label (we would have to implement
+ // relaxation).
+ Section &LEB128(long long value);
+
+ // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form.
+ //
+ // The unsigned LEB128 representation of an integer N is a variable
+ // number of bytes:
+ //
+ // - If N is between 0 and 0x7f, then its unsigned LEB128
+ // representation is a single byte whose value is N.
+ //
+ // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) |
+ // 0x80, followed by the unsigned LEB128 representation of N /
+ // 128, rounded towards negative infinity.
+ //
+ // Note that VALUE cannot be a Label (we would have to implement
+ // relaxation).
+ Section &ULEB128(uint64_t value);
+
+ // Jump to the next location aligned on an ALIGNMENT-byte boundary,
+ // relative to the start of the section. Fill the gap with PAD_BYTE.
+ // ALIGNMENT must be a power of two. Return a reference to this
+ // section.
+ Section &Align(size_t alignment, uint8_t pad_byte = 0);
+
+ // Clear the contents of this section.
+ void Clear();
+
+ // Return the current size of the section.
+ size_t Size() const { return contents_.size(); }
+
+ // Return a label representing the start of the section.
+ //
+ // It is up to the user whether this label represents the section's
+ // position in an object file, the section's address in memory, or
+ // what have you; some applications may need both, in which case
+ // this simple-minded interface won't be enough. This class only
+ // provides a single start label, for use with the Here and Mark
+ // member functions.
+ //
+ // Ideally, we'd provide this in a subclass that actually knows more
+ // about the application at hand and can provide an appropriate
+ // collection of start labels. But then the appending member
+ // functions like Append and D32 would return a reference to the
+ // base class, not the derived class, and the chaining won't work.
+ // Since the only value here is in pretty notation, that's a fatal
+ // flaw.
+ Label start() const { return start_; }
+
+ // Return a label representing the point at which the next Appended
+ // item will appear in the section, relative to start().
+ Label Here() const { return start_ + Size(); }
+
+ // Set *LABEL to Here, and return a reference to this section.
+ Section &Mark(Label *label) { *label = Here(); return *this; }
+
+ // If there are no undefined label references left in this
+ // section, set CONTENTS to the contents of this section, as a
+ // string, and clear this section. Return true on success, or false
+ // if there were still undefined labels.
+ bool GetContents(string *contents);
+
+ private:
+ // Used internally. A reference to a label's value.
+ struct Reference {
+ Reference(size_t set_offset, Endianness set_endianness, size_t set_size,
+ const Label &set_label)
+ : offset(set_offset), endianness(set_endianness), size(set_size),
+ label(set_label) { }
+
+ // The offset of the reference within the section.
+ size_t offset;
+
+ // The endianness of the reference.
+ Endianness endianness;
+
+ // The size of the reference.
+ size_t size;
+
+ // The label to which this is a reference.
+ Label label;
+ };
+
+ // The default endianness of this section.
+ Endianness endianness_;
+
+ // The contents of the section.
+ string contents_;
+
+ // References to labels within those contents.
+ vector<Reference> references_;
+
+ // A label referring to the beginning of the section.
+ Label start_;
+};
+
+} // namespace test_assembler
+} // namespace google_breakpad
+
+#endif // PROCESSOR_TEST_ASSEMBLER_H_
diff --git a/3rdParty/Breakpad/src/common/test_assembler_unittest.cc b/3rdParty/Breakpad/src/common/test_assembler_unittest.cc
new file mode 100644
index 0000000..94b5a5c
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/test_assembler_unittest.cc
@@ -0,0 +1,1662 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler.
+
+#include <string>
+#include <string.h>
+
+#include "breakpad_googletest_includes.h"
+#include "common/test_assembler.h"
+#include "common/using_std_string.h"
+
+using google_breakpad::test_assembler::Label;
+using google_breakpad::test_assembler::Section;
+using google_breakpad::test_assembler::kBigEndian;
+using google_breakpad::test_assembler::kLittleEndian;
+using testing::Test;
+
+TEST(ConstructLabel, Simple) {
+ Label l;
+}
+
+TEST(ConstructLabel, Undefined) {
+ Label l;
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(ConstructLabelDeathTest, Undefined) {
+ Label l;
+ ASSERT_DEATH(l.Value(), "IsKnownConstant\\(&v\\)");
+}
+
+TEST(ConstructLabel, Constant) {
+ Label l(0x060b9f974eaf301eULL);
+ uint64_t v;
+ EXPECT_TRUE(l.IsKnownConstant(&v));
+ EXPECT_EQ(v, 0x060b9f974eaf301eULL);
+ EXPECT_EQ(l.Value(), 0x060b9f974eaf301eULL);
+}
+
+TEST(ConstructLabel, Copy) {
+ Label l;
+ Label m(l);
+ uint64_t v;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &v));
+ EXPECT_EQ(0U, v);
+}
+
+// The left-hand-side of a label assignment can be either
+// unconstrained, related, or known. The right-hand-side can be any of
+// those, or an integer.
+TEST(Assignment, UnconstrainedToUnconstrained) {
+ Label l, m;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ uint64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, UnconstrainedToRelated) {
+ Label l, m, n;
+ l = n;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ uint64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, UnconstrainedToKnown) {
+ Label l, m;
+ l = 0x8fd16e55b20a39c1ULL;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ uint64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x8fd16e55b20a39c1ULL, m.Value());
+}
+
+TEST(Assignment, RelatedToUnconstrained) {
+ Label l, m, n;
+ m = n;
+ l = m;
+ EXPECT_EQ(0U, l-n);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(n));
+ uint64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(n, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, RelatedToRelated) {
+ Label l, m, n, o;
+ l = n;
+ m = o;
+ l = m;
+ EXPECT_EQ(0U, n-o);
+ EXPECT_TRUE(n.IsKnownOffsetFrom(o));
+ uint64_t d;
+ EXPECT_TRUE(n.IsKnownOffsetFrom(o, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, RelatedToKnown) {
+ Label l, m, n;
+ m = n;
+ l = 0xd2011f8c82ad56f2ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, m.Value());
+ EXPECT_TRUE(n.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, n.Value());
+}
+
+TEST(Assignment, KnownToUnconstrained) {
+ Label l, m;
+ m = 0x50b024c0d6073887ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x50b024c0d6073887ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x50b024c0d6073887ULL, m.Value());
+}
+
+TEST(Assignment, KnownToRelated) {
+ Label l, m, n;
+ l = n;
+ m = 0x5348883655c727e5ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, m.Value());
+ EXPECT_TRUE(n.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, n.Value());
+}
+
+TEST(Assignment, KnownToKnown) {
+ Label l, m;
+ l = 0x36c209c20987564eULL;
+ m = 0x36c209c20987564eULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x36c209c20987564eULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x36c209c20987564eULL, m.Value());
+}
+
+TEST(Assignment, ConstantToUnconstrained) {
+ Label l;
+ l = 0xc02495f4d7f5a957ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xc02495f4d7f5a957ULL, l.Value());
+}
+
+TEST(Assignment, ConstantToRelated) {
+ Label l, m;
+ l = m;
+ l = 0x4577901cf275488dULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x4577901cf275488dULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x4577901cf275488dULL, m.Value());
+}
+
+TEST(Assignment, ConstantToKnown) {
+ Label l;
+ l = 0xec0b9c369b7e8ea7ULL;
+ l = 0xec0b9c369b7e8ea7ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xec0b9c369b7e8ea7ULL, l.Value());
+}
+
+TEST(AssignmentDeathTest, Self) {
+ Label l;
+ ASSERT_DEATH(l = l, "binding != this");
+}
+
+TEST(AssignmentDeathTest, IndirectCycle) {
+ Label l, m, n;
+ l = m;
+ m = n;
+ ASSERT_DEATH(n = l, "binding != this");
+}
+
+TEST(AssignmentDeathTest, Cycle) {
+ Label l, m, n, o;
+ l = m;
+ m = n;
+ o = n;
+ ASSERT_DEATH(o = l, "binding != this");
+}
+
+TEST(Addition, LabelConstant) {
+ Label l, m;
+ m = l + 0x5248d93e8bbe9497ULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x5248d93e8bbe9497ULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Addition, ConstantLabel) {
+ Label l, m;
+ m = 0xf51e94e00d6e3c84ULL + l;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0xf51e94e00d6e3c84ULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Addition, KnownLabelConstant) {
+ Label l, m;
+ l = 0x16286307042ce0d8ULL;
+ m = l + 0x3fdddd91306719d7ULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x3fdddd91306719d7ULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x16286307042ce0d8ULL + 0x3fdddd91306719d7ULL, m.Value());
+}
+
+TEST(Addition, ConstantKnownLabel) {
+ Label l, m;
+ l = 0x50f62d0cdd1031deULL;
+ m = 0x1b13462d8577c538ULL + l;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x1b13462d8577c538ULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x50f62d0cdd1031deULL + 0x1b13462d8577c538ULL, m.Value());
+}
+
+TEST(Subtraction, LabelConstant) {
+ Label l, m;
+ m = l - 0x0620884d21d3138eULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(-0x0620884d21d3138eULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Subtraction, KnownLabelConstant) {
+ Label l, m;
+ l = 0x6237fbaf9ef7929eULL;
+ m = l - 0x317730995d2ab6eeULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ uint64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(-0x317730995d2ab6eeULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x6237fbaf9ef7929eULL - 0x317730995d2ab6eeULL, m.Value());
+}
+
+TEST(SubtractionDeathTest, LabelLabel) {
+ Label l, m;
+ ASSERT_DEATH(l - m, "IsKnownOffsetFrom\\(label, &offset\\)");
+}
+
+TEST(Subtraction, LabelLabel) {
+ Label l, m;
+ l = m + 0x7fa77ec63e28a17aULL;
+ EXPECT_EQ(0x7fa77ec63e28a17aULL, l - m);
+ EXPECT_EQ(-0x7fa77ec63e28a17aULL, m - l);
+}
+
+TEST(IsKnownConstant, Undefined) {
+ Label l;
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(IsKnownConstant, RelatedLabel) {
+ Label l, m;
+ l = m;
+ EXPECT_FALSE(l.IsKnownConstant());
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(IsKnownConstant, Constant) {
+ Label l;
+ l = 0xf374b1bdd6a22576ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+}
+
+TEST(IsKnownOffsetFrom, Unrelated) {
+ Label l, m;
+ EXPECT_FALSE(l.IsKnownOffsetFrom(m));
+}
+
+TEST(IsKnownOffsetFrom, Related) {
+ Label l, m;
+ l = m;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+}
+
+// Test the construction of chains of related labels, and the
+// propagation of values through them.
+//
+// Although the relations between labels are supposed to behave
+// symmetrically --- that is, 'a = b' should put a and b in
+// indistinguishable states --- there's a distinction made internally
+// between the target (a) and the source (b).
+//
+// So there are five test axes to cover:
+//
+// - Do we construct the chain with assignment ("Assign") or with constructors
+// ("Construct")?
+//
+// - Do we set the value of the label at the start of the chain
+// ("Start") or the label at the end ("End")?
+//
+// - Are we testing the propagation of a relationship between variable
+// values ("Relation"), or the propagation of a known constant value
+// ("Value")?
+//
+// - Do we set the value before building the chain ("Before") or after
+// the chain has been built ("After")?
+//
+// - Do we add new relationships to the end of the existing chain
+// ("Forward") or to the beginning ("Backward")?
+//
+// Of course, "Construct" and "Backward" can't be combined, which
+// eliminates eight combinations, and "Construct", "End", and "Before"
+// can't be combined, which eliminates two more, so there are are 22
+// combinations, not 32.
+
+TEST(LabelChain, AssignStartRelationBeforeForward) {
+ Label a, b, c, d;
+ Label x;
+ a = x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationBeforeBackward) {
+ Label a, b, c, d;
+ Label x;
+ a = x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationAfterForward) {
+ Label a, b, c, d;
+ Label x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationAfterBackward) {
+ Label a, b, c, d;
+ Label x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartValueBeforeForward) {
+ Label a, b, c, d;
+ a = 0xa131200190546ac2ULL;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x111U, d.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x11U, c.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x1U, b.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueBeforeBackward) {
+ Label a, b, c, d;
+ a = 0x8da17e1670ad4fa2ULL;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x111U, d.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x11U, c.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x1U, b.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueAfterForward) {
+ Label a, b, c, d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ a = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x111U, d.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x11U, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x1U, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueAfterBackward) {
+ Label a, b, c, d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ a = 0xc86ca1d97ab5df6eULL;
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x111U, d.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x11U, c.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x1U, b.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignEndRelationBeforeForward) {
+ Label a, b, c, d;
+ Label x;
+ x = d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(-(uint64_t)0x111U, a-x);
+ EXPECT_EQ(-(uint64_t)0x110U, b-x);
+ EXPECT_EQ(-(uint64_t)0x100U, c-x);
+ EXPECT_EQ(-(uint64_t)0U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationBeforeBackward) {
+ Label a, b, c, d;
+ Label x;
+ x = d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(-(uint64_t)0x111U, a-x);
+ EXPECT_EQ(-(uint64_t)0x110U, b-x);
+ EXPECT_EQ(-(uint64_t)0x100U, c-x);
+ EXPECT_EQ(-(uint64_t)0U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationAfterForward) {
+ Label a, b, c, d;
+ Label x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ x = d;
+ EXPECT_EQ(-(uint64_t)0x111U, a-x);
+ EXPECT_EQ(-(uint64_t)0x110U, b-x);
+ EXPECT_EQ(-(uint64_t)0x100U, c-x);
+ EXPECT_EQ(-(uint64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationAfterBackward) {
+ Label a, b, c, d;
+ Label x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ x = d;
+ EXPECT_EQ(-(uint64_t)0x111U, a-x);
+ EXPECT_EQ(-(uint64_t)0x110U, b-x);
+ EXPECT_EQ(-(uint64_t)0x100U, c-x);
+ EXPECT_EQ(-(uint64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, AssignEndValueBeforeForward) {
+ Label a, b, c, d;
+ d = 0xa131200190546ac2ULL;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x111, a.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x110, b.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x100, c.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueBeforeBackward) {
+ Label a, b, c, d;
+ d = 0x8da17e1670ad4fa2ULL;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x111, a.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x110, b.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x100, c.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueAfterForward) {
+ Label a, b, c, d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ d = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueAfterBackward) {
+ Label a, b, c, d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ d = 0xc86ca1d97ab5df6eULL;
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x111, a.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x110, b.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x100, c.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, ConstructStartRelationBeforeForward) {
+ Label x;
+ Label a(x);
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, ConstructStartRelationAfterForward) {
+ Label x;
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, ConstructStartValueBeforeForward) {
+ Label a(0x5d234d177d01ccc8ULL);
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x111U, d.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x011U, c.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x001U, b.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x000U, a.Value());
+}
+
+TEST(LabelChain, ConstructStartValueAfterForward) {
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ a = 0xded85d54586e84fcULL;
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x111U, d.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x011U, c.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x001U, b.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x000U, a.Value());
+}
+
+TEST(LabelChain, ConstructEndRelationAfterForward) {
+ Label x;
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ x = d;
+ EXPECT_EQ(-(uint64_t)0x111U, a-x);
+ EXPECT_EQ(-(uint64_t)0x110U, b-x);
+ EXPECT_EQ(-(uint64_t)0x100U, c-x);
+ EXPECT_EQ(-(uint64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, ConstructEndValueAfterForward) {
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ d = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value());
+}
+
+TEST(LabelTree, KnownValue) {
+ Label l, m, n, o, p;
+ l = m;
+ m = n;
+ o = p;
+ p = n;
+ l = 0x536b5de3d468a1b5ULL;
+ EXPECT_EQ(0x536b5de3d468a1b5ULL, o.Value());
+}
+
+TEST(LabelTree, Related) {
+ Label l, m, n, o, p;
+ l = m - 1;
+ m = n - 10;
+ o = p + 100;
+ p = n + 1000;
+ EXPECT_EQ(1111U, o - l);
+}
+
+TEST(EquationDeathTest, EqualConstants) {
+ Label m = 0x0d3962f280f07d24ULL;
+ Label n = 0x0d3962f280f07d24ULL;
+ m = n; // no death expected
+}
+
+TEST(EquationDeathTest, EqualIndirectConstants) {
+ Label m = 0xa347f1e5238fe6a1ULL;
+ Label n;
+ Label o = n;
+ n = 0xa347f1e5238fe6a1ULL;
+ n = m; // no death expected
+}
+
+TEST(EquationDeathTest, ConstantClash) {
+ Label m = 0xd4cc0f4f630ec741ULL;
+ Label n = 0x934cd2d8254fc3eaULL;
+ ASSERT_DEATH(m = n, "addend_ == addend");
+}
+
+TEST(EquationDeathTest, IndirectConstantClash) {
+ Label m = 0xd4cc0f4f630ec741ULL;
+ Label n, o;
+ n = o;
+ o = 0xcfbe3b83ac49ce86ULL;
+ ASSERT_DEATH(m = n, "addend_ == addend");
+}
+
+// Assigning to a related label may free the next Binding on its
+// chain. This test always passes; it is interesting to memory
+// checkers and coverage analysis.
+TEST(LabelReferenceCount, AssignmentFree) {
+ Label l;
+ {
+ Label m;
+ l = m;
+ }
+ // This should free m's Binding.
+ l = 0xca8bae92f0376d4fULL;
+ ASSERT_EQ(0xca8bae92f0376d4fULL, l.Value());
+}
+
+// Finding the value of a label may free the Binding it refers to. This test
+// always passes; it is interesting to memory checkers and coverage analysis.
+TEST(LabelReferenceCount, FindValueFree) {
+ Label l;
+ {
+ Label m, n;
+ l = m;
+ m = n;
+ n = 0x7a0b0c576672daafULL;
+ // At this point, l's Binding refers to m's Binding, which refers
+ // to n's binding.
+ }
+ // Now, l is the only reference keeping the three Bindings alive.
+ // Resolving its value should free l's and m's original bindings.
+ ASSERT_EQ(0x7a0b0c576672daafULL, l.Value());
+}
+
+TEST(ConstructSection, Simple) {
+ Section s;
+}
+
+TEST(ConstructSection, WithEndian) {
+ Section s(kBigEndian);
+}
+
+// A fixture class for TestAssembler::Section tests.
+class SectionFixture {
+ public:
+ Section section;
+ string contents;
+ static const uint8_t data[];
+ static const size_t data_size;
+};
+
+const uint8_t SectionFixture::data[] = {
+ 0x87, 0x4f, 0x43, 0x67, 0x30, 0xd0, 0xd4, 0x0e
+};
+
+#define I0()
+#define I1(a) { a }
+#define I2(a,b) { a,b }
+#define I3(a,b,c) { a,b,c }
+#define I4(a,b,c,d) { a,b,c,d }
+#define I5(a,b,c,d,e) { a,b,c,d,e }
+#define I6(a,b,c,d,e,f) { a,b,c,d,e,f }
+#define I7(a,b,c,d,e,f,g) { a,b,c,d,e,f,g }
+#define I8(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h }
+#define I9(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i }
+#define ASSERT_BYTES(s, b) \
+ do \
+ { \
+ static const uint8_t expected_bytes[] = b; \
+ ASSERT_EQ(sizeof(expected_bytes), s.size()); \
+ ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \
+ sizeof(expected_bytes)) == 0); \
+ } \
+ while(0)
+
+class Append: public SectionFixture, public Test { };
+
+TEST_F(Append, Bytes) {
+ section.Append(data, sizeof(data));
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(sizeof(data), contents.size());
+ EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+}
+
+TEST_F(Append, BytesTwice) {
+ section.Append(data, sizeof(data));
+ section.Append(data, sizeof(data));
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(2 * sizeof(data), contents.size());
+ ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+ ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data),
+ (const char *) data, sizeof(data)));
+}
+
+TEST_F(Append, String) {
+ string s1 = "howdy ";
+ string s2 = "there";
+ section.Append(s1);
+ section.Append(s2);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_STREQ(contents.c_str(), "howdy there");
+}
+
+TEST_F(Append, CString) {
+ section.AppendCString("howdy");
+ section.AppendCString("");
+ section.AppendCString("there");
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(string("howdy\0\0there\0", 13), contents);
+}
+
+TEST_F(Append, CStringSize) {
+ section.AppendCString("howdy", 3);
+ section.AppendCString("there", 5);
+ section.AppendCString("fred", 6);
+ section.AppendCString("natalie", 0);
+ section.AppendCString("", 10);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(string("howtherefred\0\0\0\0\0\0\0\0\0\0\0\0", 24), contents);
+}
+
+TEST_F(Append, RepeatedBytes) {
+ section.Append((size_t) 10, '*');
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_STREQ(contents.c_str(), "**********");
+}
+
+TEST_F(Append, GeneralLE1) {
+ section.Append(kLittleEndian, 1, 42);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+}
+
+TEST_F(Append, GeneralLE2) {
+ section.Append(kLittleEndian, 2, 0x15a1);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0xa1, 0x15));
+}
+
+TEST_F(Append, GeneralLE3) {
+ section.Append(kLittleEndian, 3, 0x59ae8d);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59));
+}
+
+TEST_F(Append, GeneralLE4) {
+ section.Append(kLittleEndian, 4, 0x51603c56);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51));
+}
+
+TEST_F(Append, GeneralLE5) {
+ section.Append(kLittleEndian, 5, 0x385e2803b4ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38));
+}
+
+TEST_F(Append, GeneralLE6) {
+ section.Append(kLittleEndian, 6, 0xc7db9534dd1fULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7));
+}
+
+TEST_F(Append, GeneralLE7) {
+ section.Append(kLittleEndian, 7, 0x1445c9f1b843e6ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14));
+}
+
+TEST_F(Append, GeneralLE8) {
+ section.Append(kLittleEndian, 8, 0xaf48019dfe5c01e5ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf));
+}
+
+TEST_F(Append, GeneralBE1) {
+ section.Append(kBigEndian, 1, 0xd0ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(0xd0));
+}
+
+TEST_F(Append, GeneralBE2) {
+ section.Append(kBigEndian, 2, 0x2e7eULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2e, 0x7e));
+}
+
+TEST_F(Append, GeneralBE3) {
+ section.Append(kBigEndian, 3, 0x37dad6ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6));
+}
+
+TEST_F(Append, GeneralBE4) {
+ section.Append(kBigEndian, 4, 0x715935c7ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7));
+}
+
+TEST_F(Append, GeneralBE5) {
+ section.Append(kBigEndian, 5, 0x42baeb02b7ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7));
+}
+
+TEST_F(Append, GeneralBE6) {
+ section.Append(kBigEndian, 6, 0xf1cdf10e7b18ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18));
+}
+
+TEST_F(Append, GeneralBE7) {
+ section.Append(kBigEndian, 7, 0xf50a724f0b0d20ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20));
+}
+
+TEST_F(Append, GeneralBE8) {
+ section.Append(kBigEndian, 8, 0xa6b2cb5e98dc9c16ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16));
+}
+
+TEST_F(Append, GeneralLE1Label) {
+ Label l;
+ section.Append(kLittleEndian, 1, l);
+ l = 42;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+}
+
+TEST_F(Append, GeneralLE2Label) {
+ Label l;
+ section.Append(kLittleEndian, 2, l);
+ l = 0x15a1;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0xa1, 0x15));
+}
+
+TEST_F(Append, GeneralLE3Label) {
+ Label l;
+ section.Append(kLittleEndian, 3, l);
+ l = 0x59ae8d;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59));
+}
+
+TEST_F(Append, GeneralLE4Label) {
+ Label l;
+ section.Append(kLittleEndian, 4, l);
+ l = 0x51603c56;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51));
+}
+
+TEST_F(Append, GeneralLE5Label) {
+ Label l;
+ section.Append(kLittleEndian, 5, l);
+ l = 0x385e2803b4ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38));
+}
+
+TEST_F(Append, GeneralLE6Label) {
+ Label l;
+ section.Append(kLittleEndian, 6, l);
+ l = 0xc7db9534dd1fULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7));
+}
+
+TEST_F(Append, GeneralLE7Label) {
+ Label l;
+ section.Append(kLittleEndian, 7, l);
+ l = 0x1445c9f1b843e6ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14));
+}
+
+TEST_F(Append, GeneralLE8Label) {
+ Label l;
+ section.Append(kLittleEndian, 8, l);
+ l = 0xaf48019dfe5c01e5ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf));
+}
+
+TEST_F(Append, GeneralBE1Label) {
+ Label l;
+ section.Append(kBigEndian, 1, l);
+ l = 0xd0ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(0xd0));
+}
+
+TEST_F(Append, GeneralBE2Label) {
+ Label l;
+ section.Append(kBigEndian, 2, l);
+ l = 0x2e7eULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2e, 0x7e));
+}
+
+TEST_F(Append, GeneralBE3Label) {
+ Label l;
+ section.Append(kBigEndian, 3, l);
+ l = 0x37dad6ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6));
+}
+
+TEST_F(Append, GeneralBE4Label) {
+ Label l;
+ section.Append(kBigEndian, 4, l);
+ l = 0x715935c7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7));
+}
+
+TEST_F(Append, GeneralBE5Label) {
+ Label l;
+ section.Append(kBigEndian, 5, l);
+ l = 0x42baeb02b7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7));
+}
+
+TEST_F(Append, GeneralBE6Label) {
+ Label l;
+ section.Append(kBigEndian, 6, l);
+ l = 0xf1cdf10e7b18ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18));
+}
+
+TEST_F(Append, GeneralBE7Label) {
+ Label l;
+ section.Append(kBigEndian, 7, l);
+ l = 0xf50a724f0b0d20ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20));
+}
+
+TEST_F(Append, GeneralBE8Label) {
+ Label l;
+ section.Append(kBigEndian, 8, l);
+ l = 0xa6b2cb5e98dc9c16ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16));
+}
+
+TEST_F(Append, B8) {
+ section.Append(1, 0x2a);
+ section.B8(0xd3U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xd3));
+}
+
+TEST_F(Append, B8Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B8(l);
+ l = 0x4bU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x4b));
+}
+
+TEST_F(Append, B16) {
+ section.Append(1, 0x2a);
+ section.B16(0x472aU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x47, 0x2a));
+}
+
+TEST_F(Append, B16Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B16(l);
+ l = 0x55e8U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x55, 0xe8));
+}
+
+TEST_F(Append, B32) {
+ section.Append(1, 0x2a);
+ section.B32(0xbd412cbcU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xbd, 0x41, 0x2c, 0xbc));
+}
+
+TEST_F(Append, B32Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B32(l);
+ l = 0x208e37d5U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x20, 0x8e, 0x37, 0xd5));
+}
+
+TEST_F(Append, B64) {
+ section.Append(1, 0x2a);
+ section.B64(0x3402a013111e68adULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x34, 0x02, 0xa0, 0x13, 0x11, 0x1e, 0x68, 0xad));
+}
+
+TEST_F(Append, B64Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B64(l);
+ l = 0x355dbfbb4ac6d57fULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x35, 0x5d, 0xbf, 0xbb, 0x4a, 0xc6, 0xd5, 0x7f));
+}
+
+TEST_F(Append, L8) {
+ section.Append(1, 0x2a);
+ section.L8(0x26U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x26));
+}
+
+TEST_F(Append, L8Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L8(l);
+ l = 0xa8U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xa8));
+}
+
+TEST_F(Append, L16) {
+ section.Append(1, 0x2a);
+ section.L16(0xca6dU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x6d, 0xca));
+}
+
+TEST_F(Append, L16Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L16(l);
+ l = 0xd21fU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x1f, 0xd2));
+}
+
+TEST_F(Append, L32) {
+ section.Append(1, 0x2a);
+ section.L32(0x558f6181U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x81, 0x61, 0x8f, 0x55));
+}
+
+TEST_F(Append, L32Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L32(l);
+ l = 0x4b810f82U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x82, 0x0f, 0x81, 0x4b));
+}
+
+TEST_F(Append, L64) {
+ section.Append(1, 0x2a);
+ section.L64(0x564384f7579515bfULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xbf, 0x15, 0x95, 0x57, 0xf7, 0x84, 0x43, 0x56));
+}
+
+TEST_F(Append, L64Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L64(l);
+ l = 0x424b1d020667c8dbULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xdb, 0xc8, 0x67, 0x06, 0x02, 0x1d, 0x4b, 0x42));
+}
+
+TEST_F(Append, D8Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D8(0xe6U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xe6));
+}
+
+TEST_F(Append, D8BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D8(l);
+ l = 0xeeU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xee));
+}
+
+TEST_F(Append, D16Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D16(0x83b1U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x83, 0xb1));
+}
+
+TEST_F(Append, D16BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D16(l);
+ l = 0x5b55U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x5b, 0x55));
+}
+
+TEST_F(Append, D32Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D32(0xd0b0e431U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xd0, 0xb0, 0xe4, 0x31));
+}
+
+TEST_F(Append, D32BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D32(l);
+ l = 0x312fb340U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x31, 0x2f, 0xb3, 0x40));
+}
+
+TEST_F(Append, D64Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D64(0xb109843500dbcb16ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xb1, 0x09, 0x84, 0x35, 0x00, 0xdb, 0xcb, 0x16));
+}
+
+TEST_F(Append, D64BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D64(l);
+ l = 0x9a0d61b70f671fd7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x9a, 0x0d, 0x61, 0xb7, 0x0f, 0x67, 0x1f, 0xd7));
+}
+
+TEST_F(Append, D8Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D8(0x42U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x42));
+}
+
+TEST_F(Append, D8LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D8(l);
+ l = 0x05U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x05));
+}
+
+TEST_F(Append, D16Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D16(0xc5c5U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0xc5, 0xc5));
+}
+
+TEST_F(Append, D16LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D16(l);
+ l = 0xb620U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x20, 0xb6));
+}
+
+TEST_F(Append, D32Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D32(0x1a87d0feU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xfe, 0xd0, 0x87, 0x1a));
+}
+
+TEST_F(Append, D32LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D32(l);
+ l = 0xb8012d6bU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x6b, 0x2d, 0x01, 0xb8));
+}
+
+TEST_F(Append, D64Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D64(0x42de75c61375a1deULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xde, 0xa1, 0x75, 0x13, 0xc6, 0x75, 0xde, 0x42));
+}
+
+TEST_F(Append, D64LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D64(l);
+ l = 0x8b3bececf3fb5312ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x12, 0x53, 0xfb, 0xf3, 0xec, 0xec, 0x3b, 0x8b));
+}
+
+TEST_F(Append, Variety) {
+ Label a, b, c, d, e, f, g, h;
+ section.Append(kBigEndian, 1, a)
+ .Append(kLittleEndian, 8, h)
+ .Append(kBigEndian, 1, 0x8bULL)
+ .Append(kLittleEndian, 8, 0x0ea56540448f4439ULL)
+ .Append(kBigEndian, 2, b)
+ .Append(kLittleEndian, 7, g)
+ .Append(kBigEndian, 2, 0xcf15ULL)
+ .Append(kLittleEndian, 7, 0x29694f04c5724aULL)
+ .Append(kBigEndian, 3, c)
+ .Append(kLittleEndian, 6, f)
+ .Append(kBigEndian, 3, 0x8c3ffdULL)
+ .Append(kLittleEndian, 6, 0x6f11ba80187aULL)
+ .Append(kBigEndian, 4, d)
+ .Append(kLittleEndian, 5, e)
+ .Append(kBigEndian, 4, 0x2fda2472ULL)
+ .Append(kLittleEndian, 5, 0x0aa02d423fULL)
+ .Append(kBigEndian, 5, e)
+ .Append(kLittleEndian, 4, d)
+ .Append(kBigEndian, 5, 0x53ba432138ULL)
+ .Append(kLittleEndian, 4, 0xf139ae60ULL)
+ .Append(kBigEndian, 6, f)
+ .Append(kLittleEndian, 3, c)
+ .Append(kBigEndian, 6, 0x168e436af716ULL)
+ .Append(kLittleEndian, 3, 0x3ef189ULL)
+ .Append(kBigEndian, 7, g)
+ .Append(kLittleEndian, 2, b)
+ .Append(kBigEndian, 7, 0xacd4ef233e47d9ULL)
+ .Append(kLittleEndian, 2, 0x5311ULL)
+ .Append(kBigEndian, 8, h)
+ .Append(kLittleEndian, 1, a)
+ .Append(kBigEndian, 8, 0x4668d5f1c93637a1ULL)
+ .Append(kLittleEndian, 1, 0x65ULL);
+ a = 0x79ac9bd8aa256b35ULL;
+ b = 0x22d13097ef86c91cULL;
+ c = 0xf204968b0a05862fULL;
+ d = 0x163177f15a0eb4ecULL;
+ e = 0xbd1b0f1d977f2246ULL;
+ f = 0x2b0842eee83c6461ULL;
+ g = 0x92f4b928a4bf875eULL;
+ h = 0x61a199a8f7286ba6ULL;
+ ASSERT_EQ(8 * 18U, section.Size());
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ static const uint8_t expected[] = {
+ 0x35, 0xa6, 0x6b, 0x28, 0xf7, 0xa8, 0x99, 0xa1, 0x61,
+ 0x8b, 0x39, 0x44, 0x8f, 0x44, 0x40, 0x65, 0xa5, 0x0e,
+ 0xc9, 0x1c, 0x5e, 0x87, 0xbf, 0xa4, 0x28, 0xb9, 0xf4,
+ 0xcf, 0x15, 0x4a, 0x72, 0xc5, 0x04, 0x4f, 0x69, 0x29,
+ 0x05, 0x86, 0x2f, 0x61, 0x64, 0x3c, 0xe8, 0xee, 0x42,
+ 0x8c, 0x3f, 0xfd, 0x7a, 0x18, 0x80, 0xba, 0x11, 0x6f,
+ 0x5a, 0x0e, 0xb4, 0xec, 0x46, 0x22, 0x7f, 0x97, 0x1d,
+ 0x2f, 0xda, 0x24, 0x72, 0x3f, 0x42, 0x2d, 0xa0, 0x0a,
+ 0x1d, 0x97, 0x7f, 0x22, 0x46, 0xec, 0xb4, 0x0e, 0x5a,
+ 0x53, 0xba, 0x43, 0x21, 0x38, 0x60, 0xae, 0x39, 0xf1,
+ 0x42, 0xee, 0xe8, 0x3c, 0x64, 0x61, 0x2f, 0x86, 0x05,
+ 0x16, 0x8e, 0x43, 0x6a, 0xf7, 0x16, 0x89, 0xf1, 0x3e,
+ 0xf4, 0xb9, 0x28, 0xa4, 0xbf, 0x87, 0x5e, 0x1c, 0xc9,
+ 0xac, 0xd4, 0xef, 0x23, 0x3e, 0x47, 0xd9, 0x11, 0x53,
+ 0x61, 0xa1, 0x99, 0xa8, 0xf7, 0x28, 0x6b, 0xa6, 0x35,
+ 0x46, 0x68, 0xd5, 0xf1, 0xc9, 0x36, 0x37, 0xa1, 0x65,
+ };
+
+ ASSERT_TRUE(0 == memcmp(contents.data(), expected, sizeof(expected)));
+}
+
+TEST_F(Append, Section) {
+ section.Append("murder");
+ {
+ Section middle;
+ middle.Append(" she");
+ section.Append(middle);
+ }
+ section.Append(" wrote");
+ EXPECT_EQ(16U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_STREQ(contents.c_str(), "murder she wrote");
+}
+
+TEST_F(Append, SectionRefs) {
+ section.Append("sugar ");
+ Label l;
+ {
+ Section middle;
+ Label m;
+ middle.B32(m);
+ section.Append(middle);
+ m = 0x66726565;
+ }
+ section.Append(" jazz");
+ EXPECT_EQ(15U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_STREQ(contents.c_str(), "sugar free jazz");
+}
+
+TEST_F(Append, LEB128_0) {
+ section.LEB128(0);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\0", 1), contents);
+}
+
+TEST_F(Append, LEB128_0x3f) {
+ section.LEB128(0x3f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x3f", 1), contents);
+}
+
+TEST_F(Append, LEB128_0x40) {
+ section.LEB128(0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xc0\x00", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x7f) {
+ section.LEB128(0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x00", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x80) {
+ section.LEB128(0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x01", 2), contents);
+}
+
+TEST_F(Append, LEB128_0xff) {
+ section.LEB128(0xff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x01", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x1fff) {
+ section.LEB128(0x1fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x3f", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x2000) {
+ section.LEB128(0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\xc0\x00", 3), contents);
+}
+
+TEST_F(Append, LEB128_n1) {
+ section.LEB128(-1);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x7f", 1), contents);
+}
+
+TEST_F(Append, LEB128_n0x40) {
+ section.LEB128(-0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x40", 1), contents);
+}
+
+TEST_F(Append, LEB128_n0x41) {
+ section.LEB128(-0x41);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xbf\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x7f) {
+ section.LEB128(-0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x81\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x80) {
+ section.LEB128(-0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x2000) {
+ section.LEB128(-0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x40", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x2001) {
+ section.LEB128(-0x2001);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\xbf\x7f", 3), contents);
+}
+
+TEST_F(Append,ULEB128_0) {
+ section.ULEB128(0);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\0", 1), contents);
+}
+
+TEST_F(Append,ULEB128_1) {
+ section.ULEB128(1);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x01", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x3f) {
+ section.ULEB128(0x3f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x3f", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x40) {
+ section.ULEB128(0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x40", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x7f) {
+ section.ULEB128(0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x7f", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x80) {
+ section.ULEB128(0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x01", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0xff) {
+ section.ULEB128(0xff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x01", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x100) {
+ section.ULEB128(0x100);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x02", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x1fff) {
+ section.ULEB128(0x1fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x3f", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x2000) {
+ section.ULEB128(0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x40", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x3fff) {
+ section.ULEB128(0x3fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x7f", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x4000) {
+ section.ULEB128(0x4000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x80\x01", 3), contents);
+}
+
+TEST_F(Append,ULEB128_12857) {
+ section.ULEB128(12857);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xb9\x64", 2), contents);
+}
+
+TEST_F(Append, LEBChain) {
+ section.LEB128(-0x80).ULEB128(12857).Append("*");
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x7f\xb9\x64*", 5), contents);
+}
+
+
+class GetContents: public SectionFixture, public Test { };
+
+TEST_F(GetContents, Undefined) {
+ Label l;
+ section.Append(kLittleEndian, 8, l);
+ ASSERT_FALSE(section.GetContents(&contents));
+}
+
+TEST_F(GetContents, ClearsContents) {
+ section.Append((size_t) 10, '*');
+ EXPECT_EQ(10U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(0U, section.Size());
+}
+
+TEST_F(GetContents, ClearsReferences) {
+ Label l;
+ section.Append(kBigEndian, 1, l);
+ l = 42;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+ ASSERT_TRUE(section.GetContents(&contents)); // should not die
+}
+
+class Miscellanea: public SectionFixture, public Test { };
+
+TEST_F(Miscellanea, Clear) {
+ section.Append("howdy");
+ Label l;
+ section.L32(l);
+ EXPECT_EQ(9U, section.Size());
+ section.Clear();
+ EXPECT_EQ(0U, section.Size());
+ l = 0x8d231bf0U;
+ ASSERT_TRUE(section.GetContents(&contents)); // should not die
+}
+
+TEST_F(Miscellanea, Align) {
+ section.Append("*");
+ EXPECT_EQ(1U, section.Size());
+ section.Align(4).Append("*");
+ EXPECT_EQ(5U, section.Size());
+ section.Append("*").Align(2);
+ EXPECT_EQ(6U, section.Size());
+}
+
+TEST_F(Miscellanea, AlignPad) {
+ section.Append("*");
+ EXPECT_EQ(1U, section.Size());
+ section.Align(4, ' ').Append("*");
+ EXPECT_EQ(5U, section.Size());
+ section.Append("*").Align(2, ' ');
+ EXPECT_EQ(6U, section.Size());
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(string("* **"), contents);
+}
+
+TEST_F(Miscellanea, StartHereMark) {
+ Label m;
+ section.Append(42, ' ').Mark(&m).Append(13, '+');
+ EXPECT_EQ(42U, m - section.start());
+ EXPECT_EQ(42U + 13U, section.Here() - section.start());
+ EXPECT_FALSE(section.start().IsKnownConstant());
+ EXPECT_FALSE(m.IsKnownConstant());
+ EXPECT_FALSE(section.Here().IsKnownConstant());
+}
+
+TEST_F(Miscellanea, Endianness) {
+ section.set_endianness(kBigEndian);
+ EXPECT_EQ(kBigEndian, section.endianness());
+ section.set_endianness(kLittleEndian);
+ EXPECT_EQ(kLittleEndian, section.endianness());
+}
diff --git a/3rdParty/Breakpad/src/common/unordered.h b/3rdParty/Breakpad/src/common/unordered.h
new file mode 100644
index 0000000..ec665cc
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/unordered.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Include this file to use unordered_map and unordered_set. If tr1
+// or C++11 is not available, you can switch to using hash_set and
+// hash_map by defining BP_USE_HASH_SET.
+
+#ifndef COMMON_UNORDERED_H_
+#define COMMON_UNORDERED_H_
+
+#if defined(BP_USE_HASH_SET)
+#include <hash_map>
+#include <hash_set>
+
+// For hash<string>.
+#include "util/hash/hash.h"
+
+template <class T, class U, class H = __gnu_cxx::hash<T> >
+struct unordered_map : public hash_map<T, U, H> {};
+template <class T, class H = __gnu_cxx::hash<T> >
+struct unordered_set : public hash_set<T, H> {};
+
+#elif defined(_LIBCPP_VERSION) // c++11
+#include <unordered_map>
+#include <unordered_set>
+using std::unordered_map;
+using std::unordered_set;
+
+#else // Fallback to tr1::unordered
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+using std::tr1::unordered_map;
+using std::tr1::unordered_set;
+#endif
+
+#endif // COMMON_UNORDERED_H_
diff --git a/3rdParty/Breakpad/src/common/windows/dia_util.cc b/3rdParty/Breakpad/src/common/windows/dia_util.cc
new file mode 100644
index 0000000..f4cfa1d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/dia_util.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/windows/dia_util.h"
+
+#include <atlbase.h>
+
+namespace google_breakpad {
+
+bool FindDebugStream(const wchar_t* name,
+ IDiaSession* session,
+ IDiaEnumDebugStreamData** debug_stream) {
+ CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
+ if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
+ fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
+ fetched == 1) {
+ CComBSTR stream_name;
+ if (FAILED(temp_debug_stream->get_name(&stream_name))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
+ return false;
+ }
+
+ // Found the stream?
+ if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
+ *debug_stream = temp_debug_stream.Detach();
+ return true;
+ }
+
+ temp_debug_stream.Release();
+ }
+
+ // No table was found.
+ return false;
+}
+
+bool FindTable(REFIID iid, IDiaSession* session, void** table) {
+ // Get the table enumerator.
+ CComPtr<IDiaEnumTables> enum_tables;
+ if (FAILED(session->getEnumTables(&enum_tables))) {
+ fprintf(stderr, "IDiaSession::getEnumTables failed\n");
+ return false;
+ }
+
+ // Iterate through the tables.
+ CComPtr<IDiaTable> temp_table;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
+ fetched == 1) {
+ void* temp = NULL;
+ if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
+ *table = temp;
+ return true;
+ }
+ temp_table.Release();
+ }
+
+ // The table was not found.
+ return false;
+}
+
+} // namespace google_breakpad \ No newline at end of file
diff --git a/3rdParty/Breakpad/src/common/windows/dia_util.h b/3rdParty/Breakpad/src/common/windows/dia_util.h
new file mode 100644
index 0000000..b9e0df2
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/dia_util.h
@@ -0,0 +1,64 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utilities for loading debug streams and tables from a PDB file.
+
+#ifndef COMMON_WINDOWS_DIA_UTIL_H_
+#define COMMON_WINDOWS_DIA_UTIL_H_
+
+#include <Windows.h>
+#include <dia2.h>
+
+namespace google_breakpad {
+
+// Find the debug stream of the given |name| in the given |session|. Returns
+// true on success, false on error of if the stream does not exist. On success
+// the stream will be returned via |debug_stream|.
+bool FindDebugStream(const wchar_t* name,
+ IDiaSession* session,
+ IDiaEnumDebugStreamData** debug_stream);
+
+// Finds the first table implementing the COM interface with ID |iid| in the
+// given |session|. Returns true on success, false on error or if no such
+// table is found. On success the table will be returned via |table|.
+bool FindTable(REFIID iid, IDiaSession* session, void** table);
+
+// A templated version of FindTable. Finds the first table implementing type
+// |InterfaceType| in the given |session|. Returns true on success, false on
+// error or if no such table is found. On success the table will be returned via
+// |table|.
+template<typename InterfaceType>
+bool FindTable(IDiaSession* session, InterfaceType** table) {
+ return FindTable(__uuidof(InterfaceType),
+ session,
+ reinterpret_cast<void**>(table));
+}
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_DIA_UTIL_H_
diff --git a/3rdParty/Breakpad/src/common/windows/guid_string.h b/3rdParty/Breakpad/src/common/windows/guid_string.h
index f8aa8a2..48a5c1d 100644
--- a/3rdParty/Breakpad/src/common/windows/guid_string.h
+++ b/3rdParty/Breakpad/src/common/windows/guid_string.h
@@ -29,10 +29,10 @@
// guid_string.cc: Convert GUIDs to strings.
-#ifndef COMMON_WINDOWS_GUID_STRING_H__
-#define COMMON_WINDOWS_GUID_STRING_H__
+#ifndef COMMON_WINDOWS_GUID_STRING_H_
+#define COMMON_WINDOWS_GUID_STRING_H_
-#include <Guiddef.h>
+#include <guiddef.h>
#include <string>
@@ -55,4 +55,4 @@ class GUIDString {
} // namespace google_breakpad
-#endif // COMMON_WINDOWS_GUID_STRING_H__
+#endif // COMMON_WINDOWS_GUID_STRING_H_
diff --git a/3rdParty/Breakpad/src/common/windows/http_upload.cc b/3rdParty/Breakpad/src/common/windows/http_upload.cc
new file mode 100644
index 0000000..7676bdc
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/http_upload.cc
@@ -0,0 +1,420 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+
+// Disable exception handler warnings.
+#pragma warning(disable:4530)
+
+#include <fstream>
+
+#include "common/windows/string_utils-inl.h"
+
+#include "common/windows/http_upload.h"
+
+namespace google_breakpad {
+
+using std::ifstream;
+using std::ios;
+
+static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";
+
+// Helper class which closes an internet handle when it goes away
+class HTTPUpload::AutoInternetHandle {
+ public:
+ explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}
+ ~AutoInternetHandle() {
+ if (handle_) {
+ InternetCloseHandle(handle_);
+ }
+ }
+
+ HINTERNET get() { return handle_; }
+
+ private:
+ HINTERNET handle_;
+};
+
+// static
+bool HTTPUpload::SendRequest(const wstring &url,
+ const map<wstring, wstring> &parameters,
+ const map<wstring, wstring> &files,
+ int *timeout,
+ wstring *response_body,
+ int *response_code) {
+ if (response_code) {
+ *response_code = 0;
+ }
+
+ // TODO(bryner): support non-ASCII parameter names
+ if (!CheckParameters(parameters)) {
+ return false;
+ }
+
+ // Break up the URL and make sure we can handle it
+ wchar_t scheme[16], host[256], path[256];
+ URL_COMPONENTS components;
+ memset(&components, 0, sizeof(components));
+ components.dwStructSize = sizeof(components);
+ components.lpszScheme = scheme;
+ components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
+ components.lpszHostName = host;
+ components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
+ components.lpszUrlPath = path;
+ components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
+ if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),
+ 0, &components)) {
+ return false;
+ }
+ bool secure = false;
+ if (wcscmp(scheme, L"https") == 0) {
+ secure = true;
+ } else if (wcscmp(scheme, L"http") != 0) {
+ return false;
+ }
+
+ AutoInternetHandle internet(InternetOpen(kUserAgent,
+ INTERNET_OPEN_TYPE_PRECONFIG,
+ NULL, // proxy name
+ NULL, // proxy bypass
+ 0)); // flags
+ if (!internet.get()) {
+ return false;
+ }
+
+ AutoInternetHandle connection(InternetConnect(internet.get(),
+ host,
+ components.nPort,
+ NULL, // user name
+ NULL, // password
+ INTERNET_SERVICE_HTTP,
+ 0, // flags
+ NULL)); // context
+ if (!connection.get()) {
+ return false;
+ }
+
+ DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;
+ http_open_flags |= INTERNET_FLAG_NO_COOKIES;
+ AutoInternetHandle request(HttpOpenRequest(connection.get(),
+ L"POST",
+ path,
+ NULL, // version
+ NULL, // referer
+ NULL, // agent type
+ http_open_flags,
+ NULL)); // context
+ if (!request.get()) {
+ return false;
+ }
+
+ wstring boundary = GenerateMultipartBoundary();
+ wstring content_type_header = GenerateRequestHeader(boundary);
+ HttpAddRequestHeaders(request.get(),
+ content_type_header.c_str(),
+ static_cast<DWORD>(-1),
+ HTTP_ADDREQ_FLAG_ADD);
+
+ string request_body;
+ if (!GenerateRequestBody(parameters, files, boundary, &request_body)) {
+ return false;
+ }
+
+ if (timeout) {
+ if (!InternetSetOption(request.get(),
+ INTERNET_OPTION_SEND_TIMEOUT,
+ timeout,
+ sizeof(*timeout))) {
+ fwprintf(stderr, L"Could not unset send timeout, continuing...\n");
+ }
+
+ if (!InternetSetOption(request.get(),
+ INTERNET_OPTION_RECEIVE_TIMEOUT,
+ timeout,
+ sizeof(*timeout))) {
+ fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");
+ }
+ }
+
+ if (!HttpSendRequest(request.get(), NULL, 0,
+ const_cast<char *>(request_body.data()),
+ static_cast<DWORD>(request_body.size()))) {
+ return false;
+ }
+
+ // The server indicates a successful upload with HTTP status 200.
+ wchar_t http_status[4];
+ DWORD http_status_size = sizeof(http_status);
+ if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,
+ static_cast<LPVOID>(&http_status), &http_status_size,
+ 0)) {
+ return false;
+ }
+
+ int http_response = wcstol(http_status, NULL, 10);
+ if (response_code) {
+ *response_code = http_response;
+ }
+
+ bool result = (http_response == 200);
+
+ if (result) {
+ result = ReadResponse(request.get(), response_body);
+ }
+
+ return result;
+}
+
+// static
+bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {
+ bool has_content_length_header = false;
+ wchar_t content_length[32];
+ DWORD content_length_size = sizeof(content_length);
+ DWORD claimed_size = 0;
+ string response_body;
+
+ if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,
+ static_cast<LPVOID>(&content_length),
+ &content_length_size, 0)) {
+ has_content_length_header = true;
+ claimed_size = wcstol(content_length, NULL, 10);
+ response_body.reserve(claimed_size);
+ }
+
+
+ DWORD bytes_available;
+ DWORD total_read = 0;
+ BOOL return_code;
+
+ while (((return_code = InternetQueryDataAvailable(request, &bytes_available,
+ 0, 0)) != 0) && bytes_available > 0) {
+ vector<char> response_buffer(bytes_available);
+ DWORD size_read;
+
+ return_code = InternetReadFile(request,
+ &response_buffer[0],
+ bytes_available, &size_read);
+
+ if (return_code && size_read > 0) {
+ total_read += size_read;
+ response_body.append(&response_buffer[0], size_read);
+ } else {
+ break;
+ }
+ }
+
+ bool succeeded = return_code && (!has_content_length_header ||
+ (total_read == claimed_size));
+ if (succeeded && response) {
+ *response = UTF8ToWide(response_body);
+ }
+
+ return succeeded;
+}
+
+// static
+wstring HTTPUpload::GenerateMultipartBoundary() {
+ // The boundary has 27 '-' characters followed by 16 hex digits
+ static const wchar_t kBoundaryPrefix[] = L"---------------------------";
+ static const int kBoundaryLength = 27 + 16 + 1;
+
+ // Generate some random numbers to fill out the boundary
+ int r0 = rand();
+ int r1 = rand();
+
+ wchar_t temp[kBoundaryLength];
+ swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);
+
+ // remove when VC++7.1 is no longer supported
+ temp[kBoundaryLength - 1] = L'\0';
+
+ return wstring(temp);
+}
+
+// static
+wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
+ wstring header = L"Content-Type: multipart/form-data; boundary=";
+ header += boundary;
+ return header;
+}
+
+// static
+bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,
+ const map<wstring, wstring> &files,
+ const wstring &boundary,
+ string *request_body) {
+ string boundary_str = WideToUTF8(boundary);
+ if (boundary_str.empty()) {
+ return false;
+ }
+
+ request_body->clear();
+
+ // Append each of the parameter pairs as a form-data part
+ for (map<wstring, wstring>::const_iterator pos = parameters.begin();
+ pos != parameters.end(); ++pos) {
+ request_body->append("--" + boundary_str + "\r\n");
+ request_body->append("Content-Disposition: form-data; name=\"" +
+ WideToUTF8(pos->first) + "\"\r\n\r\n" +
+ WideToUTF8(pos->second) + "\r\n");
+ }
+
+ for (map<wstring, wstring>::const_iterator pos = files.begin();
+ pos != files.end(); ++pos) {
+ vector<char> contents;
+ if (!GetFileContents(pos->second, &contents)) {
+ return false;
+ }
+
+ // Now append the upload files as a binary (octet-stream) part
+ string filename_utf8 = WideToUTF8(pos->second);
+ if (filename_utf8.empty()) {
+ return false;
+ }
+
+ string file_part_name_utf8 = WideToUTF8(pos->first);
+ if (file_part_name_utf8.empty()) {
+ return false;
+ }
+
+ request_body->append("--" + boundary_str + "\r\n");
+ request_body->append("Content-Disposition: form-data; "
+ "name=\"" + file_part_name_utf8 + "\"; "
+ "filename=\"" + filename_utf8 + "\"\r\n");
+ request_body->append("Content-Type: application/octet-stream\r\n");
+ request_body->append("\r\n");
+
+ if (!contents.empty()) {
+ request_body->append(&(contents[0]), contents.size());
+ }
+ request_body->append("\r\n");
+ }
+ request_body->append("--" + boundary_str + "--\r\n");
+ return true;
+}
+
+// static
+bool HTTPUpload::GetFileContents(const wstring &filename,
+ vector<char> *contents) {
+ bool rv = false;
+ // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
+ // wchar_t* filename, so use _wfopen directly in that case. For VC8 and
+ // later, _wfopen has been deprecated in favor of _wfopen_s, which does
+ // not exist in earlier versions, so let the ifstream open the file itself.
+ // GCC doesn't support wide file name and opening on FILE* requires ugly
+ // hacks, so fallback to multi byte file.
+#ifdef _MSC_VER
+ ifstream file;
+ file.open(filename.c_str(), ios::binary);
+#else // GCC
+ ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary);
+#endif // _MSC_VER >= 1400
+ if (file.is_open()) {
+ file.seekg(0, ios::end);
+ std::streamoff length = file.tellg();
+ // Check for loss of data when converting lenght from std::streamoff into
+ // std::vector<char>::size_type
+ std::vector<char>::size_type vector_size =
+ static_cast<std::vector<char>::size_type>(length);
+ if (static_cast<std::streamoff>(vector_size) == length) {
+ contents->resize(vector_size);
+ if (length != 0) {
+ file.seekg(0, ios::beg);
+ file.read(&((*contents)[0]), length);
+ }
+ rv = true;
+ }
+ file.close();
+ }
+ return rv;
+}
+
+// static
+wstring HTTPUpload::UTF8ToWide(const string &utf8) {
+ if (utf8.length() == 0) {
+ return wstring();
+ }
+
+ // compute the length of the buffer we'll need
+ int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
+
+ if (charcount == 0) {
+ return wstring();
+ }
+
+ // convert
+ wchar_t* buf = new wchar_t[charcount];
+ MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);
+ wstring result(buf);
+ delete[] buf;
+ return result;
+}
+
+// static
+string HTTPUpload::WideToMBCP(const wstring &wide, unsigned int cp) {
+ if (wide.length() == 0) {
+ return string();
+ }
+
+ // compute the length of the buffer we'll need
+ int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1,
+ NULL, 0, NULL, NULL);
+ if (charcount == 0) {
+ return string();
+ }
+
+ // convert
+ char *buf = new char[charcount];
+ WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount,
+ NULL, NULL);
+
+ string result(buf);
+ delete[] buf;
+ return result;
+}
+
+// static
+bool HTTPUpload::CheckParameters(const map<wstring, wstring> &parameters) {
+ for (map<wstring, wstring>::const_iterator pos = parameters.begin();
+ pos != parameters.end(); ++pos) {
+ const wstring &str = pos->first;
+ if (str.size() == 0) {
+ return false; // disallow empty parameter names
+ }
+ for (unsigned int i = 0; i < str.size(); ++i) {
+ wchar_t c = str[i];
+ if (c < 32 || c == '"' || c > 127) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/windows/http_upload.h b/3rdParty/Breakpad/src/common/windows/http_upload.h
new file mode 100644
index 0000000..f8d48cb
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/http_upload.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
+// request using wininet. It currently supports requests that contain
+// a set of string parameters (key/value pairs), and a file to upload.
+
+#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_
+#define COMMON_WINDOWS_HTTP_UPLOAD_H_
+
+#pragma warning(push)
+// Disable exception handler warnings.
+#pragma warning(disable : 4530)
+
+#include <windows.h>
+#include <wininet.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace google_breakpad {
+
+using std::string;
+using std::wstring;
+using std::map;
+using std::vector;
+
+class HTTPUpload {
+ public:
+ // Sends the given sets of parameters and files as a multipart POST
+ // request to the given URL.
+ // Each key in |files| is the name of the file part of the request
+ // (i.e. it corresponds to the name= attribute on an <input type="file">.
+ // Parameter names must contain only printable ASCII characters,
+ // and may not contain a quote (") character.
+ // Only HTTP(S) URLs are currently supported. Returns true on success.
+ // If the request is successful and response_body is non-NULL,
+ // the response body will be returned in response_body.
+ // If response_code is non-NULL, it will be set to the HTTP response code
+ // received (or 0 if the request failed before getting an HTTP response).
+ static bool SendRequest(const wstring &url,
+ const map<wstring, wstring> &parameters,
+ const map<wstring, wstring> &files,
+ int *timeout,
+ wstring *response_body,
+ int *response_code);
+
+ private:
+ class AutoInternetHandle;
+
+ // Retrieves the HTTP response. If NULL is passed in for response,
+ // this merely checks (via the return value) that we were successfully
+ // able to retrieve exactly as many bytes of content in the response as
+ // were specified in the Content-Length header.
+ static bool ReadResponse(HINTERNET request, wstring* response);
+
+ // Generates a new multipart boundary for a POST request
+ static wstring GenerateMultipartBoundary();
+
+ // Generates a HTTP request header for a multipart form submit.
+ static wstring GenerateRequestHeader(const wstring &boundary);
+
+ // Given a set of parameters, a set of upload files, and a file part name,
+ // generates a multipart request body string with these parameters
+ // and minidump contents. Returns true on success.
+ static bool GenerateRequestBody(const map<wstring, wstring> &parameters,
+ const map<wstring, wstring> &files,
+ const wstring &boundary,
+ string *request_body);
+
+ // Fills the supplied vector with the contents of filename.
+ static bool GetFileContents(const wstring &filename, vector<char> *contents);
+
+ // Converts a UTF8 string to UTF16.
+ static wstring UTF8ToWide(const string &utf8);
+
+ // Converts a UTF16 string to UTF8.
+ static string WideToUTF8(const wstring &wide) {
+ return WideToMBCP(wide, CP_UTF8);
+ }
+
+ // Converts a UTF16 string to specified code page.
+ static string WideToMBCP(const wstring &wide, unsigned int cp);
+
+ // Checks that the given list of parameters has only printable
+ // ASCII characters in the parameter name, and does not contain
+ // any quote (") characters. Returns true if so.
+ static bool CheckParameters(const map<wstring, wstring> &parameters);
+
+ // No instances of this class should be created.
+ // Disallow all constructors, destructors, and operator=.
+ HTTPUpload();
+ explicit HTTPUpload(const HTTPUpload &);
+ void operator=(const HTTPUpload &);
+ ~HTTPUpload();
+};
+
+} // namespace google_breakpad
+
+#pragma warning(pop)
+
+#endif // COMMON_WINDOWS_HTTP_UPLOAD_H_
diff --git a/3rdParty/Breakpad/src/common/windows/omap.cc b/3rdParty/Breakpad/src/common/windows/omap.cc
new file mode 100644
index 0000000..ba3ce86
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/omap.cc
@@ -0,0 +1,716 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This contains a suite of tools for transforming symbol information when
+// when that information has been extracted from a PDB containing OMAP
+// information.
+
+// OMAP information is a lightweight description of a mapping between two
+// address spaces. It consists of two streams, each of them a vector 2-tuples.
+// The OMAPTO stream contains tuples of the form
+//
+// (RVA in transformed image, RVA in original image)
+//
+// while the OMAPFROM stream contains tuples of the form
+//
+// (RVA in original image, RVA in transformed image)
+//
+// The entries in each vector are sorted by the first value of the tuple, and
+// the lengths associated with a mapping are implicit as the distance between
+// two successive addresses in the vector.
+
+// Consider a trivial 10-byte function described by the following symbol:
+//
+// Function: RVA 0x00001000, length 10, "foo"
+//
+// Now consider the same function, but with 5-bytes of instrumentation injected
+// at offset 5. The OMAP streams describing this would look like:
+//
+// OMAPTO : [ [0x00001000, 0x00001000],
+// [0x00001005, 0xFFFFFFFF],
+// [0x0000100a, 0x00001005] ]
+// OMAPFROM: [ [0x00001000, 0x00001000],
+// [0x00001005, 0x0000100a] ]
+//
+// In this case the injected code has been marked as not originating in the
+// source image, and thus it will have no symbol information at all. However,
+// the injected code may also be associated with an original address range;
+// for example, when prepending instrumentation to a basic block the
+// instrumentation can be labelled as originating from the same source BB such
+// that symbol resolution will still find the appropriate source code line
+// number. In this case the OMAP stream would look like:
+//
+// OMAPTO : [ [0x00001000, 0x00001000],
+// [0x00001005, 0x00001005],
+// [0x0000100a, 0x00001005] ]
+// OMAPFROM: [ [0x00001000, 0x00001000],
+// [0x00001005, 0x0000100a] ]
+//
+// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the
+// instrumented image. It would first run this through the OMAPTO table and
+// translate that address to 0x00001005. It would then lookup the symbol
+// at that address and return the symbol for the function "foo". This is the
+// correct result.
+//
+// However, if we query DIA for the length and address of the symbol it will
+// tell us that it has length 10 and is at RVA 0x00001000. The location is
+// correct, but the length doesn't take into account the 5-bytes of injected
+// code. Symbol resolution works (starting from an instrumented address,
+// mapping to an original address, and looking up a symbol), but the symbol
+// metadata is incorrect.
+//
+// If we dump the symbols using DIA they will have their addresses
+// appropriately transformed and reflect positions in the instrumented image.
+// However, if we try to do a lookup using those symbols resolution can fail.
+// For example, the address 0x0000100a will not map to the symbol for "foo",
+// because DIA tells us it is at location 0x00001000 (correct) with length
+// 10 (incorrect). The problem is one of order of operations: in this case
+// we're attempting symbol resolution by looking up an instrumented address
+// in the table of translated symbols.
+//
+// One way to handle this is to dump the OMAP information as part of the
+// breakpad symbols. This requires the rest of the toolchain to be aware of
+// OMAP information and to use it when present prior to performing lookup. The
+// other option is to properly transform the symbols (updating length as well as
+// position) so that resolution will work as expected for translated addresses.
+// This is transparent to the rest of the toolchain.
+
+#include "common/windows/omap.h"
+
+#include <atlbase.h>
+
+#include <algorithm>
+#include <cassert>
+#include <set>
+
+#include "common/windows/dia_util.h"
+
+namespace google_breakpad {
+
+namespace {
+
+static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO";
+static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM";
+
+// Dependending on where this is used in breakpad we sometimes get min/max from
+// windef, and other times from algorithm. To get around this we simply
+// define our own min/max functions.
+template<typename T>
+const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; }
+template<typename T>
+const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; }
+
+// It makes things more readable to have two different OMAP types. We cast
+// normal OMAPs into these. They must be the same size as the OMAP structure
+// for this to work, hence the static asserts.
+struct OmapOrigToTran {
+ DWORD rva_original;
+ DWORD rva_transformed;
+};
+struct OmapTranToOrig {
+ DWORD rva_transformed;
+ DWORD rva_original;
+};
+static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP),
+ "OmapOrigToTran must have same size as OMAP.");
+static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP),
+ "OmapTranToOrig must have same size as OMAP.");
+typedef std::vector<OmapOrigToTran> OmapFromTable;
+typedef std::vector<OmapTranToOrig> OmapToTable;
+
+// Used for sorting and searching through a Mapping.
+bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) {
+ if (lhs.rva_original < rhs.rva_original)
+ return true;
+ if (lhs.rva_original > rhs.rva_original)
+ return false;
+ return lhs.length < rhs.length;
+}
+bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) {
+ if (lhs.rva_transformed < rhs.rva_transformed)
+ return true;
+ if (lhs.rva_transformed > rhs.rva_transformed)
+ return false;
+ return lhs.length < rhs.length;
+}
+
+// Used for searching through the EndpointIndexMap.
+bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) {
+ return ei1.endpoint < ei2.endpoint;
+}
+
+// Finds the debug stream with the given |name| in the given |session|, and
+// populates |table| with its contents. Casts the data directly into OMAP
+// structs.
+bool FindAndLoadOmapTable(const wchar_t* name,
+ IDiaSession* session,
+ OmapTable* table) {
+ assert(name != NULL);
+ assert(session != NULL);
+ assert(table != NULL);
+
+ CComPtr<IDiaEnumDebugStreamData> stream;
+ if (!FindDebugStream(name, session, &stream))
+ return false;
+ assert(stream.p != NULL);
+
+ LONG count = 0;
+ if (FAILED(stream->get_Count(&count))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream "
+ "\"%ws\"\n", name);
+ return false;
+ }
+
+ // Get the length of the stream in bytes.
+ DWORD bytes_read = 0;
+ ULONG count_read = 0;
+ if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading "
+ "length of stream \"%ws\"\n", name);
+ return false;
+ }
+
+ // Ensure it's consistent with the OMAP data type.
+ DWORD bytes_expected = count * sizeof(OmapTable::value_type);
+ if (count * sizeof(OmapTable::value_type) != bytes_read) {
+ fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name);
+ return false;
+ }
+
+ // Read the table.
+ table->resize(count);
+ bytes_read = 0;
+ count_read = 0;
+ if (FAILED(stream->Next(count, bytes_expected, &bytes_read,
+ reinterpret_cast<BYTE*>(&table->at(0)),
+ &count_read))) {
+ fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading "
+ "data from stream \"%ws\"\n", name);
+ return false;
+ }
+
+ return true;
+}
+
+// This determines the original image length by looking through the segment
+// table.
+bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) {
+ assert(session != NULL);
+ assert(image_length != NULL);
+
+ CComPtr<IDiaEnumSegments> enum_segments;
+ if (!FindTable(session, &enum_segments))
+ return false;
+ assert(enum_segments.p != NULL);
+
+ DWORD temp_image_length = 0;
+ CComPtr<IDiaSegment> segment;
+ ULONG fetched = 0;
+ while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) &&
+ fetched == 1) {
+ assert(segment.p != NULL);
+
+ DWORD rva = 0;
+ DWORD length = 0;
+ DWORD frame = 0;
+ if (FAILED(segment->get_relativeVirtualAddress(&rva)) ||
+ FAILED(segment->get_length(&length)) ||
+ FAILED(segment->get_frame(&frame))) {
+ fprintf(stderr, "Failed to get basic properties for IDiaSegment\n");
+ return false;
+ }
+
+ if (frame > 0) {
+ DWORD segment_end = rva + length;
+ if (segment_end > temp_image_length)
+ temp_image_length = segment_end;
+ }
+ segment.Release();
+ }
+
+ *image_length = temp_image_length;
+ return true;
+}
+
+// Detects regions of the original image that have been removed in the
+// transformed image, and sets the 'removed' property on all mapped ranges
+// immediately preceding a gap. The mapped ranges must be sorted by
+// 'rva_original'.
+void FillInRemovedLengths(Mapping* mapping) {
+ assert(mapping != NULL);
+
+ // Find and fill gaps. We do this with two sweeps. We first sweep forward
+ // looking for gaps. When we identify a gap we then sweep forward with a
+ // second scan and set the 'removed' property for any intervals that
+ // immediately precede the gap.
+ //
+ // Gaps are typically between two successive intervals, but not always:
+ //
+ // Range 1: ---------------
+ // Range 2: -------
+ // Range 3: -------------
+ // Gap : ******
+ //
+ // In the above example the gap is between range 1 and range 3. A forward
+ // sweep finds the gap, and a second forward sweep identifies that range 1
+ // immediately precedes the gap and sets its 'removed' property.
+
+ size_t fill = 0;
+ DWORD rva_front = 0;
+ for (size_t find = 0; find < mapping->size(); ++find) {
+#ifndef NDEBUG
+ // We expect the mapped ranges to be sorted by 'rva_original'.
+ if (find > 0) {
+ assert(mapping->at(find - 1).rva_original <=
+ mapping->at(find).rva_original);
+ }
+#endif
+
+ if (rva_front < mapping->at(find).rva_original) {
+ // We've found a gap. Fill it in by setting the 'removed' property for
+ // any affected intervals.
+ DWORD removed = mapping->at(find).rva_original - rva_front;
+ for (; fill < find; ++fill) {
+ if (mapping->at(fill).rva_original + mapping->at(fill).length !=
+ rva_front) {
+ continue;
+ }
+
+ // This interval ends right where the gap starts. It needs to have its
+ // 'removed' information filled in.
+ mapping->at(fill).removed = removed;
+ }
+ }
+
+ // Advance the front that indicates the covered portion of the image.
+ rva_front = mapping->at(find).rva_original + mapping->at(find).length;
+ }
+}
+
+// Builds a unified view of the mapping between the original and transformed
+// image space by merging OMAPTO and OMAPFROM data.
+void BuildMapping(const OmapData& omap_data, Mapping* mapping) {
+ assert(mapping != NULL);
+
+ mapping->clear();
+
+ if (omap_data.omap_from.empty() || omap_data.omap_to.empty())
+ return;
+
+ // The names 'omap_to' and 'omap_from' are awfully confusing, so we make
+ // ourselves more explicit here. This cast is only safe because the underlying
+ // types have the exact same size.
+ const OmapToTable& tran2orig =
+ reinterpret_cast<const OmapToTable&>(omap_data.omap_to);
+ const OmapFromTable& orig2tran = reinterpret_cast<const OmapFromTable&>(
+ omap_data.omap_from);
+
+ // Handle the range of data at the beginning of the image. This is not usually
+ // specified by the OMAP data.
+ if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) {
+ DWORD header_transformed = tran2orig[0].rva_transformed;
+ DWORD header_original = orig2tran[0].rva_original;
+ DWORD header = Min(header_transformed, header_original);
+
+ MappedRange mr = {};
+ mr.length = header;
+ mr.injected = header_transformed - header;
+ mr.removed = header_original - header;
+ mapping->push_back(mr);
+ }
+
+ // Convert the implied lengths to explicit lengths, and infer which content
+ // has been injected into the transformed image. Injected content is inferred
+ // as regions of the transformed address space that does not map back to
+ // known valid content in the original image.
+ for (size_t i = 0; i < tran2orig.size(); ++i) {
+ const OmapTranToOrig& o1 = tran2orig[i];
+
+ // This maps to content that is outside the original image, thus it
+ // describes injected content. We can skip this entry.
+ if (o1.rva_original >= omap_data.length_original)
+ continue;
+
+ // Calculate the length of the current OMAP entry. This is implicit as the
+ // distance between successive |rva| values, capped at the end of the
+ // original image.
+ DWORD length = 0;
+ if (i + 1 < tran2orig.size()) {
+ const OmapTranToOrig& o2 = tran2orig[i + 1];
+
+ // We expect the table to be sorted by rva_transformed.
+ assert(o1.rva_transformed <= o2.rva_transformed);
+
+ length = o2.rva_transformed - o1.rva_transformed;
+ if (o1.rva_original + length > omap_data.length_original) {
+ length = omap_data.length_original - o1.rva_original;
+ }
+ } else {
+ length = omap_data.length_original - o1.rva_original;
+ }
+
+ // Zero-length entries don't describe anything and can be ignored.
+ if (length == 0)
+ continue;
+
+ // Any gaps in the transformed address-space are due to injected content.
+ if (!mapping->empty()) {
+ MappedRange& prev_mr = mapping->back();
+ prev_mr.injected += o1.rva_transformed -
+ (prev_mr.rva_transformed + prev_mr.length);
+ }
+
+ MappedRange mr = {};
+ mr.rva_original = o1.rva_original;
+ mr.rva_transformed = o1.rva_transformed;
+ mr.length = length;
+ mapping->push_back(mr);
+ }
+
+ // Sort based on the original image addresses.
+ std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess);
+
+ // Fill in the 'removed' lengths by looking for gaps in the coverage of the
+ // original address space.
+ FillInRemovedLengths(mapping);
+
+ return;
+}
+
+void BuildEndpointIndexMap(ImageMap* image_map) {
+ assert(image_map != NULL);
+
+ if (image_map->mapping.size() == 0)
+ return;
+
+ const Mapping& mapping = image_map->mapping;
+ EndpointIndexMap& eim = image_map->endpoint_index_map;
+
+ // Get the unique set of interval endpoints.
+ std::set<DWORD> endpoints;
+ for (size_t i = 0; i < mapping.size(); ++i) {
+ endpoints.insert(mapping[i].rva_original);
+ endpoints.insert(mapping[i].rva_original +
+ mapping[i].length +
+ mapping[i].removed);
+ }
+
+ // Use the endpoints to initialize the secondary search structure for the
+ // mapping.
+ eim.resize(endpoints.size());
+ std::set<DWORD>::const_iterator it = endpoints.begin();
+ for (size_t i = 0; it != endpoints.end(); ++it, ++i) {
+ eim[i].endpoint = *it;
+ eim[i].index = mapping.size();
+ }
+
+ // For each endpoint we want the smallest index of any interval containing
+ // it. We iterate over the intervals and update the indices associated with
+ // each interval endpoint contained in the current interval. In the general
+ // case of an arbitrary set of intervals this is O(n^2), but the structure of
+ // OMAP data makes this O(n).
+ for (size_t i = 0; i < mapping.size(); ++i) {
+ EndpointIndex ei1 = { mapping[i].rva_original, 0 };
+ EndpointIndexMap::iterator it1 = std::lower_bound(
+ eim.begin(), eim.end(), ei1, EndpointIndexLess);
+
+ EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length +
+ mapping[i].removed, 0 };
+ EndpointIndexMap::iterator it2 = std::lower_bound(
+ eim.begin(), eim.end(), ei2, EndpointIndexLess);
+
+ for (; it1 != it2; ++it1)
+ it1->index = Min(i, it1->index);
+ }
+}
+
+void BuildSubsequentRVAMap(const OmapData &omap_data,
+ std::map<DWORD, DWORD> *subsequent) {
+ assert(subsequent->empty());
+ const OmapFromTable &orig2tran =
+ reinterpret_cast<const OmapFromTable &>(omap_data.omap_from);
+
+ if (orig2tran.empty())
+ return;
+
+ for (size_t i = 0; i < orig2tran.size() - 1; ++i) {
+ // Expect that orig2tran is sorted.
+ if (orig2tran[i].rva_original >= orig2tran[i + 1].rva_original) {
+ fprintf(stderr, "OMAP 'from' table unexpectedly unsorted\n");
+ subsequent->clear();
+ return;
+ }
+ subsequent->insert(std::make_pair(orig2tran[i].rva_original,
+ orig2tran[i + 1].rva_original));
+ }
+}
+
+// Clips the given mapped range.
+void ClipMappedRangeOriginal(const AddressRange& clip_range,
+ MappedRange* mapped_range) {
+ assert(mapped_range != NULL);
+
+ // The clipping range is entirely outside of the mapped range.
+ if (clip_range.end() <= mapped_range->rva_original ||
+ mapped_range->rva_original + mapped_range->length +
+ mapped_range->removed <= clip_range.rva) {
+ mapped_range->length = 0;
+ mapped_range->injected = 0;
+ mapped_range->removed = 0;
+ return;
+ }
+
+ // Clip the left side.
+ if (mapped_range->rva_original < clip_range.rva) {
+ DWORD clip_left = clip_range.rva - mapped_range->rva_original;
+ mapped_range->rva_original += clip_left;
+ mapped_range->rva_transformed += clip_left;
+
+ if (clip_left > mapped_range->length) {
+ // The left clipping boundary entirely erases the content section of the
+ // range.
+ DWORD trim = clip_left - mapped_range->length;
+ mapped_range->length = 0;
+ mapped_range->injected -= Min(trim, mapped_range->injected);
+ // We know that trim <= mapped_range->remove.
+ mapped_range->removed -= trim;
+ } else {
+ // The left clipping boundary removes some, but not all, of the content.
+ // As such it leaves the removed/injected component intact.
+ mapped_range->length -= clip_left;
+ }
+ }
+
+ // Clip the right side.
+ DWORD end_original = mapped_range->rva_original + mapped_range->length;
+ if (clip_range.end() < end_original) {
+ // The right clipping boundary lands in the 'content' section of the range,
+ // entirely clearing the injected/removed portion.
+ DWORD clip_right = end_original - clip_range.end();
+ mapped_range->length -= clip_right;
+ mapped_range->injected = 0;
+ mapped_range->removed = 0;
+ return;
+ } else {
+ // The right clipping boundary is outside of the content, but may affect
+ // the removed/injected portion of the range.
+ DWORD end_removed = end_original + mapped_range->removed;
+ if (clip_range.end() < end_removed)
+ mapped_range->removed = clip_range.end() - end_original;
+
+ DWORD end_injected = end_original + mapped_range->injected;
+ if (clip_range.end() < end_injected)
+ mapped_range->injected = clip_range.end() - end_original;
+ }
+
+ return;
+}
+
+} // namespace
+
+int AddressRange::Compare(const AddressRange& rhs) const {
+ if (end() <= rhs.rva)
+ return -1;
+ if (rhs.end() <= rva)
+ return 1;
+ return 0;
+}
+
+bool GetOmapDataAndDisableTranslation(IDiaSession* session,
+ OmapData* omap_data) {
+ assert(session != NULL);
+ assert(omap_data != NULL);
+
+ CComPtr<IDiaAddressMap> address_map;
+ if (FAILED(session->QueryInterface(&address_map))) {
+ fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n");
+ return false;
+ }
+ assert(address_map.p != NULL);
+
+ BOOL omap_enabled = FALSE;
+ if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) {
+ fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n");
+ return false;
+ }
+
+ if (!omap_enabled) {
+ // We indicate the non-presence of OMAP data by returning empty tables.
+ omap_data->omap_from.clear();
+ omap_data->omap_to.clear();
+ omap_data->length_original = 0;
+ return true;
+ }
+
+ // OMAP data is present. Disable translation.
+ if (FAILED(address_map->put_addressMapEnabled(FALSE))) {
+ fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n");
+ return false;
+ }
+
+ // Read the OMAP streams.
+ if (!FindAndLoadOmapTable(kOmapFromDebugStreamName,
+ session,
+ &omap_data->omap_from)) {
+ return false;
+ }
+ if (!FindAndLoadOmapTable(kOmapToDebugStreamName,
+ session,
+ &omap_data->omap_to)) {
+ return false;
+ }
+
+ // Get the lengths of the address spaces.
+ if (!GetOriginalImageLength(session, &omap_data->length_original))
+ return false;
+
+ return true;
+}
+
+void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) {
+ assert(image_map != NULL);
+
+ BuildMapping(omap_data, &image_map->mapping);
+ BuildEndpointIndexMap(image_map);
+ BuildSubsequentRVAMap(omap_data, &image_map->subsequent_rva_block);
+}
+
+void MapAddressRange(const ImageMap& image_map,
+ const AddressRange& original_range,
+ AddressRangeVector* mapped_ranges) {
+ assert(mapped_ranges != NULL);
+
+ const Mapping& map = image_map.mapping;
+
+ // Handle the trivial case of an empty image_map. This means that there is
+ // no transformation to be applied, and we can simply return the original
+ // range.
+ if (map.empty()) {
+ mapped_ranges->push_back(original_range);
+ return;
+ }
+
+ // If we get a query of length 0 we need to handle it by using a non-zero
+ // query length.
+ AddressRange query_range(original_range);
+ if (query_range.length == 0)
+ query_range.length = 1;
+
+ // Find the range of intervals that can potentially intersect our query range.
+ size_t imin = 0;
+ size_t imax = 0;
+ {
+ // The index of the earliest possible range that can affect is us done by
+ // searching through the secondary indexing structure.
+ const EndpointIndexMap& eim = image_map.endpoint_index_map;
+ EndpointIndex q1 = { query_range.rva, 0 };
+ EndpointIndexMap::const_iterator it1 = std::lower_bound(
+ eim.begin(), eim.end(), q1, EndpointIndexLess);
+ if (it1 == eim.end()) {
+ imin = map.size();
+ } else {
+ // Backup to find the interval that contains our query point.
+ if (it1 != eim.begin() && query_range.rva < it1->endpoint)
+ --it1;
+ imin = it1->index;
+ }
+
+ // The first range that can't possibly intersect us is found by searching
+ // through the image map directly as it is already sorted by interval start
+ // point.
+ MappedRange q2 = { query_range.end(), 0 };
+ Mapping::const_iterator it2 = std::lower_bound(
+ map.begin(), map.end(), q2, MappedRangeOriginalLess);
+ imax = it2 - map.begin();
+ }
+
+ // Find all intervals that intersect the query range.
+ Mapping temp_map;
+ for (size_t i = imin; i < imax; ++i) {
+ MappedRange mr = map[i];
+ ClipMappedRangeOriginal(query_range, &mr);
+ if (mr.length + mr.injected > 0)
+ temp_map.push_back(mr);
+ }
+
+ // If there are no intersecting ranges then the query range has been removed
+ // from the image in question.
+ if (temp_map.empty())
+ return;
+
+ // Sort based on transformed addresses.
+ std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess);
+
+ // Zero-length queries can't actually be merged. We simply output the set of
+ // unique RVAs that correspond to the query RVA.
+ if (original_range.length == 0) {
+ mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0));
+ for (size_t i = 1; i < temp_map.size(); ++i) {
+ if (temp_map[i].rva_transformed > mapped_ranges->back().rva)
+ mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0));
+ }
+ return;
+ }
+
+ // Merge any ranges that are consecutive in the mapped image. We merge over
+ // injected content if it makes ranges contiguous, but we ignore any injected
+ // content at the tail end of a range. This allows us to detect symbols that
+ // have been lengthened by injecting content in the middle. However, it
+ // misses the case where content has been injected at the head or the tail.
+ // The problem is that it doesn't know whether to attribute it to the
+ // preceding or following symbol. It is up to the author of the transform to
+ // output explicit OMAP info in these cases to ensure full coverage of the
+ // transformed address space.
+ DWORD rva_begin = temp_map[0].rva_transformed;
+ DWORD rva_cur_content = rva_begin + temp_map[0].length;
+ DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected;
+ for (size_t i = 1; i < temp_map.size(); ++i) {
+ if (rva_cur_injected < temp_map[i].rva_transformed) {
+ // This marks the end of a continuous range in the image. Output the
+ // current range and start a new one.
+ if (rva_begin < rva_cur_content) {
+ mapped_ranges->push_back(
+ AddressRange(rva_begin, rva_cur_content - rva_begin));
+ }
+ rva_begin = temp_map[i].rva_transformed;
+ }
+
+ rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length;
+ rva_cur_injected = rva_cur_content + temp_map[i].injected;
+ }
+
+ // Output the range in progress.
+ if (rva_begin < rva_cur_content) {
+ mapped_ranges->push_back(
+ AddressRange(rva_begin, rva_cur_content - rva_begin));
+ }
+
+ return;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/windows/omap.h b/3rdParty/Breakpad/src/common/windows/omap.h
new file mode 100644
index 0000000..bc293af
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/omap.h
@@ -0,0 +1,72 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Provides an API for mapping symbols through OMAP information, if a PDB file
+// is augmented with it. This allows breakpad to work with addresses in
+// transformed images by transforming the symbols themselves, rather than
+// transforming addresses prior to querying symbols (the way it is typically
+// done by Windows-native tools, including the DIA).
+
+#ifndef COMMON_WINDOWS_OMAP_H_
+#define COMMON_WINDOWS_OMAP_H_
+
+#include "common/windows/omap_internal.h"
+
+namespace google_breakpad {
+
+// If the given session contains OMAP data this extracts it, populating
+// |omap_data|, and then disabling automatic translation for the session.
+// OMAP data is present in the PDB if |omap_data| is not empty. This returns
+// true on success, false otherwise.
+bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session,
+ OmapData* omap_data);
+
+// Given raw OMAP data builds an ImageMap. This can be used to query individual
+// image ranges using MapAddressRange.
+// |omap_data|| is the OMAP data extracted from the PDB.
+// |image_map| will be populated with a description of the image mapping. If
+// |omap_data| is empty then this will also be empty.
+void BuildImageMap(const OmapData& omap_data, ImageMap* image_map);
+
+// Given an address range in the original image space determines how exactly it
+// has been tranformed.
+// |omap_data| is the OMAP data extracted from the PDB, which must not be
+// empty.
+// |original_range| is the address range in the original image being queried.
+// |mapped_ranges| will be populated with a full description of the mapping.
+// They may be disjoint in the transformed image so a vector is needed to
+// fully represent the mapping. This will be appended to if it is not
+// empty. If |omap_data| is empty then |mapped_ranges| will simply be
+// populated with a copy of |original_range| (the identity transform).
+void MapAddressRange(const ImageMap& image_map,
+ const AddressRange& original_range,
+ AddressRangeVector* mapped_ranges);
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_OMAP_H_
diff --git a/3rdParty/Breakpad/src/common/windows/omap_internal.h b/3rdParty/Breakpad/src/common/windows/omap_internal.h
new file mode 100644
index 0000000..2a4713d
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/omap_internal.h
@@ -0,0 +1,140 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Declares internal implementation details for functionality in omap.h and
+// omap.cc.
+
+#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H_
+#define COMMON_WINDOWS_OMAP_INTERNAL_H_
+
+#include <windows.h>
+#include <dia2.h>
+
+#include <map>
+#include <vector>
+
+namespace google_breakpad {
+
+// The OMAP struct is defined by debughlp.h, which doesn't play nicely with
+// imagehlp.h. We simply redefine it.
+struct OMAP {
+ DWORD rva;
+ DWORD rvaTo;
+};
+static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure.");
+typedef std::vector<OMAP> OmapTable;
+
+// This contains the OMAP data extracted from an image.
+struct OmapData {
+ // The table of OMAP entries describing the transformation from the
+ // original image to the transformed image.
+ OmapTable omap_from;
+ // The table of OMAP entries describing the transformation from the
+ // instrumented image to the original image.
+ OmapTable omap_to;
+ // The length of the original untransformed image.
+ DWORD length_original;
+
+ OmapData() : length_original(0) { }
+};
+
+// This represents a range of addresses in an image.
+struct AddressRange {
+ DWORD rva;
+ DWORD length;
+
+ AddressRange() : rva(0), length(0) { }
+ AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { }
+
+ // Returns the end address of this range.
+ DWORD end() const { return rva + length; }
+
+ // Addreses only compare as less-than or greater-than if they are not
+ // overlapping. Otherwise, they compare equal.
+ int Compare(const AddressRange& rhs) const;
+ bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; }
+ bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; }
+
+ // Equality operators compare exact values.
+ bool operator==(const AddressRange& rhs) const {
+ return rva == rhs.rva && length == rhs.length;
+ }
+ bool operator!=(const AddressRange& rhs) const { return !((*this) == rhs); }
+};
+
+typedef std::vector<AddressRange> AddressRangeVector;
+
+// This represents an address range in an original image, and its corresponding
+// range in the transformed image.
+struct MappedRange {
+ // An address in the original image.
+ DWORD rva_original;
+ // The corresponding addresses in the transformed image.
+ DWORD rva_transformed;
+ // The length of the address range.
+ DWORD length;
+ // It is possible for code to be injected into a transformed image, for which
+ // there is no corresponding code in the original image. If this range of
+ // transformed image is immediately followed by such injected code we maintain
+ // a record of its length here.
+ DWORD injected;
+ // It is possible for code to be removed from the original image. This happens
+ // for things like padding between blocks. There is no actual content lost,
+ // but the spacing between items may be lost. This keeps track of any removed
+ // content immediately following the |original| range.
+ DWORD removed;
+};
+// A vector of mapped ranges is used as a more useful representation of
+// OMAP data.
+typedef std::vector<MappedRange> Mapping;
+
+// Used as a secondary search structure accompanying a Mapping.
+struct EndpointIndex {
+ DWORD endpoint;
+ size_t index;
+};
+typedef std::vector<EndpointIndex> EndpointIndexMap;
+
+// An ImageMap is vector of mapped ranges, plus a secondary index into it for
+// doing interval searches. (An interval tree would also work, but is overkill
+// because we don't need insertion and deletion.)
+struct ImageMap {
+ // This is a description of the mapping between original and transformed
+ // image, sorted by addresses in the original image.
+ Mapping mapping;
+ // For all interval endpoints in |mapping| this stores the minimum index of
+ // an interval in |mapping| that contains the endpoint. Useful for doing
+ // interval intersection queries.
+ EndpointIndexMap endpoint_index_map;
+
+ std::map<DWORD, DWORD> subsequent_rva_block;
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_OMAP_INTERNAL_H_
diff --git a/3rdParty/Breakpad/src/common/windows/omap_unittest.cc b/3rdParty/Breakpad/src/common/windows/omap_unittest.cc
new file mode 100644
index 0000000..b244334
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/omap_unittest.cc
@@ -0,0 +1,329 @@
+// Copyright 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Unittests for OMAP related functions.
+
+#include "common/windows/omap.h"
+
+#include "breakpad_googletest_includes.h"
+
+namespace google_breakpad {
+
+// Equality operators for ContainerEq. These must be outside of the anonymous
+// namespace in order for them to be found.
+bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
+ return mr1.rva_original == mr2.rva_original &&
+ mr1.rva_transformed == mr2.rva_transformed &&
+ mr1.length == mr2.length &&
+ mr1.injected == mr2.injected &&
+ mr1.removed == mr2.removed;
+}
+bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
+ return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
+}
+
+// Pretty printers for more meaningful error messages. Also need to be outside
+// the anonymous namespace.
+std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
+ os << "MappedRange(rva_original=" << mr.rva_original
+ << ", rva_transformed=" << mr.rva_transformed
+ << ", length=" << mr.length
+ << ", injected=" << mr.injected
+ << ", removed=" << mr.removed << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
+ os << "EndpointIndex(endpoint=" << ei.endpoint
+ << ", index=" << ei.index << ")";
+ return os;
+}
+std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
+ os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
+ return os;
+}
+
+namespace {
+
+OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
+ OMAP o = { rva, rvaTo };
+ return o;
+}
+
+MappedRange CreateMappedRange(DWORD rva_original,
+ DWORD rva_transformed,
+ DWORD length,
+ DWORD injected,
+ DWORD removed) {
+ MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
+ return mr;
+}
+
+EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
+ EndpointIndex ei = { endpoint, index };
+ return ei;
+}
+
+// (C is removed)
+// Original : A B C D E F G H
+// Transformed: A B D F E * H1 G1 G2 H2
+// (* is injected, G is copied, H is split)
+// A is implied.
+
+// Layout of the original image.
+const AddressRange B(100, 15);
+const AddressRange C(B.end(), 10);
+const AddressRange D(C.end(), 25);
+const AddressRange E(D.end(), 10);
+const AddressRange F(E.end(), 40);
+const AddressRange G(F.end(), 3);
+const AddressRange H(G.end(), 7);
+
+// Layout of the transformed image.
+const AddressRange Bt(100, 15);
+const AddressRange Dt(Bt.end(), 20); // D is shortened.
+const AddressRange Ft(Dt.end(), F.length);
+const AddressRange Et(Ft.end(), E.length);
+const AddressRange injected(Et.end(), 5);
+const AddressRange H1t(injected.end(), 4); // H is split.
+const AddressRange G1t(H1t.end(), G.length); // G is copied.
+const AddressRange G2t(G1t.end(), G.length); // G is copied.
+const AddressRange H2t(G2t.end(), 3); // H is split.
+
+class BuildImageMapTest : public testing::Test {
+ public:
+ static const DWORD kInvalidAddress = 0xFFFFFFFF;
+
+ void InitOmapData() {
+ omap_data.length_original = H.end();
+
+ // Build the OMAPTO vector (from transformed to original).
+ omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
+ omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
+ omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
+ omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
+ omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
+ omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
+ omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
+ omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
+ omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
+
+ // Build the OMAPFROM vector (from original to transformed).
+ omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
+ omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
+ omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
+ omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
+ omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
+ omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
+ omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
+ }
+
+ OmapData omap_data;
+};
+
+} // namespace
+
+TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
+ ASSERT_EQ(0u, omap_data.omap_from.size());
+ ASSERT_EQ(0u, omap_data.omap_to.size());
+ ASSERT_EQ(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_EQ(0u, image_map.mapping.size());
+ EXPECT_EQ(0u, image_map.endpoint_index_map.size());
+}
+
+TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
+ InitOmapData();
+ ASSERT_LE(0u, omap_data.omap_from.size());
+ ASSERT_LE(0u, omap_data.omap_to.size());
+ ASSERT_LE(0u, omap_data.length_original);
+
+ ImageMap image_map;
+ BuildImageMap(omap_data, &image_map);
+ EXPECT_LE(9u, image_map.mapping.size());
+ EXPECT_LE(9u, image_map.endpoint_index_map.size());
+
+ Mapping mapping;
+ mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
+ // C is removed, and it originally comes immediately after B.
+ mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
+ // D is shortened by a length of 5.
+ mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
+ // The injected content comes immediately after E in the transformed image.
+ mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
+ 0));
+ mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
+ // G is copied so creates two entries.
+ mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
+ mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
+ // H is split, so create two entries.
+ mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
+ mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
+ 0, 0));
+ EXPECT_THAT(mapping,
+ testing::ContainerEq(image_map.mapping));
+
+ EndpointIndexMap endpoint_index_map;
+ endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
+ endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
+ endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
+ endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
+ endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
+ // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
+ endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
+ // H is split so we expect 2 endpoints to show up attributed to it.
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
+ endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
+ EXPECT_THAT(endpoint_index_map,
+ testing::ContainerEq(image_map.endpoint_index_map));
+}
+
+namespace {
+
+class MapAddressRangeTest : public BuildImageMapTest {
+ public:
+ typedef BuildImageMapTest Super;
+ virtual void SetUp() {
+ Super::SetUp();
+ InitOmapData();
+ BuildImageMap(omap_data, &image_map);
+ }
+
+ ImageMap image_map;
+
+ private:
+ using BuildImageMapTest::InitOmapData;
+ using BuildImageMapTest::omap_data;
+};
+
+} // namespace
+
+TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
+ ImageMap im;
+ AddressRangeVector mapped_ranges;
+ AddressRange ar(0, 1024);
+ MapAddressRange(im, ar, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_EQ(ar, mapped_ranges[0]);
+}
+
+TEST_F(MapAddressRangeTest, MapOutOfImage) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapIdentity) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, B, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
+}
+
+TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange DEF(D.rva, F.end() - D.rva);
+ MapAddressRange(image_map, DEF, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptySingle) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapEmptyCopied) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
+ AddressRange(G2t.rva, 0)));
+}
+
+TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, G, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(
+ AddressRange(G1t.rva, G2t.end() - G1t.rva)));
+}
+
+TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, H, &mapped_ranges);
+ EXPECT_EQ(2u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
+}
+
+TEST_F(MapAddressRangeTest, MapInjected) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange EFGH(E.rva, H.end() - E.rva);
+ MapAddressRange(image_map, EFGH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, C, &mapped_ranges);
+ EXPECT_EQ(0u, mapped_ranges.size());
+}
+
+TEST_F(MapAddressRangeTest, MapRemovedPartly) {
+ AddressRangeVector mapped_ranges;
+ MapAddressRange(image_map, D, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
+}
+
+TEST_F(MapAddressRangeTest, MapFull) {
+ AddressRangeVector mapped_ranges;
+
+ AddressRange AH(0, H.end());
+ MapAddressRange(image_map, AH, &mapped_ranges);
+ EXPECT_EQ(1u, mapped_ranges.size());
+
+ AddressRange AHt(0, H2t.end());
+ EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.cc b/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.cc
new file mode 100644
index 0000000..31920ba
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.cc
@@ -0,0 +1,1412 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/windows/pdb_source_line_writer.h"
+
+#include <windows.h>
+#include <winnt.h>
+#include <atlbase.h>
+#include <dia2.h>
+#include <diacreate.h>
+#include <ImageHlp.h>
+#include <stdio.h>
+
+#include <limits>
+#include <set>
+
+#include "common/windows/dia_util.h"
+#include "common/windows/guid_string.h"
+#include "common/windows/string_utils-inl.h"
+
+// This constant may be missing from DbgHelp.h. See the documentation for
+// IDiaSymbol::get_undecoratedNameEx.
+#ifndef UNDNAME_NO_ECSU
+#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union.
+#endif // UNDNAME_NO_ECSU
+
+/*
+ * Not defined in WinNT.h for some reason. Definitions taken from:
+ * http://uninformed.org/index.cgi?v=4&a=1&p=13
+ *
+ */
+typedef unsigned char UBYTE;
+
+#if !defined(_WIN64)
+#define UNW_FLAG_EHANDLER 0x01
+#define UNW_FLAG_UHANDLER 0x02
+#define UNW_FLAG_CHAININFO 0x04
+#endif
+
+union UnwindCode {
+ struct {
+ UBYTE offset_in_prolog;
+ UBYTE unwind_operation_code : 4;
+ UBYTE operation_info : 4;
+ };
+ USHORT frame_offset;
+};
+
+enum UnwindOperationCodes {
+ UWOP_PUSH_NONVOL = 0, /* info == register number */
+ UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
+ UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
+ UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+ UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
+ UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
+ // XXX: these are missing from MSDN!
+ // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm
+ UWOP_SAVE_XMM,
+ UWOP_SAVE_XMM_FAR,
+ UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
+ UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
+ UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
+};
+
+// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
+// Note: some fields removed as we don't use them.
+struct UnwindInfo {
+ UBYTE version : 3;
+ UBYTE flags : 5;
+ UBYTE size_of_prolog;
+ UBYTE count_of_codes;
+ UBYTE frame_register : 4;
+ UBYTE frame_offset : 4;
+ UnwindCode unwind_code[1];
+};
+
+namespace google_breakpad {
+
+namespace {
+
+using std::vector;
+
+// A helper class to scope a PLOADED_IMAGE.
+class AutoImage {
+ public:
+ explicit AutoImage(PLOADED_IMAGE img) : img_(img) {}
+ ~AutoImage() {
+ if (img_)
+ ImageUnload(img_);
+ }
+
+ operator PLOADED_IMAGE() { return img_; }
+ PLOADED_IMAGE operator->() { return img_; }
+
+ private:
+ PLOADED_IMAGE img_;
+};
+
+bool SymbolsMatch(IDiaSymbol* a, IDiaSymbol* b) {
+ DWORD a_section, a_offset, b_section, b_offset;
+ if (FAILED(a->get_addressSection(&a_section)) ||
+ FAILED(a->get_addressOffset(&a_offset)) ||
+ FAILED(b->get_addressSection(&b_section)) ||
+ FAILED(b->get_addressOffset(&b_offset)))
+ return false;
+ return a_section == b_section && a_offset == b_offset;
+}
+
+bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) {
+ if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) {
+ return true;
+ }
+
+ class DECLSPEC_UUID("B86AE24D-BF2F-4ac9-B5A2-34B14E4CE11D") DiaSource100;
+ class DECLSPEC_UUID("761D3BCD-1304-41D5-94E8-EAC54E4AC172") DiaSource110;
+ class DECLSPEC_UUID("3BFCEA48-620F-4B6B-81F7-B9AF75454C7D") DiaSource120;
+ class DECLSPEC_UUID("E6756135-1E65-4D17-8576-610761398C3C") DiaSource140;
+
+ // If the CoCreateInstance call above failed, msdia*.dll is not registered.
+ // We can try loading the DLL corresponding to the #included DIA SDK, but
+ // the DIA headers don't provide a version. Lets try to figure out which DIA
+ // version we're compiling against by comparing CLSIDs.
+ const wchar_t *msdia_dll = nullptr;
+ if (CLSID_DiaSource == _uuidof(DiaSource100)) {
+ msdia_dll = L"msdia100.dll";
+ } else if (CLSID_DiaSource == _uuidof(DiaSource110)) {
+ msdia_dll = L"msdia110.dll";
+ } else if (CLSID_DiaSource == _uuidof(DiaSource120)) {
+ msdia_dll = L"msdia120.dll";
+ } else if (CLSID_DiaSource == _uuidof(DiaSource140)) {
+ msdia_dll = L"msdia140.dll";
+ }
+
+ if (msdia_dll &&
+ SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource,
+ reinterpret_cast<void **>(&data_source)))) {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) {
+}
+
+PDBSourceLineWriter::~PDBSourceLineWriter() {
+}
+
+bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) {
+ if (code_file_.empty()) {
+ code_file_ = exe_file;
+ return true;
+ }
+ // Setting a different code file path is an error. It is success only if the
+ // file paths are the same.
+ return exe_file == code_file_;
+}
+
+bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
+ Close();
+ code_file_.clear();
+
+ if (FAILED(CoInitialize(NULL))) {
+ fprintf(stderr, "CoInitialize failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaDataSource> data_source;
+ if (!CreateDiaDataSourceInstance(data_source)) {
+ const int kGuidSize = 64;
+ wchar_t classid[kGuidSize] = {0};
+ StringFromGUID2(CLSID_DiaSource, classid, kGuidSize);
+ fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed "
+ "(msdia*.dll unregistered?)\n", classid);
+ return false;
+ }
+
+ switch (format) {
+ case PDB_FILE:
+ if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
+ fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
+ return false;
+ }
+ break;
+ case EXE_FILE:
+ if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
+ fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
+ return false;
+ }
+ code_file_ = file;
+ break;
+ case ANY_FILE:
+ if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
+ if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
+ fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n",
+ file.c_str());
+ return false;
+ }
+ code_file_ = file;
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown file format\n");
+ return false;
+ }
+
+ if (FAILED(data_source->openSession(&session_))) {
+ fprintf(stderr, "openSession failed\n");
+ }
+
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) {
+ // The line number format is:
+ // <rva> <line number> <source file id>
+ CComPtr<IDiaLineNumber> line;
+ ULONG count;
+
+ while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) {
+ DWORD rva;
+ if (FAILED(line->get_relativeVirtualAddress(&rva))) {
+ fprintf(stderr, "failed to get line rva\n");
+ return false;
+ }
+
+ DWORD length;
+ if (FAILED(line->get_length(&length))) {
+ fprintf(stderr, "failed to get line code length\n");
+ return false;
+ }
+
+ DWORD dia_source_id;
+ if (FAILED(line->get_sourceFileId(&dia_source_id))) {
+ fprintf(stderr, "failed to get line source file id\n");
+ return false;
+ }
+ // duplicate file names are coalesced to share one ID
+ DWORD source_id = GetRealFileID(dia_source_id);
+
+ DWORD line_num;
+ if (FAILED(line->get_lineNumber(&line_num))) {
+ fprintf(stderr, "failed to get line number\n");
+ return false;
+ }
+
+ AddressRangeVector ranges;
+ MapAddressRange(image_map_, AddressRange(rva, length), &ranges);
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ fprintf(output_, "%lx %lx %lu %lu\n", ranges[i].rva, ranges[i].length,
+ line_num, source_id);
+ }
+ line.Release();
+ }
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function,
+ IDiaSymbol *block) {
+ // The function format is:
+ // FUNC <address> <length> <param_stack_size> <function>
+ DWORD rva;
+ if (FAILED(block->get_relativeVirtualAddress(&rva))) {
+ fprintf(stderr, "couldn't get rva\n");
+ return false;
+ }
+
+ ULONGLONG length;
+ if (FAILED(block->get_length(&length))) {
+ fprintf(stderr, "failed to get function length\n");
+ return false;
+ }
+
+ if (length == 0) {
+ // Silently ignore zero-length functions, which can infrequently pop up.
+ return true;
+ }
+
+ CComBSTR name;
+ int stack_param_size;
+ if (!GetSymbolFunctionName(function, &name, &stack_param_size)) {
+ return false;
+ }
+
+ // If the decorated name didn't give the parameter size, try to
+ // calculate it.
+ if (stack_param_size < 0) {
+ stack_param_size = GetFunctionStackParamSize(function);
+ }
+
+ AddressRangeVector ranges;
+ MapAddressRange(image_map_, AddressRange(rva, static_cast<DWORD>(length)),
+ &ranges);
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ fprintf(output_, "FUNC %lx %lx %x %ws\n",
+ ranges[i].rva, ranges[i].length, stack_param_size,
+ name.m_str);
+ }
+
+ CComPtr<IDiaEnumLineNumbers> lines;
+ if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) {
+ return false;
+ }
+
+ if (!PrintLines(lines)) {
+ return false;
+ }
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintSourceFiles() {
+ CComPtr<IDiaSymbol> global;
+ if (FAILED(session_->get_globalScope(&global))) {
+ fprintf(stderr, "get_globalScope failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaEnumSymbols> compilands;
+ if (FAILED(global->findChildren(SymTagCompiland, NULL,
+ nsNone, &compilands))) {
+ fprintf(stderr, "findChildren failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaSymbol> compiland;
+ ULONG count;
+ while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
+ CComPtr<IDiaEnumSourceFiles> source_files;
+ if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) {
+ return false;
+ }
+ CComPtr<IDiaSourceFile> file;
+ while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) {
+ DWORD file_id;
+ if (FAILED(file->get_uniqueId(&file_id))) {
+ return false;
+ }
+
+ CComBSTR file_name;
+ if (FAILED(file->get_fileName(&file_name))) {
+ return false;
+ }
+
+ wstring file_name_string(file_name);
+ if (!FileIDIsCached(file_name_string)) {
+ // this is a new file name, cache it and output a FILE line.
+ CacheFileID(file_name_string, file_id);
+ fwprintf(output_, L"FILE %d %ws\n", file_id, file_name_string.c_str());
+ } else {
+ // this file name has already been seen, just save this
+ // ID for later lookup.
+ StoreDuplicateFileID(file_name_string, file_id);
+ }
+ file.Release();
+ }
+ compiland.Release();
+ }
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintFunctions() {
+ ULONG count = 0;
+ DWORD rva = 0;
+ CComPtr<IDiaSymbol> global;
+ HRESULT hr;
+
+ if (FAILED(session_->get_globalScope(&global))) {
+ fprintf(stderr, "get_globalScope failed\n");
+ return false;
+ }
+
+ CComPtr<IDiaEnumSymbols> symbols = NULL;
+
+ // Find all function symbols first.
+ std::set<DWORD> rvas;
+ hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols);
+
+ if (SUCCEEDED(hr)) {
+ CComPtr<IDiaSymbol> symbol = NULL;
+
+ while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
+ if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
+ // To maintain existing behavior of one symbol per address, place the
+ // rva onto a set here to uniquify them.
+ rvas.insert(rva);
+ } else {
+ fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
+ return false;
+ }
+
+ symbol.Release();
+ }
+
+ symbols.Release();
+ }
+
+ // Find all public symbols. Store public symbols that are not also private
+ // symbols for later.
+ std::set<DWORD> public_only_rvas;
+ hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols);
+
+ if (SUCCEEDED(hr)) {
+ CComPtr<IDiaSymbol> symbol = NULL;
+
+ while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) {
+ if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) {
+ if (rvas.count(rva) == 0) {
+ rvas.insert(rva); // Keep symbols in rva order.
+ public_only_rvas.insert(rva);
+ }
+ } else {
+ fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n");
+ return false;
+ }
+
+ symbol.Release();
+ }
+
+ symbols.Release();
+ }
+
+ std::set<DWORD>::iterator it;
+
+ // For each rva, dump the first symbol DIA knows about at the address.
+ for (it = rvas.begin(); it != rvas.end(); ++it) {
+ CComPtr<IDiaSymbol> symbol = NULL;
+ // If the symbol is not in the public list, look for SymTagFunction. This is
+ // a workaround to a bug where DIA will hang if searching for a private
+ // symbol at an address where only a public symbol exists.
+ // See http://connect.microsoft.com/VisualStudio/feedback/details/722366
+ if (public_only_rvas.count(*it) == 0) {
+ if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) {
+ // Sometimes findSymbolByRVA returns S_OK, but NULL.
+ if (symbol) {
+ if (!PrintFunction(symbol, symbol))
+ return false;
+ symbol.Release();
+ }
+ } else {
+ fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n");
+ return false;
+ }
+ } else if (SUCCEEDED(session_->findSymbolByRVA(*it,
+ SymTagPublicSymbol,
+ &symbol))) {
+ // Sometimes findSymbolByRVA returns S_OK, but NULL.
+ if (symbol) {
+ if (!PrintCodePublicSymbol(symbol))
+ return false;
+ symbol.Release();
+ }
+ } else {
+ fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n");
+ return false;
+ }
+ }
+
+ // When building with PGO, the compiler can split functions into
+ // "hot" and "cold" blocks, and move the "cold" blocks out to separate
+ // pages, so the function can be noncontiguous. To find these blocks,
+ // we have to iterate over all the compilands, and then find blocks
+ // that are children of them. We can then find the lexical parents
+ // of those blocks and print out an extra FUNC line for blocks
+ // that are not contained in their parent functions.
+ CComPtr<IDiaEnumSymbols> compilands;
+ if (FAILED(global->findChildren(SymTagCompiland, NULL,
+ nsNone, &compilands))) {
+ fprintf(stderr, "findChildren failed on the global\n");
+ return false;
+ }
+
+ CComPtr<IDiaSymbol> compiland;
+ while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) {
+ CComPtr<IDiaEnumSymbols> blocks;
+ if (FAILED(compiland->findChildren(SymTagBlock, NULL,
+ nsNone, &blocks))) {
+ fprintf(stderr, "findChildren failed on a compiland\n");
+ return false;
+ }
+
+ CComPtr<IDiaSymbol> block;
+ while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) {
+ // find this block's lexical parent function
+ CComPtr<IDiaSymbol> parent;
+ DWORD tag;
+ if (SUCCEEDED(block->get_lexicalParent(&parent)) &&
+ SUCCEEDED(parent->get_symTag(&tag)) &&
+ tag == SymTagFunction) {
+ // now get the block's offset and the function's offset and size,
+ // and determine if the block is outside of the function
+ DWORD func_rva, block_rva;
+ ULONGLONG func_length;
+ if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) &&
+ SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) &&
+ SUCCEEDED(parent->get_length(&func_length))) {
+ if (block_rva < func_rva || block_rva > (func_rva + func_length)) {
+ if (!PrintFunction(parent, block)) {
+ return false;
+ }
+ }
+ }
+ }
+ parent.Release();
+ block.Release();
+ }
+ blocks.Release();
+ compiland.Release();
+ }
+
+ global.Release();
+ return true;
+}
+
+#undef max
+
+bool PDBSourceLineWriter::PrintFrameDataUsingPDB() {
+ // It would be nice if it were possible to output frame data alongside the
+ // associated function, as is done with line numbers, but the DIA API
+ // doesn't make it possible to get the frame data in that way.
+
+ CComPtr<IDiaEnumFrameData> frame_data_enum;
+ if (!FindTable(session_, &frame_data_enum))
+ return false;
+
+ DWORD last_type = std::numeric_limits<DWORD>::max();
+ DWORD last_rva = std::numeric_limits<DWORD>::max();
+ DWORD last_code_size = 0;
+ DWORD last_prolog_size = std::numeric_limits<DWORD>::max();
+
+ CComPtr<IDiaFrameData> frame_data;
+ ULONG count = 0;
+ while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) &&
+ count == 1) {
+ DWORD type;
+ if (FAILED(frame_data->get_type(&type)))
+ return false;
+
+ DWORD rva;
+ if (FAILED(frame_data->get_relativeVirtualAddress(&rva)))
+ return false;
+
+ DWORD code_size;
+ if (FAILED(frame_data->get_lengthBlock(&code_size)))
+ return false;
+
+ DWORD prolog_size;
+ if (FAILED(frame_data->get_lengthProlog(&prolog_size)))
+ return false;
+
+ // parameter_size is the size of parameters passed on the stack. If any
+ // parameters are not passed on the stack (such as in registers), their
+ // sizes will not be included in parameter_size.
+ DWORD parameter_size;
+ if (FAILED(frame_data->get_lengthParams(&parameter_size)))
+ return false;
+
+ DWORD saved_register_size;
+ if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size)))
+ return false;
+
+ DWORD local_size;
+ if (FAILED(frame_data->get_lengthLocals(&local_size)))
+ return false;
+
+ // get_maxStack can return S_FALSE, just use 0 in that case.
+ DWORD max_stack_size = 0;
+ if (FAILED(frame_data->get_maxStack(&max_stack_size)))
+ return false;
+
+ // get_programString can return S_FALSE, indicating that there is no
+ // program string. In that case, check whether %ebp is used.
+ HRESULT program_string_result;
+ CComBSTR program_string;
+ if (FAILED(program_string_result = frame_data->get_program(
+ &program_string))) {
+ return false;
+ }
+
+ // get_allocatesBasePointer can return S_FALSE, treat that as though
+ // %ebp is not used.
+ BOOL allocates_base_pointer = FALSE;
+ if (program_string_result != S_OK) {
+ if (FAILED(frame_data->get_allocatesBasePointer(
+ &allocates_base_pointer))) {
+ return false;
+ }
+ }
+
+ // Only print out a line if type, rva, code_size, or prolog_size have
+ // changed from the last line. It is surprisingly common (especially in
+ // system library PDBs) for DIA to return a series of identical
+ // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86,
+ // this check reduces the size of the dumped symbol file by a third.
+ if (type != last_type || rva != last_rva || code_size != last_code_size ||
+ prolog_size != last_prolog_size) {
+ // The prolog and the code portions of the frame have to be treated
+ // independently as they may have independently changed in size, or may
+ // even have been split.
+ // NOTE: If epilog size is ever non-zero, we have to do something
+ // similar with it.
+
+ // Figure out where the prolog bytes have landed.
+ AddressRangeVector prolog_ranges;
+ if (prolog_size > 0) {
+ MapAddressRange(image_map_, AddressRange(rva, prolog_size),
+ &prolog_ranges);
+ }
+
+ // And figure out where the code bytes have landed.
+ AddressRangeVector code_ranges;
+ MapAddressRange(image_map_,
+ AddressRange(rva + prolog_size,
+ code_size - prolog_size),
+ &code_ranges);
+
+ struct FrameInfo {
+ DWORD rva;
+ DWORD code_size;
+ DWORD prolog_size;
+ };
+ std::vector<FrameInfo> frame_infos;
+
+ // Special case: The prolog and the code bytes remain contiguous. This is
+ // only done for compactness of the symbol file, and we could actually
+ // be outputting independent frame info for the prolog and code portions.
+ if (prolog_ranges.size() == 1 && code_ranges.size() == 1 &&
+ prolog_ranges[0].end() == code_ranges[0].rva) {
+ FrameInfo fi = { prolog_ranges[0].rva,
+ prolog_ranges[0].length + code_ranges[0].length,
+ prolog_ranges[0].length };
+ frame_infos.push_back(fi);
+ } else {
+ // Otherwise we output the prolog and code frame info independently.
+ for (size_t i = 0; i < prolog_ranges.size(); ++i) {
+ FrameInfo fi = { prolog_ranges[i].rva,
+ prolog_ranges[i].length,
+ prolog_ranges[i].length };
+ frame_infos.push_back(fi);
+ }
+ for (size_t i = 0; i < code_ranges.size(); ++i) {
+ FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 };
+ frame_infos.push_back(fi);
+ }
+ }
+
+ for (size_t i = 0; i < frame_infos.size(); ++i) {
+ const FrameInfo& fi(frame_infos[i]);
+ fprintf(output_, "STACK WIN %lx %lx %lx %lx %x %lx %lx %lx %lx %d ",
+ type, fi.rva, fi.code_size, fi.prolog_size,
+ 0 /* epilog_size */, parameter_size, saved_register_size,
+ local_size, max_stack_size, program_string_result == S_OK);
+ if (program_string_result == S_OK) {
+ fprintf(output_, "%ws\n", program_string.m_str);
+ } else {
+ fprintf(output_, "%d\n", allocates_base_pointer);
+ }
+ }
+
+ last_type = type;
+ last_rva = rva;
+ last_code_size = code_size;
+ last_prolog_size = prolog_size;
+ }
+
+ frame_data.Release();
+ }
+
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintFrameDataUsingEXE() {
+ if (code_file_.empty() && !FindPEFile()) {
+ fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
+ return false;
+ }
+
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string code_file;
+ if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to load %s\n", code_file.c_str());
+ return false;
+ }
+ PIMAGE_OPTIONAL_HEADER64 optional_header =
+ &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader;
+ if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ fprintf(stderr, "Not a PE32+ image\n");
+ return false;
+ }
+
+ // Read Exception Directory
+ DWORD exception_rva = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
+ DWORD exception_size = optional_header->
+ DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY funcs =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ exception_rva,
+ &img->LastRvaSection));
+ for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) {
+ DWORD unwind_rva = funcs[i].UnwindInfoAddress;
+ // handle chaining
+ while (unwind_rva & 0x1) {
+ unwind_rva ^= 0x1;
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+ unwind_rva = chained_func->UnwindInfoAddress;
+ }
+
+ UnwindInfo *unwind_info = static_cast<UnwindInfo *>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ unwind_rva,
+ &img->LastRvaSection));
+
+ DWORD stack_size = 8; // minimal stack size is 8 for RIP
+ DWORD rip_offset = 8;
+ do {
+ for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) {
+ UnwindCode *unwind_code = &unwind_info->unwind_code[c];
+ switch (unwind_code->unwind_operation_code) {
+ case UWOP_PUSH_NONVOL: {
+ stack_size += 8;
+ break;
+ }
+ case UWOP_ALLOC_LARGE: {
+ if (unwind_code->operation_info == 0) {
+ c++;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset * 8;
+ } else {
+ c += 2;
+ if (c < unwind_info->count_of_codes)
+ stack_size += (unwind_code + 1)->frame_offset |
+ ((unwind_code + 2)->frame_offset << 16);
+ }
+ break;
+ }
+ case UWOP_ALLOC_SMALL: {
+ stack_size += unwind_code->operation_info * 8 + 8;
+ break;
+ }
+ case UWOP_SET_FPREG:
+ case UWOP_SAVE_XMM:
+ case UWOP_SAVE_XMM_FAR:
+ break;
+ case UWOP_SAVE_NONVOL:
+ case UWOP_SAVE_XMM128: {
+ c++; // skip slot with offset
+ break;
+ }
+ case UWOP_SAVE_NONVOL_FAR:
+ case UWOP_SAVE_XMM128_FAR: {
+ c += 2; // skip 2 slots with offset
+ break;
+ }
+ case UWOP_PUSH_MACHFRAME: {
+ if (unwind_code->operation_info) {
+ stack_size += 88;
+ } else {
+ stack_size += 80;
+ }
+ rip_offset += 80;
+ break;
+ }
+ }
+ }
+ if (unwind_info->flags & UNW_FLAG_CHAININFO) {
+ PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func =
+ reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>(
+ (unwind_info->unwind_code +
+ ((unwind_info->count_of_codes + 1) & ~1)));
+
+ unwind_info = static_cast<UnwindInfo *>(
+ ImageRvaToVa(img->FileHeader,
+ img->MappedAddress,
+ chained_func->UnwindInfoAddress,
+ &img->LastRvaSection));
+ } else {
+ unwind_info = NULL;
+ }
+ } while (unwind_info);
+ fprintf(output_, "STACK CFI INIT %lx %lx .cfa: $rsp .ra: .cfa %lu - ^\n",
+ funcs[i].BeginAddress,
+ funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset);
+ fprintf(output_, "STACK CFI %lx .cfa: $rsp %lu +\n",
+ funcs[i].BeginAddress, stack_size);
+ }
+
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintFrameData() {
+ PDBModuleInfo info;
+ if (GetModuleInfo(&info) && info.cpu == L"x86_64") {
+ return PrintFrameDataUsingEXE();
+ } else {
+ return PrintFrameDataUsingPDB();
+ }
+ return false;
+}
+
+bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) {
+ BOOL is_code;
+ if (FAILED(symbol->get_code(&is_code))) {
+ return false;
+ }
+ if (!is_code) {
+ return true;
+ }
+
+ DWORD rva;
+ if (FAILED(symbol->get_relativeVirtualAddress(&rva))) {
+ return false;
+ }
+
+ CComBSTR name;
+ int stack_param_size;
+ if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) {
+ return false;
+ }
+
+ AddressRangeVector ranges;
+ MapAddressRange(image_map_, AddressRange(rva, 1), &ranges);
+ for (size_t i = 0; i < ranges.size(); ++i) {
+ fprintf(output_, "PUBLIC %lx %x %ws\n", ranges[i].rva,
+ stack_param_size > 0 ? stack_param_size : 0,
+ name.m_str);
+ }
+
+ // Now walk the function in the original untranslated space, asking DIA
+ // what function is at that location, stepping through OMAP blocks. If
+ // we're still in the same function, emit another entry, because the
+ // symbol could have been split into multiple pieces. If we've gotten to
+ // another symbol in the original address space, then we're done for
+ // this symbol. See https://crbug.com/678874.
+ for (;;) {
+ // This steps to the next block in the original image. Simply doing
+ // rva++ would also be correct, but would emit tons of unnecessary
+ // entries.
+ rva = image_map_.subsequent_rva_block[rva];
+ if (rva == 0)
+ break;
+
+ CComPtr<IDiaSymbol> next_sym = NULL;
+ LONG displacement;
+ if (FAILED(session_->findSymbolByRVAEx(rva, SymTagPublicSymbol, &next_sym,
+ &displacement))) {
+ break;
+ }
+
+ if (!SymbolsMatch(symbol, next_sym))
+ break;
+
+ AddressRangeVector next_ranges;
+ MapAddressRange(image_map_, AddressRange(rva, 1), &next_ranges);
+ for (size_t i = 0; i < next_ranges.size(); ++i) {
+ fprintf(output_, "PUBLIC %lx %x %ws\n", next_ranges[i].rva,
+ stack_param_size > 0 ? stack_param_size : 0, name.m_str);
+ }
+ }
+
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintPDBInfo() {
+ PDBModuleInfo info;
+ if (!GetModuleInfo(&info)) {
+ return false;
+ }
+
+ // Hard-code "windows" for the OS because that's the only thing that makes
+ // sense for PDB files. (This might not be strictly correct for Windows CE
+ // support, but we don't care about that at the moment.)
+ fprintf(output_, "MODULE windows %ws %ws %ws\n",
+ info.cpu.c_str(), info.debug_identifier.c_str(),
+ info.debug_file.c_str());
+
+ return true;
+}
+
+bool PDBSourceLineWriter::PrintPEInfo() {
+ PEModuleInfo info;
+ if (!GetPEInfo(&info)) {
+ return false;
+ }
+
+ fprintf(output_, "INFO CODE_ID %ws %ws\n",
+ info.code_identifier.c_str(),
+ info.code_file.c_str());
+ return true;
+}
+
+// wcstol_positive_strict is sort of like wcstol, but much stricter. string
+// should be a buffer pointing to a null-terminated string containing only
+// decimal digits. If the entire string can be converted to an integer
+// without overflowing, and there are no non-digit characters before the
+// result is set to the value and this function returns true. Otherwise,
+// this function returns false. This is an alternative to the strtol, atoi,
+// and scanf families, which are not as strict about input and in some cases
+// don't provide a good way for the caller to determine if a conversion was
+// successful.
+static bool wcstol_positive_strict(wchar_t *string, int *result) {
+ int value = 0;
+ for (wchar_t *c = string; *c != '\0'; ++c) {
+ int last_value = value;
+ value *= 10;
+ // Detect overflow.
+ if (value / 10 != last_value || value < 0) {
+ return false;
+ }
+ if (*c < '0' || *c > '9') {
+ return false;
+ }
+ unsigned int c_value = *c - '0';
+ last_value = value;
+ value += c_value;
+ // Detect overflow.
+ if (value < last_value) {
+ return false;
+ }
+ // Forbid leading zeroes unless the string is just "0".
+ if (value == 0 && *(c+1) != '\0') {
+ return false;
+ }
+ }
+ *result = value;
+ return true;
+}
+
+bool PDBSourceLineWriter::FindPEFile() {
+ CComPtr<IDiaSymbol> global;
+ if (FAILED(session_->get_globalScope(&global))) {
+ fprintf(stderr, "get_globalScope failed\n");
+ return false;
+ }
+
+ CComBSTR symbols_file;
+ if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) {
+ wstring file(symbols_file);
+
+ // Look for an EXE or DLL file.
+ const wchar_t *extensions[] = { L"exe", L"dll" };
+ for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) {
+ size_t dot_pos = file.find_last_of(L".");
+ if (dot_pos != wstring::npos) {
+ file.replace(dot_pos + 1, wstring::npos, extensions[i]);
+ // Check if this file exists.
+ if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) {
+ code_file_ = file;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// static
+bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function,
+ BSTR *name,
+ int *stack_param_size) {
+ *stack_param_size = -1;
+ const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS |
+ UNDNAME_NO_FUNCTION_RETURNS |
+ UNDNAME_NO_ALLOCATION_MODEL |
+ UNDNAME_NO_ALLOCATION_LANGUAGE |
+ UNDNAME_NO_THISTYPE |
+ UNDNAME_NO_ACCESS_SPECIFIERS |
+ UNDNAME_NO_THROW_SIGNATURES |
+ UNDNAME_NO_MEMBER_TYPE |
+ UNDNAME_NO_RETURN_UDT_MODEL |
+ UNDNAME_NO_ECSU;
+
+ // Use get_undecoratedNameEx to get readable C++ names with arguments.
+ if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) {
+ if (function->get_name(name) != S_OK) {
+ fprintf(stderr, "failed to get function name\n");
+ return false;
+ }
+
+ // It's possible for get_name to return an empty string, so
+ // special-case that.
+ if (wcscmp(*name, L"") == 0) {
+ SysFreeString(*name);
+ // dwarf_cu_to_module.cc uses "<name omitted>", so match that.
+ *name = SysAllocString(L"<name omitted>");
+ return true;
+ }
+
+ // If a name comes from get_name because no undecorated form existed,
+ // it's already formatted properly to be used as output. Don't do any
+ // additional processing.
+ //
+ // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's.
+ // This will result in calling get_name for some C++ symbols, so
+ // all of the parameter and return type information may not be included in
+ // the name string.
+ } else {
+ // C++ uses a bogus "void" argument for functions and methods that don't
+ // take any parameters. Take it out of the undecorated name because it's
+ // ugly and unnecessary.
+ const wchar_t *replace_string = L"(void)";
+ const size_t replace_length = wcslen(replace_string);
+ const wchar_t *replacement_string = L"()";
+ size_t length = wcslen(*name);
+ if (length >= replace_length) {
+ wchar_t *name_end = *name + length - replace_length;
+ if (wcscmp(name_end, replace_string) == 0) {
+ WindowsStringUtils::safe_wcscpy(name_end, replace_length,
+ replacement_string);
+ length = wcslen(*name);
+ }
+ }
+
+ // Undecorate names used for stdcall and fastcall. These names prefix
+ // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it
+ // with '@' followed by the number of bytes of parameters, in decimal.
+ // If such a name is found, take note of the size and undecorate it.
+ // Only do this for names that aren't C++, which is determined based on
+ // whether the undecorated name contains any ':' or '(' characters.
+ if (!wcschr(*name, ':') && !wcschr(*name, '(') &&
+ (*name[0] == '_' || *name[0] == '@')) {
+ wchar_t *last_at = wcsrchr(*name + 1, '@');
+ if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) {
+ // If this function adheres to the fastcall convention, it accepts up
+ // to the first 8 bytes of parameters in registers (%ecx and %edx).
+ // We're only interested in the stack space used for parameters, so
+ // so subtract 8 and don't let the size go below 0.
+ if (*name[0] == '@') {
+ if (*stack_param_size > 8) {
+ *stack_param_size -= 8;
+ } else {
+ *stack_param_size = 0;
+ }
+ }
+
+ // Undecorate the name by moving it one character to the left in its
+ // buffer, and terminating it where the last '@' had been.
+ WindowsStringUtils::safe_wcsncpy(*name, length,
+ *name + 1, last_at - *name - 1);
+ } else if (*name[0] == '_') {
+ // This symbol's name is encoded according to the cdecl rules. The
+ // name doesn't end in a '@' character followed by a decimal positive
+ // integer, so it's not a stdcall name. Strip off the leading
+ // underscore.
+ WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length);
+ }
+ }
+ }
+
+ return true;
+}
+
+// static
+int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) {
+ // This implementation is highly x86-specific.
+
+ // Gather the symbols corresponding to data.
+ CComPtr<IDiaEnumSymbols> data_children;
+ if (FAILED(function->findChildren(SymTagData, NULL, nsNone,
+ &data_children))) {
+ return 0;
+ }
+
+ // lowest_base is the lowest %ebp-relative byte offset used for a parameter.
+ // highest_end is one greater than the highest offset (i.e. base + length).
+ // Stack parameters are assumed to be contiguous, because in reality, they
+ // are.
+ int lowest_base = INT_MAX;
+ int highest_end = INT_MIN;
+
+ CComPtr<IDiaSymbol> child;
+ DWORD count;
+ while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) {
+ // If any operation fails at this point, just proceed to the next child.
+ // Use the next_child label instead of continue because child needs to
+ // be released before it's reused. Declare constructable/destructable
+ // types early to avoid gotos that cross initializations.
+ CComPtr<IDiaSymbol> child_type;
+
+ // DataIsObjectPtr is only used for |this|. Because |this| can be passed
+ // as a stack parameter, look for it in addition to traditional
+ // parameters.
+ DWORD child_kind;
+ if (FAILED(child->get_dataKind(&child_kind)) ||
+ (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) {
+ goto next_child;
+ }
+
+ // Only concentrate on register-relative parameters. Parameters may also
+ // be enregistered (passed directly in a register), but those don't
+ // consume any stack space, so they're not of interest.
+ DWORD child_location_type;
+ if (FAILED(child->get_locationType(&child_location_type)) ||
+ child_location_type != LocIsRegRel) {
+ goto next_child;
+ }
+
+ // Of register-relative parameters, the only ones that make any sense are
+ // %ebp- or %esp-relative. Note that MSVC's debugging information always
+ // gives parameters as %ebp-relative even when a function doesn't use a
+ // traditional frame pointer and stack parameters are accessed relative to
+ // %esp, so just look for %ebp-relative parameters. If you wanted to
+ // access parameters, you'd probably want to treat these %ebp-relative
+ // offsets as if they were relative to %esp before a function's prolog
+ // executed.
+ DWORD child_register;
+ if (FAILED(child->get_registerId(&child_register)) ||
+ child_register != CV_REG_EBP) {
+ goto next_child;
+ }
+
+ LONG child_register_offset;
+ if (FAILED(child->get_offset(&child_register_offset))) {
+ goto next_child;
+ }
+
+ // IDiaSymbol::get_type can succeed but still pass back a NULL value.
+ if (FAILED(child->get_type(&child_type)) || !child_type) {
+ goto next_child;
+ }
+
+ ULONGLONG child_length;
+ if (FAILED(child_type->get_length(&child_length))) {
+ goto next_child;
+ }
+
+ int child_end = child_register_offset + static_cast<ULONG>(child_length);
+ if (child_register_offset < lowest_base) {
+ lowest_base = child_register_offset;
+ }
+ if (child_end > highest_end) {
+ highest_end = child_end;
+ }
+
+next_child:
+ child.Release();
+ }
+
+ int param_size = 0;
+ // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest
+ // possible address to find a stack parameter before executing a function's
+ // prolog (see above). Some optimizations cause parameter offsets to be
+ // lower than 4, but we're not concerned with those because we're only
+ // looking for parameters contained in addresses higher than where the
+ // return address is stored.
+ if (lowest_base < 4) {
+ lowest_base = 4;
+ }
+ if (highest_end > lowest_base) {
+ // All stack parameters are pushed as at least 4-byte quantities. If the
+ // last type was narrower than 4 bytes, promote it. This assumes that all
+ // parameters' offsets are 4-byte-aligned, which is always the case. Only
+ // worry about the last type, because we're not summing the type sizes,
+ // just looking at the lowest and highest offsets.
+ int remainder = highest_end % 4;
+ if (remainder) {
+ highest_end += 4 - remainder;
+ }
+
+ param_size = highest_end - lowest_base;
+ }
+
+ return param_size;
+}
+
+bool PDBSourceLineWriter::WriteMap(FILE *map_file) {
+ output_ = map_file;
+
+ // Load the OMAP information, and disable auto-translation of addresses in
+ // preference of doing it ourselves.
+ OmapData omap_data;
+ if (!GetOmapDataAndDisableTranslation(session_, &omap_data))
+ return false;
+ BuildImageMap(omap_data, &image_map_);
+
+ bool ret = PrintPDBInfo();
+ // This is not a critical piece of the symbol file.
+ PrintPEInfo();
+ ret = ret &&
+ PrintSourceFiles() &&
+ PrintFunctions() &&
+ PrintFrameData();
+
+ output_ = NULL;
+ return ret;
+}
+
+void PDBSourceLineWriter::Close() {
+ session_.Release();
+}
+
+bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) {
+ if (!info) {
+ return false;
+ }
+
+ info->debug_file.clear();
+ info->debug_identifier.clear();
+ info->cpu.clear();
+
+ CComPtr<IDiaSymbol> global;
+ if (FAILED(session_->get_globalScope(&global))) {
+ return false;
+ }
+
+ DWORD machine_type;
+ // get_machineType can return S_FALSE.
+ if (global->get_machineType(&machine_type) == S_OK) {
+ // The documentation claims that get_machineType returns a value from
+ // the CV_CPU_TYPE_e enumeration, but that's not the case.
+ // Instead, it returns one of the IMAGE_FILE_MACHINE values as
+ // defined here:
+ // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx
+ switch (machine_type) {
+ case IMAGE_FILE_MACHINE_I386:
+ info->cpu = L"x86";
+ break;
+ case IMAGE_FILE_MACHINE_AMD64:
+ info->cpu = L"x86_64";
+ break;
+ default:
+ info->cpu = L"unknown";
+ break;
+ }
+ } else {
+ // Unexpected, but handle gracefully.
+ info->cpu = L"unknown";
+ }
+
+ // DWORD* and int* are not compatible. This is clean and avoids a cast.
+ DWORD age;
+ if (FAILED(global->get_age(&age))) {
+ return false;
+ }
+
+ bool uses_guid;
+ if (!UsesGUID(&uses_guid)) {
+ return false;
+ }
+
+ if (uses_guid) {
+ GUID guid;
+ if (FAILED(global->get_guid(&guid))) {
+ return false;
+ }
+
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t age_string[9];
+ swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
+ L"%x", age);
+
+ // remove when VC++7.1 is no longer supported
+ age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
+
+ info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
+ info->debug_identifier.append(age_string);
+ } else {
+ DWORD signature;
+ if (FAILED(global->get_signature(&signature))) {
+ return false;
+ }
+
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ wchar_t identifier_string[17];
+ swprintf(identifier_string,
+ sizeof(identifier_string) / sizeof(identifier_string[0]),
+ L"%08X%x", signature, age);
+
+ // remove when VC++7.1 is no longer supported
+ identifier_string[sizeof(identifier_string) /
+ sizeof(identifier_string[0]) - 1] = L'\0';
+
+ info->debug_identifier = identifier_string;
+ }
+
+ CComBSTR debug_file_string;
+ if (FAILED(global->get_symbolsFileName(&debug_file_string))) {
+ return false;
+ }
+ info->debug_file =
+ WindowsStringUtils::GetBaseName(wstring(debug_file_string));
+
+ return true;
+}
+
+bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) {
+ if (!info) {
+ return false;
+ }
+
+ if (code_file_.empty() && !FindPEFile()) {
+ fprintf(stderr, "Couldn't locate EXE or DLL file.\n");
+ return false;
+ }
+
+ // Convert wchar to native charset because ImageLoad only takes
+ // a PSTR as input.
+ string code_file;
+ if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) {
+ return false;
+ }
+
+ AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL));
+ if (!img) {
+ fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str());
+ return false;
+ }
+
+ info->code_file = WindowsStringUtils::GetBaseName(code_file_);
+
+ // The date and time that the file was created by the linker.
+ DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp;
+ // The size of the file in bytes, including all headers.
+ DWORD SizeOfImage = 0;
+ PIMAGE_OPTIONAL_HEADER64 opt =
+ &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader;
+ if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ // 64-bit PE file.
+ SizeOfImage = opt->SizeOfImage;
+ } else {
+ // 32-bit PE file.
+ SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage;
+ }
+ wchar_t code_identifier[32];
+ swprintf(code_identifier,
+ sizeof(code_identifier) / sizeof(code_identifier[0]),
+ L"%08X%X", TimeDateStamp, SizeOfImage);
+ info->code_identifier = code_identifier;
+
+ return true;
+}
+
+bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) {
+ if (!uses_guid)
+ return false;
+
+ CComPtr<IDiaSymbol> global;
+ if (FAILED(session_->get_globalScope(&global)))
+ return false;
+
+ GUID guid;
+ if (FAILED(global->get_guid(&guid)))
+ return false;
+
+ DWORD signature;
+ if (FAILED(global->get_signature(&signature)))
+ return false;
+
+ // There are two possibilities for guid: either it's a real 128-bit GUID
+ // as identified in a code module by a new-style CodeView record, or it's
+ // a 32-bit signature (timestamp) as identified by an old-style record.
+ // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h.
+ //
+ // Because DIA doesn't provide a way to directly determine whether a module
+ // uses a GUID or a 32-bit signature, this code checks whether the first 32
+ // bits of guid are the same as the signature, and if the rest of guid is
+ // zero. If so, then with a pretty high degree of certainty, there's an
+ // old-style CodeView record in use. This method will only falsely find an
+ // an old-style CodeView record if a real 128-bit GUID has its first 32
+ // bits set the same as the module's signature (timestamp) and the rest of
+ // the GUID is set to 0. This is highly unlikely.
+
+ GUID signature_guid = {signature}; // 0-initializes other members
+ *uses_guid = !IsEqualGUID(guid, signature_guid);
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.h b/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.h
new file mode 100644
index 0000000..e9e89bb
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/pdb_source_line_writer.h
@@ -0,0 +1,257 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output
+// a line/address map for use with BasicSourceLineResolver.
+
+#ifndef COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_
+#define COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_
+
+#include <atlcomcli.h>
+
+#include <unordered_map>
+#include <string>
+
+#include "common/windows/omap.h"
+
+struct IDiaEnumLineNumbers;
+struct IDiaSession;
+struct IDiaSymbol;
+
+namespace google_breakpad {
+
+using std::wstring;
+using std::unordered_map;
+
+// A structure that carries information that identifies a pdb file.
+struct PDBModuleInfo {
+ public:
+ // The basename of the pdb file from which information was loaded.
+ wstring debug_file;
+
+ // The pdb's identifier. For recent pdb files, the identifier consists
+ // of the pdb's guid, in uppercase hexadecimal form without any dashes
+ // or separators, followed immediately by the pdb's age, also in
+ // uppercase hexadecimal form. For older pdb files which have no guid,
+ // the identifier is the pdb's 32-bit signature value, in zero-padded
+ // hexadecimal form, followed immediately by the pdb's age, in lowercase
+ // hexadecimal form.
+ wstring debug_identifier;
+
+ // A string identifying the cpu that the pdb is associated with.
+ // Currently, this may be "x86" or "unknown".
+ wstring cpu;
+};
+
+// A structure that carries information that identifies a PE file,
+// either an EXE or a DLL.
+struct PEModuleInfo {
+ // The basename of the PE file.
+ wstring code_file;
+
+ // The PE file's code identifier, which consists of its timestamp
+ // and file size concatenated together into a single hex string.
+ // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and
+ // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp
+ // documentation.) This is not well documented, if it's documented
+ // at all, but it's what symstore does and what DbgHelp supports.
+ wstring code_identifier;
+};
+
+class PDBSourceLineWriter {
+ public:
+ enum FileFormat {
+ PDB_FILE, // a .pdb file containing debug symbols
+ EXE_FILE, // a .exe or .dll file
+ ANY_FILE // try PDB_FILE and then EXE_FILE
+ };
+
+ explicit PDBSourceLineWriter();
+ ~PDBSourceLineWriter();
+
+ // Opens the given file. For executable files, the corresponding pdb
+ // file must be available; Open will be if it is not.
+ // If there is already a pdb file open, it is automatically closed.
+ // Returns true on success.
+ bool Open(const wstring &file, FileFormat format);
+
+ // Sets the code file full path. This is optional for 32-bit modules. It is
+ // also optional for 64-bit modules when there is an executable file stored
+ // in the same directory as the PDB file. It is only required for 64-bit
+ // modules when the executable file is not in the same location as the PDB
+ // file and it must be called after Open() and before WriteMap().
+ // If Open() was called for an executable file, then it is an error to call
+ // SetCodeFile() with a different file path and it will return false.
+ bool SetCodeFile(const wstring &exe_file);
+
+ // Writes a map file from the current pdb file to the given file stream.
+ // Returns true on success.
+ bool WriteMap(FILE *map_file);
+
+ // Closes the current pdb file and its associated resources.
+ void Close();
+
+ // Retrieves information about the module's debugging file. Returns
+ // true on success and false on failure.
+ bool GetModuleInfo(PDBModuleInfo *info);
+
+ // Retrieves information about the module's PE file. Returns
+ // true on success and false on failure.
+ bool GetPEInfo(PEModuleInfo *info);
+
+ // Sets uses_guid to true if the opened file uses a new-style CodeView
+ // record with a 128-bit GUID, or false if the opened file uses an old-style
+ // CodeView record. When no GUID is available, a 32-bit signature should be
+ // used to identify the module instead. If the information cannot be
+ // determined, this method returns false.
+ bool UsesGUID(bool *uses_guid);
+
+ private:
+ // Outputs the line/address pairs for each line in the enumerator.
+ // Returns true on success.
+ bool PrintLines(IDiaEnumLineNumbers *lines);
+
+ // Outputs a function address and name, followed by its source line list.
+ // block can be the same object as function, or it can be a reference
+ // to a code block that is lexically part of this function, but
+ // resides at a separate address.
+ // Returns true on success.
+ bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block);
+
+ // Outputs all functions as described above. Returns true on success.
+ bool PrintFunctions();
+
+ // Outputs all of the source files in the session's pdb file.
+ // Returns true on success.
+ bool PrintSourceFiles();
+
+ // Outputs all of the frame information necessary to construct stack
+ // backtraces in the absence of frame pointers. For x86 data stored in
+ // .pdb files. Returns true on success.
+ bool PrintFrameDataUsingPDB();
+
+ // Outputs all of the frame information necessary to construct stack
+ // backtraces in the absence of frame pointers. For x64 data stored in
+ // .exe, .dll files. Returns true on success.
+ bool PrintFrameDataUsingEXE();
+
+ // Outputs all of the frame information necessary to construct stack
+ // backtraces in the absence of frame pointers. Returns true on success.
+ bool PrintFrameData();
+
+ // Outputs a single public symbol address and name, if the symbol corresponds
+ // to a code address. Returns true on success. If symbol is does not
+ // correspond to code, returns true without outputting anything.
+ bool PrintCodePublicSymbol(IDiaSymbol *symbol);
+
+ // Outputs a line identifying the PDB file that is being dumped, along with
+ // its uuid and age.
+ bool PrintPDBInfo();
+
+ // Outputs a line identifying the PE file corresponding to the PDB
+ // file that is being dumped, along with its code identifier,
+ // which consists of its timestamp and file size.
+ bool PrintPEInfo();
+
+ // Returns true if this filename has already been seen,
+ // and an ID is stored for it, or false if it has not.
+ bool FileIDIsCached(const wstring &file) {
+ return unique_files_.find(file) != unique_files_.end();
+ }
+
+ // Cache this filename and ID for later reuse.
+ void CacheFileID(const wstring &file, DWORD id) {
+ unique_files_[file] = id;
+ }
+
+ // Store this ID in the cache as a duplicate for this filename.
+ void StoreDuplicateFileID(const wstring &file, DWORD id) {
+ unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file);
+ if (iter != unique_files_.end()) {
+ // map this id to the previously seen one
+ file_ids_[id] = iter->second;
+ }
+ }
+
+ // Given a file's unique ID, return the ID that should be used to
+ // reference it. There may be multiple files with identical filenames
+ // but different unique IDs. The cache attempts to coalesce these into
+ // one ID per unique filename.
+ DWORD GetRealFileID(DWORD id) {
+ unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id);
+ if (iter == file_ids_.end())
+ return id;
+ return iter->second;
+ }
+
+ // Find the PE file corresponding to the loaded PDB file, and
+ // set the code_file_ member. Returns false on failure.
+ bool FindPEFile();
+
+ // Returns the function name for a symbol. If possible, the name is
+ // undecorated. If the symbol's decorated form indicates the size of
+ // parameters on the stack, this information is returned in stack_param_size.
+ // Returns true on success. If the symbol doesn't encode parameter size
+ // information, stack_param_size is set to -1.
+ static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name,
+ int *stack_param_size);
+
+ // Returns the number of bytes of stack space used for a function's
+ // parameters. function must have the tag SymTagFunction. In the event of
+ // a failure, returns 0, which is also a valid number of bytes.
+ static int GetFunctionStackParamSize(IDiaSymbol *function);
+
+ // The filename of the PE file corresponding to the currently-open
+ // pdb file.
+ wstring code_file_;
+
+ // The session for the currently-open pdb file.
+ CComPtr<IDiaSession> session_;
+
+ // The current output file for this WriteMap invocation.
+ FILE *output_;
+
+ // There may be many duplicate filenames with different IDs.
+ // This maps from the DIA "unique ID" to a single ID per unique
+ // filename.
+ unordered_map<DWORD, DWORD> file_ids_;
+ // This maps unique filenames to file IDs.
+ unordered_map<wstring, DWORD> unique_files_;
+
+ // This is used for calculating post-transform symbol addresses and lengths.
+ ImageMap image_map_;
+
+ // Disallow copy ctor and operator=
+ PDBSourceLineWriter(const PDBSourceLineWriter&);
+ void operator=(const PDBSourceLineWriter&);
+};
+
+} // namespace google_breakpad
+
+#endif // COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_
diff --git a/3rdParty/Breakpad/src/common/windows/string_utils-inl.h b/3rdParty/Breakpad/src/common/windows/string_utils-inl.h
index d281aaa..9b63607 100644
--- a/3rdParty/Breakpad/src/common/windows/string_utils-inl.h
+++ b/3rdParty/Breakpad/src/common/windows/string_utils-inl.h
@@ -30,8 +30,8 @@
// string_utils-inl.h: Safer string manipulation on Windows, supporting
// pre-MSVC8 environments.
-#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__
-#define COMMON_WINDOWS_STRING_UTILS_INL_H__
+#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H_
+#define COMMON_WINDOWS_STRING_UTILS_INL_H_
#include <stdarg.h>
#include <wchar.h>
@@ -139,4 +139,4 @@ inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
} // namespace google_breakpad
-#endif // COMMON_WINDOWS_STRING_UTILS_INL_H__
+#endif // COMMON_WINDOWS_STRING_UTILS_INL_H_
diff --git a/3rdParty/Breakpad/src/common/windows/string_utils.cc b/3rdParty/Breakpad/src/common/windows/string_utils.cc
new file mode 100644
index 0000000..2728000
--- /dev/null
+++ b/3rdParty/Breakpad/src/common/windows/string_utils.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cassert>
+#include <vector>
+
+#include "common/windows/string_utils-inl.h"
+
+namespace google_breakpad {
+
+// static
+wstring WindowsStringUtils::GetBaseName(const wstring &filename) {
+ wstring base_name(filename);
+ size_t slash_pos = base_name.find_last_of(L"/\\");
+ if (slash_pos != wstring::npos) {
+ base_name.erase(0, slash_pos + 1);
+ }
+ return base_name;
+}
+
+// static
+bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) {
+ assert(wcs);
+
+ // First, determine the length of the destination buffer.
+ size_t wcs_length;
+
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ errno_t err;
+ if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) {
+ return false;
+ }
+ assert(wcs_length > 0);
+#else // _MSC_VER >= 1400
+ if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) == (size_t)-1) {
+ return false;
+ }
+
+ // Leave space for the 0-terminator.
+ ++wcs_length;
+#endif // _MSC_VER >= 1400
+
+ std::vector<wchar_t> wcs_v(wcs_length);
+
+ // Now, convert.
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(),
+ _TRUNCATE)) != 0) {
+ return false;
+ }
+#else // _MSC_VER >= 1400
+ if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) == (size_t)-1) {
+ return false;
+ }
+
+ // Ensure presence of 0-terminator.
+ wcs_v[wcs_length - 1] = '\0';
+#endif // _MSC_VER >= 1400
+
+ *wcs = &wcs_v[0];
+ return true;
+}
+
+// static
+bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) {
+ assert(mbs);
+
+ // First, determine the length of the destination buffer.
+ size_t mbs_length;
+
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ errno_t err;
+ if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) {
+ return false;
+ }
+ assert(mbs_length > 0);
+#else // _MSC_VER >= 1400
+ if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) == (size_t)-1) {
+ return false;
+ }
+
+ // Leave space for the 0-terminator.
+ ++mbs_length;
+#endif // _MSC_VER >= 1400
+
+ std::vector<char> mbs_v(mbs_length);
+
+ // Now, convert.
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(),
+ _TRUNCATE)) != 0) {
+ return false;
+ }
+#else // _MSC_VER >= 1400
+ if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) == (size_t)-1) {
+ return false;
+ }
+
+ // Ensure presence of 0-terminator.
+ mbs_v[mbs_length - 1] = '\0';
+#endif // _MSC_VER >= 1400
+
+ *mbs = &mbs_v[0];
+ return true;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/config.h.in b/3rdParty/Breakpad/src/config.h.in
new file mode 100644
index 0000000..618e283
--- /dev/null
+++ b/3rdParty/Breakpad/src/config.h.in
@@ -0,0 +1,91 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the <a.out.h> header file. */
+#undef HAVE_A_OUT_H
+
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
+/* Define to 1 if you have the `getrandom' function. */
+#undef HAVE_GETRANDOM
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/random.h> header file. */
+#undef HAVE_SYS_RANDOM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Fallback definition for old systems */
+#undef O_CLOEXEC
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/breakpad_types.h b/3rdParty/Breakpad/src/google_breakpad/common/breakpad_types.h
index 926b47f..d882804 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/breakpad_types.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/breakpad_types.h
@@ -31,7 +31,7 @@
*
* (This is C99 source, please don't corrupt it with C++.)
*
- * This file ensures that types u_intN_t are defined for N = 8, 16, 32, and
+ * This file ensures that types uintN_t are defined for N = 8, 16, 32, and
* 64. Types of precise widths are crucial to the task of writing data
* structures on one platform and reading them on another.
*
@@ -40,38 +40,23 @@
#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
-#ifndef _WIN32
+#if (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
+ !defined(__STDC_FORMAT_MACROS)
+#error "inttypes.h has already been included before this header file, but "
+#error "without __STDC_FORMAT_MACROS defined."
+#endif
-#include <sys/types.h>
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */
#include <inttypes.h>
-#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__))
-typedef uint8_t u_int8_t;
-typedef uint16_t u_int16_t;
-typedef uint32_t u_int32_t;
-typedef uint64_t u_int64_t;
-#endif
-
-#else /* !_WIN32 */
-
-#include <WTypes.h>
-
-typedef unsigned __int8 u_int8_t;
-typedef unsigned __int16 u_int16_t;
-typedef unsigned __int32 u_int32_t;
-typedef unsigned __int64 u_int64_t;
-
-#endif /* !_WIN32 */
-
typedef struct {
- u_int64_t high;
- u_int64_t low;
-} u_int128_t;
+ uint64_t high;
+ uint64_t low;
+} uint128_struct;
-typedef u_int64_t breakpad_time_t;
+typedef uint64_t breakpad_time_t;
/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
* llx, which is the format string for "long long" - this is a 64-bit
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_amd64.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
index fa6a996..4256706 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
@@ -67,7 +67,7 @@
* equivalent types and values in the Windows Platform SDK are given in
* comments.
*
- * Author: Mark Mentovai
+ * Author: Mark Mentovai
* Change to split into its own file: Neal Sidhwaney */
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
@@ -79,22 +79,22 @@
*/
typedef struct {
- u_int16_t control_word;
- u_int16_t status_word;
- u_int8_t tag_word;
- u_int8_t reserved1;
- u_int16_t error_opcode;
- u_int32_t error_offset;
- u_int16_t error_selector;
- u_int16_t reserved2;
- u_int32_t data_offset;
- u_int16_t data_selector;
- u_int16_t reserved3;
- u_int32_t mx_csr;
- u_int32_t mx_csr_mask;
- u_int128_t float_registers[8];
- u_int128_t xmm_registers[16];
- u_int8_t reserved4[96];
+ uint16_t control_word;
+ uint16_t status_word;
+ uint8_t tag_word;
+ uint8_t reserved1;
+ uint16_t error_opcode;
+ uint32_t error_offset;
+ uint16_t error_selector;
+ uint16_t reserved2;
+ uint32_t data_offset;
+ uint16_t data_selector;
+ uint16_t reserved3;
+ uint32_t mx_csr;
+ uint32_t mx_csr_mask;
+ uint128_struct float_registers[8];
+ uint128_struct xmm_registers[16];
+ uint8_t reserved4[96];
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
#define MD_CONTEXT_AMD64_VR_COUNT 26
@@ -103,63 +103,63 @@ typedef struct {
/*
* Register parameter home addresses.
*/
- u_int64_t p1_home;
- u_int64_t p2_home;
- u_int64_t p3_home;
- u_int64_t p4_home;
- u_int64_t p5_home;
- u_int64_t p6_home;
+ uint64_t p1_home;
+ uint64_t p2_home;
+ uint64_t p3_home;
+ uint64_t p4_home;
+ uint64_t p5_home;
+ uint64_t p6_home;
/* The next field determines the layout of the structure, and which parts
* of it are populated */
- u_int32_t context_flags;
- u_int32_t mx_csr;
+ uint32_t context_flags;
+ uint32_t mx_csr;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
- u_int16_t cs;
+ uint16_t cs;
/* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
- u_int16_t ds;
- u_int16_t es;
- u_int16_t fs;
- u_int16_t gs;
+ uint16_t ds;
+ uint16_t es;
+ uint16_t fs;
+ uint16_t gs;
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
- u_int16_t ss;
- u_int32_t eflags;
-
+ uint16_t ss;
+ uint32_t eflags;
+
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
- u_int64_t dr0;
- u_int64_t dr1;
- u_int64_t dr2;
- u_int64_t dr3;
- u_int64_t dr6;
- u_int64_t dr7;
+ uint64_t dr0;
+ uint64_t dr1;
+ uint64_t dr2;
+ uint64_t dr3;
+ uint64_t dr6;
+ uint64_t dr7;
/* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
- u_int64_t rax;
- u_int64_t rcx;
- u_int64_t rdx;
- u_int64_t rbx;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rbx;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
- u_int64_t rsp;
+ uint64_t rsp;
/* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
- u_int64_t rbp;
- u_int64_t rsi;
- u_int64_t rdi;
- u_int64_t r8;
- u_int64_t r9;
- u_int64_t r10;
- u_int64_t r11;
- u_int64_t r12;
- u_int64_t r13;
- u_int64_t r14;
- u_int64_t r15;
+ uint64_t rbp;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
/* The next register is included with MD_CONTEXT_AMD64_CONTROL */
- u_int64_t rip;
+ uint64_t rip;
/* The next set of registers are included with
* MD_CONTEXT_AMD64_FLOATING_POINT
@@ -167,37 +167,37 @@ typedef struct {
union {
MDXmmSaveArea32AMD64 flt_save;
struct {
- u_int128_t header[2];
- u_int128_t legacy[8];
- u_int128_t xmm0;
- u_int128_t xmm1;
- u_int128_t xmm2;
- u_int128_t xmm3;
- u_int128_t xmm4;
- u_int128_t xmm5;
- u_int128_t xmm6;
- u_int128_t xmm7;
- u_int128_t xmm8;
- u_int128_t xmm9;
- u_int128_t xmm10;
- u_int128_t xmm11;
- u_int128_t xmm12;
- u_int128_t xmm13;
- u_int128_t xmm14;
- u_int128_t xmm15;
+ uint128_struct header[2];
+ uint128_struct legacy[8];
+ uint128_struct xmm0;
+ uint128_struct xmm1;
+ uint128_struct xmm2;
+ uint128_struct xmm3;
+ uint128_struct xmm4;
+ uint128_struct xmm5;
+ uint128_struct xmm6;
+ uint128_struct xmm7;
+ uint128_struct xmm8;
+ uint128_struct xmm9;
+ uint128_struct xmm10;
+ uint128_struct xmm11;
+ uint128_struct xmm12;
+ uint128_struct xmm13;
+ uint128_struct xmm14;
+ uint128_struct xmm15;
} sse_registers;
};
- u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
- u_int64_t vector_control;
+ uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT];
+ uint64_t vector_control;
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
- u_int64_t debug_control;
- u_int64_t last_branch_to_rip;
- u_int64_t last_branch_from_rip;
- u_int64_t last_exception_to_rip;
- u_int64_t last_exception_from_rip;
-
+ uint64_t debug_control;
+ uint64_t last_branch_to_rip;
+ uint64_t last_branch_from_rip;
+ uint64_t last_exception_to_rip;
+ uint64_t last_exception_from_rip;
+
} MDRawContextAMD64; /* CONTEXT */
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm.h
index dd07129..6a71138 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm.h
@@ -77,13 +77,13 @@
* are not exactly minidumps.
*/
typedef struct {
- u_int64_t fpscr; /* FPU status register */
+ uint64_t fpscr; /* FPU status register */
/* 32 64-bit floating point registers, d0 .. d31. */
- u_int64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
+ uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
/* Miscellaneous control words */
- u_int32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT];
+ uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT];
} MDFloatingSaveAreaARM;
#define MD_CONTEXT_ARM_GPR_COUNT 16
@@ -92,7 +92,7 @@ typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated
*/
- u_int32_t context_flags;
+ uint32_t context_flags;
/* 16 32-bit integer registers, r0 .. r15
* Note the following fixed uses:
@@ -100,7 +100,7 @@ typedef struct {
* r14 is the link register
* r15 is the program counter
*/
- u_int32_t iregs[MD_CONTEXT_ARM_GPR_COUNT];
+ uint32_t iregs[MD_CONTEXT_ARM_GPR_COUNT];
/* CPSR (flags, basically): 32 bits:
bit 31 - N (negative)
@@ -109,14 +109,14 @@ typedef struct {
bit 28 - V (overflow)
bit 27 - Q (saturation flag, sticky)
All other fields -- ignore */
- u_int32_t cpsr;
+ uint32_t cpsr;
/* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */
MDFloatingSaveAreaARM float_save;
} MDRawContextARM;
-/* Indices into iregs for registers with a dedicated or conventional
+/* Indices into iregs for registers with a dedicated or conventional
* purpose.
*/
enum MDARMRegisterNumbers {
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm64.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm64.h
new file mode 100644
index 0000000..5ace0d9
--- /dev/null
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_arm64.h
@@ -0,0 +1,140 @@
+/* Copyright 2013 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on ARM. These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used. The structures defined
+ * by this file have been laid out to minimize alignment problems by
+ * ensuring that all members are aligned on their natural boundaries.
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors. To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++. In these cases,
+ * *_minsize constants are provided to be used in place of sizeof. For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.
+ *
+ * Author: Colin Blundell
+ */
+
+/*
+ * ARM64 support
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__
+
+#define MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT 32
+
+typedef struct {
+ uint32_t fpsr; /* FPU status register */
+ uint32_t fpcr; /* FPU control register */
+
+ /* 32 128-bit floating point registers, d0 .. d31. */
+ uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT];
+} MDFloatingSaveAreaARM64;
+
+#define MD_CONTEXT_ARM64_GPR_COUNT 33
+
+/* Use the same 32-bit alignment when accessing this structure from 64-bit code
+ * as is used natively in 32-bit code. */
+#pragma pack(push, 4)
+
+typedef struct {
+ /* The next field determines the layout of the structure, and which parts
+ * of it are populated
+ */
+ uint64_t context_flags;
+
+ /* 33 64-bit integer registers, x0 .. x31 + the PC
+ * Note the following fixed uses:
+ * x29 is the frame pointer
+ * x30 is the link register
+ * x31 is the stack pointer
+ * The PC is effectively x32.
+ */
+ uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT];
+
+ /* CPSR (flags, basically): 32 bits:
+ bit 31 - N (negative)
+ bit 30 - Z (zero)
+ bit 29 - C (carry)
+ bit 28 - V (overflow)
+ bit 27 - Q (saturation flag, sticky)
+ All other fields -- ignore */
+ uint32_t cpsr;
+
+ /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */
+ MDFloatingSaveAreaARM64 float_save;
+
+} MDRawContextARM64;
+
+#pragma pack(pop)
+
+/* Indices into iregs for registers with a dedicated or conventional
+ * purpose.
+ */
+enum MDARM64RegisterNumbers {
+ MD_CONTEXT_ARM64_REG_FP = 29,
+ MD_CONTEXT_ARM64_REG_LR = 30,
+ MD_CONTEXT_ARM64_REG_SP = 31,
+ MD_CONTEXT_ARM64_REG_PC = 32
+};
+
+/* For (MDRawContextARM64).context_flags. These values indicate the type of
+ * context stored in the structure. MD_CONTEXT_ARM64 is Breakpad-defined.
+ * This value was chosen to avoid likely conflicts with MD_CONTEXT_*
+ * for other CPUs. */
+#define MD_CONTEXT_ARM64 0x80000000
+#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002)
+#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004)
+
+#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_INTEGER | \
+ MD_CONTEXT_ARM64_FLOATING_POINT)
+
+#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_INTEGER | \
+ MD_CONTEXT_ARM64_FLOATING_POINT)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_mips.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_mips.h
new file mode 100644
index 0000000..f4e2b58
--- /dev/null
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_mips.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on MIPS. These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used. The structures defined
+ * by this file have been laid out to minimize alignment problems by
+ * ensuring that all members are aligned on their natural boundaries.
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors. To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++. In these cases,
+ * *_minsize constants are provided to be used in place of sizeof. For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.
+ *
+ * Author: Chris Dearman
+ */
+
+/*
+ * MIPS support
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
+
+#define MD_CONTEXT_MIPS_GPR_COUNT 32
+#define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32
+#define MD_CONTEXT_MIPS_DSP_COUNT 3
+
+/*
+ * Note that these structures *do not* map directly to the CONTEXT
+ * structure defined in WinNT.h in the Windows Mobile SDK. That structure
+ * does not accomodate VFPv3, and I'm unsure if it was ever used in the
+ * wild anyway, as Windows CE only seems to produce "cedumps" which
+ * are not exactly minidumps.
+ */
+typedef struct {
+ /* 32 64-bit floating point registers, f0..f31 */
+ uint64_t regs[MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT];
+
+ uint32_t fpcsr; /* FPU status register. */
+ uint32_t fir; /* FPU implementation register. */
+} MDFloatingSaveAreaMIPS;
+
+typedef struct {
+ /* The next field determines the layout of the structure, and which parts
+ * of it are populated.
+ */
+ uint32_t context_flags;
+ uint32_t _pad0;
+
+ /* 32 64-bit integer registers, r0..r31.
+ * Note the following fixed uses:
+ * r29 is the stack pointer.
+ * r31 is the return address.
+ */
+ uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT];
+
+ /* multiply/divide result. */
+ uint64_t mdhi, mdlo;
+
+ /* DSP accumulators. */
+ uint32_t hi[MD_CONTEXT_MIPS_DSP_COUNT];
+ uint32_t lo[MD_CONTEXT_MIPS_DSP_COUNT];
+ uint32_t dsp_control;
+ uint32_t _pad1;
+
+ uint64_t epc;
+ uint64_t badvaddr;
+ uint32_t status;
+ uint32_t cause;
+
+ /* The next field is included with MD_CONTEXT_MIPS_FLOATING_POINT. */
+ MDFloatingSaveAreaMIPS float_save;
+
+} MDRawContextMIPS;
+
+/* Indices into iregs for registers with a dedicated or conventional
+ * purpose.
+ */
+enum MDMIPSRegisterNumbers {
+ MD_CONTEXT_MIPS_REG_S0 = 16,
+ MD_CONTEXT_MIPS_REG_S1 = 17,
+ MD_CONTEXT_MIPS_REG_S2 = 18,
+ MD_CONTEXT_MIPS_REG_S3 = 19,
+ MD_CONTEXT_MIPS_REG_S4 = 20,
+ MD_CONTEXT_MIPS_REG_S5 = 21,
+ MD_CONTEXT_MIPS_REG_S6 = 22,
+ MD_CONTEXT_MIPS_REG_S7 = 23,
+ MD_CONTEXT_MIPS_REG_GP = 28,
+ MD_CONTEXT_MIPS_REG_SP = 29,
+ MD_CONTEXT_MIPS_REG_FP = 30,
+ MD_CONTEXT_MIPS_REG_RA = 31,
+};
+
+/* For (MDRawContextMIPS).context_flags. These values indicate the type of
+ * context stored in the structure. */
+/* CONTEXT_MIPS 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 MIPS CPUs.
+ */
+#define MD_CONTEXT_MIPS 0x00040000
+#define MD_CONTEXT_MIPS_INTEGER (MD_CONTEXT_MIPS | 0x00000002)
+#define MD_CONTEXT_MIPS_FLOATING_POINT (MD_CONTEXT_MIPS | 0x00000004)
+#define MD_CONTEXT_MIPS_DSP (MD_CONTEXT_MIPS | 0x00000008)
+
+#define MD_CONTEXT_MIPS_FULL (MD_CONTEXT_MIPS_INTEGER | \
+ MD_CONTEXT_MIPS_FLOATING_POINT | \
+ MD_CONTEXT_MIPS_DSP)
+
+#define MD_CONTEXT_MIPS_ALL (MD_CONTEXT_MIPS_INTEGER | \
+ MD_CONTEXT_MIPS_FLOATING_POINT \
+ MD_CONTEXT_MIPS_DSP)
+
+/**
+ * Breakpad defines for MIPS64
+ */
+#define MD_CONTEXT_MIPS64 0x00080000
+#define MD_CONTEXT_MIPS64_INTEGER (MD_CONTEXT_MIPS64 | 0x00000002)
+#define MD_CONTEXT_MIPS64_FLOATING_POINT (MD_CONTEXT_MIPS64 | 0x00000004)
+#define MD_CONTEXT_MIPS64_DSP (MD_CONTEXT_MIPS64 | 0x00000008)
+
+#define MD_CONTEXT_MIPS64_FULL (MD_CONTEXT_MIPS64_INTEGER | \
+ MD_CONTEXT_MIPS64_FLOATING_POINT | \
+ MD_CONTEXT_MIPS64_DSP)
+
+#define MD_CONTEXT_MIPS64_ALL (MD_CONTEXT_MIPS64_INTEGER | \
+ MD_CONTEXT_MIPS64_FLOATING_POINT \
+ MD_CONTEXT_MIPS64_DSP)
+
+#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
index 038e921..b24cc42 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
@@ -81,11 +81,11 @@
#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
typedef struct {
- /* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
+ /* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used
* here for precise sizing. */
- u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
- u_int32_t fpscr_pad;
- u_int32_t fpscr; /* Status/control */
+ uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
+ uint32_t fpscr_pad;
+ uint32_t fpscr; /* Status/control */
} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */
@@ -94,11 +94,11 @@ typedef struct {
typedef struct {
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
* exposes them as four 32-bit quantities. */
- u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
- u_int128_t save_vscr; /* Status/control */
- u_int32_t save_pad5[4];
- u_int32_t save_vrvalid; /* Identifies which vector registers are saved */
- u_int32_t save_pad6[7];
+ uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
+ uint128_struct save_vscr; /* Status/control */
+ uint32_t save_pad5[4];
+ uint32_t save_vrvalid; /* Indicates which vector registers are saved */
+ uint32_t save_pad6[7];
} MDVectorSaveAreaPPC; /* ppc_vector_state */
@@ -117,21 +117,21 @@ typedef struct {
/* context_flags is not present in ppc_thread_state, but it aids
* identification of MDRawContextPPC among other raw context types,
* and it guarantees alignment when we get to float_save. */
- u_int32_t context_flags;
+ uint32_t context_flags;
- u_int32_t srr0; /* Machine status save/restore: stores pc
+ uint32_t srr0; /* Machine status save/restore: stores pc
* (instruction) */
- u_int32_t srr1; /* Machine status save/restore: stores msr
+ uint32_t srr1; /* Machine status save/restore: stores msr
* (ps, program/machine state) */
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
* used for brevity. */
- u_int32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
- u_int32_t cr; /* Condition */
- u_int32_t xer; /* Integer (fiXed-point) exception */
- u_int32_t lr; /* Link */
- u_int32_t ctr; /* Count */
- u_int32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
- u_int32_t vrsave; /* Vector save */
+ uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
+ uint32_t cr; /* Condition */
+ uint32_t xer; /* Integer (fiXed-point) exception */
+ uint32_t lr; /* Link */
+ uint32_t ctr; /* Count */
+ uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
+ uint32_t vrsave; /* Vector save */
/* float_save and vector_save aren't present in ppc_thread_state, but
* are represented in separate structures that still define a thread's
@@ -140,6 +140,11 @@ typedef struct {
MDVectorSaveAreaPPC vector_save;
} MDRawContextPPC; /* Based on ppc_thread_state */
+/* Indices into gpr for registers with a dedicated or conventional purpose. */
+enum MDPPCRegisterNumbers {
+ MD_CONTEXT_PPC_REG_SP = 1
+};
+
#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
#pragma pack(0)
#else
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
index a788e5d..61f4193 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
@@ -90,20 +90,20 @@ typedef struct {
/* context_flags is not present in ppc_thread_state, but it aids
* identification of MDRawContextPPC among other raw context types,
* and it guarantees alignment when we get to float_save. */
- u_int64_t context_flags;
+ uint64_t context_flags;
- u_int64_t srr0; /* Machine status save/restore: stores pc
+ uint64_t srr0; /* Machine status save/restore: stores pc
* (instruction) */
- u_int64_t srr1; /* Machine status save/restore: stores msr
+ uint64_t srr1; /* Machine status save/restore: stores msr
* (ps, program/machine state) */
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
* used for brevity. */
- u_int64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
- u_int64_t cr; /* Condition */
- u_int64_t xer; /* Integer (fiXed-point) exception */
- u_int64_t lr; /* Link */
- u_int64_t ctr; /* Count */
- u_int64_t vrsave; /* Vector save */
+ uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
+ uint64_t cr; /* Condition */
+ uint64_t xer; /* Integer (fiXed-point) exception */
+ uint64_t lr; /* Link */
+ uint64_t ctr; /* Count */
+ uint64_t vrsave; /* Vector save */
/* float_save and vector_save aren't present in ppc_thread_state, but
* are represented in separate structures that still define a thread's
@@ -112,18 +112,23 @@ typedef struct {
MDVectorSaveAreaPPC vector_save;
} MDRawContextPPC64; /* Based on ppc_thread_state */
+/* Indices into gpr for registers with a dedicated or conventional purpose. */
+enum MDPPC64RegisterNumbers {
+ MD_CONTEXT_PPC64_REG_SP = 1
+};
+
/* For (MDRawContextPPC).context_flags. These values indicate the type of
* context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
* CPUs. */
-#define MD_CONTEXT_PPC 0x20000000
-#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001)
-#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
-#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020)
+#define MD_CONTEXT_PPC64 0x01000000
+#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001)
+#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008)
+#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020)
-#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE
-#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \
- MD_CONTEXT_PPC_FLOATING_POINT | \
- MD_CONTEXT_PPC_VECTOR)
+#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE
+#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \
+ MD_CONTEXT_PPC64_FLOATING_POINT | \
+ MD_CONTEXT_PPC64_VECTOR)
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_sparc.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
index ee95b64..95c08b1 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
@@ -82,10 +82,10 @@
typedef struct {
/* FPU floating point regs */
- u_int64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
+ uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
- u_int64_t filler;
- u_int64_t fsr; /* FPU status register */
+ uint64_t filler;
+ uint64_t fsr; /* FPU status register */
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
#define MD_CONTEXT_SPARC_GPR_COUNT 32
@@ -94,8 +94,8 @@ typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated
*/
- u_int32_t context_flags;
- u_int32_t flag_pad;
+ uint32_t context_flags;
+ uint32_t flag_pad;
/*
* General register access (SPARC).
* Don't confuse definitions here with definitions in <sys/regset.h>.
@@ -110,34 +110,39 @@ typedef struct {
* g_r[16-23] local registers(l0-l7)
* g_r[24-31] in registers(i0-i7)
*/
- u_int64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
+ uint64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT];
/* several control registers */
/* Processor State register(PSR) for SPARC V7/V8
* Condition Code register (CCR) for SPARC V9
*/
- u_int64_t ccr;
+ uint64_t ccr;
- u_int64_t pc; /* Program Counter register (PC) */
- u_int64_t npc; /* Next Program Counter register (nPC) */
- u_int64_t y; /* Y register (Y) */
+ uint64_t pc; /* Program Counter register (PC) */
+ uint64_t npc; /* Next Program Counter register (nPC) */
+ uint64_t y; /* Y register (Y) */
/* Address Space Identifier register (ASI) for SPARC V9
* WIM for SPARC V7/V8
*/
- u_int64_t asi;
+ uint64_t asi;
/* Floating-Point Registers State register (FPRS) for SPARC V9
* TBR for for SPARC V7/V8
*/
- u_int64_t fprs;
+ uint64_t fprs;
/* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
MDFloatingSaveAreaSPARC float_save;
} MDRawContextSPARC; /* CONTEXT_SPARC */
+/* Indices into g_r for registers with a dedicated or conventional purpose. */
+enum MDSPARCRegisterNumbers {
+ MD_CONTEXT_SPARC_REG_SP = 14
+};
+
/* For (MDRawContextSPARC).context_flags. These values indicate the type of
* context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its
* value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_x86.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_x86.h
index 32aff8a..e09cb7c 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_x86.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_cpu_x86.h
@@ -76,18 +76,18 @@
/* SIZE_OF_80387_REGISTERS */
typedef struct {
- u_int32_t control_word;
- u_int32_t status_word;
- u_int32_t tag_word;
- u_int32_t error_offset;
- u_int32_t error_selector;
- u_int32_t data_offset;
- u_int32_t data_selector;
+ uint32_t control_word;
+ uint32_t status_word;
+ uint32_t tag_word;
+ uint32_t error_offset;
+ uint32_t error_selector;
+ uint32_t data_offset;
+ uint32_t data_selector;
/* register_area contains eight 80-bit (x87 "long double") quantities for
* floating-point registers %st0 (%mm0) through %st7 (%mm7). */
- u_int8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
- u_int32_t cr0_npx_state;
+ uint8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
+ uint32_t cr0_npx_state;
} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */
@@ -97,46 +97,46 @@ typedef struct {
typedef struct {
/* The next field determines the layout of the structure, and which parts
* of it are populated */
- u_int32_t context_flags;
+ uint32_t context_flags;
/* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
- u_int32_t dr0;
- u_int32_t dr1;
- u_int32_t dr2;
- u_int32_t dr3;
- u_int32_t dr6;
- u_int32_t dr7;
+ uint32_t dr0;
+ uint32_t dr1;
+ uint32_t dr2;
+ uint32_t dr3;
+ uint32_t dr6;
+ uint32_t dr7;
/* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
MDFloatingSaveAreaX86 float_save;
/* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
- u_int32_t gs;
- u_int32_t fs;
- u_int32_t es;
- u_int32_t ds;
+ uint32_t gs;
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
/* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
- u_int32_t edi;
- u_int32_t esi;
- u_int32_t ebx;
- u_int32_t edx;
- u_int32_t ecx;
- u_int32_t eax;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
/* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
- u_int32_t ebp;
- u_int32_t eip;
- u_int32_t cs; /* WinNT.h says "must be sanitized" */
- u_int32_t eflags; /* WinNT.h says "must be sanitized" */
- u_int32_t esp;
- u_int32_t ss;
+ uint32_t ebp;
+ uint32_t eip;
+ uint32_t cs; /* WinNT.h says "must be sanitized" */
+ uint32_t eflags; /* WinNT.h says "must be sanitized" */
+ uint32_t esp;
+ uint32_t ss;
/* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
* It contains vector (MMX/SSE) registers. It it laid out in the
* format used by the fxsave and fsrstor instructions, so it includes
* a copy of the x87 floating-point registers as well. See FXSAVE in
* "Intel Architecture Software Developer's Manual, Volume 2." */
- u_int8_t extended_registers[
+ uint8_t extended_registers[
MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
} MDRawContextX86; /* CONTEXT */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_linux.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_linux.h
index d52c751..9e7e4f1 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_linux.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_linux.h
@@ -79,7 +79,9 @@ typedef enum {
MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
- MD_EXCEPTION_CODE_LIN_SIGSYS = 31 /* Bad system call */
+ MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */
+ MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception,
+ dump requested. */
} MDExceptionCodeLinux;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_mac.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_mac.h
index 01f8feb..a42a152 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_mac.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_mac.h
@@ -34,7 +34,7 @@
*
* Author: Mark Mentovai
* Split into its own file: Neal Sidhwaney */
-
+
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
@@ -65,8 +65,10 @@ typedef enum {
/* EXC_SYSCALL */
MD_EXCEPTION_MAC_MACH_SYSCALL = 8,
/* EXC_MACH_SYSCALL */
- MD_EXCEPTION_MAC_RPC_ALERT = 9
+ MD_EXCEPTION_MAC_RPC_ALERT = 9,
/* EXC_RPC_ALERT */
+ MD_EXCEPTION_MAC_SIMULATED = 0x43507378
+ /* Fake exception code used by Crashpad's SimulateCrash ('CPsx'). */
} MDExceptionMac;
/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X
@@ -93,6 +95,16 @@ typedef enum {
/* Custom values */
MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */
+ /* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */
+ MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */
+ MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */
+
+ /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */
+ MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */
+
+ /* With MD_EXCEPTION_MAC_BREAKPOINT on arm */
+ MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */
+
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
/* EXC_PPC_VM_PROT_READ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_ps3.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_ps3.h
new file mode 100644
index 0000000..adff5a6
--- /dev/null
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_ps3.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_exception_ps3.h: A definition of exception codes for
+ * PS3 */
+
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+typedef enum {
+ MD_EXCEPTION_CODE_PS3_UNKNOWN = 0,
+ MD_EXCEPTION_CODE_PS3_TRAP_EXCEP = 1,
+ MD_EXCEPTION_CODE_PS3_PRIV_INSTR = 2,
+ MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR = 3,
+ MD_EXCEPTION_CODE_PS3_INSTR_STORAGE = 4,
+ MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT = 5,
+ MD_EXCEPTION_CODE_PS3_DATA_STORAGE = 6,
+ MD_EXCEPTION_CODE_PS3_DATA_SEGMENT = 7,
+ MD_EXCEPTION_CODE_PS3_FLOAT_POINT = 8,
+ MD_EXCEPTION_CODE_PS3_DABR_MATCH = 9,
+ MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP = 10,
+ MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS = 11,
+ MD_EXCEPTION_CODE_PS3_COPRO_ALIGN = 12,
+ MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM = 13,
+ MD_EXCEPTION_CODE_PS3_COPRO_ERR = 14,
+ MD_EXCEPTION_CODE_PS3_COPRO_FIR = 15,
+ MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT = 16,
+ MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE = 17,
+ MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR = 18,
+ MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR = 19,
+ MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN = 20,
+ MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS = 21,
+ MD_EXCEPTION_CODE_PS3_GRAPHIC = 22
+} MDExceptionCodePS3;
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_win32.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_win32.h
index 458a705..4b5d57c 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_win32.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_exception_win32.h
@@ -94,17 +94,2162 @@ typedef enum {
/* EXCEPTION_PRIV_INSTRUCTION */
MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd,
/* EXCEPTION_STACK_OVERFLOW */
+ MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE = 0xc00000ff,
+ /* EXCEPTION_BAD_FUNCTION_TABLE */
MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194,
/* EXCEPTION_POSSIBLE_DEADLOCK */
MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409,
/* STATUS_STACK_BUFFER_OVERRUN */
MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374,
/* STATUS_HEAP_CORRUPTION */
- MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363
+ MD_EXCEPTION_OUT_OF_MEMORY = 0xe0000008,
+ /* Exception thrown by Chromium allocators to indicate OOM.
+ See base/process/memory.h in Chromium for rationale. */
+ MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363,
/* Per http://support.microsoft.com/kb/185294,
generated by Visual C++ compiler */
+ MD_EXCEPTION_CODE_WIN_SIMULATED = 0x0517a7ed
+ /* Fake exception code used by Crashpad's
+ CrashpadClient::DumpWithoutCrash. */
} MDExceptionCodeWin;
+
+/* For (MDException).exception_information[2], when (MDException).exception_code
+ * is MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR. This describes the underlying reason
+ * for the error. These values come from ntstatus.h.
+ *
+ * The content of this enum was created from ntstatus.h in the 8.1 SDK with
+ *
+ * egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0xC[0-9A-F]+L\)' ntstatus.h
+ * | tr -d '\r'
+ * | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0xC[0-9A-F]+)L\).*@\2 \1@'
+ * | sort
+ * | sed -r 's@(0xC[0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2 = \1,@'
+ *
+ * With easy copy to clipboard with
+ * | xclip -selection c # on linux
+ * | clip # on windows
+ * | pbcopy # on mac
+ *
+ * and then the last comma manually removed. */
+typedef enum {
+ MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL = 0xC0000001,
+ MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED = 0xC0000002,
+ MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS = 0xC0000003,
+ MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH = 0xC0000004,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION = 0xC0000005,
+ MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR = 0xC0000006,
+ MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA = 0xC0000007,
+ MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE = 0xC0000008,
+ MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK = 0xC0000009,
+ MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC = 0xC000000A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_CID = 0xC000000B,
+ MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED = 0xC000000C,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER = 0xC000000D,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE = 0xC000000E,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE = 0xC000000F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
+ MD_NTSTATUS_WIN_STATUS_END_OF_FILE = 0xC0000011,
+ MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME = 0xC0000012,
+ MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE = 0xC0000013,
+ MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA = 0xC0000014,
+ MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR = 0xC0000015,
+ MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016,
+ MD_NTSTATUS_WIN_STATUS_NO_MEMORY = 0xC0000017,
+ MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES = 0xC0000018,
+ MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW = 0xC0000019,
+ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM = 0xC000001A,
+ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION = 0xC000001B,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE = 0xC000001C,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION = 0xC000001D,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE = 0xC000001E,
+ MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE = 0xC000001F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION = 0xC0000020,
+ MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED = 0xC0000021,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED = 0xC0000022,
+ MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL = 0xC0000023,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024,
+ MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION = 0xC0000025,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION = 0xC0000026,
+ MD_NTSTATUS_WIN_STATUS_UNWIND = 0xC0000027,
+ MD_NTSTATUS_WIN_STATUS_BAD_STACK = 0xC0000028,
+ MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET = 0xC0000029,
+ MD_NTSTATUS_WIN_STATUS_NOT_LOCKED = 0xC000002A,
+ MD_NTSTATUS_WIN_STATUS_PARITY_ERROR = 0xC000002B,
+ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM = 0xC000002C,
+ MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED = 0xC000002D,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES = 0xC000002E,
+ MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG = 0xC000002F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX = 0xC0000030,
+ MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER = 0xC0000031,
+ MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR = 0xC0000032,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID = 0xC0000033,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION = 0xC0000035,
+ MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED = 0xC0000037,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED = 0xC0000038,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID = 0xC0000039,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B,
+ MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN = 0xC000003C,
+ MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR = 0xC000003D,
+ MD_NTSTATUS_WIN_STATUS_DATA_ERROR = 0xC000003E,
+ MD_NTSTATUS_WIN_STATUS_CRC_ERROR = 0xC000003F,
+ MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG = 0xC0000040,
+ MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED = 0xC0000041,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE = 0xC0000042,
+ MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION = 0xC0000043,
+ MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED = 0xC0000044,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION = 0xC0000045,
+ MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED = 0xC0000046,
+ MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED = 0xC0000047,
+ MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET = 0xC0000048,
+ MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE = 0xC0000049,
+ MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED = 0xC000004A,
+ MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING = 0xC000004B,
+ MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT = 0xC000004C,
+ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP = 0xC000004D,
+ MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION = 0xC000004E,
+ MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED = 0xC000004F,
+ MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE = 0xC0000050,
+ MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY = 0xC0000051,
+ MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE = 0xC0000052,
+ MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR = 0xC0000053,
+ MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT = 0xC0000054,
+ MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED = 0xC0000055,
+ MD_NTSTATUS_WIN_STATUS_DELETE_PENDING = 0xC0000056,
+ MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED = 0xC0000057,
+ MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION = 0xC0000058,
+ MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH = 0xC0000059,
+ MD_NTSTATUS_WIN_STATUS_INVALID_OWNER = 0xC000005A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP = 0xC000005B,
+ MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN = 0xC000005C,
+ MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY = 0xC000005D,
+ MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS = 0xC000005E,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION = 0xC000005F,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE = 0xC0000060,
+ MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD = 0xC0000061,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME = 0xC0000062,
+ MD_NTSTATUS_WIN_STATUS_USER_EXISTS = 0xC0000063,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER = 0xC0000064,
+ MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS = 0xC0000065,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP = 0xC0000066,
+ MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP = 0xC0000067,
+ MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP = 0xC0000068,
+ MD_NTSTATUS_WIN_STATUS_LAST_ADMIN = 0xC0000069,
+ MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD = 0xC000006A,
+ MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD = 0xC000006B,
+ MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION = 0xC000006C,
+ MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE = 0xC000006D,
+ MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION = 0xC000006E,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS = 0xC000006F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION = 0xC0000070,
+ MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED = 0xC0000071,
+ MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED = 0xC0000072,
+ MD_NTSTATUS_WIN_STATUS_NONE_MAPPED = 0xC0000073,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED = 0xC0000074,
+ MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED = 0xC0000075,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY = 0xC0000076,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ACL = 0xC0000077,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SID = 0xC0000078,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR = 0xC0000079,
+ MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND = 0xC000007A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT = 0xC000007B,
+ MD_NTSTATUS_WIN_STATUS_NO_TOKEN = 0xC000007C,
+ MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL = 0xC000007D,
+ MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED = 0xC000007E,
+ MD_NTSTATUS_WIN_STATUS_DISK_FULL = 0xC000007F,
+ MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED = 0xC0000080,
+ MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED = 0xC0000081,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED = 0xC0000082,
+ MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED = 0xC0000083,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY = 0xC0000084,
+ MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED = 0xC0000085,
+ MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL = 0xC0000086,
+ MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED = 0xC0000087,
+ MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA = 0xC0000088,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND = 0xC0000089,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND = 0xC000008A,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND = 0xC000008B,
+ MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED = 0xC000008C,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND = 0xC000008D,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO = 0xC000008E,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT = 0xC000008F,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION = 0xC0000090,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW = 0xC0000091,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK = 0xC0000092,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW = 0xC0000093,
+ MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094,
+ MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW = 0xC0000095,
+ MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES = 0xC0000097,
+ MD_NTSTATUS_WIN_STATUS_FILE_INVALID = 0xC0000098,
+ MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED = 0xC0000099,
+ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES = 0xC000009A,
+ MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND = 0xC000009B,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR = 0xC000009C,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED = 0xC000009D,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE = 0xC000009E,
+ MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE = 0xC000009F,
+ MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED = 0xC00000A0,
+ MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA = 0xC00000A1,
+ MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED = 0xC00000A2,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY = 0xC00000A3,
+ MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES = 0xC00000A4,
+ MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL = 0xC00000A5,
+ MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS = 0xC00000A6,
+ MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS = 0xC00000A7,
+ MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE = 0xC00000A8,
+ MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD = 0xC00000A9,
+ MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT = 0xC00000AA,
+ MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE = 0xC00000AB,
+ MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE = 0xC00000AC,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE = 0xC00000AD,
+ MD_NTSTATUS_WIN_STATUS_PIPE_BUSY = 0xC00000AE,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION = 0xC00000AF,
+ MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED = 0xC00000B0,
+ MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING = 0xC00000B1,
+ MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED = 0xC00000B2,
+ MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING = 0xC00000B3,
+ MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE = 0xC00000B4,
+ MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT = 0xC00000B5,
+ MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED = 0xC00000B6,
+ MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED = 0xC00000B7,
+ MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED = 0xC00000B8,
+ MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET = 0xC00000B9,
+ MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA,
+ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED = 0xC00000BB,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING = 0xC00000BC,
+ MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME = 0xC00000BD,
+ MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH = 0xC00000BE,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY = 0xC00000BF,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST = 0xC00000C0,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS = 0xC00000C1,
+ MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR = 0xC00000C2,
+ MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE = 0xC00000C3,
+ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR = 0xC00000C4,
+ MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER = 0xC00000C5,
+ MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL = 0xC00000C6,
+ MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE = 0xC00000C7,
+ MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED = 0xC00000C8,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED = 0xC00000C9,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED = 0xC00000CA,
+ MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE = 0xC00000CB,
+ MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME = 0xC00000CC,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES = 0xC00000CD,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS = 0xC00000CE,
+ MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED = 0xC00000CF,
+ MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED = 0xC00000D0,
+ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED = 0xC00000D1,
+ MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT = 0xC00000D2,
+ MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT = 0xC00000D3,
+ MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE = 0xC00000D4,
+ MD_NTSTATUS_WIN_STATUS_FILE_RENAMED = 0xC00000D5,
+ MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED = 0xC00000D6,
+ MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT = 0xC00000D7,
+ MD_NTSTATUS_WIN_STATUS_CANT_WAIT = 0xC00000D8,
+ MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY = 0xC00000D9,
+ MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO = 0xC00000DA,
+ MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF = 0xC00000DB,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE = 0xC00000DC,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE = 0xC00000DD,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE = 0xC00000DE,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN = 0xC00000DF,
+ MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS = 0xC00000E0,
+ MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED = 0xC00000E1,
+ MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED = 0xC00000E2,
+ MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL = 0xC00000E3,
+ MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION = 0xC00000E4,
+ MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR = 0xC00000E5,
+ MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED = 0xC00000E6,
+ MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT = 0xC00000E7,
+ MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER = 0xC00000E8,
+ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR = 0xC00000E9,
+ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR = 0xC00000EA,
+ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR = 0xC00000EB,
+ MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR = 0xC00000EC,
+ MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS = 0xC00000ED,
+ MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS = 0xC00000EE,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1 = 0xC00000EF,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2 = 0xC00000F0,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3 = 0xC00000F1,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4 = 0xC00000F2,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5 = 0xC00000F3,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6 = 0xC00000F4,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7 = 0xC00000F5,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8 = 0xC00000F6,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9 = 0xC00000F7,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10 = 0xC00000F8,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11 = 0xC00000F9,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12 = 0xC00000FA,
+ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED = 0xC00000FB,
+ MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED = 0xC00000FC,
+ MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW = 0xC00000FD,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE = 0xC00000FE,
+ MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE = 0xC00000FF,
+ MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND = 0xC0000100,
+ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101,
+ MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR = 0xC0000102,
+ MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY = 0xC0000103,
+ MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE = 0xC0000104,
+ MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION = 0xC0000105,
+ MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG = 0xC0000106,
+ MD_NTSTATUS_WIN_STATUS_FILES_OPEN = 0xC0000107,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE = 0xC0000108,
+ MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND = 0xC0000109,
+ MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING = 0xC000010A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE = 0xC000010B,
+ MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION = 0xC000010C,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE = 0xC000010D,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED = 0xC000010E,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT = 0xC000010F,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST = 0xC0000110,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED = 0xC0000111,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER = 0xC0000112,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND = 0xC0000113,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID = 0xC0000114,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE = 0xC0000115,
+ MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR = 0xC0000116,
+ MD_NTSTATUS_WIN_STATUS_NO_LDT = 0xC0000117,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE = 0xC0000118,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET = 0xC0000119,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR = 0xC000011A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT = 0xC000011B,
+ MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE = 0xC000011C,
+ MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE = 0xC000011D,
+ MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO = 0xC000011E,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES = 0xC000011F,
+ MD_NTSTATUS_WIN_STATUS_CANCELLED = 0xC0000120,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE = 0xC0000121,
+ MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME = 0xC0000122,
+ MD_NTSTATUS_WIN_STATUS_FILE_DELETED = 0xC0000123,
+ MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT = 0xC0000124,
+ MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP = 0xC0000125,
+ MD_NTSTATUS_WIN_STATUS_SPECIAL_USER = 0xC0000126,
+ MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP = 0xC0000127,
+ MD_NTSTATUS_WIN_STATUS_FILE_CLOSED = 0xC0000128,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS = 0xC0000129,
+ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS = 0xC000012A,
+ MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE = 0xC000012B,
+ MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED = 0xC000012C,
+ MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT = 0xC000012D,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT = 0xC000012E,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ = 0xC000012F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT = 0xC0000130,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16 = 0xC0000131,
+ MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT = 0xC0000132,
+ MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC = 0xC0000133,
+ MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED = 0xC0000134,
+ MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND = 0xC0000135,
+ MD_NTSTATUS_WIN_STATUS_OPEN_FAILED = 0xC0000136,
+ MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED = 0xC0000137,
+ MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND = 0xC0000138,
+ MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139,
+ MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT = 0xC000013A,
+ MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT = 0xC000013B,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT = 0xC000013C,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES = 0xC000013D,
+ MD_NTSTATUS_WIN_STATUS_LINK_FAILED = 0xC000013E,
+ MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT = 0xC000013F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION = 0xC0000140,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS = 0xC0000141,
+ MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED = 0xC0000142,
+ MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE = 0xC0000143,
+ MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION = 0xC0000144,
+ MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE = 0xC0000145,
+ MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED = 0xC0000146,
+ MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE = 0xC0000147,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL = 0xC0000148,
+ MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE = 0xC0000149,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT = 0xC000014A,
+ MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN = 0xC000014B,
+ MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT = 0xC000014C,
+ MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED = 0xC000014D,
+ MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR = 0xC000014E,
+ MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME = 0xC000014F,
+ MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED = 0xC0000150,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS = 0xC0000151,
+ MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS = 0xC0000152,
+ MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS = 0xC0000153,
+ MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS = 0xC0000154,
+ MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED = 0xC0000155,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS = 0xC0000156,
+ MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG = 0xC0000157,
+ MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR = 0xC0000158,
+ MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE = 0xC0000159,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS = 0xC000015A,
+ MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015B,
+ MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE = 0xC000015C,
+ MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED = 0xC000015D,
+ MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR = 0xC000015E,
+ MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER = 0xC000015F,
+ MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY = 0xC0000160,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER = 0xC0000161,
+ MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER = 0xC0000162,
+ MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER = 0xC0000163,
+ MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME = 0xC0000164,
+ MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND = 0xC0000165,
+ MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER = 0xC0000166,
+ MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR = 0xC0000167,
+ MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS = 0xC0000168,
+ MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED = 0xC0000169,
+ MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED = 0xC000016A,
+ MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED = 0xC000016B,
+ MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY = 0xC000016C,
+ MD_NTSTATUS_WIN_STATUS_FT_ORPHANING = 0xC000016D,
+ MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT = 0xC000016E,
+ MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE = 0xC0000172,
+ MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH = 0xC0000173,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED = 0xC0000174,
+ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA = 0xC0000175,
+ MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA = 0xC0000176,
+ MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW = 0xC0000177,
+ MD_NTSTATUS_WIN_STATUS_NO_MEDIA = 0xC0000178,
+ MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER = 0xC000017A,
+ MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER = 0xC000017B,
+ MD_NTSTATUS_WIN_STATUS_KEY_DELETED = 0xC000017C,
+ MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE = 0xC000017D,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS = 0xC000017E,
+ MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED = 0xC000017F,
+ MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN = 0xC0000180,
+ MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE = 0xC0000181,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR = 0xC0000182,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR = 0xC0000183,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE = 0xC0000184,
+ MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR = 0xC0000185,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR = 0xC0000186,
+ MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER = 0xC0000187,
+ MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL = 0xC0000188,
+ MD_NTSTATUS_WIN_STATUS_TOO_LATE = 0xC0000189,
+ MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET = 0xC000018A,
+ MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT = 0xC000018B,
+ MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE = 0xC000018C,
+ MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE = 0xC000018D,
+ MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT = 0xC000018E,
+ MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START = 0xC000018F,
+ MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE = 0xC0000190,
+ MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED = 0xC0000191,
+ MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED = 0xC0000192,
+ MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED = 0xC0000193,
+ MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK = 0xC0000194,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT = 0xC0000195,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT = 0xC0000196,
+ MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED = 0xC0000197,
+ MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xC0000198,
+ MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xC0000199,
+ MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT = 0xC000019A,
+ MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT = 0xC000019B,
+ MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED = 0xC000019C,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL = 0xC000019D,
+ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0xC000019E,
+ MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0xC000019F,
+ MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT = 0xC00001A0,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE = 0xC00001A1,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION = 0xC00001A2,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3,
+ MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4,
+ MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER = 0xC00001A5,
+ MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES = 0xC00001A6,
+ MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE = 0xC00001A7,
+ MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED = 0xC00001A8,
+ MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED = 0xC00001A9,
+ MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE = 0xC00001AA,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION = 0xC0000201,
+ MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY = 0xC0000202,
+ MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED = 0xC0000203,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND = 0xC0000204,
+ MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205,
+ MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE = 0xC0000206,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT = 0xC0000207,
+ MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD = 0xC0000208,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES = 0xC0000209,
+ MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS = 0xC000020A,
+ MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED = 0xC000020B,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED = 0xC000020C,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET = 0xC000020D,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES = 0xC000020E,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED = 0xC000020F,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT = 0xC0000210,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE = 0xC0000211,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH = 0xC0000212,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED = 0xC0000213,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID = 0xC0000214,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE = 0xC0000215,
+ MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION = 0xC0000216,
+ MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION = 0xC0000217,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE = 0xC0000218,
+ MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED = 0xC0000219,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED = 0xC000021A,
+ MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED = 0xC000021B,
+ MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND = 0xC000021C,
+ MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR = 0xC000021D,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT = 0xC000021E,
+ MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH = 0xC000021F,
+ MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT = 0xC0000220,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH = 0xC0000221,
+ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA = 0xC0000222,
+ MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID = 0xC0000223,
+ MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE = 0xC0000224,
+ MD_NTSTATUS_WIN_STATUS_NOT_FOUND = 0xC0000225,
+ MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM = 0xC0000226,
+ MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE = 0xC0000227,
+ MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ = 0xC0000228,
+ MD_NTSTATUS_WIN_STATUS_FAIL_CHECK = 0xC0000229,
+ MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID = 0xC000022A,
+ MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS = 0xC000022B,
+ MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE = 0xC000022C,
+ MD_NTSTATUS_WIN_STATUS_RETRY = 0xC000022D,
+ MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE = 0xC000022E,
+ MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET = 0xC000022F,
+ MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND = 0xC0000230,
+ MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW = 0xC0000231,
+ MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT = 0xC0000232,
+ MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND = 0xC0000233,
+ MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234,
+ MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE = 0xC0000235,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED = 0xC0000236,
+ MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT = 0xC0000237,
+ MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED = 0xC0000238,
+ MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED = 0xC0000239,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID = 0xC000023A,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE = 0xC000023B,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE = 0xC000023C,
+ MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE = 0xC000023D,
+ MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE = 0xC000023E,
+ MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE = 0xC000023F,
+ MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED = 0xC0000240,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED = 0xC0000241,
+ MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER = 0xC0000242,
+ MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE = 0xC0000243,
+ MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED = 0xC0000244,
+ MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET = 0xC0000245,
+ MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT = 0xC0000246,
+ MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION = 0xC0000247,
+ MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION = 0xC0000248,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH = 0xC0000249,
+ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO = 0xC0000250,
+ MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT = 0xC0000251,
+ MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT = 0xC0000252,
+ MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST = 0xC0000253,
+ MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1 = 0xC0000254,
+ MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2 = 0xC0000255,
+ MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT = 0xC0000256,
+ MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED = 0xC0000257,
+ MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE = 0xC0000258,
+ MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED = 0xC0000259,
+ MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT = 0xC000025A,
+ MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT = 0xC000025B,
+ MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT = 0xC000025C,
+ MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE = 0xC000025E,
+ MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION = 0xC000025F,
+ MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE = 0xC0000260,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH = 0xC0000261,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND = 0xC0000262,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND = 0xC0000263,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED = 0xC0000264,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS = 0xC0000265,
+ MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT = 0xC0000266,
+ MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE = 0xC0000267,
+ MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION = 0xC0000268,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION = 0xC0000269,
+ MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION = 0xC000026A,
+ MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF = 0xC000026B,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD = 0xC000026C,
+ MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE = 0xC000026D,
+ MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED = 0xC000026E,
+ MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR = 0xC000026F,
+ MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK = 0xC0000270,
+ MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE = 0xC0000271,
+ MD_NTSTATUS_WIN_STATUS_NO_MATCH = 0xC0000272,
+ MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES = 0xC0000273,
+ MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT = 0xC0000275,
+ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID = 0xC0000276,
+ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH = 0xC0000277,
+ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID = 0xC0000278,
+ MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279,
+ MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG = 0xC000027A,
+ MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION = 0xC000027B,
+ MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED = 0xC0000280,
+ MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281,
+ MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT = 0xC0000282,
+ MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY = 0xC0000283,
+ MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL = 0xC0000284,
+ MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS = 0xC0000285,
+ MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT = 0xC0000286,
+ MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED = 0xC0000287,
+ MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED = 0xC000028A,
+ MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED = 0xC000028B,
+ MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND = 0xC000028C,
+ MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY = 0xC000028D,
+ MD_NTSTATUS_WIN_STATUS_NO_EFS = 0xC000028E,
+ MD_NTSTATUS_WIN_STATUS_WRONG_EFS = 0xC000028F,
+ MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS = 0xC0000290,
+ MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED = 0xC0000291,
+ MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT = 0xC0000292,
+ MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED = 0xC0000293,
+ MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND = 0xC0000295,
+ MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND = 0xC0000296,
+ MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND = 0xC0000297,
+ MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN = 0xC0000298,
+ MD_NTSTATUS_WIN_STATUS_SHARED_POLICY = 0xC0000299,
+ MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND = 0xC000029A,
+ MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS = 0xC000029B,
+ MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED = 0xC000029C,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE = 0xC000029D,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR = 0xC000029E,
+ MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE = 0xC000029F,
+ MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH = 0xC00002A0,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE = 0xC00002A1,
+ MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX = 0xC00002A2,
+ MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED = 0xC00002A3,
+ MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS = 0xC00002A4,
+ MD_NTSTATUS_WIN_STATUS_DS_BUSY = 0xC00002A5,
+ MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE = 0xC00002A6,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED = 0xC00002A7,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS = 0xC00002A8,
+ MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER = 0xC00002A9,
+ MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR = 0xC00002AA,
+ MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION = 0xC00002AB,
+ MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF = 0xC00002AC,
+ MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN = 0xC00002AD,
+ MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS = 0xC00002AE,
+ MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED = 0xC00002AF,
+ MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE = 0xC00002B0,
+ MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED = 0xC00002B1,
+ MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT = 0xC00002B2,
+ MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY = 0xC00002B3,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS = 0xC00002B4,
+ MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS = 0xC00002B5,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED = 0xC00002B6,
+ MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS = 0xC00002B7,
+ MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE = 0xC00002B8,
+ MD_NTSTATUS_WIN_STATUS_NOINTERFACE = 0xC00002B9,
+ MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED = 0xC00002BA,
+ MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED = 0xC00002C1,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP = 0xC00002C2,
+ MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED = 0xC00002C3,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE = 0xC00002C4,
+ MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR = 0xC00002C5,
+ MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY = 0xC00002C6,
+ MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE = 0xC00002C7,
+ MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM = 0xC00002C8,
+ MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION = 0xC00002C9,
+ MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL = 0xC00002CA,
+ MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE = 0xC00002CB,
+ MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED = 0xC00002CC,
+ MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION = 0xC00002CD,
+ MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION = 0xC00002CE,
+ MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED = 0xC00002CF,
+ MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID = 0xC00002D0,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE = 0xC00002D1,
+ MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED = 0xC00002D2,
+ MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID = 0xC00002D3,
+ MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE = 0xC00002D4,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 0xC00002D5,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 0xC00002D6,
+ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D7,
+ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 0xC00002D8,
+ MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D9,
+ MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 0xC00002DA,
+ MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 0xC00002DB,
+ MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS = 0xC00002DC,
+ MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED = 0xC00002DD,
+ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER = 0xC00002DE,
+ MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD = 0xC00002DF,
+ MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY = 0xC00002E0,
+ MD_NTSTATUS_WIN_STATUS_DS_CANT_START = 0xC00002E1,
+ MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE = 0xC00002E2,
+ MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE = 0xC00002E3,
+ MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED = 0xC00002E4,
+ MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 0xC00002E5,
+ MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS = 0xC00002E6,
+ MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 0xC00002E7,
+ MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION = 0xC00002E8,
+ MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED = 0xC00002E9,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE = 0xC00002EA,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN = 0xC00002EB,
+ MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE = 0xC00002EC,
+ MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE = 0xC00002ED,
+ MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED = 0xC00002EE,
+ MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY = 0xC00002EF,
+ MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND = 0xC00002F0,
+ MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES = 0xC00002F1,
+ MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE = 0xC00002F2,
+ MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID = 0xC00002F3,
+ MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED = 0xC00002F4,
+ MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC = 0xC00002F5,
+ MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED = 0xC00002F6,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS = 0xC00002F7,
+ MD_NTSTATUS_WIN_STATUS_NO_PA_DATA = 0xC00002F8,
+ MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH = 0xC00002F9,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED = 0xC00002FA,
+ MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST = 0xC00002FB,
+ MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER = 0xC00002FC,
+ MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE = 0xC00002FD,
+ MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS = 0xC00002FE,
+ MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS = 0xC00002FF,
+ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS = 0xC0000300,
+ MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED = 0xC0000301,
+ MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED = 0xC0000302,
+ MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED = 0xC0000303,
+ MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED = 0xC0000304,
+ MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE = 0xC0000305,
+ MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE = 0xC0000306,
+ MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT = 0xC0000307,
+ MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED = 0xC0000308,
+ MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR = 0xC0000309,
+ MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH = 0xC000030A,
+ MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED = 0xC000030B,
+ MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED = 0xC000030C,
+ MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE = 0xC0000320,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321,
+ MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY = 0xC0000322,
+ MD_NTSTATUS_WIN_STATUS_HOST_DOWN = 0xC0000350,
+ MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH = 0xC0000351,
+ MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG = 0xC0000352,
+ MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET = 0xC0000353,
+ MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE = 0xC0000354,
+ MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE = 0xC0000355,
+ MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED = 0xC0000356,
+ MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT = 0xC0000357,
+ MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 0xC0000358,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32 = 0xC0000359,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64 = 0xC000035A,
+ MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS = 0xC000035B,
+ MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED = 0xC000035C,
+ MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK = 0xC000035D,
+ MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED = 0xC000035E,
+ MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER = 0xC000035F,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT = 0xC0000361,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH = 0xC0000362,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER = 0xC0000363,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER = 0xC0000364,
+ MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY = 0xC0000365,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR = 0xC0000366,
+ MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED = 0xC0000368,
+ MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER = 0xC0000369,
+ MD_NTSTATUS_WIN_STATUS_MCA_OCCURED = 0xC000036A,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL = 0xC000036B,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED = 0xC000036C,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR = 0xC000036D,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE = 0xC000036E,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL = 0xC000036F,
+ MD_NTSTATUS_WIN_STATUS_NO_SECRETS = 0xC0000371,
+ MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 0xC0000372,
+ MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH = 0xC0000373,
+ MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION = 0xC0000374,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN = 0xC0000380,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED = 0xC0000381,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED = 0xC0000382,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD = 0xC0000383,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER = 0xC0000384,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE = 0xC0000385,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET = 0xC0000386,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR = 0xC0000387,
+ MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED = 0xC0000388,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED = 0xC0000389,
+ MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED = 0xC000038A,
+ MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C = 0xC000038B,
+ MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE = 0xC000038C,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED = 0xC000038D,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD = 0xC000038E,
+ MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT = 0xC000038F,
+ MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED = 0xC0000401,
+ MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED = 0xC0000402,
+ MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED = 0xC0000403,
+ MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE = 0xC0000404,
+ MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND = 0xC0000405,
+ MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR = 0xC0000406,
+ MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE = 0xC0000407,
+ MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED = 0xC0000408,
+ MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN = 0xC0000409,
+ MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT = 0xC000040A,
+ MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE = 0xC000040B,
+ MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC = 0xC000040C,
+ MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC = 0xC000040D,
+ MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED = 0xC000040E,
+ MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED = 0xC000040F,
+ MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED = 0xC0000410,
+ MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE = 0xC0000411,
+ MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED = 0xC0000412,
+ MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED = 0xC0000413,
+ MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED = 0xC0000414,
+ MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD = 0xC0000415,
+ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 0xC0000416,
+ MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER = 0xC0000417,
+ MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED = 0xC0000418,
+ MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST = 0xC0000419,
+ MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST = 0xC000041A,
+ MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST = 0xC000041B,
+ MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME = 0xC000041C,
+ MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION = 0xC000041D,
+ MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE = 0xC0000420,
+ MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP = 0xC0000421,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK = 0xC0000423,
+ MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED = 0xC0000424,
+ MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED = 0xC0000425,
+ MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED = 0xC0000426,
+ MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION = 0xC0000427,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH = 0xC0000428,
+ MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE = 0xC0000429,
+ MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE = 0xC000042A,
+ MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B,
+ MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED = 0xC000042C,
+ MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT = 0xC000042D,
+ MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE = 0xC000042F,
+ MD_NTSTATUS_WIN_STATUS_BEYOND_VDL = 0xC0000432,
+ MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS = 0xC0000433,
+ MD_NTSTATUS_WIN_STATUS_PTE_CHANGED = 0xC0000434,
+ MD_NTSTATUS_WIN_STATUS_PURGE_FAILED = 0xC0000435,
+ MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION = 0xC0000440,
+ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 0xC0000441,
+ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER = 0xC0000442,
+ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 0xC0000443,
+ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 0xC0000444,
+ MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE = 0xC0000445,
+ MD_NTSTATUS_WIN_STATUS_INVALID_LABEL = 0xC0000446,
+ MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED = 0xC0000450,
+ MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE = 0xC0000451,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND = 0xC0000452,
+ MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION = 0xC0000453,
+ MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES = 0xC0000454,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SESSION = 0xC0000455,
+ MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION = 0xC0000456,
+ MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION = 0xC0000457,
+ MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT = 0xC0000458,
+ MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED = 0xC0000459,
+ MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED = 0xC0000460,
+ MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED = 0xC0000461,
+ MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION = 0xC0000462,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED = 0xC0000463,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE = 0xC0000464,
+ MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN = 0xC0000465,
+ MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE = 0xC0000466,
+ MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE = 0xC0000467,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES = 0xC0000468,
+ MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING = 0xC0000469,
+ MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY = 0xC000046A,
+ MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE = 0xC000046B,
+ MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED = 0xC000046C,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED = 0xC000046D,
+ MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 0xC000046E,
+ MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR = 0xC0000470,
+ MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION = 0xC0000471,
+ MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED = 0xC0000472,
+ MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS = 0xC0000473,
+ MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT = 0xC0000474,
+ MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST = 0xC0000475,
+ MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS = 0xC0000476,
+ MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH = 0xC0000477,
+ MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED = 0xC0000478,
+ MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE = 0xC0000479,
+ MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED = 0xC000047A,
+ MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED = 0xC000047B,
+ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED = 0xC000047C,
+ MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT = 0xC000047D,
+ MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION = 0xC000047E,
+ MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN = 0xC000047F,
+ MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE = 0xC0000480,
+ MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED = 0xC0000481,
+ MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT = 0xC0000482,
+ MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR = 0xC0000483,
+ MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME = 0xC0000500,
+ MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX = 0xC0000501,
+ MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK = 0xC0000502,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS = 0xC0000503,
+ MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE = 0xC0000504,
+ MD_NTSTATUS_WIN_STATUS_INVALID_CAP = 0xC0000505,
+ MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS = 0xC0000506,
+ MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION = 0xC0000602,
+ MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED = 0xC0000603,
+ MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED = 0xC0000604,
+ MD_NTSTATUS_WIN_STATUS_PORT_CLOSED = 0xC0000700,
+ MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST = 0xC0000701,
+ MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE = 0xC0000702,
+ MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED = 0xC0000703,
+ MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH = 0xC0000704,
+ MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705,
+ MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE = 0xC0000706,
+ MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED = 0xC0000707,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE = 0xC0000708,
+ MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR = 0xC0000709,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION = 0xC000070A,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED = 0xC000070B,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED = 0xC000070C,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED = 0xC000070D,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED = 0xC000070E,
+ MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION = 0xC000070F,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING = 0xC0000710,
+ MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING = 0xC0000711,
+ MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED = 0xC0000712,
+ MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION = 0xC0000713,
+ MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE = 0xC0000714,
+ MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED = 0xC0000715,
+ MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION = 0xC0000716,
+ MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION = 0xC0000717,
+ MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED = 0xC0000718,
+ MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH = 0xC0000719,
+ MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B,
+ MD_NTSTATUS_WIN_STATUS_INVALID_THREAD = 0xC000071C,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION = 0xC000071D,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK = 0xC000071E,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG = 0xC000071F,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK = 0xC0000720,
+ MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721,
+ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED = 0xC0000800,
+ MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801,
+ MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED = 0xC0000802,
+ MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED = 0xC0000804,
+ MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS = 0xC0000805,
+ MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY = 0xC0000806,
+ MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL = 0xC0000808,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL = 0xC0000809,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED = 0xC000080A,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE = 0xC000080B,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL = 0xC000080C,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED = 0xC000080D,
+ MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED = 0xC000080E,
+ MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS = 0xC000080F,
+ MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE = 0xC0000810,
+ MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS = 0xC0000811,
+ MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT = 0xC0000901,
+ MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED = 0xC0000902,
+ MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE = 0xC0000903,
+ MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE = 0xC0000904,
+ MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED = 0xC0000905,
+ MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED = 0xC0000906,
+ MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED = 0xC0000907,
+ MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE = 0xC0000908,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK = 0xC0000909,
+ MD_NTSTATUS_WIN_STATUS_BAD_KEY = 0xC000090A,
+ MD_NTSTATUS_WIN_STATUS_BAD_DATA = 0xC000090B,
+ MD_NTSTATUS_WIN_STATUS_NO_KEY = 0xC000090C,
+ MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED = 0xC0000910,
+ MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION = 0xC0009898,
+ MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE = 0xC000A000,
+ MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED = 0xC000A001,
+ MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH = 0xC000A002,
+ MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION = 0xC000A003,
+ MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION = 0xC000A004,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION = 0xC000A005,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW = 0xC000A010,
+ MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW = 0xC000A011,
+ MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED = 0xC000A012,
+ MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED = 0xC000A013,
+ MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED = 0xC000A014,
+ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080,
+ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081,
+ MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082,
+ MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR = 0xC000A083,
+ MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR = 0xC000A084,
+ MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT = 0xC000A085,
+ MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE = 0xC000A086,
+ MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 0xC000A087,
+ MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND = 0xC000A088,
+ MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE = 0xC000A089,
+ MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED = 0xC000A100,
+ MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT = 0xC000A101,
+ MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED = 0xC000A121,
+ MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID = 0xC000A122,
+ MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED = 0xC000A123,
+ MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET = 0xC000A124,
+ MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED = 0xC000A125,
+ MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE = 0xC000A126,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL = 0xC000A141,
+ MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING = 0xC000A142,
+ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT = 0xC000A143,
+ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 0xC000A145,
+ MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS = 0xC000A146,
+ MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER = 0xC000A200,
+ MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER = 0xC000A201,
+ MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH = 0xC000A202,
+ MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND = 0xC000A281,
+ MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED = 0xC000A282,
+ MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT = 0xC000A283,
+ MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED = 0xC000A284,
+ MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED = 0xC000A285,
+ MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1,
+ MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2,
+ MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3,
+ MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4,
+ MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE = 0xC0010001,
+ MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE = 0xC0010002,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING = 0xC0020001,
+ MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING = 0xC0020003,
+ MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID = 0xC0020006,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT = 0xC0020007,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR = 0xC0020008,
+ MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND = 0xC0020009,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT = 0xC002000A,
+ MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND = 0xC002000B,
+ MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED = 0xC002000C,
+ MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED = 0xC002000D,
+ MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING = 0xC002000E,
+ MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED = 0xC002000F,
+ MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING = 0xC0020010,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE = 0xC0020011,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF = 0xC0020012,
+ MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS = 0xC0020013,
+ MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS = 0xC0020014,
+ MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT = 0xC0020015,
+ MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES = 0xC0020016,
+ MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE = 0xC0020017,
+ MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY = 0xC0020018,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS = 0xC0020019,
+ MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE = 0xC002001A,
+ MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED = 0xC002001B,
+ MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE = 0xC002001C,
+ MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR = 0xC002001D,
+ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN = 0xC002001F,
+ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE = 0xC0020021,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG = 0xC0020022,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND = 0xC0020023,
+ MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME = 0xC0020024,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX = 0xC0020025,
+ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX = 0xC0020026,
+ MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS = 0xC0020028,
+ MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT = 0xC0020029,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE = 0xC002002A,
+ MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL = 0xC002002B,
+ MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG = 0xC002002C,
+ MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND = 0xC002002D,
+ MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE = 0xC002002E,
+ MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH = 0xC002002F,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE = 0xC0020030,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL = 0xC0020031,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY = 0xC0020032,
+ MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE = 0xC0020033,
+ MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY = 0xC0020034,
+ MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP = 0xC0020035,
+ MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED = 0xC0020036,
+ MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT = 0xC0020037,
+ MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME = 0xC0020038,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION = 0xC0020039,
+ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS = 0xC002003A,
+ MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED = 0xC002003B,
+ MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND = 0xC002003C,
+ MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS = 0xC002003D,
+ MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND = 0xC002003E,
+ MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE = 0xC002003F,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID = 0xC0020040,
+ MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT = 0xC0020041,
+ MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE = 0xC0020042,
+ MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR = 0xC0020043,
+ MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE = 0xC0020044,
+ MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR = 0xC0020045,
+ MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO = 0xC0020046,
+ MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW = 0xC0020047,
+ MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW = 0xC0020048,
+ MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS = 0xC0020049,
+ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS = 0xC002004A,
+ MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND = 0xC002004B,
+ MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE = 0xC002004C,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT = 0xC002004D,
+ MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES = 0xC002004F,
+ MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED = 0xC0020050,
+ MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE = 0xC0020051,
+ MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE = 0xC0020052,
+ MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL = 0xC0020053,
+ MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME = 0xC0020054,
+ MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR = 0xC0020055,
+ MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR = 0xC0020057,
+ MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED = 0xC0020058,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE = 0xC0020062,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL = 0xC0020063,
+ MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED = 0xC0020064,
+ MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED = 0xC0020065,
+ MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES = 0xC0030001,
+ MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL = 0xC0030002,
+ MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE = 0xC0030003,
+ MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT = 0xC0030004,
+ MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH = 0xC0030005,
+ MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED = 0xC0030006,
+ MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH = 0xC0030007,
+ MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE = 0xC0030008,
+ MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER = 0xC0030009,
+ MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE = 0xC003000A,
+ MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL = 0xC003000B,
+ MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA = 0xC003000C,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION = 0xC0030059,
+ MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION = 0xC003005A,
+ MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION = 0xC003005B,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT = 0xC003005C,
+ MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION = 0xC003005D,
+ MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION = 0xC003005E,
+ MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED = 0xC003005F,
+ MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR = 0xC0030060,
+ MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY = 0xC0030061,
+ MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE = 0xC0040035,
+ MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED = 0xC0040036,
+ MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED = 0xC0040037,
+ MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID = 0xC0040038,
+ MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED = 0xC0040039,
+ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID = 0xC00A0001,
+ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD = 0xC00A0002,
+ MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND = 0xC00A0003,
+ MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING = 0xC00A0006,
+ MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF = 0xC00A0007,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND = 0xC00A0008,
+ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME = 0xC00A0009,
+ MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR = 0xC00A000A,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT = 0xC00A000B,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER = 0xC00A000C,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE = 0xC00A000D,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY = 0xC00A000E,
+ MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE = 0xC00A000F,
+ MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR = 0xC00A0010,
+ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID = 0xC00A0012,
+ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE = 0xC00A0013,
+ MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED = 0xC00A0014,
+ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND = 0xC00A0015,
+ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION = 0xC00A0016,
+ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY = 0xC00A0017,
+ MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE = 0xC00A0018,
+ MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID = 0xC00A0022,
+ MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE = 0xC00A0024,
+ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT = 0xC00A0026,
+ MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT = 0xC00A0027,
+ MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT = 0xC00A0028,
+ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED = 0xC00A002A,
+ MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED = 0xC00A002B,
+ MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD = 0xC00A002E,
+ MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND = 0xC00A002F,
+ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID = 0xC00A0030,
+ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED = 0xC00A0031,
+ MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR = 0xC00A0032,
+ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET = 0xC00A0033,
+ MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE = 0xC00A0034,
+ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE = 0xC00A0035,
+ MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING = 0xC00A0036,
+ MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED = 0xC00A0037,
+ MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR = 0xC00A0038,
+ MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS = 0xC00A0039,
+ MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR = 0xC00A003A,
+ MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND = 0xC00B0001,
+ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE = 0xC00B0002,
+ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG = 0xC00B0003,
+ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME = 0xC00B0004,
+ MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME = 0xC00B0005,
+ MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED = 0xC00B0006,
+ MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP = 0xC00B0007,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE = 0xC0130001,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS = 0xC0130002,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS = 0xC0130003,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND = 0xC0130004,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND = 0xC0130005,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS = 0xC0130006,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND = 0xC0130007,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS = 0xC0130008,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND = 0xC0130009,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST = 0xC013000A,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER = 0xC013000B,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN = 0xC013000C,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE = 0xC013000D,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER = 0xC013000E,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS = 0xC013000F,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK = 0xC0130010,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS = 0xC0130011,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP = 0xC0130012,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED = 0xC0130013,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED = 0xC0130014,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT = 0xC0130015,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL = 0xC0130016,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED = 0xC0130017,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH = 0xC0130018,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL = 0xC0130019,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS = 0xC0130020,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR = 0xC0130021,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED = 0xC0130022,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED = 0xC0130023,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING = 0xC0130024,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS = 0xC0130025,
+ MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL = 0xC0130026,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE = 0xC0140001,
+ MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW = 0xC0140002,
+ MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED = 0xC0140003,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX = 0xC0140004,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT = 0xC0140005,
+ MD_NTSTATUS_WIN_STATUS_ACPI_FATAL = 0xC0140006,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME = 0xC0140007,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE = 0xC0140008,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE = 0xC0140009,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE = 0xC014000A,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT = 0xC014000B,
+ MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED = 0xC014000C,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE = 0xC014000D,
+ MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION = 0xC014000E,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA = 0xC014000F,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION = 0xC0140010,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE = 0xC0140011,
+ MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK = 0xC0140012,
+ MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED = 0xC0140013,
+ MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED = 0xC0140014,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL = 0xC0140015,
+ MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED = 0xC0140016,
+ MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER = 0xC0140017,
+ MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS = 0xC0140018,
+ MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE = 0xC0140019,
+ MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED = 0xC0140020,
+ MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED = 0xC0140021,
+ MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND = 0xC0150001,
+ MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX = 0xC0150002,
+ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT = 0xC0150003,
+ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND = 0xC0150004,
+ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR = 0xC0150005,
+ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR = 0xC0150006,
+ MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED = 0xC0150007,
+ MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND = 0xC0150008,
+ MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT = 0xC0150009,
+ MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE = 0xC015000A,
+ MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED = 0xC015000B,
+ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING = 0xC015000C,
+ MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET = 0xC015000E,
+ MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION = 0xC015000F,
+ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION = 0xC0150010,
+ MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION = 0xC0150011,
+ MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 0xC0150012,
+ MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED = 0xC0150013,
+ MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK = 0xC0150014,
+ MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION = 0xC0150015,
+ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 0xC0150016,
+ MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 0xC0150017,
+ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 0xC0150018,
+ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR = 0xC0150019,
+ MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT = 0xC015001A,
+ MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH = 0xC015001B,
+ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 0xC015001C,
+ MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT = 0xC015001D,
+ MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 0xC015001E,
+ MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY = 0xC015001F,
+ MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED = 0xC0150020,
+ MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH = 0xC0150021,
+ MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG = 0xC0150022,
+ MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED = 0xC0150023,
+ MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE = 0xC0150024,
+ MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED = 0xC0150025,
+ MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED = 0xC0150026,
+ MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING = 0xC0150027,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT = 0xC0190001,
+ MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION = 0xC0190002,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE = 0xC0190003,
+ MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED = 0xC0190004,
+ MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE = 0xC0190005,
+ MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT = 0xC0190006,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED = 0xC0190007,
+ MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM = 0xC0190008,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE = 0xC019000A,
+ MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE = 0xC019000B,
+ MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH = 0xC019000C,
+ MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS = 0xC019000F,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED = 0xC0190010,
+ MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND = 0xC0190011,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS = 0xC0190012,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID = 0xC0190013,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED = 0xC0190014,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED = 0xC0190015,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED = 0xC0190016,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER = 0xC0190017,
+ MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID = 0xC0190018,
+ MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED = 0xC0190019,
+ MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS = 0xC0190021,
+ MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND = 0xC0190022,
+ MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID = 0xC0190023,
+ MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xC0190024,
+ MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xC0190025,
+ MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xC0190026,
+ MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID = 0xC0190028,
+ MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED = 0xC0190030,
+ MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED = 0xC0190032,
+ MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR = 0xC0190033,
+ MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT = 0xC0190036,
+ MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xC0190037,
+ MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY = 0xC0190038,
+ MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY = 0xC0190039,
+ MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST = 0xC019003A,
+ MD_NTSTATUS_WIN_STATUS_TM_VOLATILE = 0xC019003B,
+ MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED = 0xC019003C,
+ MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT = 0xC019003D,
+ MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION = 0xC019003E,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xC019003F,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xC0190040,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION = 0xC0190043,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xC0190044,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN = 0xC0190045,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS = 0xC0190046,
+ MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME = 0xC0190047,
+ MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES = 0xC0190048,
+ MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION = 0xC0190049,
+ MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH = 0xC019004A,
+ MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION = 0xC019004B,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK = 0xC019004C,
+ MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS = 0xC019004D,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND = 0xC019004E,
+ MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND = 0xC019004F,
+ MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND = 0xC0190050,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND = 0xC0190051,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE = 0xC0190052,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 0xC0190053,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT = 0xC0190054,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED = 0xC0190055,
+ MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 0xC0190056,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED = 0xC0190057,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG = 0xC0190058,
+ MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION = 0xC0190059,
+ MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 0xC019005A,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED = 0xC019005B,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH = 0xC019005C,
+ MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT = 0xC019005D,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH = 0xC019005E,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR = 0xC019005F,
+ MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE = 0xC0190060,
+ MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED = 0xC0190061,
+ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID = 0xC01A0001,
+ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID = 0xC01A0002,
+ MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED = 0xC01A0003,
+ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE = 0xC01A0004,
+ MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE = 0xC01A0005,
+ MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED = 0xC01A0006,
+ MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID = 0xC01A0007,
+ MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID = 0xC01A0008,
+ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION = 0xC01A0009,
+ MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID = 0xC01A000A,
+ MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID = 0xC01A000B,
+ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT = 0xC01A000D,
+ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID = 0xC01A000E,
+ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT = 0xC01A000F,
+ MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID = 0xC01A0010,
+ MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE = 0xC01A0011,
+ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED = 0xC01A0012,
+ MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG = 0xC01A0013,
+ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED = 0xC01A0014,
+ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED = 0xC01A0015,
+ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID = 0xC01A0016,
+ MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT = 0xC01A0017,
+ MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL = 0xC01A0018,
+ MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT = 0xC01A0019,
+ MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID = 0xC01A001A,
+ MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID = 0xC01A001B,
+ MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID = 0xC01A001C,
+ MD_NTSTATUS_WIN_STATUS_LOG_FULL = 0xC01A001D,
+ MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED = 0xC01A001E,
+ MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED = 0xC01A001F,
+ MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS = 0xC01A0020,
+ MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS = 0xC01A0021,
+ MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL = 0xC01A0022,
+ MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS = 0xC01A0023,
+ MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED = 0xC01A0024,
+ MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED = 0xC01A0025,
+ MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS = 0xC01A0026,
+ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED = 0xC01A0027,
+ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED = 0xC01A0028,
+ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED = 0xC01A0029,
+ MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID = 0xC01A002A,
+ MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID = 0xC01A002B,
+ MD_NTSTATUS_WIN_STATUS_LOG_PINNED = 0xC01A002C,
+ MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED = 0xC01A002D,
+ MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY = 0xC01A002E,
+ MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED = 0xC01A002F,
+ MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION = 0xC01A0030,
+ MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD = 0xC01B00EA,
+ MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED = 0xC01C0001,
+ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED = 0xC01C0002,
+ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST = 0xC01C0003,
+ MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO = 0xC01C0004,
+ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST = 0xC01C0005,
+ MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION = 0xC01C0006,
+ MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED = 0xC01C0007,
+ MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY = 0xC01C0008,
+ MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP = 0xC01C0009,
+ MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR = 0xC01C000A,
+ MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT = 0xC01C000B,
+ MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL = 0xC01C000C,
+ MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY = 0xC01C000D,
+ MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED = 0xC01C000E,
+ MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH = 0xC01C000F,
+ MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH = 0xC01C0010,
+ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION = 0xC01C0011,
+ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION = 0xC01C0012,
+ MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND = 0xC01C0013,
+ MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND = 0xC01C0014,
+ MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND = 0xC01C0015,
+ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND = 0xC01C0016,
+ MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION = 0xC01C0017,
+ MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS = 0xC01C0018,
+ MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT = 0xC01C0019,
+ MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED = 0xC01C001A,
+ MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED = 0xC01C001B,
+ MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED = 0xC01C001C,
+ MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY = 0xC01C0020,
+ MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY = 0xC01C0023,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR = 0xC01D0001,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT = 0xC01D0002,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM = 0xC01D0003,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK = 0xC01D0004,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED = 0xC01D0005,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK = 0xC01D0006,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK = 0xC01D0007,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA = 0xC01D0008,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK = 0xC01D0009,
+ MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE = 0xC01D000A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER = 0xC01E0000,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER = 0xC01E0001,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER = 0xC01E0002,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET = 0xC01E0003,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL = 0xC01E0004,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED = 0xC01E0005,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED = 0xC01E0007,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH = 0xC01E0009,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE = 0xC01E000D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED = 0xC01E000E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY = 0xC01E0102,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID = 0xC01E0106,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED = 0xC01E0108,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION = 0xC01E0109,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE = 0xC01E0110,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION = 0xC01E0111,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED = 0xC01E0112,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE = 0xC01E0113,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE = 0xC01E0114,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE = 0xC01E0115,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST = 0xC01E0116,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE = 0xC01E0200,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY = 0xC01E0300,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED = 0xC01E0301,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED = 0xC01E0302,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN = 0xC01E0303,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE = 0xC01E0304,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET = 0xC01E0305,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED = 0xC01E0306,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET = 0xC01E0308,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET = 0xC01E0309,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY = 0xC01E030A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION = 0xC01E030B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION = 0xC01E030C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE = 0xC01E0310,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE = 0xC01E0311,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET = 0xC01E0312,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY = 0xC01E0313,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET = 0xC01E0314,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET = 0xC01E0315,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET = 0xC01E0316,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET = 0xC01E0317,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET = 0xC01E0318,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH = 0xC01E0319,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY = 0xC01E031A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET = 0xC01E031B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE = 0xC01E031C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET = 0xC01E031D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET = 0xC01E031F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET = 0xC01E0320,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET = 0xC01E0321,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE = 0xC01E0322,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN = 0xC01E0323,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE = 0xC01E0324,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION = 0xC01E0325,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES = 0xC01E0326,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY = 0xC01E0327,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE = 0xC01E0328,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET = 0xC01E0329,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET = 0xC01E032A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR = 0xC01E032B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET = 0xC01E032C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET = 0xC01E032D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE = 0xC01E032E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE = 0xC01E032F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED = 0xC01E0330,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE = 0xC01E0331,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE = 0xC01E0332,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET = 0xC01E0333,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER = 0xC01E0334,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR = 0xC01E0335,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN = 0xC01E0336,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY = 0xC01E0337,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED = 0xC01E0338,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY = 0xC01E0339,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE = 0xC01E033A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE = 0xC01E033B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE = 0xC01E033C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT = 0xC01E033D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS = 0xC01E033E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE = 0xC01E033F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY = 0xC01E0340,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT = 0xC01E0341,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE = 0xC01E0342,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN = 0xC01E0343,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL = 0xC01E0344,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION = 0xC01E0345,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED = 0xC01E0346,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP = 0xC01E0347,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED = 0xC01E0348,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED = 0xC01E0349,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET = 0xC01E034A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON = 0xC01E034D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE = 0xC01E034E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE = 0xC01E034F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS = 0xC01E0350,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING = 0xC01E0352,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED = 0xC01E0353,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS = 0xC01E0354,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT = 0xC01E0355,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM = 0xC01E0356,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN = 0xC01E0357,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT = 0xC01E0358,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED = 0xC01E0359,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION = 0xC01E035A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE = 0xC01E035B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET = 0xC01E035C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED = 0xC01E0400,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED = 0xC01E0401,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER = 0xC01E0430,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED = 0xC01E0431,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED = 0xC01E0432,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY = 0xC01E0433,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED = 0xC01E0434,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON = 0xC01E0435,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE = 0xC01E0436,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER = 0xC01E0438,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED = 0xC01E043B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED = 0xC01E0500,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED = 0xC01E0501,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED = 0xC01E0502,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS = 0xC01E0503,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST = 0xC01E0505,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR = 0xC01E050B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE = 0xC01E050C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH = 0xC01E050E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED = 0xC01E050F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED = 0xC01E0510,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED = 0xC01E0511,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM = 0xC01E0512,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP = 0xC01E0513,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP = 0xC01E0514,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA = 0xC01E0515,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET = 0xC01E0516,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH = 0xC01E0517,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE = 0xC01E0518,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS = 0xC01E051A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS = 0xC01E051C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST = 0xC01E051D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR = 0xC01E051E,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS = 0xC01E051F,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED = 0xC01E0520,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST = 0xC01E0521,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED = 0xC01E0580,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST = 0xC01E0581,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA = 0xC01E0582,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA = 0xC01E0583,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED = 0xC01E0584,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA = 0xC01E0585,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE = 0xC01E0586,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING = 0xC01E0587,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR = 0xC01E0588,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND = 0xC01E0589,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH = 0xC01E058A,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM = 0xC01E058B,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE = 0xC01E058C,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS = 0xC01E058D,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED = 0xC01E05E0,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E05E1,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E05E2,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E05E3,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER = 0xC01E05E4,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E05E5,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL = 0xC01E05E6,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR = 0xC01E05E7,
+ MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E05E8,
+ MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME = 0xC0210000,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED = 0xC0210001,
+ MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION = 0xC0210002,
+ MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL = 0xC0210003,
+ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS = 0xC0210004,
+ MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE = 0xC0210005,
+ MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED = 0xC0210006,
+ MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED = 0xC0210007,
+ MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE = 0xC0210008,
+ MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED = 0xC0210009,
+ MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA = 0xC021000A,
+ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND = 0xC021000B,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME = 0xC021000C,
+ MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR = 0xC021000D,
+ MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR = 0xC021000E,
+ MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE = 0xC021000F,
+ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE = 0xC0210010,
+ MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION = 0xC0210011,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME = 0xC0210012,
+ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND = 0xC0210013,
+ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID = 0xC0210014,
+ MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK = 0xC0210015,
+ MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED = 0xC0210016,
+ MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO = 0xC0210017,
+ MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR = 0xC0210018,
+ MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK = 0xC0210019,
+ MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID = 0xC021001A,
+ MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION = 0xC021001B,
+ MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG = 0xC021001C,
+ MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED = 0xC021001D,
+ MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED = 0xC021001E,
+ MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER = 0xC021001F,
+ MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY = 0xC0210020,
+ MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED = 0xC0210021,
+ MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS = 0xC0210022,
+ MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED = 0xC0210023,
+ MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY = 0xC0210024,
+ MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED = 0xC0210025,
+ MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE = 0xC0210026,
+ MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED = 0xC0210027,
+ MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED = 0xC0210028,
+ MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG = 0xC0210029,
+ MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE = 0xC021002A,
+ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL = 0xC0210030,
+ MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID = 0xC0210031,
+ MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210032,
+ MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210033,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK = 0xC0210034,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER = 0xC0210035,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING = 0xC0210036,
+ MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE = 0xC0210037,
+ MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED = 0xC0210038,
+ MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED = 0xC0210039,
+ MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE = 0xC021003A,
+ MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT = 0xC021003B,
+ MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT = 0xC021003C,
+ MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME = 0xC021003D,
+ MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED = 0xC021003E,
+ MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED = 0xC021003F,
+ MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND = 0xC0220001,
+ MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND = 0xC0220002,
+ MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND = 0xC0220003,
+ MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND = 0xC0220004,
+ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND = 0xC0220005,
+ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006,
+ MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND = 0xC0220007,
+ MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND = 0xC0220008,
+ MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS = 0xC0220009,
+ MD_NTSTATUS_WIN_STATUS_FWP_IN_USE = 0xC022000A,
+ MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS = 0xC022000B,
+ MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION = 0xC022000C,
+ MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS = 0xC022000D,
+ MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS = 0xC022000E,
+ MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED = 0xC022000F,
+ MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED = 0xC0220010,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN = 0xC0220011,
+ MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT = 0xC0220012,
+ MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED = 0xC0220013,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER = 0xC0220014,
+ MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY = 0xC0220015,
+ MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH = 0xC0220016,
+ MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT = 0xC0220017,
+ MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS = 0xC0220018,
+ MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED = 0xC0220019,
+ MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH = 0xC022001A,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE = 0xC022001B,
+ MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER = 0xC022001C,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR = 0xC022001D,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS = 0xC022001E,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK = 0xC022001F,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE = 0xC0220020,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL = 0xC0220021,
+ MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY = 0xC0220022,
+ MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME = 0xC0220023,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE = 0xC0220024,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT = 0xC0220025,
+ MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH = 0xC0220026,
+ MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH = 0xC0220027,
+ MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS = 0xC0220028,
+ MD_NTSTATUS_WIN_STATUS_FWP_RESERVED = 0xC0220029,
+ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION = 0xC022002A,
+ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD = 0xC022002B,
+ MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER = 0xC022002C,
+ MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER = 0xC022002D,
+ MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER = 0xC022002E,
+ MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT = 0xC022002F,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD = 0xC0220030,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP = 0xC0220031,
+ MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED = 0xC0220032,
+ MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH = 0xC0220033,
+ MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH = 0xC0220034,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER = 0xC0220035,
+ MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS = 0xC0220036,
+ MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED = 0xC0220037,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM = 0xC0220038,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM = 0xC0220039,
+ MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM = 0xC022003A,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION = 0xC022003B,
+ MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD = 0xC022003C,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT = 0xC022003D,
+ MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY = 0xC022003E,
+ MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED = 0xC022003F,
+ MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL = 0xC0220040,
+ MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED = 0xC0220041,
+ MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME = 0xC0220042,
+ MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON = 0xC0220043,
+ MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING = 0xC0220044,
+ MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY = 0xC0220100,
+ MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING = 0xC0220101,
+ MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE = 0xC0220102,
+ MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND = 0xC0220103,
+ MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP = 0xC0220104,
+ MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING = 0xC0230002,
+ MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION = 0xC0230004,
+ MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS = 0xC0230005,
+ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND = 0xC0230006,
+ MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED = 0xC0230007,
+ MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED = 0xC0230008,
+ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL = 0xC0230009,
+ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS = 0xC023000A,
+ MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND = 0xC023000B,
+ MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED = 0xC023000C,
+ MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS = 0xC023000D,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET = 0xC023000F,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST = 0xC0230010,
+ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY = 0xC0230011,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH = 0xC0230014,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA = 0xC0230015,
+ MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT = 0xC0230016,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID = 0xC0230017,
+ MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED = 0xC0230018,
+ MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA = 0xC0230019,
+ MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE = 0xC023001A,
+ MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND = 0xC023001B,
+ MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE = 0xC023001C,
+ MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED = 0xC023001D,
+ MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT = 0xC023001E,
+ MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED = 0xC023001F,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS = 0xC0230022,
+ MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED = 0xC023002A,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND = 0xC023002B,
+ MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION = 0xC023002C,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT = 0xC023002D,
+ MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE = 0xC023002E,
+ MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE = 0xC023002F,
+ MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED = 0xC0230030,
+ MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED = 0xC02300BB,
+ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY = 0xC023100F,
+ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012,
+ MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013,
+ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000,
+ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE = 0xC0232001,
+ MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002,
+ MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003,
+ MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004,
+ MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK = 0xC0290000,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL = 0xC0290001,
+ MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX = 0xC0290002,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER = 0xC0290003,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE = 0xC0290004,
+ MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED = 0xC0290005,
+ MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED = 0xC0290006,
+ MD_NTSTATUS_WIN_STATUS_TPM_DISABLED = 0xC0290007,
+ MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD = 0xC0290008,
+ MD_NTSTATUS_WIN_STATUS_TPM_FAIL = 0xC0290009,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL = 0xC029000A,
+ MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED = 0xC029000B,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE = 0xC029000C,
+ MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND = 0xC029000D,
+ MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC = 0xC029000E,
+ MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL = 0xC029000F,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO = 0xC0290010,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE = 0xC0290011,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOSRK = 0xC0290012,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB = 0xC0290013,
+ MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET = 0xC0290014,
+ MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES = 0xC0290015,
+ MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM = 0xC0290016,
+ MD_NTSTATUS_WIN_STATUS_TPM_SIZE = 0xC0290017,
+ MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL = 0xC0290018,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE = 0xC0290019,
+ MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD = 0xC029001A,
+ MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR = 0xC029001B,
+ MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST = 0xC029001C,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL = 0xC029001D,
+ MD_NTSTATUS_WIN_STATUS_TPM_BADTAG = 0xC029001E,
+ MD_NTSTATUS_WIN_STATUS_TPM_IOERROR = 0xC029001F,
+ MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR = 0xC0290020,
+ MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR = 0xC0290021,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE = 0xC0290022,
+ MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT = 0xC0290023,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE = 0xC0290024,
+ MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE = 0xC0290025,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT = 0xC0290026,
+ MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG = 0xC0290027,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY = 0xC0290028,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION = 0xC0290029,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME = 0xC029002A,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE = 0xC029002B,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE = 0xC029002C,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE = 0xC029002D,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION = 0xC029002E,
+ MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT = 0xC029002F,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL = 0xC0290030,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL = 0xC0290031,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE = 0xC0290032,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL = 0xC0290033,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE = 0xC0290034,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE = 0xC0290035,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS = 0xC0290036,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY = 0xC0290037,
+ MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION = 0xC0290038,
+ MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN = 0xC0290039,
+ MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED = 0xC029003A,
+ MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT = 0xC029003B,
+ MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED = 0xC029003C,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY = 0xC029003D,
+ MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY = 0xC029003E,
+ MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE = 0xC029003F,
+ MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT = 0xC0290040,
+ MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED = 0xC0290041,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES = 0xC0290042,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE = 0xC0290043,
+ MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL = 0xC0290044,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER = 0xC0290045,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE = 0xC0290046,
+ MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP = 0xC0290047,
+ MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES = 0xC0290048,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR = 0xC0290049,
+ MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING = 0xC029004A,
+ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK = 0xC029004B,
+ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY = 0xC029004C,
+ MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN = 0xC029004D,
+ MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE = 0xC029004E,
+ MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL = 0xC029004F,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES = 0xC0290050,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0 = 0xC0290051,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1 = 0xC0290052,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS = 0xC0290053,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS = 0xC0290054,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE = 0xC0290055,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY = 0xC0290056,
+ MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W = 0xC0290057,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE = 0xC0290058,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE = 0xC0290059,
+ MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT = 0xC029005A,
+ MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS = 0xC029005B,
+ MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE = 0xC029005C,
+ MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION = 0xC029005D,
+ MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE = 0xC029005E,
+ MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY = 0xC029005F,
+ MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK = 0xC0290061,
+ MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE = 0xC0290062,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE = 0xC0290063,
+ MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED = 0xC0290400,
+ MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE = 0xC0290401,
+ MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE = 0xC0290402,
+ MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED = 0xC0290403,
+ MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED = 0xC0290404,
+ MD_NTSTATUS_WIN_STATUS_TPM_RETRY = 0xC0290800,
+ MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST = 0xC0290801,
+ MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST = 0xC0290802,
+ MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING = 0xC0290803,
+ MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED = 0xC0291001,
+ MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS = 0xC0291002,
+ MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND = 0xC0291003,
+ MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED = 0xC0291004,
+ MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER = 0xC0291005,
+ MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED = 0xC0291006,
+ MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK = 0xC0292000,
+ MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY = 0xC0292001,
+ MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE = 0xC0292002,
+ MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER = 0xC0292003,
+ MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED = 0xC0292004,
+ MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED = 0xC0292005,
+ MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL = 0xC0292006,
+ MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR = 0xC0292007,
+ MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED = 0xC0292008,
+ MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED = 0xC0292009,
+ MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND = 0xC029200A,
+ MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND = 0xC029200B,
+ MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED = 0xC029200C,
+ MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND = 0xC029200D,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE = 0xC0350002,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT = 0xC0350003,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT = 0xC0350004,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER = 0xC0350005,
+ MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED = 0xC0350006,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE = 0xC0350007,
+ MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED = 0xC0350008,
+ MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY = 0xC0350009,
+ MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE = 0xC035000A,
+ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY = 0xC035000B,
+ MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP = 0xC035000C,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID = 0xC035000D,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX = 0xC035000E,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID = 0xC0350011,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID = 0xC0350012,
+ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS = 0xC0350013,
+ MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED = 0xC0350014,
+ MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED = 0xC0350016,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE = 0xC0350017,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE = 0xC0350018,
+ MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE = 0xC0350019,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO = 0xC035001A,
+ MD_NTSTATUS_WIN_STATUS_HV_NO_DATA = 0xC035001B,
+ MD_NTSTATUS_WIN_STATUS_HV_INACTIVE = 0xC035001C,
+ MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES = 0xC035001D,
+ MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE = 0xC035001E,
+ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER = 0xC0350033,
+ MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS = 0xC0350038,
+ MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX = 0xC0350041,
+ MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT = 0xC0351000,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI = 0xC0360001,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA = 0xC0360003,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED = 0xC0360004,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET = 0xC0360005,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP = 0xC0360007,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP = 0xC0360008,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP = 0xC0360009,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK = 0xC0368000,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST = 0xC0368001,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET = 0xC0368002,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED = 0xC0368003,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES = 0xC0368004,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 0xC0368005,
+ MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 0xC0368006,
+ MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER = 0xC0370001,
+ MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS = 0xC0370002,
+ MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL = 0xC0370003,
+ MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT = 0xC0370004,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME = 0xC0370005,
+ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG = 0xC0370006,
+ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG = 0xC0370007,
+ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS = 0xC0370008,
+ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST = 0xC0370009,
+ MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND = 0xC037000A,
+ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS = 0xC037000B,
+ MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT = 0xC037000C,
+ MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED = 0xC037000D,
+ MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED = 0xC037000E,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS = 0xC037000F,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX = 0xC0370010,
+ MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED = 0xC0370011,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE = 0xC0370012,
+ MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW = 0xC0370013,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE = 0xC0370014,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE = 0xC0370015,
+ MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE = 0xC0370016,
+ MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED = 0xC0370017,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE = 0xC0370018,
+ MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED = 0xC0370019,
+ MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED = 0xC037001A,
+ MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED = 0xC037001B,
+ MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING = 0xC037001C,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE = 0xC037001D,
+ MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT = 0xC037001E,
+ MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED = 0xC037001F,
+ MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET = 0xC0370020,
+ MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED = 0xC0370021,
+ MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET = 0xC0370022,
+ MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED = 0xC0370023,
+ MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL = 0xC0370024,
+ MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE = 0xC0370025,
+ MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT = 0xC0370026,
+ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT = 0xC0370027,
+ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM = 0xC0370028,
+ MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE = 0xC0370029,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL = 0xC0380001,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED = 0xC0380002,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC = 0xC0380003,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED = 0xC0380004,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME = 0xC0380005,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE = 0xC0380006,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC = 0xC0380007,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID = 0xC0380008,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID = 0xC0380009,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER = 0xC038000A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID = 0xC038000B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS = 0xC038000C,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED = 0xC038000D,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL = 0xC038000E,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS = 0xC038000F,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS = 0xC0380010,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING = 0xC0380011,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY = 0xC0380012,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE = 0xC0380013,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED = 0xC0380014,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID = 0xC0380015,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED = 0xC0380016,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS = 0xC0380017,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES = 0xC0380018,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED = 0xC0380019,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED = 0xC038001A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS = 0xC038001B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION = 0xC038001C,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED = 0xC038001D,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION = 0xC038001E,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH = 0xC038001F,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED = 0xC0380020,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID = 0xC0380021,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS = 0xC0380022,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC = 0xC0380023,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE = 0xC0380024,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID = 0xC0380025,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING = 0xC0380026,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED = 0xC0380027,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING = 0xC0380028,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED = 0xC0380029,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS = 0xC038002A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER = 0xC038002B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET = 0xC038002C,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID = 0xC038002D,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID = 0xC038002E,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE = 0xC038002F,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID = 0xC0380030,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID = 0xC0380031,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID = 0xC0380032,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE = 0xC0380033,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM = 0xC0380034,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM = 0xC0380035,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID = 0xC0380036,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED = 0xC0380037,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC = 0xC0380038,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE = 0xC0380039,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID = 0xC038003A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE = 0xC038003B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING = 0xC038003C,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING = 0xC038003D,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID = 0xC038003E,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5 = 0xC038003F,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE = 0xC0380040,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID = 0xC0380041,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS = 0xC0380042,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS = 0xC0380043,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE = 0xC0380044,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK = 0xC0380045,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID = 0xC0380046,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID = 0xC0380047,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE = 0xC0380048,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED = 0xC0380049,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED = 0xC038004A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE = 0xC038004B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED = 0xC038004C,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID = 0xC038004D,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE = 0xC038004E,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK = 0xC038004F,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE = 0xC0380050,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE = 0xC0380051,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK = 0xC0380052,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED = 0xC0380053,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID = 0xC0380054,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID = 0xC0380055,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED = 0xC0380056,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED = 0xC0380057,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES = 0xC0380058,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT = 0xC0380059,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID = 0xC038005A,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED = 0xC038005B,
+ MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED = 0xC038005C,
+ MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS = 0xC0390002,
+ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING = 0xC03A0001,
+ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH = 0xC03A0002,
+ MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT = 0xC03A0003,
+ MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN = 0xC03A0004,
+ MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION = 0xC03A0005,
+ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH = 0xC03A0006,
+ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION = 0xC03A0007,
+ MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT = 0xC03A0008,
+ MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE = 0xC03A0009,
+ MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT = 0xC03A000A,
+ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE = 0xC03A000B,
+ MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH = 0xC03A000C,
+ MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND = 0xC03A000D,
+ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH = 0xC03A000E,
+ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH = 0xC03A000F,
+ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE = 0xC03A0010,
+ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE = 0xC03A0011,
+ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE = 0xC03A0012,
+ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE = 0xC03A0013,
+ MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND = 0xC03A0014,
+ MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK = 0xC03A0015,
+ MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED = 0xC03A0016,
+ MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH = 0xC03A0017,
+ MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED = 0xC03A0018,
+ MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT = 0xC03A0019,
+ MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION = 0xC03A001A,
+ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE = 0xC03A001B,
+ MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE = 0xC03A001C,
+ MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE = 0xC03A001D,
+ MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED = 0xC03A001E,
+ MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE = 0xC03A001F,
+ MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED = 0xC03A0020,
+ MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE = 0xC03A0021,
+ MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE = 0xC03A0022,
+ MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE = 0xC03A0023,
+ MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE = 0xC03A0024,
+ MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL = 0xC03A0028,
+ MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND = 0xC0400001,
+ MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY = 0xC0400002,
+ MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL = 0xC0400003,
+ MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL = 0xC0400004,
+ MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED = 0xC0400005,
+ MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY = 0xC0400006,
+ MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION = 0xC0410001,
+ MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION = 0xC0410002,
+ MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION = 0xC0410003,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE = 0xC0420001,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED = 0xC0420002,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED = 0xC0420003,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU = 0xC0420004,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION = 0xC0420005,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED = 0xC0420006,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET = 0xC0420007,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION = 0xC0420008,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL = 0xC0420009,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND = 0xC042000A,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG = 0xC042000B,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0xC042000C,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH = 0xC042000D,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY = 0xC042000E,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION = 0xC042000F,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE = 0xC0420010,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES = 0xC0420011,
+ MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR = 0xC0421000,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED = 0xC0430001,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION = 0xC0430002,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY = 0xC0430003,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 0xC0430004,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED = 0xC0430005,
+ MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED = 0xC0430007,
+ MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND = 0xC0440001,
+ MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST = 0xC0440002,
+ MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED = 0xC0440003,
+ MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED = 0xC0440004,
+ MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY = 0xC0440005,
+ MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID = 0xC0500003,
+ MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED = 0xC0510001,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED = 0xC05C0000,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE = 0xC05CFF00,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE = 0xC05CFF01,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED = 0xC05CFF02,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED = 0xC05CFF03,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED = 0xC05CFF04,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED = 0xC05CFF05,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED = 0xC05CFF06,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT = 0xC05CFF07,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE = 0xC05CFF08,
+ MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH = 0xC05CFF09,
+ MD_NTSTATUS_WIN_STATUS_VHD_SHARED = 0xC05CFF0A,
+ MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID = 0xC0E70003,
+ MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID = 0xC0E70004,
+ MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID = 0xC0E70009,
+ MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID = 0xC0E7000A,
+ MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES = 0xC0E7000B
+} MDNTStatusCodeWin;
+
// These constants are defined in the MSDN documentation of
// the EXCEPTION_RECORD structure.
typedef enum {
@@ -113,4 +2258,12 @@ typedef enum {
MD_ACCESS_VIOLATION_WIN_EXEC = 8
} MDAccessViolationTypeWin;
+// These constants are defined in the MSDN documentation of
+// the EXCEPTION_RECORD structure.
+typedef enum {
+ MD_IN_PAGE_ERROR_WIN_READ = 0,
+ MD_IN_PAGE_ERROR_WIN_WRITE = 1,
+ MD_IN_PAGE_ERROR_WIN_EXEC = 8
+} MDInPageErrorTypeWin;
+
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_format.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_format.h
index 28a81d4..225433b 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_format.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_format.h
@@ -79,10 +79,10 @@
*/
typedef struct {
- u_int32_t data1;
- u_int16_t data2;
- u_int16_t data3;
- u_int8_t data4[8];
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
} MDGUID; /* GUID */
@@ -97,7 +97,6 @@ typedef struct {
#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */
/* 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_MIPS 0x00010000 /* CONTEXT_R4000 (same value as x86?) */
#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */
/* As of Windows 7 SP1, the number of flag bits has increased to
@@ -110,11 +109,13 @@ typedef struct {
* structure should never be allocated directly. The actual structure type
* can be determined by examining the context_flags field. */
typedef struct {
- u_int32_t context_flags;
+ uint32_t context_flags;
} MDRawContextBase;
#include "minidump_cpu_amd64.h"
#include "minidump_cpu_arm.h"
+#include "minidump_cpu_arm64.h"
+#include "minidump_cpu_mips.h"
#include "minidump_cpu_ppc.h"
#include "minidump_cpu_ppc64.h"
#include "minidump_cpu_sparc.h"
@@ -126,19 +127,19 @@ typedef struct {
typedef struct {
- u_int32_t signature;
- u_int32_t struct_version;
- u_int32_t file_version_hi;
- u_int32_t file_version_lo;
- u_int32_t product_version_hi;
- u_int32_t product_version_lo;
- u_int32_t file_flags_mask; /* Identifies valid bits in fileFlags */
- u_int32_t file_flags;
- u_int32_t file_os;
- u_int32_t file_type;
- u_int32_t file_subtype;
- u_int32_t file_date_hi;
- u_int32_t file_date_lo;
+ uint32_t signature;
+ uint32_t struct_version;
+ uint32_t file_version_hi;
+ uint32_t file_version_lo;
+ uint32_t product_version_hi;
+ uint32_t product_version_lo;
+ uint32_t file_flags_mask; /* Identifies valid bits in fileFlags */
+ uint32_t file_flags;
+ uint32_t file_os;
+ uint32_t file_type;
+ uint32_t file_subtype;
+ uint32_t file_date_hi;
+ uint32_t file_date_lo;
} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */
/* For (MDVSFixedFileInfo).signature */
@@ -231,10 +232,10 @@ typedef struct {
/* An MDRVA is an offset into the minidump file. The beginning of the
* MDRawHeader is at offset 0. */
-typedef u_int32_t MDRVA; /* RVA */
+typedef uint32_t MDRVA; /* RVA */
typedef struct {
- u_int32_t data_size;
+ uint32_t data_size;
MDRVA rva;
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */
@@ -242,22 +243,22 @@ typedef struct {
typedef struct {
/* The base address of the memory range on the host that produced the
* minidump. */
- u_int64_t start_of_memory_range;
+ uint64_t start_of_memory_range;
MDLocationDescriptor memory;
} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */
typedef struct {
- u_int32_t signature;
- u_int32_t version;
- u_int32_t stream_count;
+ uint32_t signature;
+ uint32_t version;
+ uint32_t stream_count;
MDRVA stream_directory_rva; /* A |stream_count|-sized array of
* MDRawDirectory structures. */
- u_int32_t checksum; /* Can be 0. In fact, that's all that's
+ uint32_t checksum; /* Can be 0. In fact, that's all that's
* been found in minidump files. */
- u_int32_t time_date_stamp; /* time_t */
- u_int64_t flags;
+ uint32_t time_date_stamp; /* time_t */
+ uint64_t flags;
} MDRawHeader; /* MINIDUMP_HEADER */
/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the
@@ -302,7 +303,7 @@ typedef enum {
typedef struct {
- u_int32_t stream_type;
+ uint32_t stream_type;
MDLocationDescriptor location;
} MDRawDirectory; /* MINIDUMP_DIRECTORY */
@@ -327,6 +328,10 @@ typedef enum {
MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */
MD_THREAD_INFO_LIST_STREAM = 17,
MD_HANDLE_OPERATION_LIST_STREAM = 18,
+ MD_TOKEN_STREAM = 19,
+ MD_JAVASCRIPT_DATA_STREAM = 20,
+ MD_SYSTEM_MEMORY_INFO_STREAM = 21,
+ MD_PROCESS_VM_COUNTERS_STREAM = 22,
MD_LAST_RESERVED_STREAM = 0x0000ffff,
/* Breakpad extension types. 0x4767 = "Gg" */
@@ -341,32 +346,36 @@ typedef enum {
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
- MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug */
+ MD_LINUX_DSO_DEBUG = 0x4767000A, /* MDRawDebug{32,64} */
+
+ /* Crashpad extension types. 0x4350 = "CP"
+ * See Crashpad's minidump/minidump_extensions.h. */
+ MD_CRASHPAD_INFO_STREAM = 0x43500001, /* MDRawCrashpadInfo */
} MDStreamType; /* MINIDUMP_STREAM_TYPE */
typedef struct {
- u_int32_t length; /* Length of buffer in bytes (not characters),
- * excluding 0-terminator */
- u_int16_t buffer[1]; /* UTF-16-encoded, 0-terminated */
+ uint32_t length; /* Length of buffer in bytes (not characters),
+ * excluding 0-terminator */
+ uint16_t buffer[1]; /* UTF-16-encoded, 0-terminated */
} MDString; /* MINIDUMP_STRING */
static const size_t MDString_minsize = offsetof(MDString, buffer[0]);
typedef struct {
- u_int32_t thread_id;
- u_int32_t suspend_count;
- u_int32_t priority_class;
- u_int32_t priority;
- u_int64_t teb; /* Thread environment block */
+ uint32_t thread_id;
+ uint32_t suspend_count;
+ uint32_t priority_class;
+ uint32_t priority;
+ uint64_t teb; /* Thread environment block */
MDMemoryDescriptor stack;
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
} MDRawThread; /* MINIDUMP_THREAD */
typedef struct {
- u_int32_t number_of_threads;
+ uint32_t number_of_threads;
MDRawThread threads[1];
} MDRawThreadList; /* MINIDUMP_THREAD_LIST */
@@ -375,10 +384,10 @@ static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
typedef struct {
- u_int64_t base_of_image;
- u_int32_t size_of_image;
- u_int32_t checksum; /* 0 if unknown */
- u_int32_t time_date_stamp; /* time_t */
+ uint64_t base_of_image;
+ uint32_t size_of_image;
+ uint32_t checksum; /* 0 if unknown */
+ uint32_t time_date_stamp; /* time_t */
MDRVA module_name_rva; /* MDString, pathname or filename */
MDVSFixedFileInfo version_info;
@@ -402,8 +411,8 @@ typedef struct {
* As a workaround, reserved0 and reserved1 are instead defined here as
* four 32-bit quantities. This should be harmless, as there are
* currently no known uses for these fields. */
- u_int32_t reserved0[2];
- u_int32_t reserved1[2];
+ uint32_t reserved0[2];
+ uint32_t reserved1[2];
} MDRawModule; /* MINIDUMP_MODULE */
/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
@@ -419,15 +428,15 @@ typedef struct {
* MDCVInfoPDB70 is the expected structure type with recent toolchains. */
typedef struct {
- u_int32_t signature;
- u_int32_t offset; /* Offset to debug data (expect 0 in minidump) */
+ uint32_t signature;
+ uint32_t offset; /* Offset to debug data (expect 0 in minidump) */
} MDCVHeader;
typedef struct {
MDCVHeader cv_header;
- u_int32_t signature; /* time_t debug information created */
- u_int32_t age; /* revision of PDB file */
- u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
+ uint32_t signature; /* time_t debug information created */
+ uint32_t age; /* revision of PDB file */
+ uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
} MDCVInfoPDB20;
static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
@@ -436,10 +445,10 @@ static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */
typedef struct {
- u_int32_t cv_signature;
+ uint32_t cv_signature;
MDGUID signature; /* GUID, identifies PDB file */
- u_int32_t age; /* Identifies incremental changes to PDB file */
- u_int8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
+ uint32_t age; /* Identifies incremental changes to PDB file */
+ uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
* 0-terminated 8-bit character data (UTF-8?) */
} MDCVInfoPDB70;
@@ -448,15 +457,26 @@ static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70,
#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */
+/*
+ * Modern ELF toolchains insert a "build id" into the ELF headers that
+ * usually contains a hash of some ELF headers + sections to uniquely
+ * identify a binary.
+ *
+ * https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/compiling-build-id.html
+ * https://sourceware.org/binutils/docs-2.26/ld/Options.html#index-g_t_002d_002dbuild_002did-292
+ */
typedef struct {
- u_int32_t data1[2];
- u_int32_t data2;
- u_int32_t data3;
- u_int32_t data4;
- u_int32_t data5[3];
- u_int8_t extra[2];
+ uint32_t cv_signature;
+ uint8_t build_id[1]; /* Bytes of build id from GNU_BUILD_ID ELF note.
+ * This is variable-length, but usually 20 bytes
+ * as the binutils ld default is a SHA-1 hash. */
} MDCVInfoELF;
+static const size_t MDCVInfoELF_minsize = offsetof(MDCVInfoELF,
+ build_id[0]);
+
+#define MD_CVINFOELF_SIGNATURE 0x4270454c /* cvSignature = 'BpEL' */
+
/* In addition to the two CodeView record formats above, used for linking
* to external pdb files, it is possible for debugging data to be carried
* directly in the CodeView record itself. These signature values will
@@ -479,12 +499,12 @@ typedef struct {
* obsolete with modules built by recent toolchains. */
typedef struct {
- u_int32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
+ uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
* this debug record type is mostly obsolete. */
- u_int32_t length; /* Length of entire MDImageDebugMisc structure */
- u_int8_t unicode; /* True if data is multibyte */
- u_int8_t reserved[3];
- u_int8_t data[1];
+ uint32_t length; /* Length of entire MDImageDebugMisc structure */
+ uint8_t unicode; /* True if data is multibyte */
+ uint8_t reserved[3];
+ uint8_t data[1];
} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */
static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
@@ -492,7 +512,7 @@ static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
typedef struct {
- u_int32_t number_of_modules;
+ uint32_t number_of_modules;
MDRawModule modules[1];
} MDRawModuleList; /* MINIDUMP_MODULE_LIST */
@@ -501,7 +521,7 @@ static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,
typedef struct {
- u_int32_t number_of_memory_ranges;
+ uint32_t number_of_memory_ranges;
MDMemoryDescriptor memory_ranges[1];
} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */
@@ -512,33 +532,34 @@ static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
typedef struct {
- u_int32_t exception_code; /* Windows: MDExceptionCodeWin,
+ uint32_t exception_code; /* Windows: MDExceptionCodeWin,
* Mac OS X: MDExceptionMac,
* Linux: MDExceptionCodeLinux. */
- u_int32_t exception_flags; /* Windows: 1 if noncontinuable,
+ uint32_t exception_flags; /* Windows: 1 if noncontinuable,
Mac OS X: MDExceptionCodeMac. */
- u_int64_t exception_record; /* Address (in the minidump-producing host's
+ uint64_t exception_record; /* Address (in the minidump-producing host's
* memory) of another MDException, for
* nested exceptions. */
- u_int64_t exception_address; /* The address that caused the exception.
+ uint64_t exception_address; /* The address that caused the exception.
* Mac OS X: exception subcode (which is
* typically the address). */
- u_int32_t number_parameters; /* Number of valid elements in
+ uint32_t number_parameters; /* Number of valid elements in
* exception_information. */
- u_int32_t __align;
- u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
+ uint32_t __align;
+ uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
} MDException; /* MINIDUMP_EXCEPTION */
-#include "minidump_exception_win32.h"
-#include "minidump_exception_mac.h"
#include "minidump_exception_linux.h"
+#include "minidump_exception_mac.h"
+#include "minidump_exception_ps3.h"
#include "minidump_exception_solaris.h"
+#include "minidump_exception_win32.h"
typedef struct {
- u_int32_t thread_id; /* Thread in which the exception
+ uint32_t thread_id; /* Thread in which the exception
* occurred. Corresponds to
* (MDRawThread).thread_id. */
- u_int32_t __align;
+ uint32_t __align;
MDException exception_record;
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */
@@ -546,34 +567,63 @@ typedef struct {
typedef union {
struct {
- u_int32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
- u_int32_t version_information; /* cpuid 1: eax */
- u_int32_t feature_information; /* cpuid 1: edx */
- u_int32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
+ uint32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */
+ uint32_t version_information; /* cpuid 1: eax */
+ uint32_t feature_information; /* cpuid 1: edx */
+ uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */
} x86_cpu_info;
struct {
- u_int64_t processor_features[2];
+ uint32_t cpuid;
+ uint32_t elf_hwcaps; /* linux specific, 0 otherwise */
+ } arm_cpu_info;
+ struct {
+ uint64_t processor_features[2];
} other_cpu_info;
} MDCPUInformation; /* CPU_INFORMATION */
+/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps.
+ * This matches the Linux kernel definitions from <asm/hwcaps.h> */
+typedef enum {
+ MD_CPU_ARM_ELF_HWCAP_SWP = (1 << 0),
+ MD_CPU_ARM_ELF_HWCAP_HALF = (1 << 1),
+ MD_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2),
+ MD_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3),
+ MD_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4),
+ MD_CPU_ARM_ELF_HWCAP_FPA = (1 << 5),
+ MD_CPU_ARM_ELF_HWCAP_VFP = (1 << 6),
+ MD_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7),
+ MD_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8),
+ MD_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9),
+ MD_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10),
+ MD_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11),
+ MD_CPU_ARM_ELF_HWCAP_NEON = (1 << 12),
+ MD_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13),
+ MD_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14),
+ MD_CPU_ARM_ELF_HWCAP_TLS = (1 << 15),
+ MD_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16),
+ MD_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17),
+ MD_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18),
+} MDCPUInformationARMElfHwCaps;
typedef struct {
/* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
* structure as returned by GetSystemInfo */
- u_int16_t processor_architecture;
- u_int16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
- u_int16_t processor_revision; /* x86: 0xMMSS, where MM=model,
+ uint16_t processor_architecture;
+ uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
+ /* ARM: 6 = ARMv6, 7 = ARMv7 ... */
+ uint16_t processor_revision; /* x86: 0xMMSS, where MM=model,
* SS=stepping */
+ /* ARM: 0 */
- u_int8_t number_of_processors;
- u_int8_t product_type; /* Windows: VER_NT_* from WinNT.h */
+ uint8_t number_of_processors;
+ uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */
/* The next 5 fields are from the OSVERSIONINFO structure as returned
* by GetVersionEx */
- u_int32_t major_version;
- u_int32_t minor_version;
- u_int32_t build_number;
- u_int32_t platform_id;
+ uint32_t major_version;
+ uint32_t minor_version;
+ uint32_t build_number;
+ uint32_t platform_id;
MDRVA csd_version_rva; /* MDString further identifying the
* host OS.
* Windows: name of the installed OS
@@ -582,8 +632,8 @@ typedef struct {
* (sw_vers -buildVersion).
* Linux: uname -srvmo */
- u_int16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
- u_int16_t reserved2;
+ uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
+ uint16_t reserved2;
MDCPUInformation cpu;
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */
@@ -605,6 +655,9 @@ typedef enum {
MD_CPU_ARCHITECTURE_X86_WIN64 = 10,
/* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */
+ MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */
+ MD_CPU_ARCHITECTURE_ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */
+ MD_CPU_ARCHITECTURE_MIPS64 = 0x8004, /* Breakpad-defined value for MIPS64 */
MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */
} MDCPUArchitecture;
@@ -622,51 +675,221 @@ typedef enum {
MD_OS_IOS = 0x8102, /* iOS */
MD_OS_LINUX = 0x8201, /* Linux */
MD_OS_SOLARIS = 0x8202, /* Solaris */
- MD_OS_ANDROID = 0x8203 /* Android */
+ MD_OS_ANDROID = 0x8203, /* Android */
+ MD_OS_PS3 = 0x8204, /* PS3 */
+ MD_OS_NACL = 0x8205 /* Native Client (NaCl) */
} MDOSPlatform;
+typedef struct {
+ uint64_t base_of_image;
+ uint32_t size_of_image;
+ uint32_t checksum;
+ uint32_t time_date_stamp;
+ MDRVA module_name_rva;
+} MDRawUnloadedModule;
+
+typedef struct {
+ uint32_t size_of_header;
+ uint32_t size_of_entry;
+ uint32_t number_of_entries;
+} MDRawUnloadedModuleList; /* MINIDUMP_UNLOADED_MODULE_LIST */
+
+typedef struct {
+ uint16_t year;
+ uint16_t month;
+ uint16_t day_of_week;
+ uint16_t day;
+ uint16_t hour;
+ uint16_t minute;
+ uint16_t second;
+ uint16_t milliseconds;
+} MDSystemTime; /* SYSTEMTIME */
typedef struct {
- u_int32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */
- u_int32_t flags1;
+ /* Required field. The bias is the difference, in minutes, between
+ * Coordinated Universal Time (UTC) and local time.
+ * Formula: UTC = local time + bias */
+ int32_t bias;
+ /* A description for standard time. For example, "EST" could indicate Eastern
+ * Standard Time. In practice this contains the full time zone names. This
+ * string can be empty. */
+ uint16_t standard_name[32]; /* UTF-16-encoded, 0-terminated */
+ /* A MDSystemTime structure that contains a date and local time when the
+ * transition from daylight saving time to standard time occurs on this
+ * operating system. If the time zone does not support daylight saving time,
+ * the month member in the MDSystemTime structure is zero. */
+ MDSystemTime standard_date;
+ /* The bias value to be used during local time translations that occur during
+ * standard time. */
+ int32_t standard_bias;
+ /* A description for daylight saving time. For example, "PDT" could indicate
+ * Pacific Daylight Time. In practice this contains the full time zone names.
+ * This string can be empty. */
+ uint16_t daylight_name[32]; /* UTF-16-encoded, 0-terminated */
+ /* A MDSystemTime structure that contains a date and local time when the
+ * transition from standard time to daylight saving time occurs on this
+ * operating system. If the time zone does not support daylight saving time,
+ * the month member in the MDSystemTime structure is zero.*/
+ MDSystemTime daylight_date;
+ /* The bias value to be used during local time translations that occur during
+ * daylight saving time. */
+ int32_t daylight_bias;
+} MDTimeZoneInformation; /* TIME_ZONE_INFORMATION */
+
+/* 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
+ * bit is set. */
+typedef struct {
+ uint32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */
+ uint32_t flags1;
/* The next field is only valid if flags1 contains
* MD_MISCINFO_FLAGS1_PROCESS_ID. */
- u_int32_t process_id;
+ uint32_t process_id;
/* The next 3 fields are only valid if flags1 contains
* MD_MISCINFO_FLAGS1_PROCESS_TIMES. */
- u_int32_t process_create_time; /* time_t process started */
- u_int32_t process_user_time; /* seconds of user CPU time */
- u_int32_t process_kernel_time; /* seconds of kernel CPU time */
+ uint32_t process_create_time; /* time_t process started */
+ uint32_t process_user_time; /* seconds of user CPU time */
+ uint32_t process_kernel_time; /* seconds of kernel CPU time */
/* The following fields are not present in MINIDUMP_MISC_INFO but are
* in MINIDUMP_MISC_INFO_2. When this struct is populated, these values
- * may not be set. Use flags1 or sizeOfInfo to determine whether these
+ * may not be set. Use flags1 and size_of_info to determine whether these
* values are present. These are only valid when flags1 contains
* MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */
- u_int32_t processor_max_mhz;
- u_int32_t processor_current_mhz;
- u_int32_t processor_mhz_limit;
- u_int32_t processor_max_idle_state;
- u_int32_t processor_current_idle_state;
-} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2 */
-
-#define MD_MISCINFO_SIZE 24
-#define MD_MISCINFO2_SIZE 44
+ uint32_t processor_max_mhz;
+ uint32_t processor_current_mhz;
+ uint32_t processor_mhz_limit;
+ uint32_t processor_max_idle_state;
+ uint32_t processor_current_idle_state;
+
+ /* The following fields are not present in MINIDUMP_MISC_INFO_2 but are
+ * in MINIDUMP_MISC_INFO_3. 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 is only valid if flags1 contains
+ * MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY. */
+ uint32_t process_integrity_level;
+
+ /* The following field is only valid if flags1 contains
+ * MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS. */
+ uint32_t process_execute_flags;
+
+ /* The following field is only valid if flags1 contains
+ * MD_MISCINFO_FLAGS1_PROTECTED_PROCESS. */
+ uint32_t protected_process;
+
+ /* The following 2 fields are only valid if flags1 contains
+ * MD_MISCINFO_FLAGS1_TIMEZONE. */
+ uint32_t time_zone_id;
+ MDTimeZoneInformation time_zone;
+
+ /* The following fields are not present in MINIDUMP_MISC_INFO_3 but are
+ * in MINIDUMP_MISC_INFO_4. 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 2 fields are only valid if flags1 contains
+ * 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_5, MINIDUMP_MISC_INFO_N */
+
+static const size_t MD_MISCINFO_SIZE =
+ offsetof(MDRawMiscInfo, processor_max_mhz);
+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 =
+ 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. */
typedef enum {
- MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001,
+ MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001,
/* MINIDUMP_MISC1_PROCESS_ID */
- MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002,
+ MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002,
/* MINIDUMP_MISC1_PROCESS_TIMES */
- MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004
+ MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004,
/* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */
+ MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY = 0x00000010,
+ /* MINIDUMP_MISC3_PROCESS_INTEGRITY */
+ MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS = 0x00000020,
+ /* MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS */
+ MD_MISCINFO_FLAGS1_TIMEZONE = 0x00000040,
+ /* MINIDUMP_MISC3_TIMEZONE */
+ MD_MISCINFO_FLAGS1_PROTECTED_PROCESS = 0x00000080,
+ /* MINIDUMP_MISC3_PROTECTED_PROCESS */
+ MD_MISCINFO_FLAGS1_BUILDSTRING = 0x00000100,
+ /* MINIDUMP_MISC4_BUILDSTRING */
+ MD_MISCINFO_FLAGS1_PROCESS_COOKIE = 0x00000200,
+ /* MINIDUMP_MISC5_PROCESS_COOKIE */
} MDMiscInfoFlags1;
-/*
+/*
* Around DbgHelp version 6.0, the style of new LIST structures changed
* from including an array of length 1 at the end of the struct to
* represent the variable-length data to including explicit
@@ -677,24 +900,24 @@ typedef enum {
*/
typedef struct {
- u_int32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */
- u_int32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */
- u_int64_t number_of_entries;
+ uint32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */
+ uint32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */
+ uint64_t number_of_entries;
} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */
typedef struct {
- u_int64_t base_address; /* Base address of a region of pages */
- u_int64_t allocation_base; /* Base address of a range of pages
+ uint64_t base_address; /* Base address of a region of pages */
+ uint64_t allocation_base; /* Base address of a range of pages
* within this region. */
- u_int32_t allocation_protection; /* Memory protection when this region
+ uint32_t allocation_protection; /* Memory protection when this region
* was originally allocated:
* MDMemoryProtection */
- u_int32_t __alignment1;
- u_int64_t region_size;
- u_int32_t state; /* MDMemoryState */
- u_int32_t protection; /* MDMemoryProtection */
- u_int32_t type; /* MDMemoryType */
- u_int32_t __alignment2;
+ uint32_t __alignment1;
+ uint64_t region_size;
+ uint32_t state; /* MDMemoryState */
+ uint32_t protection; /* MDMemoryProtection */
+ uint32_t type; /* MDMemoryType */
+ uint32_t __alignment2;
} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */
/* For (MDRawMemoryInfo).state */
@@ -721,7 +944,7 @@ typedef enum {
} MDMemoryProtection;
/* Used to mask the mutually exclusive options from the combinable flags. */
-const u_int32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF;
+const uint32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF;
/* For (MDRawMemoryInfo).type */
typedef enum {
@@ -738,7 +961,7 @@ typedef enum {
typedef struct {
/* validity is a bitmask with values from MDBreakpadInfoValidity, indicating
* which of the other fields in the structure are valid. */
- u_int32_t validity;
+ uint32_t validity;
/* Thread ID of the handler thread. dump_thread_id should correspond to
* the thread_id of an MDRawThread in the minidump's MDRawThreadList if
@@ -746,7 +969,7 @@ typedef struct {
* the MDRawThreadList does not contain a dedicated thread used to produce
* the minidump, this field should be set to 0 and the validity field
* must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */
- u_int32_t dump_thread_id;
+ uint32_t dump_thread_id;
/* Thread ID of the thread that requested the minidump be produced. As
* with dump_thread_id, requesting_thread_id should correspond to the
@@ -759,7 +982,7 @@ typedef struct {
* other than a thread in the MDRawThreadList, this field should be set
* to 0 and the validity field must not contain
* MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */
- u_int32_t requesting_thread_id;
+ uint32_t requesting_thread_id;
} MDRawBreakpadInfo;
/* For (MDRawBreakpadInfo).validity: */
@@ -777,11 +1000,11 @@ typedef struct {
* written to a file.
* Fixed-length strings are used because MiniDumpWriteDump doesn't offer
* a way for user streams to point to arbitrary RVAs for strings. */
- u_int16_t expression[128]; /* Assertion that failed... */
- u_int16_t function[128]; /* ...within this function... */
- u_int16_t file[128]; /* ...in this file... */
- u_int32_t line; /* ...at this line. */
- u_int32_t type;
+ uint16_t expression[128]; /* Assertion that failed... */
+ uint16_t function[128]; /* ...within this function... */
+ uint16_t file[128]; /* ...in this file... */
+ uint32_t line; /* ...at this line. */
+ uint32_t type;
} MDRawAssertionInfo;
/* For (MDRawAssertionInfo).type: */
@@ -798,21 +1021,75 @@ typedef enum {
} MDAssertionInfoData;
/* These structs are used to store the DSO debug data in Linux minidumps,
- * which is necessary for converting minidumps to usable coredumps. */
+ * which is necessary for converting minidumps to usable coredumps.
+ * Because of a historical accident, several fields are variably encoded
+ * according to client word size, so tools potentially need to support both. */
+
typedef struct {
- void* addr;
+ uint32_t addr;
MDRVA name;
- void* ld;
-} MDRawLinkMap;
+ uint32_t ld;
+} MDRawLinkMap32;
+
+typedef struct {
+ uint32_t version;
+ MDRVA map; /* array of MDRawLinkMap32 */
+ uint32_t dso_count;
+ uint32_t brk;
+ uint32_t ldbase;
+ uint32_t dynamic;
+} MDRawDebug32;
+
+typedef struct {
+ uint64_t addr;
+ MDRVA name;
+ uint64_t ld;
+} MDRawLinkMap64;
+
+typedef struct {
+ uint32_t version;
+ MDRVA map; /* array of MDRawLinkMap64 */
+ uint32_t dso_count;
+ uint64_t brk;
+ uint64_t ldbase;
+ uint64_t dynamic;
+} MDRawDebug64;
+
+/* Crashpad extension types. See Crashpad's minidump/minidump_extensions.h. */
+
+typedef struct {
+ MDRVA key;
+ MDRVA value;
+} MDRawSimpleStringDictionaryEntry;
+
+typedef struct {
+ uint32_t count;
+ MDRawSimpleStringDictionaryEntry entries[0];
+} MDRawSimpleStringDictionary;
+
+typedef struct {
+ uint32_t version;
+ MDLocationDescriptor list_annotations;
+ MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
+} MDRawModuleCrashpadInfo;
+
+typedef struct {
+ uint32_t minidump_module_list_index;
+ MDLocationDescriptor location; /* MDRawModuleCrashpadInfo */
+} MDRawModuleCrashpadInfoLink;
+
+typedef struct {
+ uint32_t count;
+ MDLocationDescriptor modules[0]; /* MDRawModuleCrashpadInfoLink */
+} MDRawModuleCrashpadInfoList;
typedef struct {
- u_int32_t version;
- MDRVA map;
- u_int32_t dso_count;
- void* brk;
- void* ldbase;
- void* dynamic;
-} MDRawDebug;
+ uint32_t version;
+ MDGUID report_id;
+ MDGUID client_id;
+ MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
+ MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */
+} MDRawCrashpadInfo;
#if defined(_MSC_VER)
#pragma warning(pop)
diff --git a/3rdParty/Breakpad/src/google_breakpad/common/minidump_size.h b/3rdParty/Breakpad/src/google_breakpad/common/minidump_size.h
index 918544b..fae5792 100644
--- a/3rdParty/Breakpad/src/google_breakpad/common/minidump_size.h
+++ b/3rdParty/Breakpad/src/google_breakpad/common/minidump_size.h
@@ -76,6 +76,12 @@ class minidump_size<MDCVInfoPDB70> {
};
template<>
+class minidump_size<MDCVInfoELF> {
+ public:
+ static size_t size() { return MDCVInfoELF_minsize; }
+};
+
+template<>
class minidump_size<MDImageDebugMisc> {
public:
static size_t size() { return MDImageDebugMisc_minsize; }
diff --git a/3rdParty/Breakpad/src/processor/scoped_ptr.h b/3rdParty/Breakpad/src/processor/scoped_ptr.h
deleted file mode 100644
index 0d4f7fd..0000000
--- a/3rdParty/Breakpad/src/processor/scoped_ptr.h
+++ /dev/null
@@ -1,335 +0,0 @@
-// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
-// Copyright (c) 2001, 2002 Peter Dimov
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
-//
-
-// scoped_ptr mimics a built-in pointer except that it guarantees deletion
-// of the object pointed to, either on destruction of the scoped_ptr or via
-// an explicit reset(). scoped_ptr is a simple solution for simple needs;
-// use shared_ptr or std::auto_ptr if your needs are more complex.
-
-// *** NOTE ***
-// If your scoped_ptr is a class member of class FOO pointing to a
-// forward declared type BAR (as shown below), then you MUST use a non-inlined
-// version of the destructor. The destructor of a scoped_ptr (called from
-// FOO's destructor) must have a complete definition of BAR in order to
-// destroy it. Example:
-//
-// -- foo.h --
-// class BAR;
-//
-// class FOO {
-// public:
-// FOO();
-// ~FOO(); // Required for sources that instantiate class FOO to compile!
-//
-// private:
-// scoped_ptr<BAR> bar_;
-// };
-//
-// -- foo.cc --
-// #include "foo.h"
-// FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
-
-// scoped_ptr_malloc added by Google
-// When one of these goes out of scope, instead of doing a delete or
-// delete[], it calls free(). scoped_ptr_malloc<char> is likely to see
-// much more use than any other specializations.
-
-// release() added by Google
-// Use this to conditionally transfer ownership of a heap-allocated object
-// to the caller, usually on method success.
-
-#ifndef PROCESSOR_SCOPED_PTR_H__
-#define PROCESSOR_SCOPED_PTR_H__
-
-#include <cstddef> // for std::ptrdiff_t
-#include <assert.h> // for assert
-#include <stdlib.h> // for free() decl
-
-namespace google_breakpad {
-
-template <typename T>
-class scoped_ptr {
- private:
-
- T* ptr;
-
- scoped_ptr(scoped_ptr const &);
- scoped_ptr & operator=(scoped_ptr const &);
-
- public:
-
- typedef T element_type;
-
- explicit scoped_ptr(T* p = 0): ptr(p) {}
-
- ~scoped_ptr() {
- typedef char type_must_be_complete[sizeof(T)];
- delete ptr;
- }
-
- void reset(T* p = 0) {
- typedef char type_must_be_complete[sizeof(T)];
-
- if (ptr != p) {
- delete ptr;
- ptr = p;
- }
- }
-
- T& operator*() const {
- assert(ptr != 0);
- return *ptr;
- }
-
- T* operator->() const {
- assert(ptr != 0);
- return ptr;
- }
-
- bool operator==(T* p) const {
- return ptr == p;
- }
-
- bool operator!=(T* p) const {
- return ptr != p;
- }
-
- T* get() const {
- return ptr;
- }
-
- void swap(scoped_ptr & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
- }
-
- T* release() {
- T* tmp = ptr;
- ptr = 0;
- return tmp;
- }
-
- private:
-
- // no reason to use these: each scoped_ptr should have its own object
- template <typename U> bool operator==(scoped_ptr<U> const& p) const;
- template <typename U> bool operator!=(scoped_ptr<U> const& p) const;
-};
-
-template<typename T> inline
-void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
- a.swap(b);
-}
-
-template<typename T> inline
-bool operator==(T* p, const scoped_ptr<T>& b) {
- return p == b.get();
-}
-
-template<typename T> inline
-bool operator!=(T* p, const scoped_ptr<T>& b) {
- return p != b.get();
-}
-
-// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
-// is guaranteed, either on destruction of the scoped_array or via an explicit
-// reset(). Use shared_array or std::vector if your needs are more complex.
-
-template<typename T>
-class scoped_array {
- private:
-
- T* ptr;
-
- scoped_array(scoped_array const &);
- scoped_array & operator=(scoped_array const &);
-
- public:
-
- typedef T element_type;
-
- explicit scoped_array(T* p = 0) : ptr(p) {}
-
- ~scoped_array() {
- typedef char type_must_be_complete[sizeof(T)];
- delete[] ptr;
- }
-
- void reset(T* p = 0) {
- typedef char type_must_be_complete[sizeof(T)];
-
- if (ptr != p) {
- delete [] ptr;
- ptr = p;
- }
- }
-
- T& operator[](std::ptrdiff_t i) const {
- assert(ptr != 0);
- assert(i >= 0);
- return ptr[i];
- }
-
- bool operator==(T* p) const {
- return ptr == p;
- }
-
- bool operator!=(T* p) const {
- return ptr != p;
- }
-
- T* get() const {
- return ptr;
- }
-
- void swap(scoped_array & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
- }
-
- T* release() {
- T* tmp = ptr;
- ptr = 0;
- return tmp;
- }
-
- private:
-
- // no reason to use these: each scoped_array should have its own object
- template <typename U> bool operator==(scoped_array<U> const& p) const;
- template <typename U> bool operator!=(scoped_array<U> const& p) const;
-};
-
-template<class T> inline
-void swap(scoped_array<T>& a, scoped_array<T>& b) {
- a.swap(b);
-}
-
-template<typename T> inline
-bool operator==(T* p, const scoped_array<T>& b) {
- return p == b.get();
-}
-
-template<typename T> inline
-bool operator!=(T* p, const scoped_array<T>& b) {
- return p != b.get();
-}
-
-
-// This class wraps the c library function free() in a class that can be
-// passed as a template argument to scoped_ptr_malloc below.
-class ScopedPtrMallocFree {
- public:
- inline void operator()(void* x) const {
- free(x);
- }
-};
-
-// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
-// second template argument, the functor used to free the object.
-
-template<typename T, typename FreeProc = ScopedPtrMallocFree>
-class scoped_ptr_malloc {
- private:
-
- T* ptr;
-
- scoped_ptr_malloc(scoped_ptr_malloc const &);
- scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
-
- public:
-
- typedef T element_type;
-
- explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
-
- ~scoped_ptr_malloc() {
- typedef char type_must_be_complete[sizeof(T)];
- free_((void*) ptr);
- }
-
- void reset(T* p = 0) {
- typedef char type_must_be_complete[sizeof(T)];
-
- if (ptr != p) {
- free_((void*) ptr);
- ptr = p;
- }
- }
-
- T& operator*() const {
- assert(ptr != 0);
- return *ptr;
- }
-
- T* operator->() const {
- assert(ptr != 0);
- return ptr;
- }
-
- bool operator==(T* p) const {
- return ptr == p;
- }
-
- bool operator!=(T* p) const {
- return ptr != p;
- }
-
- T* get() const {
- return ptr;
- }
-
- void swap(scoped_ptr_malloc & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
- }
-
- T* release() {
- T* tmp = ptr;
- ptr = 0;
- return tmp;
- }
-
- private:
-
- // no reason to use these: each scoped_ptr_malloc should have its own object
- template <typename U, typename GP>
- bool operator==(scoped_ptr_malloc<U, GP> const& p) const;
- template <typename U, typename GP>
- bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;
-
- static FreeProc const free_;
-};
-
-template<typename T, typename FP>
-FP const scoped_ptr_malloc<T,FP>::free_ = FP();
-
-template<typename T, typename FP> inline
-void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {
- a.swap(b);
-}
-
-template<typename T, typename FP> inline
-bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {
- return p == b.get();
-}
-
-template<typename T, typename FP> inline
-bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {
- return p != b.get();
-}
-
-} // namespace google_breakpad
-
-#endif // PROCESSOR_SCOPED_PTR_H__