зеркало из https://github.com/mozilla/pjs.git
bug 567424 - sync to Breakpad revision 619 to pick up OS X symbol dumping changes (64-bit support + DWARF CFI support)
We still have a few local patches that have not yet been upstreamed, but they're all up in the Breakpad issue tracker now: -- Bug 544936, part 1: Add the ability to generate a minidump of a child process at any time (linux). r=ted Bug 555309, part 2: Allow a particular subprocess thread to be "blamed" in an OOP minidump. r=bsmedberg Bug 555309, part 4: Insert an artificial exception stream into non-crash browser-side minidumps. r=bsmedberg Bug 544936, part 2: Add the ability to generate a minidump of a child process at any time (windows). r=ted Bug 555309, part 2: Allow a particular subprocess thread to be blamed in an OOP minidump. (windows bits) r=bsmedberg Bug 555309, part 4: Insert an artificial exception stream into non-crash browser-side minidumps. r=bsmedberg (win32) Windows changes: http://breakpad.appspot.com/115002/show Linux changes: http://breakpad.appspot.com/123001/show -- bug 557113 - sort out crash report certificate issues on Maemo. r=mfinkle,johnath http://breakpad.appspot.com/121002/show -- Plus one more I discovered while testing this patch on 64-bit OS X: http://breakpad.appspot.com/124001/show --HG-- extra : rebase_source : f0df7e87d26822884401b8cb1a5633c958e92c93
This commit is contained in:
Родитель
69f9ac1f77
Коммит
eb08644436
|
@ -0,0 +1,44 @@
|
|||
# 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.
|
||||
|
||||
# We only use this file to ease the steps of generating projects after
|
||||
# syncing, if we use gclient. All dependencies are svn:externals instead.
|
||||
# If you're not using gclient, you need to run the gyp python script to
|
||||
# generate the projects.
|
||||
# This can be done by the following command (assuming current directory):
|
||||
# src\tools\gyp\gyp.bat src\client\windows\breakpad_client.gyp
|
||||
hooks = [
|
||||
{
|
||||
# A change to a .gyp, .gypi, or to GYP itself should run the generator.
|
||||
"pattern": ".",
|
||||
"action": ["python",
|
||||
"src/src/tools/gyp/gyp",
|
||||
"src/src/client/windows/breakpad_client.gyp"],
|
||||
},
|
||||
]
|
|
@ -74,6 +74,7 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/google_breakpad/processor/memory_region.h \
|
||||
src/google_breakpad/processor/minidump.h \
|
||||
src/google_breakpad/processor/minidump_processor.h \
|
||||
src/google-breakpad/processor/network_source_line_resolver.h \
|
||||
src/google_breakpad/processor/process_state.h \
|
||||
src/google_breakpad/processor/source_line_resolver_interface.h \
|
||||
src/google_breakpad/processor/stack_frame.h \
|
||||
|
@ -87,6 +88,8 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/processor/basic_code_modules.cc \
|
||||
src/processor/basic_code_modules.h \
|
||||
src/processor/basic_source_line_resolver.cc \
|
||||
src/processor/binarystream.h \
|
||||
src/processor/binarystream.cc \
|
||||
src/processor/call_stack.cc \
|
||||
src/processor/cfi_frame_info.cc \
|
||||
src/processor/cfi_frame_info.h \
|
||||
|
@ -97,6 +100,10 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/processor/logging.cc \
|
||||
src/processor/minidump.cc \
|
||||
src/processor/minidump_processor.cc \
|
||||
src/processor/network_interface.h \
|
||||
src/processor/network_source_line_resolver.cc \
|
||||
src/processor/network_source_line_server.cc \
|
||||
src/processor/network_source_line_server.h \
|
||||
src/processor/pathname_stripper.cc \
|
||||
src/processor/pathname_stripper.h \
|
||||
src/processor/postfix_evaluator-inl.h \
|
||||
|
@ -118,32 +125,41 @@ src_libbreakpad_la_SOURCES = \
|
|||
src/processor/stackwalker_sparc.cc \
|
||||
src/processor/stackwalker_sparc.h \
|
||||
src/processor/stackwalker_x86.cc \
|
||||
src/processor/stackwalker_x86.h
|
||||
src/processor/stackwalker_x86.h \
|
||||
src/processor/tokenize.cc \
|
||||
src/processor/tokenize.h \
|
||||
src/processor/udp_network.cc \
|
||||
src/processor/udp_network.h
|
||||
|
||||
|
||||
## Programs
|
||||
bin_PROGRAMS = \
|
||||
src/client/linux/linux_dumper_unittest_helper \
|
||||
src/processor/minidump_dump \
|
||||
src/processor/minidump_stackwalk
|
||||
src/processor/minidump_stackwalk \
|
||||
src/processor/source_daemon
|
||||
|
||||
## Tests
|
||||
check_PROGRAMS = \
|
||||
src/client/linux/linux_client_unittest \
|
||||
src/common/test_assembler_unittest \
|
||||
src/processor/address_map_unittest \
|
||||
src/processor/binarystream_unittest \
|
||||
src/processor/basic_source_line_resolver_unittest \
|
||||
src/processor/cfi_frame_info_unittest \
|
||||
src/processor/contained_range_map_unittest \
|
||||
src/processor/minidump_processor_unittest \
|
||||
src/processor/minidump_unittest \
|
||||
src/processor/network_source_line_resolver_unittest \
|
||||
src/processor/network_source_line_resolver_server_unittest \
|
||||
src/processor/network_source_line_server_unittest \
|
||||
src/processor/pathname_stripper_unittest \
|
||||
src/processor/postfix_evaluator_unittest \
|
||||
src/processor/range_map_unittest \
|
||||
src/processor/stackwalker_amd64_unittest \
|
||||
src/processor/stackwalker_arm_unittest \
|
||||
src/processor/stackwalker_x86_unittest \
|
||||
src/processor/synth_minidump_unittest \
|
||||
src/processor/test_assembler_unittest
|
||||
src/processor/synth_minidump_unittest
|
||||
|
||||
if SELFTEST
|
||||
check_PROGRAMS += \
|
||||
|
@ -198,13 +214,33 @@ src_processor_address_map_unittest_LDADD = \
|
|||
src/processor/logging.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_binarystream_unittest_SOURCES = \
|
||||
src/processor/binarystream_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_processor_binarystream_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_binarystream_unittest_LDADD = \
|
||||
src/processor/binarystream.lo
|
||||
|
||||
src_processor_basic_source_line_resolver_unittest_SOURCES = \
|
||||
src/processor/basic_source_line_resolver_unittest.cc
|
||||
src/processor/basic_source_line_resolver_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_processor_basic_source_line_resolver_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_basic_source_line_resolver_unittest_LDADD = \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/logging.lo
|
||||
src/processor/logging.lo \
|
||||
src/processor/tokenize.lo
|
||||
|
||||
src_processor_cfi_frame_info_unittest_SOURCES = \
|
||||
src/processor/cfi_frame_info_unittest.cc \
|
||||
|
@ -251,12 +287,13 @@ src_processor_minidump_processor_unittest_LDADD = \
|
|||
src/processor/stackwalker_arm.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
src/processor/stackwalker_x86.lo \
|
||||
src/processor/tokenize.lo
|
||||
|
||||
src_processor_minidump_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/processor/minidump_unittest.cc \
|
||||
src/processor/synth_minidump.cc \
|
||||
src/processor/test_assembler.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
|
@ -271,6 +308,74 @@ src_processor_minidump_unittest_LDADD = \
|
|||
src/processor/minidump.lo \
|
||||
src/processor/pathname_stripper.lo
|
||||
|
||||
src_processor_network_source_line_resolver_unittest_SOURCES = \
|
||||
src/processor/network_source_line_resolver_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_processor_network_source_line_resolver_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_network_source_line_resolver_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/binarystream.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/network_source_line_resolver.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/tokenize.lo \
|
||||
src/processor/udp_network.lo
|
||||
|
||||
src_processor_network_source_line_resolver_server_unittest_SOURCES = \
|
||||
src/processor/network_source_line_resolver_server_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_processor_network_source_line_resolver_server_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_network_source_line_resolver_server_unittest_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/binarystream.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/minidump_processor.lo \
|
||||
src/processor/minidump.lo \
|
||||
src/processor/network_source_line_resolver.lo \
|
||||
src/processor/network_source_line_server.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/process_state.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_amd64.lo \
|
||||
src/processor/stackwalker_arm.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo \
|
||||
src/processor/tokenize.lo \
|
||||
src/processor/udp_network.lo
|
||||
|
||||
src_processor_network_source_line_server_unittest_SOURCES = \
|
||||
src/processor/network_source_line_server_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_processor_network_source_line_server_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
src_processor_network_source_line_server_unittest_LDADD = \
|
||||
src/processor/binarystream.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/network_source_line_server.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/udp_network.lo
|
||||
|
||||
src_processor_pathname_stripper_unittest_SOURCES = \
|
||||
src/processor/pathname_stripper_unittest.cc
|
||||
src_processor_pathname_stripper_unittest_LDADD = \
|
||||
|
@ -302,11 +407,12 @@ src_processor_stackwalker_selftest_LDADD = \
|
|||
src/processor/stackwalker_arm.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
src/processor/stackwalker_x86.lo \
|
||||
src/processor/tokenize.lo
|
||||
|
||||
src_processor_stackwalker_amd64_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/processor/stackwalker_amd64_unittest.cc \
|
||||
src/processor/test_assembler.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
|
@ -319,8 +425,8 @@ src_processor_stackwalker_amd64_unittest_CPPFLAGS = \
|
|||
-I$(top_srcdir)/src/testing
|
||||
|
||||
src_processor_stackwalker_arm_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/processor/stackwalker_arm_unittest.cc \
|
||||
src/processor/test_assembler.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
|
@ -333,8 +439,8 @@ src_processor_stackwalker_arm_unittest_CPPFLAGS = \
|
|||
-I$(top_srcdir)/src/testing
|
||||
|
||||
src_processor_stackwalker_x86_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/processor/stackwalker_x86_unittest.cc \
|
||||
src/processor/test_assembler.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc
|
||||
|
@ -347,28 +453,28 @@ src_processor_stackwalker_x86_unittest_CPPFLAGS = \
|
|||
-I$(top_srcdir)/src/testing
|
||||
|
||||
src_processor_synth_minidump_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/common/test_assembler.h \
|
||||
src/processor/synth_minidump_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc \
|
||||
src/processor/synth_minidump.cc \
|
||||
src/processor/synth_minidump.h \
|
||||
src/processor/test_assembler.cc \
|
||||
src/processor/test_assembler.h
|
||||
src/processor/synth_minidump.h
|
||||
src_processor_synth_minidump_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
-I$(top_srcdir)/src/testing
|
||||
|
||||
src_processor_test_assembler_unittest_SOURCES = \
|
||||
src/processor/test_assembler_unittest.cc \
|
||||
src_common_test_assembler_unittest_SOURCES = \
|
||||
src/common/test_assembler.cc \
|
||||
src/common/test_assembler.h \
|
||||
src/common/test_assembler_unittest.cc \
|
||||
src/testing/gtest/src/gtest-all.cc \
|
||||
src/testing/gtest/src/gtest_main.cc \
|
||||
src/testing/src/gmock-all.cc \
|
||||
src/processor/test_assembler.cc \
|
||||
src/processor/test_assembler.h
|
||||
src_processor_test_assembler_unittest_CPPFLAGS = \
|
||||
src/testing/src/gmock-all.cc
|
||||
src_common_test_assembler_unittest_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src/testing/include \
|
||||
-I$(top_srcdir)/src/testing/gtest/include \
|
||||
-I$(top_srcdir)/src/testing/gtest \
|
||||
|
@ -391,6 +497,7 @@ src_processor_minidump_stackwalk_SOURCES = \
|
|||
src_processor_minidump_stackwalk_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/binarystream.lo \
|
||||
src/processor/call_stack.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/logging.lo \
|
||||
|
@ -398,14 +505,30 @@ src_processor_minidump_stackwalk_LDADD = \
|
|||
src/processor/minidump_processor.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/process_state.lo \
|
||||
src/processor/network_source_line_resolver.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/stackwalker.lo \
|
||||
src/processor/stackwalker_amd64.lo \
|
||||
src/processor/stackwalker_arm.lo \
|
||||
src/processor/stackwalker_ppc.lo \
|
||||
src/processor/stackwalker_sparc.lo \
|
||||
src/processor/stackwalker_x86.lo
|
||||
src/processor/stackwalker_x86.lo \
|
||||
src/processor/tokenize.lo \
|
||||
src/processor/udp_network.lo
|
||||
|
||||
src_processor_source_daemon_SOURCES = \
|
||||
src/processor/source_daemon.cc
|
||||
src_processor_source_daemon_LDADD = \
|
||||
src/processor/basic_code_modules.lo \
|
||||
src/processor/basic_source_line_resolver.lo \
|
||||
src/processor/binarystream.lo \
|
||||
src/processor/cfi_frame_info.lo \
|
||||
src/processor/logging.lo \
|
||||
src/processor/network_source_line_server.lo \
|
||||
src/processor/pathname_stripper.lo \
|
||||
src/processor/simple_symbol_supplier.lo \
|
||||
src/processor/tokenize.lo \
|
||||
src/processor/udp_network.lo
|
||||
|
||||
## Additional files to be included in a source distribution
|
||||
##
|
||||
|
|
|
@ -2460,7 +2460,7 @@ linux*oldld* | linux*aout* | linux*coff*)
|
|||
;;
|
||||
|
||||
# This must be Linux ELF.
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
|
@ -2500,6 +2500,18 @@ linux* | k*bsd*-gnu)
|
|||
dynamic_linker='GNU/Linux ld.so'
|
||||
;;
|
||||
|
||||
netbsdelf*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
|
||||
soname_spec='${libname}${release}${shared_ext}$major'
|
||||
shlibpath_var=LD_LIBRARY_PATH
|
||||
shlibpath_overrides_runpath=no
|
||||
hardcode_into_libs=yes
|
||||
dynamic_linker='NetBSD ld.elf_so'
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
version_type=sunos
|
||||
need_lib_prefix=no
|
||||
|
@ -3087,11 +3099,11 @@ irix5* | irix6* | nonstopux*)
|
|||
;;
|
||||
|
||||
# This must be Linux ELF.
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
lt_cv_deplibs_check_method=pass_all
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
|
||||
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
|
||||
else
|
||||
|
@ -3708,7 +3720,7 @@ m4_if([$1], [CXX], [
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
KCC*)
|
||||
# KAI C++ Compiler
|
||||
|
@ -3772,7 +3784,7 @@ m4_if([$1], [CXX], [
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
;;
|
||||
*qnx* | *nto*)
|
||||
# QNX uses GNU C++, but need to define -shared option too, otherwise
|
||||
|
@ -3992,7 +4004,7 @@ m4_if([$1], [CXX], [
|
|||
_LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
|
||||
;;
|
||||
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
# old Intel for x86_64 which still supported -KPIC.
|
||||
ecc*)
|
||||
|
@ -4197,6 +4209,9 @@ m4_if([$1], [CXX], [
|
|||
cygwin* | mingw* | cegcc*)
|
||||
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
_LT_TAGVAR(link_all_deplibs, $1)=no
|
||||
;;
|
||||
*)
|
||||
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
|
||||
;;
|
||||
|
@ -4261,6 +4276,9 @@ dnl Note also adjust exclude_expsyms for C++ above.
|
|||
openbsd*)
|
||||
with_gnu_ld=no
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
_LT_TAGVAR(link_all_deplibs, $1)=no
|
||||
;;
|
||||
esac
|
||||
|
||||
_LT_TAGVAR(ld_shlibs, $1)=yes
|
||||
|
@ -4282,6 +4300,7 @@ dnl Note also adjust exclude_expsyms for C++ above.
|
|||
fi
|
||||
supports_anon_versioning=no
|
||||
case `$LD -v 2>&1` in
|
||||
*GNU\ gold*) supports_anon_versioning=yes ;;
|
||||
*\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
|
||||
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
|
||||
*\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
|
||||
|
@ -4373,7 +4392,7 @@ _LT_EOF
|
|||
_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
|
||||
;;
|
||||
|
||||
gnu* | linux* | tpf* | k*bsd*-gnu)
|
||||
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
tmp_diet=no
|
||||
if test "$host_os" = linux-dietlibc; then
|
||||
case $cc_basename in
|
||||
|
@ -4443,7 +4462,7 @@ _LT_EOF
|
|||
fi
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
|
||||
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
|
||||
wlarc=
|
||||
|
@ -4618,6 +4637,7 @@ _LT_EOF
|
|||
if test "$aix_use_runtimelinking" = yes; then
|
||||
shared_flag="$shared_flag "'${wl}-G'
|
||||
fi
|
||||
_LT_TAGVAR(link_all_deplibs, $1)=no
|
||||
else
|
||||
# not using gcc
|
||||
if test "$host_cpu" = ia64; then
|
||||
|
@ -4856,7 +4876,7 @@ _LT_EOF
|
|||
_LT_TAGVAR(link_all_deplibs, $1)=yes
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
|
||||
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
|
||||
else
|
||||
|
@ -5852,7 +5872,7 @@ if test "$_lt_caught_CXX_error" != yes; then
|
|||
_LT_TAGVAR(inherit_rpath, $1)=yes
|
||||
;;
|
||||
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
KCC*)
|
||||
# Kuck and Associates, Inc. (KAI) C++ Compiler
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# This file is used by gcl to get repository specific information.
|
||||
CODE_REVIEW_SERVER: breakpad.appspot.com
|
||||
CC_LIST: google-breakpad-dev@googlegroups.com
|
||||
TRY_ON_UPLOAD: False
|
||||
VIEW_VC: http://code.google.com/p/google-breakpad/source/detail?r=
|
|
@ -2003,6 +2003,63 @@ fi
|
|||
as_fn_set_status $ac_retval
|
||||
|
||||
} # ac_fn_cxx_try_link
|
||||
|
||||
# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
|
||||
# ----------------------------------------------------
|
||||
# Tries to find if the field MEMBER exists in type AGGR, after including
|
||||
# INCLUDES, setting cache variable VAR accordingly.
|
||||
ac_fn_c_check_member ()
|
||||
{
|
||||
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
|
||||
$as_echo_n "checking for $2.$3... " >&6; }
|
||||
if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$5
|
||||
int
|
||||
main ()
|
||||
{
|
||||
static $2 ac_aggr;
|
||||
if (ac_aggr.$3)
|
||||
return 0;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
eval "$4=yes"
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$5
|
||||
int
|
||||
main ()
|
||||
{
|
||||
static $2 ac_aggr;
|
||||
if (sizeof ac_aggr.$3)
|
||||
return 0;
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
eval "$4=yes"
|
||||
else
|
||||
eval "$4=no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
fi
|
||||
eval ac_res=\$$4
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
|
||||
$as_echo "$ac_res" >&6; }
|
||||
eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
|
||||
|
||||
} # ac_fn_c_check_member
|
||||
cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
@ -5123,13 +5180,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
|
|||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:5126: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:5183: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:5129: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:5186: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:5132: output\"" >&5)
|
||||
(eval echo "\"\$as_me:5189: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
|
@ -5595,11 +5652,11 @@ irix5* | irix6* | nonstopux*)
|
|||
;;
|
||||
|
||||
# This must be Linux ELF.
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
lt_cv_deplibs_check_method=pass_all
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
|
||||
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
|
||||
else
|
||||
|
@ -6335,7 +6392,7 @@ ia64-*-hpux*)
|
|||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 6338 "configure"' > conftest.$ac_ext
|
||||
echo '#line 6395 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
|
@ -8251,11 +8308,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:8254: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:8311: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:8258: \$? = $ac_status" >&5
|
||||
echo "$as_me:8315: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
|
@ -8420,7 +8477,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
|
|||
lt_prog_compiler_static='-non_shared'
|
||||
;;
|
||||
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
# old Intel for x86_64 which still supported -KPIC.
|
||||
ecc*)
|
||||
|
@ -8590,11 +8647,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:8593: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:8650: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:8597: \$? = $ac_status" >&5
|
||||
echo "$as_me:8654: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
|
@ -8695,11 +8752,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:8698: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:8755: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:8702: \$? = $ac_status" >&5
|
||||
echo "$as_me:8759: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
|
@ -8750,11 +8807,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:8753: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:8810: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:8757: \$? = $ac_status" >&5
|
||||
echo "$as_me:8814: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
|
@ -8869,6 +8926,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
|
|||
openbsd*)
|
||||
with_gnu_ld=no
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
link_all_deplibs=no
|
||||
;;
|
||||
esac
|
||||
|
||||
ld_shlibs=yes
|
||||
|
@ -8890,6 +8950,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
|
|||
fi
|
||||
supports_anon_versioning=no
|
||||
case `$LD -v 2>&1` in
|
||||
*GNU\ gold*) supports_anon_versioning=yes ;;
|
||||
*\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
|
||||
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
|
||||
*\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
|
||||
|
@ -8981,7 +9042,7 @@ _LT_EOF
|
|||
archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
|
||||
;;
|
||||
|
||||
gnu* | linux* | tpf* | k*bsd*-gnu)
|
||||
gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
tmp_diet=no
|
||||
if test "$host_os" = linux-dietlibc; then
|
||||
case $cc_basename in
|
||||
|
@ -9051,7 +9112,7 @@ _LT_EOF
|
|||
fi
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
|
||||
archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
|
||||
wlarc=
|
||||
|
@ -9226,6 +9287,7 @@ _LT_EOF
|
|||
if test "$aix_use_runtimelinking" = yes; then
|
||||
shared_flag="$shared_flag "'${wl}-G'
|
||||
fi
|
||||
link_all_deplibs=no
|
||||
else
|
||||
# not using gcc
|
||||
if test "$host_cpu" = ia64; then
|
||||
|
@ -9552,7 +9614,7 @@ rm -f core conftest.err conftest.$ac_objext \
|
|||
link_all_deplibs=yes
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
|
||||
archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
|
||||
else
|
||||
|
@ -10442,7 +10504,7 @@ linux*oldld* | linux*aout* | linux*coff*)
|
|||
;;
|
||||
|
||||
# This must be Linux ELF.
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
|
@ -10497,6 +10559,18 @@ rm -f core conftest.err conftest.$ac_objext \
|
|||
dynamic_linker='GNU/Linux ld.so'
|
||||
;;
|
||||
|
||||
netbsdelf*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
|
||||
soname_spec='${libname}${release}${shared_ext}$major'
|
||||
shlibpath_var=LD_LIBRARY_PATH
|
||||
shlibpath_overrides_runpath=no
|
||||
hardcode_into_libs=yes
|
||||
dynamic_linker='NetBSD ld.elf_so'
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
version_type=sunos
|
||||
need_lib_prefix=no
|
||||
|
@ -11117,7 +11191,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11120 "configure"
|
||||
#line 11194 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -11213,7 +11287,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11216 "configure"
|
||||
#line 11290 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -12153,7 +12227,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
|
|||
inherit_rpath_CXX=yes
|
||||
;;
|
||||
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
KCC*)
|
||||
# Kuck and Associates, Inc. (KAI) C++ Compiler
|
||||
|
@ -12981,7 +13055,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
case $cc_basename in
|
||||
KCC*)
|
||||
# KAI C++ Compiler
|
||||
|
@ -13045,7 +13119,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; }
|
|||
;;
|
||||
esac
|
||||
;;
|
||||
netbsd*)
|
||||
netbsd* | netbsdelf*-gnu)
|
||||
;;
|
||||
*qnx* | *nto*)
|
||||
# QNX uses GNU C++, but need to define -shared option too, otherwise
|
||||
|
@ -13169,11 +13243,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:13172: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:13246: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:13176: \$? = $ac_status" >&5
|
||||
echo "$as_me:13250: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
|
@ -13268,11 +13342,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:13271: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:13345: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:13275: \$? = $ac_status" >&5
|
||||
echo "$as_me:13349: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
|
@ -13320,11 +13394,11 @@ else
|
|||
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
|
||||
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
|
||||
-e 's:$: $lt_compiler_flag:'`
|
||||
(eval echo "\"\$as_me:13323: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:13397: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:13327: \$? = $ac_status" >&5
|
||||
echo "$as_me:13401: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
|
@ -13396,6 +13470,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
|
|||
cygwin* | mingw* | cegcc*)
|
||||
export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
|
||||
;;
|
||||
linux* | k*bsd*-gnu)
|
||||
link_all_deplibs_CXX=no
|
||||
;;
|
||||
*)
|
||||
export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
|
||||
;;
|
||||
|
@ -13895,7 +13972,7 @@ linux*oldld* | linux*aout* | linux*coff*)
|
|||
;;
|
||||
|
||||
# This must be Linux ELF.
|
||||
linux* | k*bsd*-gnu)
|
||||
linux* | k*bsd*-gnu | kopensolaris*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
|
@ -13950,6 +14027,18 @@ rm -f core conftest.err conftest.$ac_objext \
|
|||
dynamic_linker='GNU/Linux ld.so'
|
||||
;;
|
||||
|
||||
netbsdelf*-gnu)
|
||||
version_type=linux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
|
||||
soname_spec='${libname}${release}${shared_ext}$major'
|
||||
shlibpath_var=LD_LIBRARY_PATH
|
||||
shlibpath_overrides_runpath=no
|
||||
hardcode_into_libs=yes
|
||||
dynamic_linker='NetBSD ld.elf_so'
|
||||
;;
|
||||
|
||||
netbsd*)
|
||||
version_type=sunos
|
||||
need_lib_prefix=no
|
||||
|
@ -14859,6 +14948,20 @@ else
|
|||
fi
|
||||
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include <sys/socket.h>
|
||||
"
|
||||
if test "x$ac_cv_member_struct_sockaddr_sa_len" = x""yes; then :
|
||||
|
||||
$as_echo "#define GET_SA_LEN(X) (((struct sockaddr*)&(X))->sa_len)" >>confdefs.h
|
||||
|
||||
else
|
||||
|
||||
$as_echo "#define GET_SA_LEN(X) (((struct sockaddr*)&(X))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : \\
|
||||
((struct sockaddr*)&(X))->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr))" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --enable-selftest was given.
|
||||
if test "${enable_selftest+set}" = set; then :
|
||||
enableval=$enable_selftest; case "${enableval}" in
|
||||
|
|
|
@ -67,6 +67,15 @@ AC_ARG_ENABLE(m32,
|
|||
esac],
|
||||
[usem32=false])
|
||||
|
||||
AC_CHECK_MEMBER(struct sockaddr.sa_len,
|
||||
[AC_DEFINE([GET_SA_LEN(X)],[(((struct sockaddr*)&(X))->sa_len)],
|
||||
[actual length of specific struct sockaddr])],
|
||||
[AC_DEFINE([GET_SA_LEN(X)],
|
||||
[(((struct sockaddr*)&(X))->sa_family == AF_INET ? sizeof(struct sockaddr_in) : \
|
||||
((struct sockaddr*)&(X))->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr))],
|
||||
[actual length of specific struct sockaddr])],
|
||||
[#include <sys/socket.h>])
|
||||
|
||||
AC_ARG_ENABLE(selftest,
|
||||
AS_HELP_STRING([--enable-selftest],
|
||||
[Run extra tests with "make check" ]
|
||||
|
|
|
@ -64,7 +64,8 @@ CrashGenerationClient::RequestDump(const void* blob, size_t blob_size)
|
|||
hdr->cmsg_level = SOL_SOCKET;
|
||||
hdr->cmsg_type = SCM_RIGHTS;
|
||||
hdr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
*((int*) CMSG_DATA(hdr)) = fds[1];
|
||||
int* p = reinterpret_cast<int*>(CMSG_DATA(hdr));
|
||||
*p = fds[1];
|
||||
|
||||
HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
|
||||
sys_close(fds[1]);
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/linux_syscall_support.h"
|
||||
|
||||
static const char kMappedFileUnsafePrefix[] = "/dev/";
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool AttachThread(pid_t pid) {
|
||||
|
@ -81,6 +83,17 @@ bool DetachThread(pid_t pid) {
|
|||
return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
|
||||
}
|
||||
|
||||
inline bool IsMappedFileOpenUnsafe(
|
||||
const google_breakpad::MappingInfo* mapping) {
|
||||
// It is unsafe to attempt to open a mapped file that lives under /dev,
|
||||
// because the semantics of the open may be driver-specific so we'd risk
|
||||
// hanging the crash dumper. And a file in /dev/ almost certainly has no
|
||||
// ELF file identifier anyways.
|
||||
return my_strncmp(mapping->name,
|
||||
kMappedFileUnsafePrefix,
|
||||
sizeof(kMappedFileUnsafePrefix) - 1) == 0;
|
||||
}
|
||||
|
||||
bool GetThreadRegisters(ThreadInfo* info) {
|
||||
pid_t tid = info->tid;
|
||||
|
||||
|
@ -193,7 +206,11 @@ LinuxDumper::ElfFileIdentifierForMapping(unsigned int mapping_id,
|
|||
uint8_t identifier[sizeof(MDGUID)])
|
||||
{
|
||||
assert(mapping_id < mappings_.size());
|
||||
my_memset(identifier, 0, sizeof(MDGUID));
|
||||
const MappingInfo* mapping = mappings_[mapping_id];
|
||||
if (IsMappedFileOpenUnsafe(mapping)) {
|
||||
return false;
|
||||
}
|
||||
int fd = sys_open(mapping->name, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
|
|
@ -108,16 +108,16 @@ TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) {
|
|||
ThreadInfo one_thread;
|
||||
for(size_t i = 0; i < dumper.threads().size(); ++i) {
|
||||
EXPECT_TRUE(dumper.ThreadInfoGet(dumper.threads()[i], &one_thread));
|
||||
// We know the threads are in a function which has allocated exactly
|
||||
// one word off the stack to store its thread id.
|
||||
// In the helper program, we stored a pointer to the thread id in a
|
||||
// specific register. Check that we can recover its value.
|
||||
#if defined(__ARM_EABI__)
|
||||
void* process_tid_location = (void *)(one_thread.regs.uregs[11] - 8);
|
||||
pid_t *process_tid_location = (pid_t *)(one_thread.regs.uregs[3]);
|
||||
#elif defined(__i386)
|
||||
void* process_tid_location = (void *)(one_thread.regs.ebp - 4);
|
||||
pid_t *process_tid_location = (pid_t *)(one_thread.regs.ecx);
|
||||
#elif defined(__x86_64)
|
||||
void* process_tid_location = (void *)(one_thread.regs.rbp - 4);
|
||||
pid_t *process_tid_location = (pid_t *)(one_thread.regs.rcx);
|
||||
#else
|
||||
#error Platform not supported!
|
||||
#error This test has not been ported to this platform.
|
||||
#endif
|
||||
pid_t one_thread_id;
|
||||
dumper.CopyFromProcess(&one_thread_id,
|
||||
|
|
|
@ -37,13 +37,22 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#pragma GCC optimize ("O0")
|
||||
void *thread_function(void *data) __attribute__((noinline, optimize("O2")));
|
||||
#if defined(__ARM_EABI__)
|
||||
#define TID_PTR_REGISTER "r3"
|
||||
#elif defined(__i386)
|
||||
#define TID_PTR_REGISTER "ecx"
|
||||
#elif defined(__x86_64)
|
||||
#define TID_PTR_REGISTER "rcx"
|
||||
#else
|
||||
#error This test has not been ported to this platform.
|
||||
#endif
|
||||
|
||||
void *thread_function(void *data) {
|
||||
pid_t thread_id = syscall(SYS_gettid);
|
||||
while (true) ;
|
||||
asm("");
|
||||
volatile pid_t thread_id = syscall(SYS_gettid);
|
||||
register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
|
||||
while (true)
|
||||
asm volatile ("" : : "r" (thread_id_ptr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
|
@ -28,9 +28,11 @@
|
|||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "common/linux/google_crashdump_uploader.h"
|
||||
#include "third_party/linux/include/glog/logging.h"
|
||||
#include "third_party/linux/include/gflags/gflags.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
|
||||
DEFINE_string(crash_server, "http://clients2.google.com/cr",
|
||||
"The crash server to upload minidumps to.");
|
||||
|
@ -75,7 +77,7 @@ bool CheckForRequiredFlagsOrDie() {
|
|||
}
|
||||
|
||||
if (!error_text.empty()) {
|
||||
LOG(ERROR) << error_text;
|
||||
std::cout << error_text;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -29,10 +29,13 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.nib */; };
|
||||
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.xib */; };
|
||||
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 33880C7E0F9E097100817F82 /* InfoPlist.strings */; };
|
||||
4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */; };
|
||||
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
|
||||
D2A5DD301188633800081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
|
||||
D2A5DD401188640400081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
|
||||
D2A5DD411188642E00081F03 /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53690ECCE3FD009BE4BA /* breakpad_nlist_64.cc */; };
|
||||
F91AF5D00FD60393009D8BE2 /* BreakpadFramework_Test.mm in Sources */ = {isa = PBXBuildFile; fileRef = F91AF5CF0FD60393009D8BE2 /* BreakpadFramework_Test.mm */; };
|
||||
F91AF6210FD60784009D8BE2 /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
F9286B3A0F7EB25800A4DCC8 /* InspectorMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9286B390F7EB25800A4DCC8 /* InspectorMain.mm */; };
|
||||
|
@ -98,7 +101,7 @@
|
|||
F9C44DB60EF07288003AEBAA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44DB00EF07288003AEBAA /* main.m */; };
|
||||
F9C44DB70EF07288003AEBAA /* TestClass.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9C44DB10EF07288003AEBAA /* TestClass.mm */; };
|
||||
F9C44DBC0EF072A0003AEBAA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DB80EF072A0003AEBAA /* InfoPlist.strings */; };
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.nib */; };
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */; };
|
||||
F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
F9C44E3C0EF08B12003AEBAA /* Breakpad.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
|
||||
F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */ = {isa = PBXBuildFile; fileRef = F92C56A00ECE04A7009BE4BA /* crash_report_sender.app */; };
|
||||
|
@ -199,49 +202,49 @@
|
|||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB87C101F949F00AA053B /* crash_report.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* crash_report */;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E;
|
||||
remoteInfo = crash_report;
|
||||
};
|
||||
F95BB891101F94AC00AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* dump_syms */;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E;
|
||||
remoteInfo = dump_syms;
|
||||
};
|
||||
F95BB89E101F94C000AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* symupload */;
|
||||
remoteGlobalIDString = 8DD76FA10486AA7600D96B5E;
|
||||
remoteInfo = symupload;
|
||||
};
|
||||
F95BB8A0101F94C000AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 9BD835FB0B0544950055103E /* minidump_upload */;
|
||||
remoteGlobalIDString = 9BD835FB0B0544950055103E;
|
||||
remoteInfo = minidump_upload;
|
||||
};
|
||||
F95BB8B2101F94D300AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* dump_syms */;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E;
|
||||
remoteInfo = dump_syms;
|
||||
};
|
||||
F95BB8B4101F94D300AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* symupload */;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E;
|
||||
remoteInfo = symupload;
|
||||
};
|
||||
F95BB8B6101F94D300AA053B /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = F95BB87C101F949F00AA053B /* crash_report.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* crash_report */;
|
||||
remoteGlobalIDString = 8DD76F960486AA7600D96B5E;
|
||||
remoteInfo = crash_report;
|
||||
};
|
||||
F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */ = {
|
||||
|
@ -279,7 +282,7 @@
|
|||
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
|
||||
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
|
||||
32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpad_Prefix.pch; path = Framework/Breakpad_Prefix.pch; sourceTree = "<group>"; };
|
||||
3329D4EC0FA16D820007BBC5 /* Breakpad.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Breakpad.nib; path = sender/Breakpad.nib; sourceTree = "<group>"; };
|
||||
3329D4EC0FA16D820007BBC5 /* Breakpad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Breakpad.xib; path = sender/Breakpad.xib; sourceTree = "<group>"; };
|
||||
33880C7F0F9E097100817F82 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = crash_report_sender.icns; path = sender/crash_report_sender.icns; sourceTree = "<group>"; };
|
||||
8DC2EF5B0486A6940098B216 /* Breakpad.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Breakpad.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -353,7 +356,7 @@
|
|||
F9C44DB00EF07288003AEBAA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = testapp/main.m; sourceTree = "<group>"; };
|
||||
F9C44DB10EF07288003AEBAA /* TestClass.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestClass.mm; path = testapp/TestClass.mm; sourceTree = "<group>"; };
|
||||
F9C44DB90EF072A0003AEBAA /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = testapp/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
F9C44DBB0EF072A0003AEBAA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = testapp/English.lproj/MainMenu.nib; sourceTree = "<group>"; };
|
||||
F9C44DBB0EF072A0003AEBAA /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = testapp/English.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
F9C44DBF0EF0778F003AEBAA /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Controller.h; path = testapp/Controller.h; sourceTree = "<group>"; };
|
||||
F9C44DC00EF0778F003AEBAA /* TestClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestClass.h; path = testapp/TestClass.h; sourceTree = "<group>"; };
|
||||
F9C44EE40EF0A006003AEBAA /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
|
||||
|
@ -598,7 +601,7 @@
|
|||
F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */,
|
||||
F945849C0F280E3C009A47BF /* Localizable.strings */,
|
||||
33880C7E0F9E097100817F82 /* InfoPlist.strings */,
|
||||
3329D4EC0FA16D820007BBC5 /* Breakpad.nib */,
|
||||
3329D4EC0FA16D820007BBC5 /* Breakpad.xib */,
|
||||
4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */,
|
||||
F92C56A20ECE04A7009BE4BA /* crash_report_sender-Info.plist */,
|
||||
);
|
||||
|
@ -646,7 +649,7 @@
|
|||
F9C44DBF0EF0778F003AEBAA /* Controller.h */,
|
||||
F9C44DC00EF0778F003AEBAA /* TestClass.h */,
|
||||
F9C44DB80EF072A0003AEBAA /* InfoPlist.strings */,
|
||||
F9C44DBA0EF072A0003AEBAA /* MainMenu.nib */,
|
||||
F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */,
|
||||
F9C44DAC0EF07288003AEBAA /* Controller.m */,
|
||||
F9C44DAD0EF07288003AEBAA /* crashduringload */,
|
||||
F9C44DAE0EF07288003AEBAA /* crashInMain */,
|
||||
|
@ -951,7 +954,7 @@
|
|||
F945849E0F280E3C009A47BF /* Localizable.strings in Resources */,
|
||||
4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */,
|
||||
33880C800F9E097100817F82 /* InfoPlist.strings in Resources */,
|
||||
3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */,
|
||||
3329D4ED0FA16D820007BBC5 /* Breakpad.xib in Resources */,
|
||||
F9B630A0100FF96B00D0F4AC /* goArrow.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -963,7 +966,7 @@
|
|||
F9C44DB30EF07288003AEBAA /* crashduringload in Resources */,
|
||||
F9C44DB40EF07288003AEBAA /* crashInMain in Resources */,
|
||||
F9C44DBC0EF072A0003AEBAA /* InfoPlist.strings in Resources */,
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.nib in Resources */,
|
||||
F9C44DBD0EF072A0003AEBAA /* MainMenu.xib in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1045,6 +1048,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D2A5DD301188633800081F03 /* breakpad_nlist_64.cc in Sources */,
|
||||
F92C563F0ECD10CA009BE4BA /* convert_UTF.c in Sources */,
|
||||
F92C56400ECD10CA009BE4BA /* dynamic_images.cc in Sources */,
|
||||
F92C56410ECD10CA009BE4BA /* file_id.cc in Sources */,
|
||||
|
@ -1074,6 +1078,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D2A5DD401188640400081F03 /* breakpad_nlist_64.cc in Sources */,
|
||||
F93803CD0F8083B7004D428B /* dynamic_images.cc in Sources */,
|
||||
F93803CE0F8083B7004D428B /* exception_handler.cc in Sources */,
|
||||
F93803CF0F8083B7004D428B /* minidump_generator.cc in Sources */,
|
||||
|
@ -1104,6 +1109,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D2A5DD411188642E00081F03 /* breakpad_nlist_64.cc in Sources */,
|
||||
F93DE3350F82C66B00608B94 /* dynamic_images.cc in Sources */,
|
||||
F93DE3360F82C66B00608B94 /* exception_handler.cc in Sources */,
|
||||
F93DE3370F82C66B00608B94 /* minidump_generator.cc in Sources */,
|
||||
|
@ -1255,12 +1261,12 @@
|
|||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F9C44DBA0EF072A0003AEBAA /* MainMenu.nib */ = {
|
||||
F9C44DBA0EF072A0003AEBAA /* MainMenu.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
F9C44DBB0EF072A0003AEBAA /* English */,
|
||||
);
|
||||
name = MainMenu.nib;
|
||||
name = MainMenu.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
@ -1314,7 +1320,7 @@
|
|||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH_PRE_XCODE_3_1 = "$(NATIVE_ARCH)";
|
||||
ONLY_ACTIVE_ARCH_PRE_XCODE_3_1 = "$(NATIVE_ARCH_ACTUAL)";
|
||||
PREBINDING = NO;
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||
};
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
#include <mach-o/loader.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <mach/mach_vm.h>
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
|
@ -50,6 +49,12 @@ using MacStringUtils::IntegerValueAtIndex;
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
#if __LP64__
|
||||
#define LC_SEGMENT_ARCH LC_SEGMENT_64
|
||||
#else
|
||||
#define LC_SEGMENT_ARCH LC_SEGMENT
|
||||
#endif
|
||||
|
||||
// constructor when generating from within the crashed process
|
||||
MinidumpGenerator::MinidumpGenerator()
|
||||
: exception_type_(0),
|
||||
|
@ -615,8 +620,10 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
|||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
|
||||
break;
|
||||
case CPU_TYPE_I386:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
|
||||
case CPU_TYPE_X86_64:
|
||||
// hw.cputype is currently always I386 even on an x86-64 system
|
||||
#ifdef __i386__
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
|
||||
// ebx is used for PIC code, so we need
|
||||
// to preserve it.
|
||||
#define cpuid(op,eax,ebx,ecx,edx) \
|
||||
|
@ -629,6 +636,18 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
|||
"=c" (ecx), \
|
||||
"=d" (edx) \
|
||||
: "0" (op))
|
||||
#elif defined(__x86_64__)
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
|
||||
#define cpuid(op,eax,ebx,ecx,edx) \
|
||||
asm ("cpuid \n\t" \
|
||||
: "=a" (eax), \
|
||||
"=b" (ebx), \
|
||||
"=c" (ecx), \
|
||||
"=d" (edx) \
|
||||
: "0" (op))
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
int unused, unused2;
|
||||
// get vendor id
|
||||
cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0],
|
||||
|
@ -659,7 +678,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(
|
|||
((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20);
|
||||
}
|
||||
|
||||
#endif // __i386__
|
||||
#endif // __i386__ || __x86_64_
|
||||
break;
|
||||
default:
|
||||
info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
|
||||
|
@ -763,7 +782,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,
|
|||
memset(module, 0, sizeof(MDRawModule));
|
||||
|
||||
for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
|
||||
if (cmd->cmd == LC_SEGMENT) {
|
||||
if (cmd->cmd == LC_SEGMENT_ARCH) {
|
||||
|
||||
const breakpad_mach_segment_command *seg =
|
||||
reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CLASS</key>
|
||||
<string>LengthLimitingTextField</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSTextField</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>cancel</key>
|
||||
<string>id</string>
|
||||
<key>sendReport</key>
|
||||
<string>id</string>
|
||||
<key>showPrivacyPolicy</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>Reporter</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>alertWindow_</key>
|
||||
<string>NSWindow</string>
|
||||
<key>cancelButton_</key>
|
||||
<string>NSButton</string>
|
||||
<key>commentMessage_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>commentsEntryField_</key>
|
||||
<string>LengthLimitingTextField</string>
|
||||
<key>countdownLabel_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>dialogTitle_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailEntryField_</key>
|
||||
<string>LengthLimitingTextField</string>
|
||||
<key>emailLabel_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailMessage_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>emailSectionBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>headerBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>preEmailBox_</key>
|
||||
<string>NSBox</string>
|
||||
<key>privacyLinkArrow_</key>
|
||||
<string>NSView</string>
|
||||
<key>privacyLinkLabel_</key>
|
||||
<string>NSTextField</string>
|
||||
<key>sendButton_</key>
|
||||
<string>NSButton</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,20 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>676</string>
|
||||
<key>IBLastKnownRelativeProjectPath</key>
|
||||
<string>../Breakpad.xcodeproj</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>132</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9J61</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCocoaFramework</string>
|
||||
</dict>
|
||||
</plist>
|
Двоичные данные
toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib
сгенерированный
Двоичные данные
toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/keyedobjects.nib
сгенерированный
Двоичный файл не отображается.
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,47 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBClasses</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>ACTIONS</key>
|
||||
<dict>
|
||||
<key>crash</key>
|
||||
<string>id</string>
|
||||
<key>forkTestGo</key>
|
||||
<string>id</string>
|
||||
<key>forkTestOptions</key>
|
||||
<string>id</string>
|
||||
<key>generateReportWithoutCrash</key>
|
||||
<string>id</string>
|
||||
<key>showForkTestWindow</key>
|
||||
<string>id</string>
|
||||
</dict>
|
||||
<key>CLASS</key>
|
||||
<string>Controller</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>OUTLETS</key>
|
||||
<dict>
|
||||
<key>forkTestOptions_</key>
|
||||
<string>NSWindow</string>
|
||||
<key>window_</key>
|
||||
<string>NSWindow</string>
|
||||
</dict>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CLASS</key>
|
||||
<string>FirstResponder</string>
|
||||
<key>LANGUAGE</key>
|
||||
<string>ObjC</string>
|
||||
<key>SUPERCLASS</key>
|
||||
<string>NSObject</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>IBVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IBFramework Version</key>
|
||||
<string>670</string>
|
||||
<key>IBLastKnownRelativeProjectPath</key>
|
||||
<string>../GoogleBreakpadTest.xcodeproj</string>
|
||||
<key>IBOldestOS</key>
|
||||
<integer>5</integer>
|
||||
<key>IBOpenObjects</key>
|
||||
<array>
|
||||
<integer>221</integer>
|
||||
<integer>29</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
<key>IBSystem Version</key>
|
||||
<string>9F33</string>
|
||||
<key>targetFramework</key>
|
||||
<string>IBCocoaFramework</string>
|
||||
</dict>
|
||||
</plist>
|
Двоичные данные
toolkit/crashreporter/google-breakpad/src/client/mac/testapp/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичные данные
toolkit/crashreporter/google-breakpad/src/client/mac/testapp/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичный файл не отображается.
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -68,7 +68,9 @@ bool MinidumpFileWriter::Close() {
|
|||
bool result = true;
|
||||
|
||||
if (file_ != -1) {
|
||||
ftruncate(file_, position_);
|
||||
if (-1 == ftruncate(file_, position_)) {
|
||||
return false;
|
||||
}
|
||||
#if __linux__
|
||||
result = (sys_close(file_) == 0);
|
||||
#else
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'build_all',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'./crash_generation/crash_generation.gyp:*',
|
||||
'./handler/exception_handler.gyp:*',
|
||||
'./sender/crash_report_sender.gyp:*',
|
||||
'./unittests/client_tests.gyp:*',
|
||||
'./unittests/gtest.gyp:*',
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'common',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
]
|
||||
},
|
||||
'sources': [
|
||||
'<(DEPTH)/common/windows/guid_string.cc',
|
||||
'<(DEPTH)/common/windows/guid_string.h',
|
||||
'<(DEPTH)/common/windows/http_upload.cc',
|
||||
'<(DEPTH)/common/windows/http_upload.h',
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler", "handler\exception_handler.vcproj", "{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4} = {A820AF62-6239-4693-8430-4F516C1838F4}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_report_sender", "sender\crash_report_sender.vcproj", "{9946A048-043B-4F8F-9E07-9297B204714C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation", "crash_generation\crash_generation.vcproj", "{A820AF62-6239-4693-8430-4F516C1838F4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler_test", "handler\exception_handler_test\exception_handler_test.vcproj", "{89094A11-CF25-4037-AF43-EACFA751405E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
DebugStaticCRT|Win32 = DebugStaticCRT|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
ReleaseStaticCRT|Win32 = ReleaseStaticCRT|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.Release|Win32.Build.0 = Release|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{B55CA863-B374-4BAF-95AC-539E4FA4C90C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.Release|Win32.Build.0 = Release|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{9946A048-043B-4F8F-9E07-9297B204714C}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.ActiveCfg = DebugStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.DebugStaticCRT|Win32.Build.0 = DebugStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.Build.0 = Release|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32
|
||||
{A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.DebugStaticCRT|Win32.ActiveCfg = Debug|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.DebugStaticCRT|Win32.Build.0 = Debug|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.Release|Win32.Build.0 = Release|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.ReleaseStaticCRT|Win32.ActiveCfg = Release|Win32
|
||||
{89094A11-CF25-4037-AF43-EACFA751405E}.ReleaseStaticCRT|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,72 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'conditions': [
|
||||
[ 'OS=="linux"', {
|
||||
'target_defaults': {
|
||||
'cflags!': [
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
],
|
||||
},
|
||||
}],
|
||||
[ 'OS=="win"', {
|
||||
'target_defaults': {
|
||||
'defines': [
|
||||
'_CRT_SECURE_NO_DEPRECATE',
|
||||
'_CRT_NONSTDC_NO_WARNINGS',
|
||||
'_CRT_NONSTDC_NO_DEPRECATE',
|
||||
'_SCL_SECURE_NO_DEPRECATE',
|
||||
],
|
||||
'msvs_disabled_warnings': [4800],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'WarnAsError': 'false',
|
||||
'Detect64BitPortabilityProblems': 'false',
|
||||
},
|
||||
},
|
||||
},
|
||||
}],
|
||||
[ 'OS=="mac"', {
|
||||
'target_defaults': {
|
||||
'xcode_settings': {
|
||||
'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO',
|
||||
'WARNING_CFLAGS!': ['-Wall'],
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:2
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'Optimizations': '2',
|
||||
'StringPooling': 'true',
|
||||
'OmitFramePointers': 'true',
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'LinkIncremental': '1',
|
||||
'OptimizeReferences': '2',
|
||||
'EnableCOMDATFolding': '2',
|
||||
'OptimizeForWindows98': '1',
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
'includes': ['release_defaults.gypi'],
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
'includes': ['release_defaults.gypi'],
|
||||
'defines': ['OFFICIAL_BUILD'],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'Optimization': '3',
|
||||
'InlineFunctionExpansion': '2',
|
||||
'EnableIntrinsicFunctions': 'true',
|
||||
'FavorSizeOrSpeed': '2',
|
||||
'OmitFramePointers': 'true',
|
||||
'EnableFiberSafeOptimizations': 'true',
|
||||
'WholeProgramOptimization': 'true',
|
||||
},
|
||||
'VCLibrarianTool': {
|
||||
'AdditionalOptions': ['/ltcg', '/expectedoutputsize:120000000'],
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'LinkTimeCodeGeneration': '1',
|
||||
},
|
||||
},
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
'conditions': [
|
||||
# Handle build types.
|
||||
['buildtype=="Dev"', {
|
||||
'includes': ['internal/release_impl.gypi'],
|
||||
}],
|
||||
['buildtype=="Official"', {
|
||||
'includes': ['internal/release_impl_official.gypi'],
|
||||
}],
|
||||
# TODO(bradnelson): may also need:
|
||||
# checksenabled
|
||||
# coverage
|
||||
# dom_stats
|
||||
# pgo_instrument
|
||||
# pgo_optimize
|
||||
# purify
|
||||
],
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'crash_generation_server',
|
||||
'type': '<(library)',
|
||||
'sources': [
|
||||
'client_info.cc',
|
||||
'crash_generation_server.cc',
|
||||
'minidump_generator.cc',
|
||||
'client_info.h',
|
||||
'crash_generation_client.h',
|
||||
'crash_generation_server.h',
|
||||
'minidump_generator.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'../breakpad_client.gyp:common'
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'crash_generation_client',
|
||||
'type': '<(library)',
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
],
|
||||
'sources': [
|
||||
'crash_generation_client.h',
|
||||
'crash_generation_client.cc',
|
||||
'crash_generation_server.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1,347 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="crash_generation"
|
||||
ProjectGUID="{A820AF62-6239-4693-8430-4F516C1838F4}"
|
||||
RootNamespace="CrashGenerationServer"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\client_info.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_client.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_server.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\guid_string.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\minidump_generator.cc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\common\auto_critical_section.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\client_info.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_client.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\crash_generation_server.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\common\ipc_protocol.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\minidump_generator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\string_utils-inl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -271,7 +271,8 @@ bool CrashGenerationClient::IsRegistered() const {
|
|||
return crash_event_ != NULL;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info,
|
||||
MDRawAssertionInfo* assert_info) {
|
||||
if (!IsRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -279,33 +280,23 @@ bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
|
|||
exception_pointers_ = ex_info;
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
assert_info_.line = 0;
|
||||
assert_info_.type = 0;
|
||||
assert_info_.expression[0] = 0;
|
||||
assert_info_.file[0] = 0;
|
||||
assert_info_.function[0] = 0;
|
||||
|
||||
return SignalCrashEventAndWait();
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
|
||||
if (!IsRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exception_pointers_ = NULL;
|
||||
|
||||
if (assert_info) {
|
||||
memcpy(&assert_info_, assert_info, sizeof(assert_info_));
|
||||
} else {
|
||||
memset(&assert_info_, 0, sizeof(assert_info_));
|
||||
}
|
||||
|
||||
thread_id_ = GetCurrentThreadId();
|
||||
|
||||
return SignalCrashEventAndWait();
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
|
||||
return RequestDump(ex_info, NULL);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
|
||||
return RequestDump(NULL, assert_info);
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::SignalCrashEventAndWait() {
|
||||
assert(crash_event_);
|
||||
assert(crash_generated_);
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
// (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_CLIENT_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
@ -73,6 +73,9 @@ class CrashGenerationClient {
|
|||
// Returns true if the registration is successful; false otherwise.
|
||||
bool Register();
|
||||
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info,
|
||||
MDRawAssertionInfo* assert_info);
|
||||
|
||||
// Requests the crash server to generate a dump with the given
|
||||
// exception information.
|
||||
//
|
||||
|
@ -156,4 +159,4 @@ class CrashGenerationClient {
|
|||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
|
||||
|
|
|
@ -68,6 +68,23 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
|||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
wstring* dump_path) {
|
||||
// Just call the full WriteMinidump with NULL as the full_dump_path.
|
||||
return this->WriteMinidump(process_handle, process_id, thread_id,
|
||||
requesting_thread_id, exception_pointers,
|
||||
assert_info, dump_type, is_client_pointers,
|
||||
dump_path, NULL);
|
||||
}
|
||||
|
||||
bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
wstring* dump_path,
|
||||
wstring* full_dump_path) {
|
||||
MiniDumpWriteDumpType write_dump = GetWriteDump();
|
||||
if (!write_dump) {
|
||||
return false;
|
||||
|
@ -223,6 +240,9 @@ bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
|
|||
if (result && dump_path) {
|
||||
*dump_path = dump_file_path;
|
||||
}
|
||||
if (result && full_memory_dump && full_dump_path) {
|
||||
*full_dump_path = full_dump_file_path;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -275,7 +295,7 @@ bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
|
|||
UUID id = {0};
|
||||
|
||||
UuidCreateType create_uuid = GetCreateUuid();
|
||||
if(!create_uuid) {
|
||||
if (!create_uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
// (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_GENERATION_H__
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
||||
#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
@ -61,6 +61,20 @@ class MinidumpGenerator {
|
|||
bool is_client_pointers,
|
||||
std::wstring* dump_path);
|
||||
|
||||
// Writes the minidump with the given parameters. Stores the dump file
|
||||
// path in the dump_path (and full_dump_path) parameter if dump
|
||||
// generation succeeds. full_dump_path and dump_path can be NULL.
|
||||
bool WriteMinidump(HANDLE process_handle,
|
||||
DWORD process_id,
|
||||
DWORD thread_id,
|
||||
DWORD requesting_thread_id,
|
||||
EXCEPTION_POINTERS* exception_pointers,
|
||||
MDRawAssertionInfo* assert_info,
|
||||
MINIDUMP_TYPE dump_type,
|
||||
bool is_client_pointers,
|
||||
std::wstring* dump_path,
|
||||
std::wstring* full_dump_path);
|
||||
|
||||
private:
|
||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||
// dynamically.
|
||||
|
@ -118,4 +132,4 @@ class MinidumpGenerator {
|
|||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
|
||||
#endif // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATOR_H_
|
||||
|
|
|
@ -27,12 +27,11 @@
|
|||
// (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>
|
||||
#include <ObjBase.h>
|
||||
#include <winternl.h>
|
||||
#include <psapi.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#include "common/windows/string_utils-inl.h"
|
||||
|
||||
|
@ -430,7 +429,7 @@ class AutoExceptionHandler {
|
|||
AutoExceptionHandler() {
|
||||
// Increment handler_stack_index_ so that if another Breakpad handler is
|
||||
// registered using this same HandleException function, and it needs to be
|
||||
// called while this handler is running (either becaause this handler
|
||||
// called while this handler is running (either because this handler
|
||||
// declines to handle the exception, or an exception occurs during
|
||||
// handling), HandleException will find the appropriate ExceptionHandler
|
||||
// object in handler_stack_ to deliver the exception to.
|
||||
|
@ -448,7 +447,6 @@ class AutoExceptionHandler {
|
|||
handler_ = ExceptionHandler::handler_stack_->at(
|
||||
ExceptionHandler::handler_stack_->size() -
|
||||
++ExceptionHandler::handler_stack_index_);
|
||||
LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
|
||||
|
||||
// In case another exception occurs while this handler is doing its thing,
|
||||
// it should be delivered to the previous filter.
|
||||
|
@ -467,7 +465,6 @@ class AutoExceptionHandler {
|
|||
#endif // _MSC_VER >= 1400
|
||||
_set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);
|
||||
|
||||
EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
|
||||
--ExceptionHandler::handler_stack_index_;
|
||||
LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
|
||||
}
|
||||
|
@ -567,16 +564,37 @@ void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
|
|||
assertion.line = line;
|
||||
assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;
|
||||
|
||||
// Make up an exception record for the current thread and CPU context
|
||||
// to make it possible for the crash processor to classify these
|
||||
// as do regular crashes, and to make it humane for developers to
|
||||
// analyze them.
|
||||
EXCEPTION_RECORD exception_record = {};
|
||||
CONTEXT exception_context = {};
|
||||
EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
|
||||
RtlCaptureContext(&exception_context);
|
||||
exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
|
||||
// We store pointers to the the expression and function strings,
|
||||
// and the line as exception parameters to make them easy to
|
||||
// access by the developer on the far side.
|
||||
exception_record.NumberParameters = 3;
|
||||
exception_record.ExceptionInformation[0] =
|
||||
reinterpret_cast<ULONG_PTR>(&assertion.expression);
|
||||
exception_record.ExceptionInformation[1] =
|
||||
reinterpret_cast<ULONG_PTR>(&assertion.file);
|
||||
exception_record.ExceptionInformation[2] = assertion.line;
|
||||
|
||||
bool success = false;
|
||||
// In case of out-of-process dump generation, directly call
|
||||
// WriteMinidumpWithException since there is no separate thread running.
|
||||
if (current_handler->IsOutOfProcess()) {
|
||||
success = current_handler->WriteMinidumpWithException(
|
||||
GetCurrentThreadId(),
|
||||
NULL,
|
||||
&exception_ptrs,
|
||||
&assertion);
|
||||
} else {
|
||||
success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
|
||||
success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
|
||||
&assertion);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
|
@ -615,6 +633,8 @@ void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
|
|||
|
||||
// static
|
||||
void ExceptionHandler::HandlePureVirtualCall() {
|
||||
// This is an pure virtual funciton call, not an exception. It's safe to
|
||||
// play with sprintf here.
|
||||
AutoExceptionHandler auto_exception_handler;
|
||||
ExceptionHandler* current_handler = auto_exception_handler.get_handler();
|
||||
|
||||
|
@ -622,6 +642,26 @@ void ExceptionHandler::HandlePureVirtualCall() {
|
|||
memset(&assertion, 0, sizeof(assertion));
|
||||
assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;
|
||||
|
||||
// Make up an exception record for the current thread and CPU context
|
||||
// to make it possible for the crash processor to classify these
|
||||
// as do regular crashes, and to make it humane for developers to
|
||||
// analyze them.
|
||||
EXCEPTION_RECORD exception_record = {};
|
||||
CONTEXT exception_context = {};
|
||||
EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
|
||||
RtlCaptureContext(&exception_context);
|
||||
exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
|
||||
|
||||
// We store pointers to the the expression and function strings,
|
||||
// and the line as exception parameters to make them easy to
|
||||
// access by the developer on the far side.
|
||||
exception_record.NumberParameters = 3;
|
||||
exception_record.ExceptionInformation[0] =
|
||||
reinterpret_cast<ULONG_PTR>(&assertion.expression);
|
||||
exception_record.ExceptionInformation[1] =
|
||||
reinterpret_cast<ULONG_PTR>(&assertion.file);
|
||||
exception_record.ExceptionInformation[2] = assertion.line;
|
||||
|
||||
bool success = false;
|
||||
// In case of out-of-process dump generation, directly call
|
||||
// WriteMinidumpWithException since there is no separate thread running.
|
||||
|
@ -629,10 +669,11 @@ void ExceptionHandler::HandlePureVirtualCall() {
|
|||
if (current_handler->IsOutOfProcess()) {
|
||||
success = current_handler->WriteMinidumpWithException(
|
||||
GetCurrentThreadId(),
|
||||
NULL,
|
||||
&exception_ptrs,
|
||||
&assertion);
|
||||
} else {
|
||||
success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
|
||||
success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
|
||||
&assertion);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
|
@ -823,13 +864,7 @@ bool ExceptionHandler::WriteMinidumpWithException(
|
|||
|
||||
bool success = false;
|
||||
if (IsOutOfProcess()) {
|
||||
// Use the EXCEPTION_POINTERS overload for RequestDump if
|
||||
// both exinfo and assertion are NULL.
|
||||
if (!assertion) {
|
||||
success = crash_generation_client_->RequestDump(exinfo);
|
||||
} else {
|
||||
success = crash_generation_client_->RequestDump(assertion);
|
||||
}
|
||||
success = crash_generation_client_->RequestDump(exinfo, assertion);
|
||||
} else {
|
||||
success = WriteMinidumpWithExceptionForProcess(requesting_thread_id,
|
||||
exinfo,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'exception_handler',
|
||||
'type': '<(library)',
|
||||
'sources': [
|
||||
"exception_handler.cc",
|
||||
"exception_handler.h",
|
||||
],
|
||||
'dependencies': [
|
||||
'../breakpad_client.gyp:common',
|
||||
'../crash_generation/crash_generation.gyp:crash_generation_server',
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="exception_handler"
|
||||
ProjectGUID="{B55CA863-B374-4BAF-95AC-539E4FA4C90C}"
|
||||
RootNamespace="exception_handler"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="crash_generation.lib"
|
||||
AdditionalLibraryDirectories="..\$(ConfigurationName)"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="crash_generation.lib"
|
||||
AdditionalLibraryDirectories="..\$(ConfigurationName)"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="crash_generation.lib"
|
||||
AdditionalLibraryDirectories="..\$(ConfigurationName)"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
AdditionalDependencies="crash_generation.lib"
|
||||
AdditionalLibraryDirectories="..\$(ConfigurationName)"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\exception_handler.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\guid_string.cc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\exception_handler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\guid_string.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\google_breakpad\common\minidump_format.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\string_utils-inl.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -1,266 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="exception_handler_test"
|
||||
ProjectGUID="{89094A11-CF25-4037-AF43-EACFA751405E}"
|
||||
RootNamespace="exception_handler_test"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
Description=""
|
||||
CommandLine=""
|
||||
Outputs=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\..\..\testing;..\..\..\..\testing\include;..\..\..\..\testing\gtest;..\..\..\..\testing\gtest\include;..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
Description="Running tests"
|
||||
CommandLine="$(OutDir)\$(ProjectName).exe"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\..\..\testing;..\..\..\..\testing\include;..\..\..\..\testing\gtest;..\..\..\..\testing\gtest\include;..\..\..\..\"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
Description="Running tests"
|
||||
CommandLine="$(OutDir)\$(ProjectName).exe"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\client_info.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\crash_generation_client.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\crash_generation_server.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\exception_handler.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\exception_handler_test.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\testing\gtest\src\gtest-all.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\testing\gtest\src\gtest_main.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\common\windows\guid_string.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\minidump_generator.cc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\client_info.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\crash_generation_client.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\crash_generation_server.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\exception_handler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\..\common\windows\guid_string.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\crash_generation\minidump_generator.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'crash_report_sender',
|
||||
'type': '<(library)',
|
||||
'sources': [
|
||||
'crash_report_sender.cc',
|
||||
'crash_report_sender.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'../breakpad_client.gyp:common'
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
|
@ -1,307 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="crash_report_sender"
|
||||
ProjectGUID="{9946A048-043B-4F8F-9E07-9297B204714C}"
|
||||
RootNamespace="crash_report_sender"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="DebugStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="ReleaseStaticCRT|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\crash_report_sender.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\http_upload.cc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\crash_report_sender.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\common\windows\http_upload.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,54 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'client_tests',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'exception_handler_test.cc',
|
||||
'exception_handler_death_test.cc',
|
||||
'minidump_test.cc',
|
||||
'dump_analysis.cc',
|
||||
'dump_analysis.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'gtest.gyp:gtest',
|
||||
'../breakpad_client.gyp:common',
|
||||
'../crash_generation/crash_generation.gyp:crash_generation_server',
|
||||
'../crash_generation/crash_generation.gyp:crash_generation_client',
|
||||
'../handler/exception_handler.gyp:exception_handler',
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
// 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 <windows.h>
|
||||
#include <objbase.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include "dump_analysis.h" // NOLINT
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
DumpAnalysis::~DumpAnalysis() {
|
||||
if (dump_file_view_ != NULL) {
|
||||
EXPECT_TRUE(::UnmapViewOfFile(dump_file_view_));
|
||||
::CloseHandle(dump_file_mapping_);
|
||||
dump_file_mapping_ = NULL;
|
||||
}
|
||||
|
||||
if (dump_file_handle_ != NULL) {
|
||||
::CloseHandle(dump_file_handle_);
|
||||
dump_file_handle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DumpAnalysis::EnsureDumpMapped() {
|
||||
if (dump_file_view_ == NULL) {
|
||||
dump_file_handle_ = ::CreateFile(dump_file_.c_str(),
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
ASSERT_TRUE(dump_file_handle_ != NULL);
|
||||
ASSERT_TRUE(dump_file_mapping_ == NULL);
|
||||
|
||||
dump_file_mapping_ = ::CreateFileMapping(dump_file_handle_,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
ASSERT_TRUE(dump_file_mapping_ != NULL);
|
||||
|
||||
dump_file_view_ = ::MapViewOfFile(dump_file_mapping_,
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
ASSERT_TRUE(dump_file_view_ != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool DumpAnalysis::HasTebs() const {
|
||||
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
||||
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
||||
|
||||
if (thread_list_size > 0 && thread_list != NULL) {
|
||||
for (ULONG i = 0; i < thread_list->NumberOfThreads; ++i) {
|
||||
if (!HasMemory(thread_list->Threads[i].Teb))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// No thread list, no TEB info.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DumpAnalysis::HasPeb() const {
|
||||
MINIDUMP_THREAD_LIST* thread_list = NULL;
|
||||
size_t thread_list_size = GetStream(ThreadListStream, &thread_list);
|
||||
|
||||
if (thread_list_size > 0 && thread_list != NULL &&
|
||||
thread_list->NumberOfThreads > 0) {
|
||||
FakeTEB* teb = NULL;
|
||||
if (!HasMemory(thread_list->Threads[0].Teb, &teb))
|
||||
return false;
|
||||
|
||||
return HasMemory(teb->peb);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DumpAnalysis::HasStream(ULONG stream_number) const {
|
||||
void* stream = NULL;
|
||||
size_t stream_size = GetStreamImpl(stream_number, &stream);
|
||||
return stream_size > 0 && stream != NULL;
|
||||
}
|
||||
|
||||
size_t DumpAnalysis::GetStreamImpl(ULONG stream_number, void** stream) const {
|
||||
MINIDUMP_DIRECTORY* directory = NULL;
|
||||
ULONG memory_list_size = 0;
|
||||
BOOL ret = ::MiniDumpReadDumpStream(dump_file_view_,
|
||||
stream_number,
|
||||
&directory,
|
||||
stream,
|
||||
&memory_list_size);
|
||||
|
||||
return ret ? memory_list_size : 0;
|
||||
}
|
||||
|
||||
bool DumpAnalysis::HasMemoryImpl(const void *addr_in, size_t structuresize,
|
||||
void **structure) const {
|
||||
uintptr_t address = reinterpret_cast<uintptr_t>(addr_in);
|
||||
MINIDUMP_MEMORY_LIST* memory_list = NULL;
|
||||
size_t memory_list_size = GetStream(MemoryListStream, &memory_list);
|
||||
if (memory_list_size > 0 && memory_list != NULL) {
|
||||
for (ULONG i = 0; i < memory_list->NumberOfMemoryRanges; ++i) {
|
||||
MINIDUMP_MEMORY_DESCRIPTOR& descr = memory_list->MemoryRanges[i];
|
||||
const uintptr_t range_start =
|
||||
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
||||
uintptr_t range_end = range_start + descr.Memory.DataSize;
|
||||
|
||||
if (address >= range_start &&
|
||||
address + structuresize < range_end) {
|
||||
// The start address falls in the range, and the end address is
|
||||
// in bounds, return a pointer to the structure if requested.
|
||||
if (structure != NULL)
|
||||
*structure = RVA_TO_ADDR(dump_file_view_, descr.Memory.Rva);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find the range in a MINIDUMP_MEMORY_LIST, so maybe this
|
||||
// is a full dump using MINIDUMP_MEMORY64_LIST with all the memory at the
|
||||
// end of the dump file.
|
||||
MINIDUMP_MEMORY64_LIST* memory64_list = NULL;
|
||||
memory_list_size = GetStream(Memory64ListStream, &memory64_list);
|
||||
if (memory_list_size > 0 && memory64_list != NULL) {
|
||||
// Keep track of where the current descriptor maps to.
|
||||
RVA64 curr_rva = memory64_list->BaseRva;
|
||||
for (ULONG i = 0; i < memory64_list->NumberOfMemoryRanges; ++i) {
|
||||
MINIDUMP_MEMORY_DESCRIPTOR64& descr = memory64_list->MemoryRanges[i];
|
||||
uintptr_t range_start =
|
||||
static_cast<uintptr_t>(descr.StartOfMemoryRange);
|
||||
uintptr_t range_end = range_start + static_cast<size_t>(descr.DataSize);
|
||||
|
||||
if (address >= range_start &&
|
||||
address + structuresize < range_end) {
|
||||
// The start address falls in the range, and the end address is
|
||||
// in bounds, return a pointer to the structure if requested.
|
||||
if (structure != NULL)
|
||||
*structure = RVA_TO_ADDR(dump_file_view_, curr_rva);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Advance the current RVA.
|
||||
curr_rva += descr.DataSize;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// 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_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||
#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||
|
||||
#include "../crash_generation/minidump_generator.h"
|
||||
|
||||
// Convenience to get to the PEB pointer in a TEB.
|
||||
struct FakeTEB {
|
||||
char dummy[0x30];
|
||||
void* peb;
|
||||
};
|
||||
|
||||
class DumpAnalysis {
|
||||
public:
|
||||
explicit DumpAnalysis(const std::wstring& file_path)
|
||||
: dump_file_(file_path), dump_file_view_(NULL), dump_file_mapping_(NULL),
|
||||
dump_file_handle_(NULL) {
|
||||
EnsureDumpMapped();
|
||||
}
|
||||
~DumpAnalysis();
|
||||
|
||||
bool HasStream(ULONG stream_number) const;
|
||||
|
||||
// This is template to keep type safety in the front, but we end up casting
|
||||
// to void** inside the implementation to pass the pointer to Win32. So
|
||||
// casting here is considered safe.
|
||||
template <class StreamType>
|
||||
size_t GetStream(ULONG stream_number, StreamType** stream) const {
|
||||
return GetStreamImpl(stream_number, reinterpret_cast<void**>(stream));
|
||||
}
|
||||
|
||||
bool HasTebs() const;
|
||||
bool HasPeb() const;
|
||||
bool HasMemory(ULONG64 address) const {
|
||||
return HasMemory<BYTE>(address, NULL);
|
||||
}
|
||||
|
||||
bool HasMemory(const void* address) const {
|
||||
return HasMemory<BYTE>(address, NULL);
|
||||
}
|
||||
|
||||
template <class StructureType>
|
||||
bool HasMemory(ULONG64 address, StructureType** structure = NULL) const {
|
||||
// We can't cope with 64 bit addresses for now.
|
||||
if (address > 0xFFFFFFFFUL)
|
||||
return false;
|
||||
|
||||
return HasMemory(reinterpret_cast<void*>(address), structure);
|
||||
}
|
||||
|
||||
template <class StructureType>
|
||||
bool HasMemory(const void* addr_in, StructureType** structure = NULL) const {
|
||||
return HasMemoryImpl(addr_in, sizeof(StructureType),
|
||||
reinterpret_cast<void**>(structure));
|
||||
}
|
||||
|
||||
protected:
|
||||
void EnsureDumpMapped();
|
||||
|
||||
HANDLE dump_file_mapping_;
|
||||
HANDLE dump_file_handle_;
|
||||
void* dump_file_view_;
|
||||
std::wstring dump_file_;
|
||||
|
||||
private:
|
||||
// This is the implementation of GetStream<>.
|
||||
size_t GetStreamImpl(ULONG stream_number, void** stream) const;
|
||||
|
||||
// This is the implementation of HasMemory<>.
|
||||
bool HasMemoryImpl(const void* addr_in, size_t pointersize,
|
||||
void** structure) const;
|
||||
};
|
||||
|
||||
#endif // CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
|
@ -27,15 +27,16 @@
|
|||
// (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 "client/windows/crash_generation/crash_generation_server.h"
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <strsafe.h>
|
||||
#include <objbase.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "../../../breakpad_googletest_includes.h"
|
||||
#include "../crash_generation/crash_generation_server.h"
|
||||
#include "../handler/exception_handler.h"
|
||||
|
||||
namespace {
|
||||
const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer";
|
||||
const char kSuccessIndicator[] = "success";
|
||||
|
@ -45,14 +46,15 @@ const char kFailureIndicator[] = "failure";
|
|||
BOOL DoesPathExist(const TCHAR *path_name);
|
||||
|
||||
class ExceptionHandlerDeathTest : public ::testing::Test {
|
||||
protected:
|
||||
protected:
|
||||
// Member variable for each test that they can use
|
||||
// for temporary storage.
|
||||
TCHAR temp_path_[MAX_PATH];
|
||||
// Actually constructs a temp path name.
|
||||
virtual void SetUp();
|
||||
// A helper method that tests can use to crash.
|
||||
void DoCrash();
|
||||
void DoCrashAccessViolation();
|
||||
void DoCrashPureVirtualCall();
|
||||
};
|
||||
|
||||
void ExceptionHandlerDeathTest::SetUp() {
|
||||
|
@ -61,12 +63,14 @@ void ExceptionHandlerDeathTest::SetUp() {
|
|||
TCHAR temp_path[MAX_PATH] = { '\0' };
|
||||
TCHAR test_name_wide[MAX_PATH] = { '\0' };
|
||||
// We want the temporary directory to be what the OS returns
|
||||
// to us, + the test case name.
|
||||
// to us, + the test case name.
|
||||
GetTempPath(MAX_PATH, temp_path);
|
||||
// THe test case name is exposed to use as a c-style string,
|
||||
// But we might be working in UNICODE here on Windows.
|
||||
int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
|
||||
(int)strlen(test_info->name()), test_name_wide, MAX_PATH);
|
||||
int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
|
||||
strlen(test_info->name()),
|
||||
test_name_wide,
|
||||
MAX_PATH);
|
||||
if (!dwRet) {
|
||||
assert(false);
|
||||
}
|
||||
|
@ -82,7 +86,7 @@ BOOL DoesPathExist(const TCHAR *path_name) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
bool MinidumpWrittenCallback(const wchar_t* dump_path,
|
||||
bool MinidumpWrittenCallback(const wchar_t* dump_path,
|
||||
const wchar_t* minidump_id,
|
||||
void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
|
@ -106,11 +110,11 @@ TEST_F(ExceptionHandlerDeathTest, InProcTest) {
|
|||
// the semantics of the exception handler being inherited/not
|
||||
// inherited across CreateProcess().
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
new google_breakpad::ExceptionHandler(
|
||||
temp_path_, NULL, &MinidumpWrittenCallback, NULL,
|
||||
temp_path_, NULL, &MinidumpWrittenCallback, NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
int *i = NULL;
|
||||
int *i = NULL;
|
||||
ASSERT_DEATH((*i)++, kSuccessIndicator);
|
||||
delete exc;
|
||||
}
|
||||
|
@ -119,19 +123,18 @@ static bool gDumpCallbackCalled = false;
|
|||
|
||||
void clientDumpCallback(void *dump_context,
|
||||
const google_breakpad::ClientInfo *client_info,
|
||||
const std::wstring *dump_path){
|
||||
|
||||
const std::wstring *dump_path) {
|
||||
gDumpCallbackCalled = true;
|
||||
}
|
||||
|
||||
void ExceptionHandlerDeathTest::DoCrash() {
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
void ExceptionHandlerDeathTest::DoCrashAccessViolation() {
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
new google_breakpad::ExceptionHandler(
|
||||
temp_path_, NULL, NULL, NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName,
|
||||
NULL);
|
||||
// Although this is executing in the child process of the death test,
|
||||
// if it's not true we'll still get an error rather than the crash
|
||||
// if it's not true we'll still get an error rather than the crash
|
||||
// being expected.
|
||||
ASSERT_TRUE(exc->IsOutOfProcess());
|
||||
int *i = NULL;
|
||||
|
@ -141,7 +144,7 @@ void ExceptionHandlerDeathTest::DoCrash() {
|
|||
TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) {
|
||||
// We can take advantage of a detail of google test here to save some
|
||||
// complexity in testing: when you do a death test, it actually forks.
|
||||
// So we can make the main test harness the crash generation server,
|
||||
// So we can make the main test harness the crash generation server,
|
||||
// and call ASSERT_DEATH on a NULL dereference, it to expecting test
|
||||
// the out of process scenario, since it's happening in a different
|
||||
// process! This is different from the above because, above, we pass
|
||||
|
@ -152,13 +155,61 @@ TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) {
|
|||
google_breakpad::CrashGenerationServer server(
|
||||
kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, true,
|
||||
&dump_path);
|
||||
|
||||
|
||||
// This HAS to be EXPECT_, because when this test case is executed in the
|
||||
// child process, the server registration will fail due to the named pipe
|
||||
// being the same.
|
||||
EXPECT_TRUE(server.Start());
|
||||
EXPECT_FALSE(gDumpCallbackCalled);
|
||||
ASSERT_DEATH(this->DoCrash(), "");
|
||||
ASSERT_DEATH(this->DoCrashAccessViolation(), "");
|
||||
EXPECT_TRUE(gDumpCallbackCalled);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ExceptionHandlerDeathTest, InvalidParameterTest) {
|
||||
using google_breakpad::ExceptionHandler;
|
||||
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
ExceptionHandler handler(temp_path_, NULL, NULL, NULL,
|
||||
ExceptionHandler::HANDLER_INVALID_PARAMETER);
|
||||
|
||||
// Disable the message box for assertions
|
||||
_CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
|
||||
// Call with a bad argument. The invalid parameter will be swallowed
|
||||
// and a dump will be generated, the process will exit(0).
|
||||
ASSERT_EXIT(printf(NULL), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
|
||||
struct PureVirtualCallBase {
|
||||
PureVirtualCallBase() {
|
||||
// We have to reinterpret so the linker doesn't get confused because the
|
||||
// method isn't defined.
|
||||
reinterpret_cast<PureVirtualCallBase*>(this)->PureFunction();
|
||||
}
|
||||
virtual ~PureVirtualCallBase() {}
|
||||
virtual void PureFunction() const = 0;
|
||||
};
|
||||
struct PureVirtualCall : public PureVirtualCallBase {
|
||||
PureVirtualCall() { PureFunction(); }
|
||||
virtual void PureFunction() const {}
|
||||
};
|
||||
|
||||
void ExceptionHandlerDeathTest::DoCrashPureVirtualCall() {
|
||||
PureVirtualCall instance;
|
||||
}
|
||||
|
||||
TEST_F(ExceptionHandlerDeathTest, PureVirtualCallTest) {
|
||||
using google_breakpad::ExceptionHandler;
|
||||
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
ExceptionHandler handler(temp_path_, NULL, NULL, NULL,
|
||||
ExceptionHandler::HANDLER_PURECALL);
|
||||
|
||||
// Disable the message box for assertions
|
||||
_CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
|
||||
// Calls a pure virtual function.
|
||||
EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
// Copyright 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 <windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <strsafe.h>
|
||||
#include <objbase.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "../../../breakpad_googletest_includes.h"
|
||||
#include "../crash_generation/crash_generation_server.h"
|
||||
#include "../handler/exception_handler.h"
|
||||
#include "dump_analysis.h" // NOLINT
|
||||
|
||||
namespace {
|
||||
const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer";
|
||||
const char kSuccessIndicator[] = "success";
|
||||
const char kFailureIndicator[] = "failure";
|
||||
|
||||
const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
MiniDumpWithFullMemory | // Full memory from process.
|
||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithHandleData); // Get all handle information.
|
||||
|
||||
class ExceptionHandlerTest : public ::testing::Test {
|
||||
protected:
|
||||
// Member variable for each test that they can use
|
||||
// for temporary storage.
|
||||
TCHAR temp_path_[MAX_PATH];
|
||||
|
||||
// Actually constructs a temp path name.
|
||||
virtual void SetUp();
|
||||
|
||||
// Deletes temporary files.
|
||||
virtual void TearDown();
|
||||
|
||||
void DoCrashInvalidParameter();
|
||||
void DoCrashPureVirtualCall();
|
||||
|
||||
// Utility function to test for a path's existence.
|
||||
static BOOL DoesPathExist(const TCHAR *path_name);
|
||||
|
||||
// Client callback.
|
||||
static void ClientDumpCallback(
|
||||
void *dump_context,
|
||||
const google_breakpad::ClientInfo *client_info,
|
||||
const std::wstring *dump_path);
|
||||
|
||||
static std::wstring dump_file;
|
||||
static std::wstring full_dump_file;
|
||||
};
|
||||
|
||||
std::wstring ExceptionHandlerTest::dump_file;
|
||||
std::wstring ExceptionHandlerTest::full_dump_file;
|
||||
|
||||
void ExceptionHandlerTest::SetUp() {
|
||||
const ::testing::TestInfo* const test_info =
|
||||
::testing::UnitTest::GetInstance()->current_test_info();
|
||||
TCHAR temp_path[MAX_PATH] = { '\0' };
|
||||
TCHAR test_name_wide[MAX_PATH] = { '\0' };
|
||||
// We want the temporary directory to be what the OS returns
|
||||
// to us, + the test case name.
|
||||
GetTempPath(MAX_PATH, temp_path);
|
||||
// THe test case name is exposed to use as a c-style string,
|
||||
// But we might be working in UNICODE here on Windows.
|
||||
int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(),
|
||||
strlen(test_info->name()),
|
||||
test_name_wide,
|
||||
MAX_PATH);
|
||||
if (!dwRet) {
|
||||
assert(false);
|
||||
}
|
||||
StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide);
|
||||
CreateDirectory(temp_path_, NULL);
|
||||
}
|
||||
|
||||
void ExceptionHandlerTest::TearDown() {
|
||||
if (!dump_file.empty()) {
|
||||
::DeleteFile(dump_file.c_str());
|
||||
dump_file = L"";
|
||||
}
|
||||
if (!full_dump_file.empty()) {
|
||||
::DeleteFile(full_dump_file.c_str());
|
||||
full_dump_file = L"";
|
||||
}
|
||||
}
|
||||
|
||||
BOOL ExceptionHandlerTest::DoesPathExist(const TCHAR *path_name) {
|
||||
DWORD flags = GetFileAttributes(path_name);
|
||||
if (flags == INVALID_FILE_ATTRIBUTES) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ExceptionHandlerTest::ClientDumpCallback(
|
||||
void *dump_context,
|
||||
const google_breakpad::ClientInfo *client_info,
|
||||
const std::wstring *dump_path) {
|
||||
dump_file = *dump_path;
|
||||
// Create the full dump file name from the dump path.
|
||||
full_dump_file = dump_file.substr(0, dump_file.length() - 4) + L"-full.dmp";
|
||||
}
|
||||
|
||||
void ExceptionHandlerTest::DoCrashInvalidParameter() {
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
new google_breakpad::ExceptionHandler(
|
||||
temp_path_, NULL, NULL, NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER,
|
||||
kFullDumpType, kPipeName, NULL);
|
||||
|
||||
// Disable the message box for assertions
|
||||
_CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
|
||||
// Although this is executing in the child process of the death test,
|
||||
// if it's not true we'll still get an error rather than the crash
|
||||
// being expected.
|
||||
ASSERT_TRUE(exc->IsOutOfProcess());
|
||||
printf(NULL);
|
||||
}
|
||||
|
||||
|
||||
struct PureVirtualCallBase {
|
||||
PureVirtualCallBase() {
|
||||
// We have to reinterpret so the linker doesn't get confused because the
|
||||
// method isn't defined.
|
||||
reinterpret_cast<PureVirtualCallBase*>(this)->PureFunction();
|
||||
}
|
||||
virtual ~PureVirtualCallBase() {}
|
||||
virtual void PureFunction() const = 0;
|
||||
};
|
||||
struct PureVirtualCall : public PureVirtualCallBase {
|
||||
PureVirtualCall() { PureFunction(); }
|
||||
virtual void PureFunction() const {}
|
||||
};
|
||||
|
||||
void ExceptionHandlerTest::DoCrashPureVirtualCall() {
|
||||
google_breakpad::ExceptionHandler *exc =
|
||||
new google_breakpad::ExceptionHandler(
|
||||
temp_path_, NULL, NULL, NULL,
|
||||
google_breakpad::ExceptionHandler::HANDLER_PURECALL,
|
||||
kFullDumpType, kPipeName, NULL);
|
||||
|
||||
// Disable the message box for assertions
|
||||
_CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
|
||||
// Although this is executing in the child process of the death test,
|
||||
// if it's not true we'll still get an error rather than the crash
|
||||
// being expected.
|
||||
ASSERT_TRUE(exc->IsOutOfProcess());
|
||||
|
||||
// Create a new frame to ensure PureVirtualCall is not optimized to some
|
||||
// other line in this function.
|
||||
{
|
||||
PureVirtualCall instance;
|
||||
}
|
||||
}
|
||||
|
||||
// This test validates that the minidump is written correctly.
|
||||
TEST_F(ExceptionHandlerTest, InvalidParameterMiniDumpTest) {
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
|
||||
// Call with a bad argument
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
std::wstring dump_path(temp_path_);
|
||||
google_breakpad::CrashGenerationServer server(
|
||||
kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, true,
|
||||
&dump_path);
|
||||
|
||||
ASSERT_TRUE(dump_file.empty() && full_dump_file.empty());
|
||||
|
||||
// This HAS to be EXPECT_, because when this test case is executed in the
|
||||
// child process, the server registration will fail due to the named pipe
|
||||
// being the same.
|
||||
EXPECT_TRUE(server.Start());
|
||||
EXPECT_EXIT(DoCrashInvalidParameter(), ::testing::ExitedWithCode(0), "");
|
||||
ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty());
|
||||
ASSERT_TRUE(DoesPathExist(dump_file.c_str()));
|
||||
|
||||
// Verify the dump for infos.
|
||||
DumpAnalysis mini(dump_file);
|
||||
DumpAnalysis full(full_dump_file);
|
||||
|
||||
// The dump should have all of these streams.
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(full.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(full.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(full.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_TRUE(full.HasStream(HandleDataStream));
|
||||
|
||||
// We expect PEB and TEBs in this dump.
|
||||
EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
|
||||
EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
|
||||
|
||||
// Minidump should have a memory listing, but no 64-bit memory.
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
|
||||
EXPECT_FALSE(full.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(full.HasStream(Memory64ListStream));
|
||||
|
||||
// This is the only place we don't use OR because we want both not
|
||||
// to have the streams.
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(full.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(full.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
EXPECT_FALSE(full.HasStream(TokenStream));
|
||||
}
|
||||
|
||||
|
||||
// This test validates that the minidump is written correctly.
|
||||
TEST_F(ExceptionHandlerTest, PureVirtualCallMiniDumpTest) {
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
|
||||
// Call with a bad argument
|
||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||
std::wstring dump_path(temp_path_);
|
||||
google_breakpad::CrashGenerationServer server(
|
||||
kPipeName, NULL, NULL, NULL, ClientDumpCallback, NULL, NULL, NULL, true,
|
||||
&dump_path);
|
||||
|
||||
ASSERT_TRUE(dump_file.empty() && full_dump_file.empty());
|
||||
|
||||
// This HAS to be EXPECT_, because when this test case is executed in the
|
||||
// child process, the server registration will fail due to the named pipe
|
||||
// being the same.
|
||||
EXPECT_TRUE(server.Start());
|
||||
EXPECT_EXIT(DoCrashPureVirtualCall(), ::testing::ExitedWithCode(0), "");
|
||||
ASSERT_TRUE(!dump_file.empty() && !full_dump_file.empty());
|
||||
ASSERT_TRUE(DoesPathExist(dump_file.c_str()));
|
||||
|
||||
// Verify the dump for infos.
|
||||
DumpAnalysis mini(dump_file);
|
||||
DumpAnalysis full(full_dump_file);
|
||||
|
||||
// The dump should have all of these streams.
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(full.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(full.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(full.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_TRUE(full.HasStream(HandleDataStream));
|
||||
|
||||
// We expect PEB and TEBs in this dump.
|
||||
EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
|
||||
EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
|
||||
|
||||
// Minidump should have a memory listing, but no 64-bit memory.
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
|
||||
EXPECT_FALSE(full.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(full.HasStream(Memory64ListStream));
|
||||
|
||||
// This is the only place we don't use OR because we want both not
|
||||
// to have the streams.
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(full.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(full.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
EXPECT_FALSE(full.HasStream(TokenStream));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../build/common.gypi',
|
||||
],
|
||||
'target_defaults': {
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'gtest',
|
||||
'type': '<(library)',
|
||||
'include_dirs': [
|
||||
'<(DEPTH)/testing/include',
|
||||
'<(DEPTH)/testing/gtest',
|
||||
'<(DEPTH)/testing/gtest/include',
|
||||
],
|
||||
'sources': [
|
||||
'<(DEPTH)/testing/gtest/src/gtest-all.cc',
|
||||
'<(DEPTH)/testing/gtest/src/gtest_main.cc',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(DEPTH)/testing/include',
|
||||
'<(DEPTH)/testing/gtest/include',
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
// 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 <windows.h>
|
||||
#include <objbase.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include "../crash_generation/minidump_generator.h"
|
||||
#include "dump_analysis.h" // NOLINT
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Minidump with stacks, PEB, TEB, and unloaded module list.
|
||||
const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||
|
||||
// Minidump with all of the above, plus memory referenced from stack.
|
||||
const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithUnloadedModules | // Get unloaded modules when available.
|
||||
MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack.
|
||||
|
||||
// Large dump with all process memory.
|
||||
const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
|
||||
MiniDumpWithFullMemory | // Full memory from process.
|
||||
MiniDumpWithProcessThreadData | // Get PEB and TEB.
|
||||
MiniDumpWithHandleData | // Get all handle information.
|
||||
MiniDumpWithUnloadedModules); // Get unloaded modules when available.
|
||||
|
||||
class MinidumpTest: public testing::Test {
|
||||
public:
|
||||
MinidumpTest() {
|
||||
wchar_t temp_dir_path[ MAX_PATH ] = {0};
|
||||
::GetTempPath(MAX_PATH, temp_dir_path);
|
||||
dump_path_ = temp_dir_path;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
// Make sure URLMon isn't loaded into our process.
|
||||
ASSERT_EQ(NULL, ::GetModuleHandle(L"urlmon.dll"));
|
||||
|
||||
// Then load and unload it to ensure we have something to
|
||||
// stock the unloaded module list with.
|
||||
HMODULE urlmon = ::LoadLibrary(L"urlmon.dll");
|
||||
ASSERT_TRUE(urlmon != NULL);
|
||||
ASSERT_TRUE(::FreeLibrary(urlmon));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (!dump_file_.empty()) {
|
||||
::DeleteFile(dump_file_.c_str());
|
||||
dump_file_ = L"";
|
||||
}
|
||||
if (!full_dump_file_.empty()) {
|
||||
::DeleteFile(full_dump_file_.c_str());
|
||||
full_dump_file_ = L"";
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteDump(ULONG flags) {
|
||||
using google_breakpad::MinidumpGenerator;
|
||||
|
||||
// Fake exception is access violation on write to this.
|
||||
EXCEPTION_RECORD ex_record = {
|
||||
STATUS_ACCESS_VIOLATION, // ExceptionCode
|
||||
0, // ExceptionFlags
|
||||
NULL, // ExceptionRecord;
|
||||
reinterpret_cast<void*>(0xCAFEBABE), // ExceptionAddress;
|
||||
2, // NumberParameters;
|
||||
{ EXCEPTION_WRITE_FAULT, reinterpret_cast<ULONG_PTR>(this) }
|
||||
};
|
||||
CONTEXT ctx_record = {};
|
||||
EXCEPTION_POINTERS ex_ptrs = {
|
||||
&ex_record,
|
||||
&ctx_record,
|
||||
};
|
||||
|
||||
MinidumpGenerator generator(dump_path_);
|
||||
|
||||
// And write a dump
|
||||
bool result = generator.WriteMinidump(::GetCurrentProcess(),
|
||||
::GetCurrentProcessId(),
|
||||
::GetCurrentThreadId(),
|
||||
::GetCurrentThreadId(),
|
||||
&ex_ptrs,
|
||||
NULL,
|
||||
static_cast<MINIDUMP_TYPE>(flags),
|
||||
TRUE,
|
||||
&dump_file_,
|
||||
&full_dump_file_);
|
||||
return result == TRUE;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::wstring dump_file_;
|
||||
std::wstring full_dump_file_;
|
||||
|
||||
std::wstring dump_path_;
|
||||
};
|
||||
|
||||
// We need to be able to get file information from Windows
|
||||
bool HasFileInfo(const std::wstring& file_path) {
|
||||
DWORD dummy;
|
||||
const wchar_t* path = file_path.c_str();
|
||||
DWORD length = ::GetFileVersionInfoSize(path, &dummy);
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
void* data = calloc(length, 1);
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (!::GetFileVersionInfo(path, dummy, length, data)) {
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* translate = NULL;
|
||||
UINT page_count;
|
||||
BOOL query_result = VerQueryValue(
|
||||
data,
|
||||
L"\\VarFileInfo\\Translation",
|
||||
static_cast<void**>(&translate),
|
||||
&page_count);
|
||||
|
||||
free(data);
|
||||
if (query_result && translate) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MinidumpTest, Version) {
|
||||
API_VERSION* version = ::ImagehlpApiVersion();
|
||||
|
||||
HMODULE dbg_help = ::GetModuleHandle(L"dbghelp.dll");
|
||||
ASSERT_TRUE(dbg_help != NULL);
|
||||
|
||||
wchar_t dbg_help_file[1024] = {};
|
||||
ASSERT_TRUE(::GetModuleFileName(dbg_help,
|
||||
dbg_help_file,
|
||||
sizeof(dbg_help_file) /
|
||||
sizeof(*dbg_help_file)));
|
||||
ASSERT_TRUE(HasFileInfo(std::wstring(dbg_help_file)) != NULL);
|
||||
|
||||
// LOG(INFO) << "DbgHelp.dll version: " << file_info->file_version();
|
||||
}
|
||||
|
||||
TEST_F(MinidumpTest, Normal) {
|
||||
EXPECT_TRUE(WriteDump(MiniDumpNormal));
|
||||
DumpAnalysis mini(dump_file_);
|
||||
|
||||
// We expect threads, modules and some memory.
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(UnloadedModuleListStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
|
||||
// We expect no PEB nor TEBs in this dump.
|
||||
EXPECT_FALSE(mini.HasTebs());
|
||||
EXPECT_FALSE(mini.HasPeb());
|
||||
|
||||
// We expect no off-stack memory in this dump.
|
||||
EXPECT_FALSE(mini.HasMemory(this));
|
||||
}
|
||||
|
||||
TEST_F(MinidumpTest, SmallDump) {
|
||||
ASSERT_TRUE(WriteDump(kSmallDumpType));
|
||||
DumpAnalysis mini(dump_file_);
|
||||
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
|
||||
// We expect PEB and TEBs in this dump.
|
||||
EXPECT_TRUE(mini.HasTebs());
|
||||
EXPECT_TRUE(mini.HasPeb());
|
||||
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
|
||||
// We expect no off-stack memory in this dump.
|
||||
EXPECT_FALSE(mini.HasMemory(this));
|
||||
}
|
||||
|
||||
TEST_F(MinidumpTest, LargerDump) {
|
||||
ASSERT_TRUE(WriteDump(kLargerDumpType));
|
||||
DumpAnalysis mini(dump_file_);
|
||||
|
||||
// The dump should have all of these streams.
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
|
||||
// We expect memory referenced by stack in this dump.
|
||||
EXPECT_TRUE(mini.HasMemory(this));
|
||||
|
||||
// We expect PEB and TEBs in this dump.
|
||||
EXPECT_TRUE(mini.HasTebs());
|
||||
EXPECT_TRUE(mini.HasPeb());
|
||||
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
}
|
||||
|
||||
TEST_F(MinidumpTest, FullDump) {
|
||||
ASSERT_TRUE(WriteDump(kFullDumpType));
|
||||
ASSERT_TRUE(dump_file_ != L"");
|
||||
ASSERT_TRUE(full_dump_file_ != L"");
|
||||
DumpAnalysis mini(dump_file_);
|
||||
DumpAnalysis full(full_dump_file_);
|
||||
|
||||
// Either dumps can contain part of the information.
|
||||
|
||||
// The dump should have all of these streams.
|
||||
EXPECT_TRUE(mini.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(full.HasStream(ThreadListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(full.HasStream(ModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(full.HasStream(ExceptionStream));
|
||||
EXPECT_TRUE(mini.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(SystemInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(UnloadedModuleListStream));
|
||||
EXPECT_TRUE(full.HasStream(UnloadedModuleListStream));
|
||||
EXPECT_TRUE(mini.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(full.HasStream(MiscInfoStream));
|
||||
EXPECT_TRUE(mini.HasStream(HandleDataStream));
|
||||
EXPECT_TRUE(full.HasStream(HandleDataStream));
|
||||
|
||||
// We expect memory referenced by stack in this dump.
|
||||
EXPECT_FALSE(mini.HasMemory(this));
|
||||
EXPECT_TRUE(full.HasMemory(this));
|
||||
|
||||
// We expect PEB and TEBs in this dump.
|
||||
EXPECT_TRUE(mini.HasTebs() || full.HasTebs());
|
||||
EXPECT_TRUE(mini.HasPeb() || full.HasPeb());
|
||||
|
||||
EXPECT_TRUE(mini.HasStream(MemoryListStream));
|
||||
EXPECT_TRUE(full.HasStream(Memory64ListStream));
|
||||
EXPECT_FALSE(mini.HasStream(Memory64ListStream));
|
||||
EXPECT_FALSE(full.HasStream(MemoryListStream));
|
||||
|
||||
// This is the only place we don't use OR because we want both not
|
||||
// to have the streams.
|
||||
EXPECT_FALSE(mini.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadExListStream));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamA));
|
||||
EXPECT_FALSE(mini.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(full.HasStream(CommentStreamW));
|
||||
EXPECT_FALSE(mini.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(full.HasStream(FunctionTableStream));
|
||||
EXPECT_FALSE(mini.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(MemoryInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(full.HasStream(ThreadInfoListStream));
|
||||
EXPECT_FALSE(mini.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(full.HasStream(HandleOperationListStream));
|
||||
EXPECT_FALSE(mini.HasStream(TokenStream));
|
||||
EXPECT_FALSE(full.HasStream(TokenStream));
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,263 @@
|
|||
// -*- 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>
|
||||
|
||||
// byte_cursor.h: Classes for parsing values from a buffer of bytes.
|
||||
// The ByteCursor class provides a convenient interface for reading
|
||||
// fixed-size integers of arbitrary endianness, being thorough about
|
||||
// checking for buffer overruns.
|
||||
|
||||
#ifndef COMMON_BYTE_CURSOR_H_
|
||||
#define COMMON_BYTE_CURSOR_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A buffer holding a series of bytes.
|
||||
struct ByteBuffer {
|
||||
ByteBuffer() : start(0), end(0) { }
|
||||
ByteBuffer(const uint8_t *set_start, size_t set_size)
|
||||
: start(set_start), end(set_start + set_size) { }
|
||||
~ByteBuffer() { };
|
||||
|
||||
// Equality operators. Useful in unit tests, and when we're using
|
||||
// ByteBuffers to refer to regions of a larger buffer.
|
||||
bool operator==(const ByteBuffer &that) const {
|
||||
return start == that.start && end == that.end;
|
||||
}
|
||||
bool operator!=(const ByteBuffer &that) const {
|
||||
return start != that.start || end != that.end;
|
||||
}
|
||||
|
||||
// Not C++ style guide compliant, but this definitely belongs here.
|
||||
size_t Size() const {
|
||||
assert(start <= end);
|
||||
return end - start;
|
||||
}
|
||||
|
||||
const uint8_t *start, *end;
|
||||
};
|
||||
|
||||
// A cursor pointing into a ByteBuffer that can parse numbers of various
|
||||
// widths and representations, strings, and data blocks, advancing through
|
||||
// the buffer as it goes. All ByteCursor operations check that accesses
|
||||
// haven't gone beyond the end of the enclosing ByteBuffer.
|
||||
class ByteCursor {
|
||||
public:
|
||||
// Create a cursor reading bytes from the start of BUFFER. By default, the
|
||||
// cursor reads multi-byte values in little-endian form.
|
||||
ByteCursor(const ByteBuffer *buffer, bool big_endian = false)
|
||||
: buffer_(buffer), here_(buffer->start),
|
||||
big_endian_(big_endian), complete_(true) { }
|
||||
|
||||
// Accessor and setter for this cursor's endianness flag.
|
||||
bool big_endian() const { return big_endian_; }
|
||||
void set_big_endian(bool big_endian) { big_endian_ = big_endian; }
|
||||
|
||||
// Accessor and setter for this cursor's current position. The setter
|
||||
// returns a reference to this cursor.
|
||||
const uint8_t *here() const { return here_; }
|
||||
ByteCursor &set_here(const uint8_t *here) {
|
||||
assert(buffer_->start <= here && here <= buffer_->end);
|
||||
here_ = here;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Return the number of bytes available to read at the cursor.
|
||||
size_t Available() const { return size_t(buffer_->end - here_); }
|
||||
|
||||
// Return true if this cursor is at the end of its buffer.
|
||||
bool AtEnd() const { return Available() == 0; }
|
||||
|
||||
// When used as a boolean value this cursor converts to true if all
|
||||
// prior reads have been completed, or false if we ran off the end
|
||||
// of the buffer.
|
||||
operator bool() const { return complete_; }
|
||||
|
||||
// Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true,
|
||||
// unsigned otherwise, using the cursor's established endianness, and set
|
||||
// *RESULT to the number. If we read off the end of our buffer, clear
|
||||
// this cursor's complete_ flag, and store a dummy value in *RESULT.
|
||||
// Return a reference to this cursor.
|
||||
template<typename T>
|
||||
ByteCursor &Read(size_t size, bool is_signed, T *result) {
|
||||
if (CheckAvailable(size)) {
|
||||
T v = 0;
|
||||
if (big_endian_) {
|
||||
for (size_t i = 0; i < size; i++)
|
||||
v = (v << 8) + here_[i];
|
||||
} else {
|
||||
// This loop condition looks weird, but size_t is unsigned, so
|
||||
// decrementing i after it is zero yields the largest size_t value.
|
||||
for (size_t i = size - 1; i < size; i--)
|
||||
v = (v << 8) + here_[i];
|
||||
}
|
||||
if (is_signed && size < sizeof(T)) {
|
||||
size_t sign_bit = (T)1 << (size * 8 - 1);
|
||||
v = (v ^ sign_bit) - sign_bit;
|
||||
}
|
||||
here_ += size;
|
||||
*result = v;
|
||||
} else {
|
||||
*result = (T) 0xdeadbeef;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read an integer, using the cursor's established endianness and
|
||||
// *RESULT's size and signedness, and set *RESULT to the number. If we
|
||||
// read off the end of our buffer, clear this cursor's complete_ flag.
|
||||
// Return a reference to this cursor.
|
||||
template<typename T>
|
||||
ByteCursor &operator>>(T &result) {
|
||||
bool T_is_signed = (T)-1 < 0;
|
||||
return Read(sizeof(T), T_is_signed, &result);
|
||||
}
|
||||
|
||||
// Copy the SIZE bytes at the cursor to BUFFER, and advance this
|
||||
// cursor to the end of them. If we read off the end of our buffer,
|
||||
// clear this cursor's complete_ flag, and set *POINTER to NULL.
|
||||
// Return a reference to this cursor.
|
||||
ByteCursor &Read(uint8_t *buffer, size_t size) {
|
||||
if (CheckAvailable(size)) {
|
||||
memcpy(buffer, here_, size);
|
||||
here_ += size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Set STR to a copy of the '\0'-terminated string at the cursor. If the
|
||||
// byte buffer does not contain a terminating zero, clear this cursor's
|
||||
// complete_ flag, and set STR to the empty string. Return a reference to
|
||||
// this cursor.
|
||||
ByteCursor &CString(std::string *str) {
|
||||
const uint8_t *end
|
||||
= static_cast<const uint8_t *>(memchr(here_, '\0', Available()));
|
||||
if (end) {
|
||||
str->assign(reinterpret_cast<const char *>(here_), end - here_);
|
||||
here_ = end + 1;
|
||||
} else {
|
||||
str->clear();
|
||||
here_ = buffer_->end;
|
||||
complete_ = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Like CString(STR), but extract the string from a fixed-width buffer
|
||||
// LIMIT bytes long, which may or may not contain a terminating '\0'
|
||||
// byte. Specifically:
|
||||
//
|
||||
// - If there are not LIMIT bytes available at the cursor, clear the
|
||||
// cursor's complete_ flag and set STR to the empty string.
|
||||
//
|
||||
// - Otherwise, if the LIMIT bytes at the cursor contain any '\0'
|
||||
// characters, set *STR to a copy of the bytes before the first '\0',
|
||||
// and advance the cursor by LIMIT bytes.
|
||||
//
|
||||
// - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the
|
||||
// cursor by LIMIT bytes.
|
||||
ByteCursor &CString(std::string *str, size_t limit) {
|
||||
if (CheckAvailable(limit)) {
|
||||
const uint8_t *end
|
||||
= static_cast<const uint8_t *>(memchr(here_, '\0', limit));
|
||||
if (end)
|
||||
str->assign(reinterpret_cast<const char *>(here_), end - here_);
|
||||
else
|
||||
str->assign(reinterpret_cast<const char *>(here_), limit);
|
||||
here_ += limit;
|
||||
} else {
|
||||
str->clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Set *POINTER to point to the SIZE bytes at the cursor, and advance
|
||||
// this cursor to the end of them. If SIZE is omitted, don't move the
|
||||
// cursor. If we read off the end of our buffer, clear this cursor's
|
||||
// complete_ flag, and set *POINTER to NULL. Return a reference to this
|
||||
// cursor.
|
||||
ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) {
|
||||
if (CheckAvailable(size)) {
|
||||
*pointer = here_;
|
||||
here_ += size;
|
||||
} else {
|
||||
*pointer = NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Skip SIZE bytes at the cursor. If doing so would advance us off
|
||||
// the end of our buffer, clear this cursor's complete_ flag, and
|
||||
// set *POINTER to NULL. Return a reference to this cursor.
|
||||
ByteCursor &Skip(size_t size) {
|
||||
if (CheckAvailable(size))
|
||||
here_ += size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// If there are at least SIZE bytes available to read from the buffer,
|
||||
// return true. Otherwise, set here_ to the end of the buffer, set
|
||||
// complete_ to false, and return false.
|
||||
bool CheckAvailable(size_t size) {
|
||||
if (Available() >= size) {
|
||||
return true;
|
||||
} else {
|
||||
here_ = buffer_->end;
|
||||
complete_ = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The buffer we're reading bytes from.
|
||||
const ByteBuffer *buffer_;
|
||||
|
||||
// The next byte within buffer_ that we'll read.
|
||||
const uint8_t *here_;
|
||||
|
||||
// True if we should read numbers in big-endian form; false if we
|
||||
// should read in little-endian form.
|
||||
bool big_endian_;
|
||||
|
||||
// True if we've been able to read all we've been asked to.
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_BYTE_CURSOR_H_
|
|
@ -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 "common/byte_cursor.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
using google_breakpad::ByteBuffer;
|
||||
using google_breakpad::ByteCursor;
|
||||
using std::string;
|
||||
|
||||
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));
|
|
@ -29,10 +29,10 @@
|
|||
#ifndef UTIL_DEBUGINFO_BYTEREADER_INL_H__
|
||||
#define UTIL_DEBUGINFO_BYTEREADER_INL_H__
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "common/dwarf/bytereader.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
inline uint8 ByteReader::ReadOneByte(const char* buffer) const {
|
||||
|
|
|
@ -43,10 +43,10 @@ using dwarf2reader::DwarfPointerEncoding;
|
|||
using dwarf2reader::ENDIANNESS_BIG;
|
||||
using dwarf2reader::ENDIANNESS_LITTLE;
|
||||
using google_breakpad::CFISection;
|
||||
using google_breakpad::TestAssembler::Label;
|
||||
using google_breakpad::TestAssembler::kBigEndian;
|
||||
using google_breakpad::TestAssembler::kLittleEndian;
|
||||
using google_breakpad::TestAssembler::Section;
|
||||
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 std::string;
|
||||
using testing::Test;
|
||||
|
||||
|
|
|
@ -32,11 +32,11 @@
|
|||
// cfi_assembler.cc: Implementation of google_breakpad::CFISection class.
|
||||
// See cfi_assembler.h for details.
|
||||
|
||||
#include <cassert>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/dwarf/cfi_assembler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using dwarf2reader::DwarfPointerEncoding;
|
||||
|
@ -52,18 +52,14 @@ CFISection &CFISection::CIEHeader(u_int64_t code_alignment_factor,
|
|||
in_fde_ = false;
|
||||
|
||||
if (dwarf64) {
|
||||
D32(0xffffffff);
|
||||
D32(kDwarf64InitialLengthMarker);
|
||||
D64(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
// Write the CIE distinguished value. In .debug_frame sections, it's
|
||||
// ~0; in .eh_frame sections, it's zero.
|
||||
D64(eh_frame_ ? 0 : ~(u_int64_t)0);
|
||||
D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier);
|
||||
} else {
|
||||
D32(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
// Write the CIE distinguished value. In .debug_frame sections, it's
|
||||
// ~0; in .eh_frame sections, it's zero.
|
||||
D32(eh_frame_ ? 0 : ~(u_int32_t)0);
|
||||
D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier);
|
||||
}
|
||||
D8(version);
|
||||
AppendCString(augmentation);
|
||||
|
@ -193,4 +189,10 @@ CFISection &CFISection::EncodedPointer(u_int64_t address,
|
|||
return *this;
|
||||
};
|
||||
|
||||
const u_int32_t CFISection::kDwarf64InitialLengthMarker;
|
||||
const u_int32_t CFISection::kDwarf32CIEIdentifier;
|
||||
const u_int64_t CFISection::kDwarf64CIEIdentifier;
|
||||
const u_int32_t CFISection::kEHFrame32CIEIdentifier;
|
||||
const u_int64_t CFISection::kEHFrame64CIEIdentifier;
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// cfi-assembler.h: Define CFISection, a class for creating properly
|
||||
// cfi_assembler.h: Define CFISection, a class for creating properly
|
||||
// (and improperly) formatted DWARF CFI data for unit tests.
|
||||
|
||||
#ifndef PROCESSOR_CFI_ASSEMBLER_H_
|
||||
|
@ -40,15 +40,15 @@
|
|||
#include <string>
|
||||
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/test_assembler.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
#include "processor/test_assembler.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using dwarf2reader::DwarfPointerEncoding;
|
||||
using google_breakpad::TestAssembler::Endianness;
|
||||
using google_breakpad::TestAssembler::Label;
|
||||
using google_breakpad::TestAssembler::Section;
|
||||
using google_breakpad::test_assembler::Endianness;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using std::string;
|
||||
|
||||
class CFISection: public Section {
|
||||
|
@ -219,6 +219,19 @@ class CFISection: public Section {
|
|||
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 u_int32_t kDwarf64InitialLengthMarker = 0xffffffffU;
|
||||
|
||||
// The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
|
||||
static const u_int32_t kDwarf32CIEIdentifier = ~(u_int32_t)0;
|
||||
static const u_int64_t kDwarf64CIEIdentifier = ~(u_int64_t)0;
|
||||
static const u_int32_t kEHFrame32CIEIdentifier = 0;
|
||||
static const u_int64_t kEHFrame64CIEIdentifier = 0;
|
||||
|
||||
// The size of a machine address for the data in this section.
|
||||
size_t address_size_;
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class.
|
||||
// See dwarf2diehandler.h for details.
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
DIEDispatcher::~DIEDispatcher() {
|
||||
|
|
|
@ -529,7 +529,7 @@ enum DwarfInline {
|
|||
DW_INL_not_inlined =0x0,
|
||||
DW_INL_inlined =0x1,
|
||||
DW_INL_declared_not_inlined =0x2,
|
||||
DW_INL_declared_inlined =0x3
|
||||
DW_INL_declared_inlined =0x3,
|
||||
};
|
||||
|
||||
// Call Frame Info instructions.
|
||||
|
@ -575,6 +575,37 @@ enum DwarfCFI
|
|||
DW_CFA_GNU_negative_offset_extended = 0x2f
|
||||
};
|
||||
|
||||
// Exception handling 'z' augmentation letters.
|
||||
enum DwarfZAugmentationCodes {
|
||||
// If the CFI augmentation string begins with 'z', then the CIE and FDE
|
||||
// have an augmentation data area just before the instructions, whose
|
||||
// contents are determined by the subsequent augmentation letters.
|
||||
DW_Z_augmentation_start = 'z',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding, and the FDE
|
||||
// augmentation data includes a language-specific data area pointer,
|
||||
// represented using that encoding.
|
||||
DW_Z_has_LSDA = 'L',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding, followed by a pointer
|
||||
// to a personality routine, represented using that encoding.
|
||||
DW_Z_has_personality_routine = 'P',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding describing how the FDE's
|
||||
// initial location, address range, and DW_CFA_set_loc operands are
|
||||
// encoded.
|
||||
DW_Z_has_FDE_address_encoding = 'R',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, then code
|
||||
// addresses covered by FDEs that cite this CIE are signal delivery
|
||||
// trampolines. Return addresses of frames in trampolines should not be
|
||||
// adjusted as described in section 6.4.4 of the DWARF 3 spec.
|
||||
DW_Z_is_signal_trampoline = 'S'
|
||||
};
|
||||
|
||||
// Exception handling frame description pointer formats, as described
|
||||
// by the Linux Standard Base Core Specification 4.0, section 11.5,
|
||||
// DWARF Extensions.
|
||||
|
|
|
@ -31,16 +31,18 @@
|
|||
// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit,
|
||||
// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/line_state_machine.h"
|
||||
|
||||
|
@ -919,7 +921,8 @@ class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule {
|
|||
return handler->UndefinedRule(address, reg);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const UndefinedRule *our_rhs = dynamic_cast<const UndefinedRule *>(&rhs);
|
||||
return (our_rhs != NULL);
|
||||
}
|
||||
|
@ -935,7 +938,8 @@ class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule {
|
|||
return handler->SameValueRule(address, reg);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const SameValueRule *our_rhs = dynamic_cast<const SameValueRule *>(&rhs);
|
||||
return (our_rhs != NULL);
|
||||
}
|
||||
|
@ -953,7 +957,8 @@ class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule {
|
|||
return handler->OffsetRule(address, reg, base_register_, offset_);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const OffsetRule *our_rhs = dynamic_cast<const OffsetRule *>(&rhs);
|
||||
return (our_rhs &&
|
||||
base_register_ == our_rhs->base_register_ &&
|
||||
|
@ -966,7 +971,7 @@ class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule {
|
|||
// computes the address at which a register is saved, not a value.
|
||||
private:
|
||||
int base_register_;
|
||||
int offset_;
|
||||
long offset_;
|
||||
};
|
||||
|
||||
// Rule: the value the register had in the caller is the value of
|
||||
|
@ -981,7 +986,8 @@ class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule {
|
|||
return handler->ValOffsetRule(address, reg, base_register_, offset_);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const ValOffsetRule *our_rhs = dynamic_cast<const ValOffsetRule *>(&rhs);
|
||||
return (our_rhs &&
|
||||
base_register_ == our_rhs->base_register_ &&
|
||||
|
@ -992,7 +998,7 @@ class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule {
|
|||
void SetOffset(long long offset) { offset_ = offset; }
|
||||
private:
|
||||
int base_register_;
|
||||
int offset_;
|
||||
long offset_;
|
||||
};
|
||||
|
||||
// Rule: the register has been saved in another register REGISTER_NUMBER_.
|
||||
|
@ -1005,7 +1011,8 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule {
|
|||
return handler->RegisterRule(address, reg, register_number_);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const RegisterRule *our_rhs = dynamic_cast<const RegisterRule *>(&rhs);
|
||||
return (our_rhs && register_number_ == our_rhs->register_number_);
|
||||
}
|
||||
|
@ -1024,7 +1031,8 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
|
|||
return handler->ExpressionRule(address, reg, expression_);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const ExpressionRule *our_rhs = dynamic_cast<const ExpressionRule *>(&rhs);
|
||||
return (our_rhs && expression_ == our_rhs->expression_);
|
||||
}
|
||||
|
@ -1043,7 +1051,8 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
|
|||
return handler->ValExpressionRule(address, reg, expression_);
|
||||
}
|
||||
bool operator==(const Rule &rhs) const {
|
||||
// dynamic_cast is prohibited by Google C++ Style Guide, but justified.
|
||||
// dynamic_cast is allowed by the Google C++ Style Guide, if the use has
|
||||
// been carefully considered; cheap RTTI-like workarounds are forbidden.
|
||||
const ValExpressionRule *our_rhs =
|
||||
dynamic_cast<const ValExpressionRule *>(&rhs);
|
||||
return (our_rhs && expression_ == our_rhs->expression_);
|
||||
|
@ -1870,7 +1879,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
|
||||
// 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 fo CFI data). For .eh_frame, we handle only
|
||||
// was never a version 2 of CFI data). For .eh_frame, we handle only
|
||||
// version 1.
|
||||
if (eh_frame_) {
|
||||
if (cie->version != 1) {
|
||||
|
@ -1878,7 +1887,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
if (cie->version < 1 || 3 < cie->version) {
|
||||
if (cie->version < 1 || cie->version > 3) {
|
||||
reporter_->UnrecognizedVersion(cie->offset, cie->version);
|
||||
return false;
|
||||
}
|
||||
|
@ -1893,18 +1902,18 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
// Skip the terminating '\0'.
|
||||
cursor++;
|
||||
|
||||
// Is this an augmentation we recognize?
|
||||
if (cie->augmentation.empty()) {
|
||||
; // Stock DWARF CFI.
|
||||
} else if (cie->augmentation[0] == 'z') {
|
||||
// Linux C++ ABI 'z' augmentation, used for exception handling data.
|
||||
cie->has_z_augmentation = true;
|
||||
} else {
|
||||
// Not an augmentation we recognize. Augmentations can have
|
||||
// arbitrary effects on the form of rest of the content, so we
|
||||
// have to give up.
|
||||
reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation);
|
||||
return false;
|
||||
// Is this CFI augmented?
|
||||
if (!cie->augmentation.empty()) {
|
||||
// Is it an augmentation we recognize?
|
||||
if (cie->augmentation[0] == DW_Z_augmentation_start) {
|
||||
// Linux C++ ABI 'z' augmentation, used for exception handling data.
|
||||
cie->has_z_augmentation = true;
|
||||
} else {
|
||||
// Not an augmentation we recognize. Augmentations can have arbitrary
|
||||
// effects on the form of rest of the content, so we have to give up.
|
||||
reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the code alignment factor.
|
||||
|
@ -1947,7 +1956,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
// augmentation data as the string directs.
|
||||
for (size_t i = 1; i < cie->augmentation.size(); i++) {
|
||||
switch (cie->augmentation[i]) {
|
||||
case 'L':
|
||||
case DW_Z_has_LSDA:
|
||||
// The CIE's augmentation data holds the language-specific data
|
||||
// area pointer's encoding, and the FDE's augmentation data holds
|
||||
// the pointer itself.
|
||||
|
@ -1965,7 +1974,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
// LSDA to use, since it appears in the FDE.
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
case DW_Z_has_personality_routine:
|
||||
// The CIE's augmentation data holds the personality routine
|
||||
// pointer's encoding, followed by the pointer itself.
|
||||
cie->has_z_personality = true;
|
||||
|
@ -1992,7 +2001,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
data += len;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
case DW_Z_has_FDE_address_encoding:
|
||||
// The CIE's augmentation data holds the pointer encoding to use
|
||||
// for addresses in the FDE.
|
||||
if (data >= data_end) return ReportIncomplete(cie);
|
||||
|
@ -2009,7 +2018,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
|||
}
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
case DW_Z_is_signal_trampoline:
|
||||
// Frames using this CIE are signal delivery frames.
|
||||
cie->has_z_signal_frame = true;
|
||||
break;
|
||||
|
@ -2295,7 +2304,8 @@ void CallFrameInfo::Reporter::UnusablePointerEncoding(uint64 offset,
|
|||
uint8 encoding) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI common information entry at offset 0x%llx in '%s':"
|
||||
" 'z' augmentation specifies a pointer encoding for which we have no base address: 0x%02x\n",
|
||||
" 'z' augmentation specifies a pointer encoding for which"
|
||||
" we have no base address: 0x%02x\n",
|
||||
filename_.c_str(), offset, section_.c_str(), encoding);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
|
||||
// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// The '.eh_frame' format, used by the Linux C++ ABI for exception
|
||||
|
@ -39,15 +40,15 @@
|
|||
// 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 an
|
||||
// ELF file containing a .debug_frame or .eh_frame section; you can then
|
||||
// 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 <cstdio>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#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;
|
||||
|
@ -63,10 +64,10 @@ extern "C" {
|
|||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
using google_breakpad::CFISection;
|
||||
using google_breakpad::TestAssembler::Label;
|
||||
using google_breakpad::TestAssembler::kBigEndian;
|
||||
using google_breakpad::TestAssembler::kLittleEndian;
|
||||
using google_breakpad::TestAssembler::Section;
|
||||
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;
|
||||
|
@ -2315,7 +2316,7 @@ TEST_F(CFIReporter, ClearingCFARule) {
|
|||
#ifdef WRITE_ELF
|
||||
// See comments at the top of the file mentioning WRITE_ELF for details.
|
||||
|
||||
using google_breakpad::TestAssembler::Section;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
|
||||
struct ELFSectionHeader {
|
||||
ELFSectionHeader(unsigned int set_type)
|
||||
|
|
|
@ -30,10 +30,13 @@
|
|||
// information from the debug info.
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "common/dwarf/functioninfo.h"
|
||||
|
||||
|
|
|
@ -36,12 +36,65 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include "common/linux/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::ostringstream;
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
|
||||
const char * const *strings,
|
||||
size_t size) {
|
||||
vector<string> names(strings, strings + size);
|
||||
return names;
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::I386() {
|
||||
static const char *const names[] = {
|
||||
"$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
|
||||
"$eip", "$eflags", "$unused1",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$unused2", "$unused3",
|
||||
"$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$fcw", "$fsw", "$mxcsr",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
|
||||
"$tr", "$ldtr"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
|
||||
static const char *const names[] = {
|
||||
"$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
|
||||
"$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
|
||||
"$rip",
|
||||
"$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$rflags",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
|
||||
"$fs.base", "$gs.base", "$unused3", "$unused4",
|
||||
"$tr", "$ldtr",
|
||||
"$mxcsr", "$fcw", "$fsw"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::ARM() {
|
||||
static const char *const names[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"fps", "cpsr"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
|
||||
uint8 version, const string &augmentation,
|
||||
unsigned return_address) {
|
|
@ -39,11 +39,12 @@
|
|||
#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H
|
||||
#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/linux/module.h"
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
@ -91,6 +92,26 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
|
|||
string file_, section_;
|
||||
};
|
||||
|
||||
// Register name tables. If TABLE is a vector returned by one of these
|
||||
// functions, then TABLE[R] is the name of the register numbered R in
|
||||
// DWARF call frame information.
|
||||
class RegisterNames {
|
||||
public:
|
||||
// Intel's "x86" or IA-32.
|
||||
static vector<string> I386();
|
||||
|
||||
// AMD x86_64, AMD64, Intel EM64T, or Intel 64
|
||||
static vector<string> X86_64();
|
||||
|
||||
// ARM.
|
||||
static vector<string> ARM();
|
||||
|
||||
private:
|
||||
// Given STRINGS, an array of C strings with SIZE elements, return an
|
||||
// equivalent vector<string>.
|
||||
static vector<string> MakeVector(const char * const *strings, size_t size);
|
||||
};
|
||||
|
||||
// Create a handler for the dwarf2reader::CallFrameInfo parser that
|
||||
// records the stack unwinding information it receives in MODULE.
|
||||
//
|
|
@ -32,7 +32,7 @@
|
|||
// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::DwarfCFIToModule;
|
||||
|
@ -258,3 +258,31 @@ TEST_F(Rule, DefaultReturnAddressRuleLater) {
|
|||
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]);
|
||||
}
|
|
@ -31,11 +31,13 @@
|
|||
|
||||
// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
#include "common/linux/dwarf_cu_to_module.h"
|
||||
#include "common/linux/dwarf_line_to_module.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
@ -441,7 +443,7 @@ dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
|
|||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void DwarfCUToModule::WarningReporter::CUHeading() {
|
||||
if (printed_cu_header_)
|
||||
|
@ -493,6 +495,8 @@ void DwarfCUToModule::WarningReporter::UncoveredHeading() {
|
|||
|
||||
void DwarfCUToModule::WarningReporter::UncoveredFunction(
|
||||
const Module::Function &function) {
|
||||
if (!uncovered_warnings_enabled_)
|
||||
return;
|
||||
UncoveredHeading();
|
||||
fprintf(stderr, " function%s: %s\n",
|
||||
function.size == 0 ? " (zero-length)" : "",
|
||||
|
@ -500,6 +504,8 @@ void DwarfCUToModule::WarningReporter::UncoveredFunction(
|
|||
}
|
||||
|
||||
void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) {
|
||||
if (!uncovered_warnings_enabled_)
|
||||
return;
|
||||
UncoveredHeading();
|
||||
fprintf(stderr, " line%s: %s:%d at 0x%llx\n",
|
||||
(line.size == 0 ? " (zero-length)" : ""),
|
||||
|
@ -615,6 +621,10 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
|||
= 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 "__"
|
||||
// instead of ".".
|
||||
if (map_entry == section_map.end())
|
||||
map_entry = section_map.find("__debug_line");
|
||||
if (map_entry == section_map.end()) {
|
||||
cu_context_->reporter->MissingSection(".debug_line");
|
||||
return;
|
|
@ -41,10 +41,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include "common/linux/language.h"
|
||||
#include "common/linux/module.h"
|
||||
#include "common/language.h"
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
@ -120,12 +118,24 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
// compilation unit at OFFSET.
|
||||
WarningReporter(const string &filename, uint64 cu_offset)
|
||||
: filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false),
|
||||
printed_unpaired_header_(false) { }
|
||||
printed_unpaired_header_(false),
|
||||
uncovered_warnings_enabled_(false) { }
|
||||
virtual ~WarningReporter() { }
|
||||
|
||||
// Set the name of the compilation unit we're processing to NAME.
|
||||
virtual void SetCUName(const string &name) { cu_name_ = name; }
|
||||
|
||||
// Accessor and setter for uncovered_warnings_enabled_.
|
||||
// UncoveredFunction and UncoveredLine only report a problem if that is
|
||||
// true. By default, these warnings are disabled, because those
|
||||
// conditions occur occasionally in healthy code.
|
||||
virtual bool uncovered_warnings_enabled() const {
|
||||
return uncovered_warnings_enabled_;
|
||||
}
|
||||
virtual void set_uncovered_warnings_enabled(bool value) {
|
||||
uncovered_warnings_enabled_ = value;
|
||||
}
|
||||
|
||||
// A DW_AT_specification in the DIE at OFFSET refers to a DIE we
|
||||
// haven't processed yet, or that wasn't marked as a declaration,
|
||||
// at TARGET.
|
||||
|
@ -154,6 +164,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
|||
string cu_name_;
|
||||
bool printed_cu_header_;
|
||||
bool printed_unpaired_header_;
|
||||
bool uncovered_warnings_enabled_;
|
||||
|
||||
private:
|
||||
// Print a per-CU heading, once.
|
|
@ -34,7 +34,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
|
@ -828,7 +828,7 @@ struct Situation {
|
|||
uncovered_functions, uncovered_lines },
|
||||
|
||||
Situation situations[] = {
|
||||
#include "common/linux/testdata/func-line-pairing.h"
|
||||
#include "common/testdata/func-line-pairing.h"
|
||||
};
|
||||
|
||||
#undef PAIRING
|
||||
|
@ -1633,5 +1633,69 @@ TEST_F(Errors, BadCURootDIETag) {
|
|||
no_attrs));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
reporter.SetCUName("compilation-unit-name");
|
||||
|
||||
function.name = "function name";
|
||||
function.address = 0x19c45c30770c1eb0ULL;
|
||||
function.size = 0x89808a5bdfa0a6a3ULL;
|
||||
function.parameter_size = 0x6a329f18683dcd51ULL;
|
||||
|
||||
file.name = "source file name";
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
// Would be nice to also test:
|
||||
// - overlapping lines, functions
|
|
@ -32,7 +32,7 @@
|
|||
// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class.
|
||||
// See dwarf_line_to_module.h for details.
|
||||
|
||||
#include "common/linux/dwarf_line_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
// Trying to support Windows paths in a reasonable way adds a lot of
|
||||
// variations to test; it would be better to just put off dealing with
|
|
@ -38,7 +38,7 @@
|
|||
#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H
|
||||
#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H
|
||||
|
||||
#include "common/linux/module.h"
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
||||
namespace google_breakpad {
|
|
@ -32,7 +32,7 @@
|
|||
// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule.
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/dwarf_line_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::Module;
|
|
@ -32,7 +32,7 @@
|
|||
// language.cc: Subclasses and singletons for google_breakpad::Language.
|
||||
// See language.h for details.
|
||||
|
||||
#include "common/linux/language.h"
|
||||
#include "common/language.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
|
@ -32,39 +32,40 @@
|
|||
// dump_symbols.cc: implement google_breakpad::WriteSymbolFile:
|
||||
// Find all the debugging info in a file and dump it as a Breakpad symbol file.
|
||||
|
||||
#include "common/linux/dump_symbols.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <link.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/linux/dump_stabs.h"
|
||||
#include "common/linux/dump_symbols.h"
|
||||
#include "common/linux/dwarf_cfi_to_module.h"
|
||||
#include "common/linux/dwarf_cu_to_module.h"
|
||||
#include "common/linux/dwarf_line_to_module.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/linux/module.h"
|
||||
#include "common/linux/stabs_reader.h"
|
||||
#include "common/module.h"
|
||||
#include "common/stabs_reader.h"
|
||||
#include "common/stabs_to_module.h"
|
||||
|
||||
// This namespace contains helper functions.
|
||||
namespace {
|
||||
|
||||
using google_breakpad::DumpStabsHandler;
|
||||
using google_breakpad::DwarfCFIToModule;
|
||||
using google_breakpad::DwarfCUToModule;
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::StabsToModule;
|
||||
|
||||
// Fix offset into virtual address by adding the mapped base into offsets.
|
||||
// Make life easier when want to find something by offset.
|
||||
|
@ -123,17 +124,32 @@ static const ElfW(Shdr) *FindSectionByName(const char *name,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static bool LoadStabs(const ElfW(Shdr) *stab_section,
|
||||
static bool LoadStabs(const ElfW(Ehdr) *elf_header,
|
||||
const ElfW(Shdr) *stab_section,
|
||||
const ElfW(Shdr) *stabstr_section,
|
||||
Module *module) {
|
||||
// Figure out what endianness this file is.
|
||||
bool big_endian;
|
||||
if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB)
|
||||
big_endian = false;
|
||||
else if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
big_endian = true;
|
||||
else {
|
||||
fprintf(stderr, "bad data encoding in ELF header: %d\n",
|
||||
elf_header->e_ident[EI_DATA]);
|
||||
return false;
|
||||
}
|
||||
// A callback object to handle data from the STABS reader.
|
||||
DumpStabsHandler handler(module);
|
||||
StabsToModule handler(module);
|
||||
// Find the addresses of the STABS data, and create a STABS reader object.
|
||||
// On Linux, STABS entries always have 32-bit values, regardless of the
|
||||
// address size of the architecture whose code they're describing, and
|
||||
// the strings are always "unitized".
|
||||
uint8_t *stabs = reinterpret_cast<uint8_t *>(stab_section->sh_offset);
|
||||
uint8_t *stabstr = reinterpret_cast<uint8_t *>(stabstr_section->sh_offset);
|
||||
google_breakpad::StabsReader reader(stabs, stab_section->sh_size,
|
||||
stabstr, stabstr_section->sh_size,
|
||||
&handler);
|
||||
big_endian, 4, true, &handler);
|
||||
// Read the STABS data, and do post-processing.
|
||||
if (!reader.Process())
|
||||
return false;
|
||||
|
@ -169,8 +185,8 @@ static bool LoadDwarf(const string &dwarf_filename,
|
|||
else if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB)
|
||||
endianness = dwarf2reader::ENDIANNESS_BIG;
|
||||
else {
|
||||
fprintf(stderr, "bad data encoding in ELF header: %d\n",
|
||||
elf_header->e_ident[EI_DATA]);
|
||||
fprintf(stderr, "%s: bad data encoding in ELF header: %d\n",
|
||||
dwarf_filename.c_str(), elf_header->e_ident[EI_DATA]);
|
||||
return false;
|
||||
}
|
||||
dwarf2reader::ByteReader byte_reader(endianness);
|
||||
|
@ -224,58 +240,20 @@ static bool LoadDwarf(const string &dwarf_filename,
|
|||
// success, or false if we don't recognize HEADER's machine
|
||||
// architecture.
|
||||
static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
|
||||
vector<string> *register_names)
|
||||
{
|
||||
static const char *const i386_names[] = {
|
||||
"$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
|
||||
"$eip", "$eflags", "$unused1",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$unused2", "$unused3",
|
||||
"$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$fcw", "$fsw", "$mxcsr",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
|
||||
"$tr", "$ldtr",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const x86_64_names[] = {
|
||||
"$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
|
||||
"$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
|
||||
"$rip",
|
||||
"$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$rflags",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
|
||||
"$fs.base", "$gs.base", "$unused3", "$unused4",
|
||||
"$tr", "$ldtr",
|
||||
"$mxcsr", "$fcw", "$fsw",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *const arm_names[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"fps", "cpsr",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char * const *name_table;
|
||||
vector<string> *register_names) {
|
||||
switch (elf_header->e_machine) {
|
||||
case EM_386: name_table = i386_names; break;
|
||||
case EM_ARM: name_table = arm_names; break;
|
||||
case EM_X86_64: name_table = x86_64_names; break;
|
||||
case EM_386:
|
||||
*register_names = DwarfCFIToModule::RegisterNames::I386();
|
||||
return true;
|
||||
case EM_ARM:
|
||||
*register_names = DwarfCFIToModule::RegisterNames::ARM();
|
||||
return true;
|
||||
case EM_X86_64:
|
||||
*register_names = DwarfCFIToModule::RegisterNames::X86_64();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
register_names->clear();
|
||||
for (int i = 0; name_table[i]; i++)
|
||||
register_names->push_back(name_table[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadDwarfCFI(const string &dwarf_filename,
|
||||
|
@ -334,7 +312,7 @@ static bool LoadDwarfCFI(const string &dwarf_filename,
|
|||
if (got_section)
|
||||
byte_reader.SetDataBase(got_section->sh_addr);
|
||||
if (text_section)
|
||||
byte_reader.SetTextBase(got_section->sh_addr);
|
||||
byte_reader.SetTextBase(text_section->sh_addr);
|
||||
|
||||
dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
|
||||
section_name);
|
||||
|
@ -367,9 +345,9 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
|
|||
const ElfW(Shdr) *stabstr_section = stab_section->sh_link + sections;
|
||||
if (stabstr_section) {
|
||||
found_debug_info_section = true;
|
||||
if (!LoadStabs(stab_section, stabstr_section, module))
|
||||
fprintf(stderr, "\".stab\" section found, but failed to load STABS"
|
||||
" debugging information\n");
|
||||
if (!LoadStabs(elf_header, stab_section, stabstr_section, module))
|
||||
fprintf(stderr, "%s: \".stab\" section found, but failed to load STABS"
|
||||
" debugging information\n", obj_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,8 +358,8 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
|
|||
if (dwarf_section) {
|
||||
found_debug_info_section = true;
|
||||
if (!LoadDwarf(obj_file, elf_header, module))
|
||||
fprintf(stderr, "\".debug_info\" section found, but failed to load "
|
||||
"DWARF debugging information\n");
|
||||
fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
|
||||
"DWARF debugging information\n", obj_file.c_str());
|
||||
}
|
||||
|
||||
// Dwarf Call Frame Information (CFI) is actually independent from
|
||||
|
@ -416,8 +394,9 @@ static bool LoadSymbols(const std::string &obj_file, ElfW(Ehdr) *elf_header,
|
|||
}
|
||||
|
||||
if (!found_debug_info_section) {
|
||||
fprintf(stderr, "file contains no debugging information"
|
||||
" (no \".stab\" or \".debug_info\" sections)\n");
|
||||
fprintf(stderr, "%s: file contains no debugging information"
|
||||
" (no \".stab\" or \".debug_info\" sections)\n",
|
||||
obj_file.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -558,14 +537,15 @@ bool WriteSymbolFile(const std::string &obj_file, FILE *sym_file) {
|
|||
unsigned char identifier[16];
|
||||
google_breakpad::FileID file_id(obj_file.c_str());
|
||||
if (!file_id.ElfFileIdentifier(identifier)) {
|
||||
fprintf(stderr, "Unable to generate file identifier\n");
|
||||
fprintf(stderr, "%s: unable to generate file identifier\n",
|
||||
obj_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *architecture = ElfArchitecture(elf_header);
|
||||
if (!architecture) {
|
||||
fprintf(stderr, "Unrecognized ELF machine architecture: %d\n",
|
||||
elf_header->e_machine);
|
||||
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
|
||||
obj_file.c_str(), elf_header->e_machine);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,9 @@
|
|||
#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__
|
||||
#define COMMON_LINUX_DUMP_SYMBOLS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
|
|
@ -33,21 +33,22 @@
|
|||
//
|
||||
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/linux_syscall_support.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <link.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
|
|
@ -30,12 +30,15 @@
|
|||
|
||||
#include "common/linux/google_crashdump_uploader.h"
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
#include "third_party/linux/include/glog/logging.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
GoogleCrashdumpUploader::GoogleCrashdumpUploader(const std::string& product,
|
||||
|
@ -115,21 +118,21 @@ void GoogleCrashdumpUploader::Init(const std::string& product,
|
|||
proxy_host_ = proxy_host;
|
||||
proxy_userpassword_ = proxy_userpassword;
|
||||
minidump_pathname_ = minidump_pathname;
|
||||
LOG(INFO) << "Uploader initializing";
|
||||
LOG(INFO) << "\tProduct: " << product_;
|
||||
LOG(INFO) << "\tVersion: " << version_;
|
||||
LOG(INFO) << "\tGUID: " << guid_;
|
||||
std::cout << "Uploader initializing";
|
||||
std::cout << "\tProduct: " << product_;
|
||||
std::cout << "\tVersion: " << version_;
|
||||
std::cout << "\tGUID: " << guid_;
|
||||
if (!ptime_.empty()) {
|
||||
LOG(INFO) << "\tProcess uptime: " << ptime_;
|
||||
std::cout << "\tProcess uptime: " << ptime_;
|
||||
}
|
||||
if (!ctime_.empty()) {
|
||||
LOG(INFO) << "\tCumulative Process uptime: " << ctime_;
|
||||
std::cout << "\tCumulative Process uptime: " << ctime_;
|
||||
}
|
||||
if (!email_.empty()) {
|
||||
LOG(INFO) << "\tEmail: " << email_;
|
||||
std::cout << "\tEmail: " << email_;
|
||||
}
|
||||
if (!comments_.empty()) {
|
||||
LOG(INFO) << "\tComments: " << comments_;
|
||||
std::cout << "\tComments: " << comments_;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +155,7 @@ bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() {
|
|||
}
|
||||
|
||||
if (!error_text.empty()) {
|
||||
LOG(ERROR) << error_text;
|
||||
std::cout << error_text;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -162,7 +165,7 @@ bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() {
|
|||
bool GoogleCrashdumpUploader::Upload() {
|
||||
bool ok = http_layer_->Init();
|
||||
if (!ok) {
|
||||
LOG(WARNING) << "http layer init failed";
|
||||
std::cout << "http layer init failed";
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -173,7 +176,7 @@ bool GoogleCrashdumpUploader::Upload() {
|
|||
struct stat st;
|
||||
int err = stat(minidump_pathname_.c_str(), &st);
|
||||
if (err) {
|
||||
LOG(WARNING) << minidump_pathname_ << " could not be found: " << errno;
|
||||
std::cout << minidump_pathname_ << " could not be found";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -188,7 +191,7 @@ bool GoogleCrashdumpUploader::Upload() {
|
|||
"upload_file_minidump")) {
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Sending request to " << crash_server_;
|
||||
std::cout << "Sending request to " << crash_server_;
|
||||
return http_layer_->SendRequest(crash_server_,
|
||||
parameters_,
|
||||
NULL);
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
// (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 <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/linux/guid_creator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//
|
||||
// GUIDGenerator
|
||||
//
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
// (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 "common/linux/http_upload.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
#include <curl/types.h>
|
||||
|
||||
#include "common/linux/http_upload.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Callback to get the response data from server.
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
#include <curl/types.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
#include "third_party/linux/include/glog/logging.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace google_breakpad {
|
||||
LibcurlWrapper::LibcurlWrapper()
|
||||
|
@ -51,10 +53,10 @@ LibcurlWrapper::LibcurlWrapper()
|
|||
curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib_) {
|
||||
LOG(WARNING) << "Could not find libcurl via dlopen";
|
||||
std::cout << "Could not find libcurl via dlopen";
|
||||
return;
|
||||
}
|
||||
LOG(INFO) << "LibcurlWrapper init succeeded";
|
||||
std::cout << "LibcurlWrapper init succeeded";
|
||||
init_ok_ = true;
|
||||
return;
|
||||
}
|
||||
|
@ -68,16 +70,16 @@ bool LibcurlWrapper::SetProxy(const std::string& proxy_host,
|
|||
if (!proxy_host.empty()) {
|
||||
(*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str());
|
||||
} else {
|
||||
LOG(WARNING) << "SetProxy called with empty proxy host.";
|
||||
std::cout << "SetProxy called with empty proxy host.";
|
||||
return false;
|
||||
}
|
||||
if (!proxy_userpwd.empty()) {
|
||||
(*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str());
|
||||
} else {
|
||||
LOG(WARNING) << "SetProxy called with empty proxy username/password.";
|
||||
std::cout << "SetProxy called with empty proxy username/password.";
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Set proxy host to " << proxy_host;
|
||||
std::cout << "Set proxy host to " << proxy_host;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -86,7 +88,7 @@ bool LibcurlWrapper::AddFile(const std::string& upload_file_path,
|
|||
if (!init_ok_) {
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Adding " << upload_file_path << " to form upload.";
|
||||
std::cout << "Adding " << upload_file_path << " to form upload.";
|
||||
// Add form file.
|
||||
(*formadd_)(&formpost_, &lastptr_,
|
||||
CURLFORM_COPYNAME, basename.c_str(),
|
||||
|
@ -128,7 +130,9 @@ bool LibcurlWrapper::SendRequest(const std::string& url,
|
|||
|
||||
CURLcode err_code = CURLE_OK;
|
||||
err_code = (*easy_perform_)(curl_);
|
||||
*(void**) (&easy_strerror_) = dlsym(curl_lib_, "curl_easy_strerror");
|
||||
easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)>
|
||||
(dlsym(curl_lib_, "curl_easy_strerror"));
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (err_code != CURLE_OK)
|
||||
fprintf(stderr, "Failed to send http request to %s, error: %s\n",
|
||||
|
@ -149,12 +153,12 @@ bool LibcurlWrapper::SendRequest(const std::string& url,
|
|||
|
||||
bool LibcurlWrapper::Init() {
|
||||
if (!init_ok_) {
|
||||
LOG(WARNING) << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages";
|
||||
std::cout << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetFunctionPointers()) {
|
||||
LOG(WARNING) << "Could not find function pointers";
|
||||
std::cout << "Could not find function pointers";
|
||||
init_ok_ = false;
|
||||
return false;
|
||||
}
|
||||
|
@ -165,7 +169,7 @@ bool LibcurlWrapper::Init() {
|
|||
|
||||
if (!curl_) {
|
||||
dlclose(curl_lib_);
|
||||
LOG(WARNING) << "Curl initialization failed";
|
||||
std::cout << "Curl initialization failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -177,10 +181,10 @@ bool LibcurlWrapper::Init() {
|
|||
return true;
|
||||
}
|
||||
|
||||
#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name) \
|
||||
*(void**) (&var) = dlsym(curl_lib_, function_name); \
|
||||
#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \
|
||||
var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \
|
||||
if (!var) { \
|
||||
LOG(WARNING) << "Could not find libcurl function " << function_name; \
|
||||
std::cout << "Could not find libcurl function " << function_name; \
|
||||
init_ok_ = false; \
|
||||
return false; \
|
||||
}
|
||||
|
@ -188,21 +192,34 @@ bool LibcurlWrapper::Init() {
|
|||
bool LibcurlWrapper::SetFunctionPointers() {
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_init_,
|
||||
"curl_easy_init");
|
||||
"curl_easy_init",
|
||||
CURL*(*)());
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_,
|
||||
"curl_easy_setopt");
|
||||
SET_AND_CHECK_FUNCTION_POINTER(formadd_,
|
||||
"curl_formadd");
|
||||
SET_AND_CHECK_FUNCTION_POINTER(slist_append_,
|
||||
"curl_slist_append");
|
||||
"curl_easy_setopt",
|
||||
CURLcode(*)(CURL*, CURLoption, ...));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd",
|
||||
CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append",
|
||||
curl_slist*(*)(curl_slist*, const char*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_perform_,
|
||||
"curl_easy_perform");
|
||||
"curl_easy_perform",
|
||||
CURLcode(*)(CURL*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_,
|
||||
"curl_easy_cleanup");
|
||||
"curl_easy_cleanup",
|
||||
void(*)(CURL*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_,
|
||||
"curl_slist_free_all");
|
||||
"curl_slist_free_all",
|
||||
void(*)(curl_slist*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(formfree_,
|
||||
"curl_formfree");
|
||||
"curl_formfree",
|
||||
void(*)(curl_httppost*));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,10 @@
|
|||
// A wrapper for libcurl to do HTTP Uploads, to support easy mocking
|
||||
// and unit testing of the HTTPUpload class.
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
class LibcurlWrapper {
|
||||
|
|
|
@ -2214,6 +2214,8 @@ struct kernel_statfs {
|
|||
#endif
|
||||
LSS_INLINE _syscall1(pid_t, getsid, pid_t, p)
|
||||
LSS_INLINE _syscall0(pid_t, _gettid)
|
||||
LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t,
|
||||
void*, tz)
|
||||
LSS_INLINE _syscall5(int, setxattr, const char *,p,
|
||||
const char *, n, const void *,v,
|
||||
size_t, s, int, f)
|
||||
|
|
|
@ -1,685 +0,0 @@
|
|||
// 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 <a.out.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <stab.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/stabs_reader.h"
|
||||
|
||||
using std::istream;
|
||||
using std::istringstream;
|
||||
using std::map;
|
||||
using std::ostream;
|
||||
using std::ostringstream;
|
||||
using std::string;
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Eq;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Return;
|
||||
using ::testing::Sequence;
|
||||
using ::testing::StrEq;
|
||||
|
||||
using google_breakpad::StabsHandler;
|
||||
using google_breakpad::StabsReader;
|
||||
|
||||
namespace {
|
||||
|
||||
// Mock stabs file parser
|
||||
//
|
||||
// In order to test StabsReader, we parse a human-readable input file
|
||||
// describing STABS entries into in-memory .stab and .stabstr
|
||||
// sections, and then pass those to StabsReader to look at. The
|
||||
// human-readable file is called a "mock stabs file".
|
||||
//
|
||||
// Except for compilation unit boundary lines (described below), each
|
||||
// line of a mock stabs file should have the following form:
|
||||
//
|
||||
// TYPE OTHER DESC VALUE NAME
|
||||
//
|
||||
// where all data is Latin-1 bytes and fields are separated by single
|
||||
// space characters, except for NAME, which may contain spaces and
|
||||
// continues to the end of the line. The fields have the following
|
||||
// meanings:
|
||||
//
|
||||
// - TYPE: the name of the stabs symbol type; like SO or FUN. These are
|
||||
// the names from /usr/include/bits/stab.def, without the leading N_.
|
||||
//
|
||||
// - OTHER, DESC, VALUE: numeric values for the n_other, n_desc, and
|
||||
// n_value fields of the stab. These can be decimal or hex,
|
||||
// using C++ notation (10, 0x10)
|
||||
//
|
||||
// - NAME: textual data for the entry. STABS packs all kinds of
|
||||
// interesting data into entries' NAME fields, so calling it a NAME
|
||||
// is misleading, but that's how it is. For SO, this may be a
|
||||
// filename; for FUN, this is the function name, plus type data; and
|
||||
// so on.
|
||||
//
|
||||
// A compilation unit boundary line has the form:
|
||||
//
|
||||
// cu-boundary FILENAME
|
||||
|
||||
// I don't know if the whole parser/handler pattern is really worth
|
||||
// the bureaucracy in this case. But just writing it out as
|
||||
// old-fashioned functions wasn't astonishingly clear either, so it
|
||||
// seemed worth a try.
|
||||
|
||||
// A handler class for mock stabs data.
|
||||
class MockStabsHandler {
|
||||
public:
|
||||
MockStabsHandler() { }
|
||||
virtual ~MockStabsHandler() { }
|
||||
// The mock stabs parser calls this member function for each entry
|
||||
// it parses, passing it the contents of the entry. If this function
|
||||
// returns true, the parser continues; if it returns false, the parser
|
||||
// stops, and its Process member function returns false.
|
||||
virtual bool Entry(enum __stab_debug_code type, char other, short desc,
|
||||
unsigned long value, const string &name) { return true; }
|
||||
// Report a compilation unit boundary whose filename is FILENAME. As
|
||||
// for the Entry function, this should return true to continue
|
||||
// parsing, or false to stop processing.
|
||||
virtual bool CUBoundary(const string &filename) { return true; }
|
||||
|
||||
// Report an error in parsing the mock stabs data. If this returns true,
|
||||
// the parser continues; if it returns false, the parser stops and
|
||||
// its Process member function returns false.
|
||||
virtual bool Error(const char *format, ...) = 0;
|
||||
};
|
||||
|
||||
// A class for parsing mock stabs files.
|
||||
class MockStabsParser {
|
||||
public:
|
||||
// Create a parser reading input from STREAM and passing data to HANDLER.
|
||||
// Use FILENAME when reporting errors.
|
||||
MockStabsParser(const string &filename, istream *stream,
|
||||
MockStabsHandler *handler);
|
||||
// Parse data from the STREAM, invoking HANDLER->Entry for each
|
||||
// entry we get. Return true if we parsed all the data succesfully,
|
||||
// or false if we stopped early because Entry returned false, or if
|
||||
// there were any errors during parsing.
|
||||
bool Process();
|
||||
private:
|
||||
// A type for maps from stab type names ("SO", "SLINE", etc.) to
|
||||
// n_type values.
|
||||
typedef map<string, unsigned char> StabTypeNameTable;
|
||||
|
||||
// Initialize the table mapping STAB type names to n_type values.
|
||||
void InitializeTypeNames();
|
||||
|
||||
// Parse LINE, one line of input from a mock stabs file, and pass
|
||||
// its contents to handler_->Entry and return the boolean value that
|
||||
// returns. If we encounter an error parsing the line, report it
|
||||
// using handler->Error.
|
||||
bool ParseLine(const string &line);
|
||||
|
||||
const string &filename_;
|
||||
istream *stream_;
|
||||
MockStabsHandler *handler_;
|
||||
int line_number_;
|
||||
StabTypeNameTable type_names_;
|
||||
};
|
||||
|
||||
MockStabsParser::MockStabsParser(const string &filename, istream *stream,
|
||||
MockStabsHandler *handler):
|
||||
filename_(filename), stream_(stream), handler_(handler),
|
||||
line_number_(0) {
|
||||
InitializeTypeNames();
|
||||
}
|
||||
|
||||
bool MockStabsParser::Process() {
|
||||
// Iterate once per line, including a line at EOF without a
|
||||
// terminating newline.
|
||||
for(;;) {
|
||||
string line;
|
||||
getline(*stream_, line, '\n');
|
||||
if (line.empty() && stream_->eof())
|
||||
break;
|
||||
line_number_++;
|
||||
if (! ParseLine(line))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MockStabsParser::InitializeTypeNames() {
|
||||
// On GLIBC-based systems, <bits/stab.def> is a file containing a
|
||||
// call to an unspecified macro __define_stab for each stab type.
|
||||
// <stab.h> uses it to define the __stab_debug_code enum type. We
|
||||
// use it here to initialize our mapping from type names to enum
|
||||
// values.
|
||||
//
|
||||
// This isn't portable to non-GLIBC systems. Feel free to just
|
||||
// hard-code the values if this becomes a problem.
|
||||
# define __define_stab(name, code, str) type_names_[string(str)] = code;
|
||||
# include <bits/stab.def>
|
||||
# undef __define_stab
|
||||
}
|
||||
|
||||
bool MockStabsParser::ParseLine(const string &line) {
|
||||
istringstream linestream(line);
|
||||
// Allow "0x" prefix for hex, and so on.
|
||||
linestream.unsetf(istringstream::basefield);
|
||||
// Parse and validate the stabs type.
|
||||
string typeName;
|
||||
linestream >> typeName;
|
||||
if (typeName == "cu-boundary") {
|
||||
if (linestream.peek() == ' ')
|
||||
linestream.get();
|
||||
string filename;
|
||||
getline(linestream, filename, '\n');
|
||||
return handler_->CUBoundary(filename);
|
||||
} else {
|
||||
StabTypeNameTable::const_iterator typeIt = type_names_.find(typeName);
|
||||
if (typeIt == type_names_.end())
|
||||
return handler_->Error("%s:%d: unrecognized stab type: %s\n",
|
||||
filename_.c_str(), line_number_, typeName.c_str());
|
||||
// These are int, not char and unsigned char, to ensure they're parsed
|
||||
// as decimal numbers, not characters.
|
||||
int otherInt, descInt;
|
||||
unsigned long value;
|
||||
linestream >> otherInt >> descInt >> value;
|
||||
if (linestream.fail())
|
||||
return handler_->Error("%s:%d: malformed mock stabs input line\n",
|
||||
filename_.c_str(), line_number_);
|
||||
if (linestream.peek() == ' ')
|
||||
linestream.get();
|
||||
string name;
|
||||
getline(linestream, name, '\n');
|
||||
return handler_->Entry(static_cast<__stab_debug_code>(typeIt->second),
|
||||
otherInt, descInt, value, name);
|
||||
}
|
||||
}
|
||||
|
||||
// A class for constructing .stab sections.
|
||||
//
|
||||
// A .stab section is an array of struct nlist entries. These
|
||||
// entries' n_un.n_strx fields are indices into an accompanying
|
||||
// .stabstr section.
|
||||
class StabSection {
|
||||
public:
|
||||
StabSection(): used_(0), size_(1) {
|
||||
entries_ = (struct nlist *) malloc(sizeof(*entries_) * size_);
|
||||
}
|
||||
~StabSection() { free(entries_); }
|
||||
|
||||
// Append a new 'struct nlist' entry to the end of the section, and
|
||||
// return a pointer to it. This pointer is valid until the next
|
||||
// call to Append. The caller should initialize the returned entry
|
||||
// as needed.
|
||||
struct nlist *Append();
|
||||
// Set the first entry's n_desc field to COUNT, and set its n_value field
|
||||
// to STRING_SIZE.
|
||||
void SetHeader(short count, unsigned long string_size);
|
||||
// Set SECTION to the contents of a .stab section holding the
|
||||
// accumulated list of entries added with Append.
|
||||
void GetSection(string *section);
|
||||
// Clear the array, and prepare this StabSection to accumulate a fresh
|
||||
// set of entries.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
// The array of stabs entries,
|
||||
struct nlist *entries_;
|
||||
// The number of elements of entries_ that are used, and the allocated size
|
||||
// of the array.
|
||||
size_t used_, size_;
|
||||
};
|
||||
|
||||
struct nlist *StabSection::Append() {
|
||||
if (used_ == size_) {
|
||||
size_ *= 2;
|
||||
entries_ = (struct nlist *) realloc(entries_, sizeof(*entries_) * size_);
|
||||
}
|
||||
assert(used_ < size_);
|
||||
return &entries_[used_++];
|
||||
}
|
||||
|
||||
void StabSection::SetHeader(short count, unsigned long string_size) {
|
||||
assert(used_ >= 1);
|
||||
entries_[0].n_desc = count;
|
||||
entries_[0].n_value = string_size;
|
||||
}
|
||||
|
||||
void StabSection::GetSection(string *section) {
|
||||
section->assign(reinterpret_cast<char *>(entries_),
|
||||
sizeof(*entries_) * used_);
|
||||
}
|
||||
|
||||
void StabSection::Clear() {
|
||||
used_ = 0;
|
||||
size_ = 1;
|
||||
entries_ = (struct nlist *) realloc(entries_, sizeof(*entries_) * size_);
|
||||
}
|
||||
|
||||
// A class for building .stabstr sections.
|
||||
//
|
||||
// A .stabstr section is an array of characters containing a bunch of
|
||||
// null-terminated strings. A string is identified by the index of
|
||||
// its initial character in the array. The array always starts with a
|
||||
// null byte, so that an index of zero refers to the empty string.
|
||||
//
|
||||
// This implementation also ensures that if two strings are equal, we
|
||||
// assign them the same indices; most linkers do this, and some
|
||||
// clients may rely upon it. (Note that this is not quite the same as
|
||||
// ensuring that a string only appears once in the section; you could
|
||||
// share space when one string is a suffix of another, but we don't.)
|
||||
class StabstrSection {
|
||||
public:
|
||||
StabstrSection(): next_byte_(1) { string_indices_[""] = 0; }
|
||||
// Ensure STR is present in the string section, and return its index.
|
||||
size_t Insert(const string &str);
|
||||
// Set SECTION to the contents of a .stabstr section in which the
|
||||
// strings passed to Insert appear at the indices we promised.
|
||||
void GetSection(string *section);
|
||||
// Clear the contents of this StabstrSection, and prepare it to
|
||||
// accumulate a new set of strings.
|
||||
void Clear();
|
||||
private:
|
||||
// Maps from strings to .stabstr indices and back.
|
||||
typedef map<string, size_t> StringToIndex;
|
||||
typedef map<size_t, const string *> IndexToString;
|
||||
|
||||
// A map from strings to the indices we've assigned them.
|
||||
StringToIndex string_indices_;
|
||||
|
||||
// The next unused byte in the section. The next string we add
|
||||
// will get this index.
|
||||
size_t next_byte_;
|
||||
};
|
||||
|
||||
size_t StabstrSection::Insert(const string &str) {
|
||||
StringToIndex::iterator it = string_indices_.find(str);
|
||||
size_t index;
|
||||
if (it != string_indices_.end()) {
|
||||
index = it->second;
|
||||
} else {
|
||||
// This is the first time we've seen STR; add it to the table.
|
||||
string_indices_[str] = next_byte_;
|
||||
index = next_byte_;
|
||||
next_byte_ += str.size() + 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void StabstrSection::GetSection(string *section) {
|
||||
// First we have to invert the map.
|
||||
IndexToString byIndex;
|
||||
for (StringToIndex::const_iterator it = string_indices_.begin();
|
||||
it != string_indices_.end(); it++)
|
||||
byIndex[it->second] = &it->first;
|
||||
// Now we build the .stabstr section.
|
||||
section->clear();
|
||||
for (IndexToString::const_iterator it = byIndex.begin();
|
||||
it != byIndex.end(); it++) {
|
||||
// Make sure we're actually assigning it the index we claim to be.
|
||||
assert(it->first == section->size());
|
||||
*section += *(it->second);
|
||||
*section += '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void StabstrSection::Clear() {
|
||||
string_indices_.clear();
|
||||
string_indices_[""] = 0;
|
||||
next_byte_ = 1;
|
||||
}
|
||||
|
||||
// A mock stabs parser handler class that builds .stab and .stabstr
|
||||
// sections.
|
||||
class StabsSectionsBuilder: public MockStabsHandler {
|
||||
public:
|
||||
// Construct a handler that will receive data from a MockStabsParser
|
||||
// and construct .stab and .stabstr sections. FILENAME should be
|
||||
// the name of the mock stabs input file; we use it in error
|
||||
// messages.
|
||||
StabsSectionsBuilder(const string &filename)
|
||||
: filename_(filename), error_count_(0), has_header_(false),
|
||||
entry_count_(0) { }
|
||||
|
||||
// Overridden virtual member functions.
|
||||
bool Entry(enum __stab_debug_code type, char other, short desc,
|
||||
unsigned long value, const string &name);
|
||||
bool CUBoundary(const string &filename);
|
||||
bool Error(const char *format, ...);
|
||||
|
||||
// Set SECTION to the contents of a .stab or .stabstr section
|
||||
// reflecting the entries that have been passed to us via Entry.
|
||||
void GetStab(string *section);
|
||||
void GetStabstr(string *section);
|
||||
|
||||
private:
|
||||
// Finish a compilation unit. If there are any entries accumulated in
|
||||
// stab_ and stabstr_, add them as a new compilation unit to
|
||||
// finished_cu_stabs_ and finished_cu_stabstr_, and then clear stab_ and
|
||||
// stabstr_.
|
||||
void FinishCU();
|
||||
|
||||
const string &filename_; // input filename, for error messages
|
||||
int error_count_; // number of errors we've seen so far
|
||||
|
||||
// The following members accumulate the contents of a single compilation
|
||||
// unit, possibly headed by an N_UNDF stab.
|
||||
bool has_header_; // true if we have an N_UNDF header
|
||||
int entry_count_; // the number of entries we've seen
|
||||
StabSection stab_; // 'struct nlist' entries
|
||||
StabstrSection stabstr_; // and the strings they love
|
||||
|
||||
// Accumulated .stab and .stabstr content for all compilation units.
|
||||
string finished_cu_stab_, finished_cu_stabstr_;
|
||||
};
|
||||
|
||||
bool StabsSectionsBuilder::Entry(enum __stab_debug_code type, char other,
|
||||
short desc, unsigned long value,
|
||||
const string &name) {
|
||||
struct nlist *entry = stab_.Append();
|
||||
entry->n_type = type;
|
||||
entry->n_other = other;
|
||||
entry->n_desc = desc;
|
||||
entry->n_value = value;
|
||||
entry->n_un.n_strx = stabstr_.Insert(name);
|
||||
entry_count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StabsSectionsBuilder::CUBoundary(const string &filename) {
|
||||
FinishCU();
|
||||
// Add a header for the compilation unit.
|
||||
assert(!has_header_);
|
||||
assert(entry_count_ == 0);
|
||||
struct nlist *entry = stab_.Append();
|
||||
entry->n_type = N_UNDF;
|
||||
entry->n_other = 0;
|
||||
entry->n_desc = 0; // will be set to number of entries
|
||||
entry->n_value = 0; // will be set to size of .stabstr data
|
||||
entry->n_un.n_strx = stabstr_.Insert(filename);
|
||||
has_header_ = true;
|
||||
// The N_UNDF header isn't included in the symbol count, so we
|
||||
// shouldn't bump entry_count_ here.
|
||||
return true;
|
||||
}
|
||||
|
||||
void StabsSectionsBuilder::FinishCU() {
|
||||
if (entry_count_ > 0) {
|
||||
// Get the strings first, so we can record their size in the header.
|
||||
string stabstr;
|
||||
stabstr_.GetSection(&stabstr);
|
||||
finished_cu_stabstr_ += stabstr;
|
||||
|
||||
// Initialize our header, if we have one, and extract the .stab data.
|
||||
if (has_header_)
|
||||
stab_.SetHeader(entry_count_, stabstr.size());
|
||||
string stab;
|
||||
stab_.GetSection(&stab);
|
||||
finished_cu_stab_ += stab;
|
||||
}
|
||||
|
||||
stab_.Clear();
|
||||
stabstr_.Clear();
|
||||
has_header_ = false;
|
||||
entry_count_ = 0;
|
||||
}
|
||||
|
||||
bool StabsSectionsBuilder::Error(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
error_count_++;
|
||||
if (error_count_ >= 20) {
|
||||
fprintf(stderr,
|
||||
"%s: lots of errors; is this really a mock stabs file?\n",
|
||||
filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void StabsSectionsBuilder::GetStab(string *section) {
|
||||
FinishCU();
|
||||
*section = finished_cu_stab_;
|
||||
}
|
||||
|
||||
void StabsSectionsBuilder::GetStabstr(string *section) {
|
||||
FinishCU();
|
||||
*section = finished_cu_stabstr_;
|
||||
}
|
||||
|
||||
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 std::string &, uint64_t));
|
||||
MOCK_METHOD1(EndFunction, bool(uint64_t));
|
||||
MOCK_METHOD3(Line, bool(uint64_t, const char *, int));
|
||||
void Warning(const char *format, ...) { MockWarning(format); }
|
||||
MOCK_METHOD1(MockWarning, void(const char *));
|
||||
};
|
||||
|
||||
// Create a StabsReader to parse the mock stabs data in INPUT_FILE,
|
||||
// passing the parsed information to HANDLER. If all goes well, return
|
||||
// the result of calling the reader's Process member function.
|
||||
// Otherwise, return false. INPUT_FILE should be relative to the top
|
||||
// of the source tree.
|
||||
static bool ApplyHandlerToMockStabsData(StabsHandler *handler,
|
||||
const string &input_file) {
|
||||
string full_input_file
|
||||
= string(getenv("srcdir") ? getenv("srcdir") : ".") + "/" + input_file;
|
||||
|
||||
// Open the input file.
|
||||
std::ifstream stream(full_input_file.c_str());
|
||||
if (stream.fail()) {
|
||||
fprintf(stderr, "error opening mock stabs input file %s: %s\n",
|
||||
full_input_file.c_str(), strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the mock stabs data, and produce stabs sections to use as
|
||||
// test input to the reader.
|
||||
StabsSectionsBuilder builder(full_input_file);
|
||||
MockStabsParser mock_parser(full_input_file, &stream, &builder);
|
||||
if (!mock_parser.Process())
|
||||
return false;
|
||||
string stab, stabstr;
|
||||
builder.GetStab(&stab);
|
||||
builder.GetStabstr(&stabstr);
|
||||
|
||||
// Run the parser on the test input, passing whatever we find to HANDLER.
|
||||
StabsReader reader(
|
||||
reinterpret_cast<const uint8_t *>(stab.data()), stab.size(),
|
||||
reinterpret_cast<const uint8_t *>(stabstr.data()), stabstr.size(),
|
||||
handler);
|
||||
return reader.Process();
|
||||
}
|
||||
|
||||
TEST(StabsReader, MockStabsInput) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file1.c"),
|
||||
0x42, StrEq("builddir1/")))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0x62))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, Line(0xe4, StrEq("file1.c"), 91))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, Line(0x164, StrEq("header.h"), 111))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndFunction(0x112))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0x112))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, Line(0x234, StrEq("header.h"), 131))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, Line(0x254, StrEq("file1.c"), 151))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndFunction(0x152))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(0x152))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"),
|
||||
0x182, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(0x192))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input1"));
|
||||
}
|
||||
|
||||
TEST(StabsReader, AbruptCU) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("file2-1.c"), 0x12, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(NULL))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input2"));
|
||||
}
|
||||
|
||||
TEST(StabsReader, AbruptFunction) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("file3-1.c"), 0x12, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0x22))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndFunction(NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(NULL))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input3"));
|
||||
}
|
||||
|
||||
TEST(StabsReader, NoCU) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _))
|
||||
.Times(0);
|
||||
EXPECT_CALL(mock_handler, StartFunction(_, _))
|
||||
.Times(0);
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input4"));
|
||||
|
||||
}
|
||||
|
||||
TEST(StabsReader, NoCUEnd) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("file5-1.c"), 0x12, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("file5-2.c"), 0x22, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(NULL))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input5"));
|
||||
|
||||
}
|
||||
|
||||
TEST(StabsReader, MultipleCUs) {
|
||||
MockStabsReaderHandler mock_handler;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("antimony"), 0x12, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x22))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndFunction(0x32))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(0x32))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler,
|
||||
StartCompilationUnit(StrEq("aluminum"), 0x42, NULL))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0x52))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndFunction(0x62))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_handler, EndCompilationUnit(0x62))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(ApplyHandlerToMockStabsData(
|
||||
&mock_handler,
|
||||
"common/linux/testdata/stabs_reader_unittest.input6"));
|
||||
}
|
||||
|
||||
// name duplication
|
||||
|
||||
} // anonymous namespace
|
|
@ -1,19 +0,0 @@
|
|||
SO 10 11 0x02 builddir/
|
||||
FUN 20 21 0x12 not the SO with source file name we expected
|
||||
SO 30 31 0x22
|
||||
SO 40 41 0x32 builddir1/
|
||||
SO 50 51 0x42 file1.c
|
||||
LSYM 60 61 0x52 not the FUN we're looking for
|
||||
FUN 70 71 0x62 fun1
|
||||
BINCL 80 81 0x72 something to ignore in a FUN body
|
||||
SLINE 90 91 0x82
|
||||
SOL 100 101 0x92 header.h
|
||||
SLINE 110 111 0x102
|
||||
FUN 120 121 0x112 fun2:some stabs type info here, to trim from the name
|
||||
SLINE 130 131 0x122
|
||||
SOL 140 141 0x132 file1.c
|
||||
SLINE 150 151 0x142
|
||||
SO 160 161 0x152
|
||||
LSYM 170 171 0x162
|
||||
SO 180 181 0x182 file3.c
|
||||
SO 190 191 0x192
|
|
@ -1 +0,0 @@
|
|||
SO 10 11 0x12 file2-1.c
|
|
@ -1,2 +0,0 @@
|
|||
SO 10 11 0x12 file3-1.c
|
||||
FUN 20 21 0x22 fun3_1
|
|
@ -1 +0,0 @@
|
|||
SO 10 11 0x12 build-directory/
|
|
@ -1,2 +0,0 @@
|
|||
SO 10 11 0x12 file5-1.c
|
||||
SO 20 21 0x22 file5-2.c
|
|
@ -1,8 +0,0 @@
|
|||
cu-boundary antimony
|
||||
SO 10 11 0x12 antimony
|
||||
FUN 20 21 0x22 arsenic
|
||||
SO 30 31 0x32
|
||||
cu-boundary aluminum
|
||||
SO 40 41 0x42 aluminum
|
||||
FUN 50 51 0x52 selenium
|
||||
SO 60 61 0x62
|
|
@ -0,0 +1,48 @@
|
|||
// -*- 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 <jim@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// byteswap.h: Overloaded functions for conveniently byteswapping values.
|
||||
|
||||
#ifndef COMMON_MAC_BYTESWAP_H_
|
||||
#define COMMON_MAC_BYTESWAP_H_
|
||||
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); }
|
||||
static inline uint32_t ByteSwap(uint32_t v) { return OSSwapInt32(v); }
|
||||
static inline uint64_t ByteSwap(uint64_t v) { return OSSwapInt64(v); }
|
||||
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); }
|
||||
|
||||
#endif // COMMON_MAC_BYTESWAP_H_
|
|
@ -1,4 +1,6 @@
|
|||
// Copyright (c) 2006, Google Inc.
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
|
@ -27,53 +29,133 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dump_syms.h: Interface for DumpSymbols. This class will take a mach-o file
|
||||
// and extract the symbol information and write it to a file using the
|
||||
// breakpad symbol file format.
|
||||
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
// dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for
|
||||
// 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 "common/dwarf/dwarf2reader.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// This will map from an architecture string to a SectionMap, which
|
||||
// will contain the offsets for all the sections in the dictionary
|
||||
typedef map<string, dwarf2reader::SectionMap *> ArchSectionMap;
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@interface DumpSymbols : NSObject {
|
||||
@protected
|
||||
NSString *sourcePath_; // Source of symbols (STRONG)
|
||||
NSString *architecture_; // Architecture to extract (STRONG)
|
||||
NSMutableDictionary *addresses_; // Addresses and symbols (STRONG)
|
||||
NSMutableSet *functionAddresses_; // Function addresses (STRONG)
|
||||
NSMutableDictionary *sources_; // Address and Source file paths (STRONG)
|
||||
NSMutableDictionary *headers_; // Mach-o header information (STRONG)
|
||||
NSMutableDictionary *sectionData_; // Keyed by seg/sect name (STRONG)
|
||||
uint32_t lastStartAddress_;
|
||||
ArchSectionMap *sectionsForArch_;
|
||||
}
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
#include "common/module.h"
|
||||
|
||||
- (id)initWithContentsOfFile:(NSString *)machoFile;
|
||||
namespace google_breakpad {
|
||||
|
||||
- (NSArray *)availableArchitectures;
|
||||
class DumpSymbols {
|
||||
public:
|
||||
DumpSymbols()
|
||||
: input_pathname_(),
|
||||
object_filename_(),
|
||||
contents_(),
|
||||
selected_object_file_(),
|
||||
selected_object_name_() { }
|
||||
~DumpSymbols() {
|
||||
[input_pathname_ release];
|
||||
[object_filename_ release];
|
||||
[contents_ release];
|
||||
}
|
||||
|
||||
// One of ppc, x86, i386, ppc64, x86_64
|
||||
// If the architecture is not available, it will return NO
|
||||
// If not set, the native architecture will be used
|
||||
- (BOOL)setArchitecture:(NSString *)architecture;
|
||||
- (NSString *)architecture;
|
||||
// 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);
|
||||
|
||||
// Write the symbols to |symbolFilePath|. Return YES if successful.
|
||||
- (BOOL)writeSymbolFile:(NSString *)symbolFilePath;
|
||||
// If this dumper's file includes an object file for |cpu_type| and
|
||||
// |cpu_subtype|, then select that object file for dumping, and return
|
||||
// true. Otherwise, return false, and leave this dumper's selected
|
||||
// architecture unchanged.
|
||||
//
|
||||
// By default, if this dumper's file contains only one object file, then
|
||||
// the dumper will dump those symbols; and if it contains more than one
|
||||
// object file, then the dumper will dump the object file whose
|
||||
// architecture matches that of this dumper program.
|
||||
bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
|
||||
|
||||
@end
|
||||
// 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.
|
||||
//
|
||||
// If there are no available architectures, this function
|
||||
// may return NULL.
|
||||
const struct fat_arch *AvailableArchitectures(size_t *count) {
|
||||
*count = object_files_.size();
|
||||
if (object_files_.size() > 0)
|
||||
return &object_files_[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@interface MachSection : NSObject {
|
||||
@protected
|
||||
struct section *sect_;
|
||||
uint32_t sectionNumber_;
|
||||
}
|
||||
- (id)initWithMachSection:(struct section *)sect andNumber:(uint32_t)sectionNumber;
|
||||
- (struct section*)sectionPointer;
|
||||
- (uint32_t)sectionNumber;
|
||||
// Read the selected object file's debugging information, and write it
|
||||
// out to |stream|. Return true on success; if an error occurs, report it
|
||||
// and return false.
|
||||
bool WriteSymbolFile(FILE *stream);
|
||||
|
||||
@end
|
||||
private:
|
||||
// Used internally.
|
||||
class DumperLineToModule;
|
||||
class LoadCommandDumper;
|
||||
|
||||
// Return an identifier string for the file this DumpSymbols is dumping.
|
||||
std::string Identifier();
|
||||
|
||||
// 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;
|
||||
|
||||
// Read DWARF CFI or .eh_frame data from |section|, belonging to
|
||||
// |macho_reader|, and record it in |module|. If |eh_frame| is true,
|
||||
// then the data is .eh_frame-format data; otherwise, it is standard DWARF
|
||||
// .debug_frame data. On success, return true; on failure, report
|
||||
// the problem and return false.
|
||||
bool ReadCFI(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::Section §ion,
|
||||
bool eh_frame) const;
|
||||
|
||||
// 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_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// The complete contents of object_filename_, mapped into memory.
|
||||
NSData *contents_;
|
||||
|
||||
// A vector of fat_arch 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_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// A string that identifies the selected object file, for use in error
|
||||
// messages. This is usually object_filename_, but if that refers to a
|
||||
// fat binary, it includes an indication of the particular architecture
|
||||
// within that binary.
|
||||
string selected_object_name_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,524 @@
|
|||
// 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.cc: Implementation of google_breakpad::Mach_O::FatReader and
|
||||
// google_breakpad::Mach_O::Reader. See macho_reader.h for details.
|
||||
|
||||
#include "common/mac/macho_reader.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace mach_o {
|
||||
|
||||
// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its
|
||||
// arguments, so you can't place expressions that do necessary work in
|
||||
// the argument of an assert. Nor can you assign the result of the
|
||||
// expression to a variable and assert that the variable's value is
|
||||
// true: you'll get unused variable warnings when NDEBUG is #defined.
|
||||
//
|
||||
// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that
|
||||
// the result is true if NDEBUG is not #defined.
|
||||
#if defined(NDEBUG)
|
||||
#define ASSERT_ALWAYS_EVAL(x) (x)
|
||||
#else
|
||||
#define ASSERT_ALWAYS_EVAL(x) assert(x)
|
||||
#endif
|
||||
|
||||
void FatReader::Reporter::BadHeader() {
|
||||
fprintf(stderr, "%s: file is neither a fat binary file"
|
||||
" nor a Mach-O object file\n", filename_.c_str());
|
||||
}
|
||||
|
||||
void FatReader::Reporter::TooShort() {
|
||||
fprintf(stderr, "%s: file too short for the data it claims to contain\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void FatReader::Reporter::MisplacedObjectFile() {
|
||||
fprintf(stderr, "%s: file too short for the object files it claims"
|
||||
" to contain\n", filename_.c_str());
|
||||
}
|
||||
|
||||
bool FatReader::Read(const uint8_t *buffer, size_t size) {
|
||||
buffer_.start = buffer;
|
||||
buffer_.end = buffer + size;
|
||||
ByteCursor cursor(&buffer_);
|
||||
|
||||
// Fat binaries always use big-endian, so read the magic number in
|
||||
// that endianness. To recognize Mach-O magic numbers, which can use
|
||||
// either endianness, check for both the proper and reversed forms
|
||||
// of the magic numbers.
|
||||
cursor.set_big_endian(true);
|
||||
if (cursor >> magic_) {
|
||||
if (magic_ == FAT_MAGIC) {
|
||||
// How many object files does this fat binary contain?
|
||||
uint32_t object_files_count;
|
||||
if (!(cursor >> object_files_count)) { // nfat_arch
|
||||
reporter_->TooShort();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
// Read this object file entry, byte-swapping as appropriate.
|
||||
cursor >> objfile->cputype
|
||||
>> objfile->cpusubtype
|
||||
>> objfile->offset
|
||||
>> objfile->size
|
||||
>> objfile->align;
|
||||
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) {
|
||||
reporter_->MisplacedObjectFile();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 ||
|
||||
magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) {
|
||||
// If this is a little-endian Mach-O file, fix the cursor's endianness.
|
||||
if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64)
|
||||
cursor.set_big_endian(false);
|
||||
// Record the entire file as a single entry in the object file list.
|
||||
object_files_.resize(1);
|
||||
|
||||
// Get the cpu type and subtype from the Mach-O header.
|
||||
if (!(cursor >> object_files_[0].cputype
|
||||
>> object_files_[0].cpusubtype)) {
|
||||
reporter_->TooShort();
|
||||
return false;
|
||||
}
|
||||
|
||||
object_files_[0].offset = 0;
|
||||
object_files_[0].size = 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;
|
||||
}
|
||||
|
||||
void Reader::Reporter::BadHeader() {
|
||||
fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected"
|
||||
" type %d, subtype %d\n",
|
||||
filename_.c_str(), cpu_type, cpu_subtype,
|
||||
expected_cpu_type, expected_cpu_subtype);
|
||||
}
|
||||
|
||||
void Reader::Reporter::HeaderTruncated() {
|
||||
fprintf(stderr, "%s: file does not contain a complete Mach-O header\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::LoadCommandRegionTruncated() {
|
||||
fprintf(stderr, "%s: file too short to hold load command region"
|
||||
" given in Mach-O header\n", filename_.c_str());
|
||||
}
|
||||
|
||||
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",
|
||||
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,"
|
||||
" extend beyond the size given in the load command's header\n",
|
||||
filename_.c_str(), i, type);
|
||||
}
|
||||
|
||||
void Reader::Reporter::SectionsMissing(const string &name) {
|
||||
fprintf(stderr, "%s: the load command for segment '%s'"
|
||||
" is too short to hold the section headers it claims to have\n",
|
||||
filename_.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSegmentData(const string &name) {
|
||||
fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
|
||||
" the end of the file\n", filename_.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSectionData(const string §ion,
|
||||
const string &segment) {
|
||||
fprintf(stderr, "%s: the section '%s' in segment '%s'"
|
||||
" claims its contents lie outside the segment's contents\n",
|
||||
filename_.c_str(), section.c_str(), segment.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::MisplacedSymbolTable() {
|
||||
fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol"
|
||||
" table's contents are located beyond the end of the file\n",
|
||||
filename_.c_str());
|
||||
}
|
||||
|
||||
void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
|
||||
fprintf(stderr, "%s: CPU type %d is not supported\n",
|
||||
filename_.c_str(), cpu_type);
|
||||
}
|
||||
|
||||
bool Reader::Read(const uint8_t *buffer,
|
||||
size_t size,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
assert(!buffer_.start);
|
||||
buffer_.start = buffer;
|
||||
buffer_.end = buffer + size;
|
||||
ByteCursor cursor(&buffer_, true);
|
||||
uint32_t magic;
|
||||
if (!(cursor >> magic)) {
|
||||
reporter_->HeaderTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_cpu_type != CPU_TYPE_ANY) {
|
||||
uint32_t expected_magic;
|
||||
// validate that magic matches the expected cpu type
|
||||
switch (expected_cpu_type) {
|
||||
case CPU_TYPE_I386:
|
||||
expected_magic = MH_CIGAM;
|
||||
break;
|
||||
case CPU_TYPE_POWERPC:
|
||||
expected_magic = MH_MAGIC;
|
||||
break;
|
||||
case CPU_TYPE_X86_64:
|
||||
expected_magic = MH_CIGAM_64;
|
||||
break;
|
||||
case CPU_TYPE_POWERPC64:
|
||||
expected_magic = MH_MAGIC_64;
|
||||
break;
|
||||
default:
|
||||
reporter_->UnsupportedCPUType(expected_cpu_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_magic != magic) {
|
||||
reporter_->BadHeader();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Since the byte cursor is in big-endian mode, a reversed magic number
|
||||
// always indicates a little-endian file, regardless of our own endianness.
|
||||
switch (magic) {
|
||||
case MH_MAGIC: big_endian_ = true; bits_64_ = false; break;
|
||||
case MH_CIGAM: big_endian_ = false; bits_64_ = false; break;
|
||||
case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break;
|
||||
case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break;
|
||||
default:
|
||||
reporter_->BadHeader();
|
||||
return false;
|
||||
}
|
||||
cursor.set_big_endian(big_endian_);
|
||||
uint32_t commands_size, reserved;
|
||||
cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_
|
||||
>> commands_size >> flags_;
|
||||
if (bits_64_)
|
||||
cursor >> reserved;
|
||||
if (!cursor) {
|
||||
reporter_->HeaderTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected_cpu_type != CPU_TYPE_ANY &&
|
||||
(expected_cpu_type != cpu_type_ ||
|
||||
expected_cpu_subtype != cpu_subtype_)) {
|
||||
reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_,
|
||||
expected_cpu_type, expected_cpu_subtype);
|
||||
return false;
|
||||
}
|
||||
|
||||
cursor
|
||||
.PointTo(&load_commands_.start, commands_size)
|
||||
.PointTo(&load_commands_.end, 0);
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandRegionTruncated();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
|
||||
ByteCursor list_cursor(&load_commands_, big_endian_);
|
||||
|
||||
for (size_t index = 0; index < load_command_count_; ++index) {
|
||||
// command refers to this load command alone, so that cursor will
|
||||
// refuse to read past the load command's end. But since we haven't
|
||||
// read the size yet, let command initially refer to the entire
|
||||
// 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)) {
|
||||
reporter_->LoadCommandsOverrun(load_command_count_, index, 0);
|
||||
return false;
|
||||
}
|
||||
if (!(cursor >> size) || size > command.Size()) {
|
||||
reporter_->LoadCommandsOverrun(load_command_count_, index, type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now that we've read the length, restrict command's range to this
|
||||
// load command only.
|
||||
command.end = command.start + size;
|
||||
|
||||
switch (type) {
|
||||
case LC_SEGMENT:
|
||||
case LC_SEGMENT_64: {
|
||||
Segment segment;
|
||||
segment.bits_64 = (type == LC_SEGMENT_64);
|
||||
size_t word_size = segment.bits_64 ? 8 : 4;
|
||||
cursor.CString(&segment.name, 16);
|
||||
size_t file_offset, file_size;
|
||||
cursor
|
||||
.Read(word_size, false, &segment.vmaddr)
|
||||
.Read(word_size, false, &segment.vmsize)
|
||||
.Read(word_size, false, &file_offset)
|
||||
.Read(word_size, false, &file_size);
|
||||
cursor >> segment.maxprot
|
||||
>> segment.initprot
|
||||
>> segment.nsects
|
||||
>> segment.flags;
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandTooShort(index, type);
|
||||
return false;
|
||||
}
|
||||
if (file_offset > buffer_.Size() ||
|
||||
file_size > buffer_.Size() - file_offset) {
|
||||
reporter_->MisplacedSegmentData(segment.name);
|
||||
return false;
|
||||
}
|
||||
// Mach-O files in .dSYM bundles have the contents of the loaded
|
||||
// segments removed, and their file offsets and file sizes zeroed
|
||||
// out. To help us handle this special case properly, give such
|
||||
// segments' contents NULL starting and ending pointers.
|
||||
if (file_offset == 0 && file_size == 0) {
|
||||
segment.contents.start = segment.contents.end = NULL;
|
||||
} else {
|
||||
segment.contents.start = buffer_.start + file_offset;
|
||||
segment.contents.end = segment.contents.start + file_size;
|
||||
}
|
||||
// The section list occupies the remainder of this load command's space.
|
||||
segment.section_list.start = cursor.here();
|
||||
segment.section_list.end = command.end;
|
||||
|
||||
if (!handler->SegmentCommand(segment))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case LC_SYMTAB: {
|
||||
uint32_t symoff, nsyms, stroff, strsize;
|
||||
cursor >> symoff >> nsyms >> stroff >> strsize;
|
||||
if (!cursor) {
|
||||
reporter_->LoadCommandTooShort(index, type);
|
||||
return false;
|
||||
}
|
||||
// How big are the entries in the symbol table?
|
||||
// sizeof(struct nlist_64) : sizeof(struct nlist),
|
||||
// but be paranoid about alignment vs. target architecture.
|
||||
size_t symbol_size = bits_64_ ? 16 : 12;
|
||||
// How big is the entire symbol array?
|
||||
size_t symbols_size = nsyms * symbol_size;
|
||||
if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff ||
|
||||
stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) {
|
||||
reporter_->MisplacedSymbolTable();
|
||||
return false;
|
||||
}
|
||||
ByteBuffer entries(buffer_.start + symoff, symbols_size);
|
||||
ByteBuffer names(buffer_.start + stroff, strsize);
|
||||
if (!handler->SymtabCommand(entries, names))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!handler->UnknownCommand(type, command))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_cursor.set_here(command.end);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// A load command handler that looks for a segment of a given name.
|
||||
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)
|
||||
: name_(name), segment_(segment), found_() { }
|
||||
|
||||
// Return true if the traversal found the segment, false otherwise.
|
||||
bool found() const { return found_; }
|
||||
|
||||
bool SegmentCommand(const Segment &segment) {
|
||||
if (segment.name == name_) {
|
||||
*segment_ = segment;
|
||||
found_ = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// The name of the segment our creator is looking for.
|
||||
const string &name_;
|
||||
|
||||
// Where we should store the segment if found. (WEAK)
|
||||
Segment *segment_;
|
||||
|
||||
// True if we found the segment.
|
||||
bool found_;
|
||||
};
|
||||
|
||||
bool Reader::FindSegment(const string &name, Segment *segment) const {
|
||||
SegmentFinder finder(name, segment);
|
||||
WalkLoadCommands(&finder);
|
||||
return finder.found();
|
||||
}
|
||||
|
||||
bool Reader::WalkSegmentSections(const Segment &segment,
|
||||
SectionHandler *handler) const {
|
||||
size_t word_size = segment.bits_64 ? 8 : 4;
|
||||
ByteCursor cursor(&segment.section_list, big_endian_);
|
||||
|
||||
for (size_t i = 0; i < segment.nsects; i++) {
|
||||
Section section;
|
||||
section.bits_64 = segment.bits_64;
|
||||
uint64_t size;
|
||||
uint32_t offset, dummy32;
|
||||
cursor
|
||||
.CString(§ion.section_name, 16)
|
||||
.CString(§ion.segment_name, 16)
|
||||
.Read(word_size, false, §ion.address)
|
||||
.Read(word_size, false, &size)
|
||||
>> offset
|
||||
>> section.align
|
||||
>> dummy32
|
||||
>> dummy32
|
||||
>> section.flags
|
||||
>> dummy32
|
||||
>> dummy32;
|
||||
if (section.bits_64)
|
||||
cursor >> dummy32;
|
||||
if (!cursor) {
|
||||
reporter_->SectionsMissing(segment.name);
|
||||
return false;
|
||||
}
|
||||
if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
|
||||
// Zero-fill sections have a size, but no contents.
|
||||
section.contents.start = section.contents.end = 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
|
||||
// out. However, the sections within those segments still have
|
||||
// non-zero sizes. There's no reason to call MisplacedSectionData in
|
||||
// this case; the caller may just need the section's load
|
||||
// address. But do set the contents' limits to NULL, for safety.
|
||||
section.contents.start = section.contents.end = NULL;
|
||||
} else {
|
||||
if (offset < size_t(segment.contents.start - buffer_.start) ||
|
||||
offset > size_t(segment.contents.end - buffer_.start) ||
|
||||
size > size_t(segment.contents.end - buffer_.start - offset)) {
|
||||
reporter_->MisplacedSectionData(section.section_name,
|
||||
section.segment_name);
|
||||
return false;
|
||||
}
|
||||
section.contents.start = buffer_.start + offset;
|
||||
section.contents.end = section.contents.start + size;
|
||||
}
|
||||
if (!handler->HandleSection(section))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// A SectionHandler that builds a SectionMap for the sections within a
|
||||
// given segment.
|
||||
class Reader::SectionMapper: public SectionHandler {
|
||||
public:
|
||||
// Create a SectionHandler that populates MAP with an entry for
|
||||
// each section it is given.
|
||||
SectionMapper(SectionMap *map) : map_(map) { }
|
||||
bool HandleSection(const Section §ion) {
|
||||
(*map_)[section.section_name] = section;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
// The map under construction. (WEAK)
|
||||
SectionMap *map_;
|
||||
};
|
||||
|
||||
bool Reader::MapSegmentSections(const Segment &segment,
|
||||
SectionMap *section_map) const {
|
||||
section_map->clear();
|
||||
SectionMapper mapper(section_map);
|
||||
return WalkSegmentSections(segment, &mapper);
|
||||
}
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace google_breakpad
|
|
@ -0,0 +1,459 @@
|
|||
// -*- 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>
|
||||
|
||||
// macho_reader.h: A class for parsing Mach-O files.
|
||||
|
||||
#ifndef BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
||||
#define BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/byte_cursor.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace mach_o {
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
// The Mac headers don't specify particular types for these groups of
|
||||
// constants, but defining them here provides some documentation
|
||||
// value. We also give them the same width as the fields in which
|
||||
// they appear, which makes them a bit easier to use with ByteCursors.
|
||||
typedef uint32_t Magic;
|
||||
typedef uint32_t FileType;
|
||||
typedef uint32_t FileFlags;
|
||||
typedef uint32_t LoadCommandType;
|
||||
typedef uint32_t SegmentFlags;
|
||||
typedef uint32_t SectionFlags;
|
||||
|
||||
// A parser for fat binary files, used to store universal binaries.
|
||||
// When applied to a (non-fat) Mach-O file, this behaves as if the
|
||||
// file were a fat file containing a single object file.
|
||||
class FatReader {
|
||||
public:
|
||||
|
||||
// A class for reporting errors found while parsing fat binary files. The
|
||||
// default definitions of these methods print messages to stderr.
|
||||
class Reporter {
|
||||
public:
|
||||
// Create a reporter that attributes problems to |filename|.
|
||||
explicit Reporter(const string &filename) : filename_(filename) { }
|
||||
|
||||
virtual ~Reporter() { }
|
||||
|
||||
// The data does not begin with a fat binary or Mach-O magic number.
|
||||
// This is a fatal error.
|
||||
virtual void BadHeader();
|
||||
|
||||
// The Mach-O fat binary file ends abruptly, without enough space
|
||||
// to contain an object file it claims is present.
|
||||
virtual void MisplacedObjectFile();
|
||||
|
||||
// The file ends abruptly: either it is not large enough to hold a
|
||||
// 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_;
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
// If the data is a plain Mach-O file, rather than a fat binary file,
|
||||
// then the reader behaves as if it had found a fat binary file whose
|
||||
// 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
|
||||
// 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.
|
||||
//
|
||||
// If there are no object files in this fat binary, then this
|
||||
// function can return NULL.
|
||||
//
|
||||
// The array is owned by this FatReader instance; it will be freed when
|
||||
// this FatReader is destroyed.
|
||||
//
|
||||
// This function returns a C-style array instead of a vector to make it
|
||||
// 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 {
|
||||
*count = object_files_.size();
|
||||
if (object_files_.size() > 0)
|
||||
return &object_files_[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
// We use this to report problems parsing the file's contents. (WEAK)
|
||||
Reporter *reporter_;
|
||||
|
||||
// The contents of the fat binary or Mach-O file we're parsing. We do not
|
||||
// own the storage it refers to.
|
||||
ByteBuffer buffer_;
|
||||
|
||||
// The magic number of this binary, in host byte order.
|
||||
Magic magic_;
|
||||
|
||||
// The list of object files in this binary.
|
||||
// object_files_.size() == fat_header.nfat_arch
|
||||
vector<struct fat_arch> object_files_;
|
||||
};
|
||||
|
||||
// A segment in a Mach-O file. All these fields have been byte-swapped as
|
||||
// appropriate for use by the executing architecture.
|
||||
struct Segment {
|
||||
// The ByteBuffers below point into the bytes passed to the Reader that
|
||||
// created this Segment.
|
||||
|
||||
ByteBuffer section_list; // This segment's section list.
|
||||
ByteBuffer contents; // This segment's contents.
|
||||
|
||||
// This segment's name.
|
||||
string name;
|
||||
|
||||
// The address at which this segment should be loaded in memory. If
|
||||
// bits_64 is false, only the bottom 32 bits of this value are valid.
|
||||
uint64_t vmaddr;
|
||||
|
||||
// The size of this segment when loaded into memory. This may be larger
|
||||
// than contents.Size(), in which case the extra area will be
|
||||
// initialized with zeros. If bits_64 is false, only the bottom 32 bits
|
||||
// of this value are valid.
|
||||
uint64_t vmsize;
|
||||
|
||||
// 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;
|
||||
|
||||
// Flags describing this segment, from SegmentFlags.
|
||||
uint32_t flags;
|
||||
|
||||
// True if this is a 64-bit section; false if it is a 32-bit section.
|
||||
bool bits_64;
|
||||
};
|
||||
|
||||
// A section in a Mach-O file. All these fields have been byte-swapped as
|
||||
// appropriate for use by the executing architecture.
|
||||
struct Section {
|
||||
// This section's contents. This points into the bytes passed to the
|
||||
// Reader that created this Section.
|
||||
ByteBuffer contents;
|
||||
|
||||
// This section's name.
|
||||
string section_name; // section[_64].sectname
|
||||
// The name of the segment this section belongs to.
|
||||
string segment_name; // section[_64].segname
|
||||
|
||||
// The address at which this section's contents should be loaded in
|
||||
// memory. If bits_64 is false, only the bottom 32 bits of this value
|
||||
// are valid.
|
||||
uint64_t address;
|
||||
|
||||
// The contents of this section should be loaded into memory at an
|
||||
// address which is a multiple of (two raised to this power).
|
||||
uint32_t align;
|
||||
|
||||
// Flags from SectionFlags describing the section's contents.
|
||||
uint32_t flags;
|
||||
|
||||
// We don't support reading relocations yet.
|
||||
|
||||
// True if this is a 64-bit section; false if it is a 32-bit section.
|
||||
bool bits_64;
|
||||
};
|
||||
|
||||
// A map from section names to Sections.
|
||||
typedef map<string, Section> SectionMap;
|
||||
|
||||
// A reader for a Mach-O file.
|
||||
//
|
||||
// This does not handle fat binaries; see FatReader above. FatReader
|
||||
// provides a friendly interface for parsing data that could be either a
|
||||
// fat binary or a Mach-O file.
|
||||
class Reader {
|
||||
public:
|
||||
|
||||
// A class for reporting errors found while parsing Mach-O files. The
|
||||
// default definitions of these member functions print messages to
|
||||
// stderr.
|
||||
class Reporter {
|
||||
public:
|
||||
// Create a reporter that attributes problems to |filename|.
|
||||
explicit Reporter(const string &filename) : filename_(filename) { }
|
||||
virtual ~Reporter() { }
|
||||
|
||||
// Reporter functions for fatal errors return void; the reader will
|
||||
// definitely return an error to its caller after calling them
|
||||
|
||||
// The data does not begin with a Mach-O magic number, or the magic
|
||||
// number does not match the expected value for the cpu architecture.
|
||||
// This is a fatal error.
|
||||
virtual void BadHeader();
|
||||
|
||||
// The data contained in a Mach-O fat binary (|cpu_type|, |cpu_subtype|)
|
||||
// does not match the expected CPU architecture
|
||||
// (|expected_cpu_type|, |expected_cpu_subtype|).
|
||||
virtual void CPUTypeMismatch(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype);
|
||||
|
||||
// The file ends abruptly: either it is not large enough to hold a
|
||||
// complete header, or the header implies that contents are present
|
||||
// beyond the actual end of the file.
|
||||
virtual void HeaderTruncated();
|
||||
|
||||
// The file's load command region, as given in the Mach-O header, is
|
||||
// too large for the file.
|
||||
virtual void LoadCommandRegionTruncated();
|
||||
|
||||
// The file's Mach-O header claims the file contains |claimed| load
|
||||
// commands, but the I'th load command, of type |type|, extends beyond
|
||||
// the end of the load command region, as given by the Mach-O header.
|
||||
// If |type| is zero, the command's type was unreadable.
|
||||
virtual void LoadCommandsOverrun(size_t claimed, size_t i,
|
||||
LoadCommandType type);
|
||||
|
||||
// The contents of the |i|'th load command, of type |type|, extend beyond
|
||||
// the size given in the load command's header.
|
||||
virtual void LoadCommandTooShort(size_t i, LoadCommandType type);
|
||||
|
||||
// The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named
|
||||
// |name| is too short to hold the sections that its header says it does.
|
||||
// (This more specific than LoadCommandTooShort.)
|
||||
virtual void SectionsMissing(const string &name);
|
||||
|
||||
// The segment named |name| claims that its contents lie beyond the end
|
||||
// of the file.
|
||||
virtual void MisplacedSegmentData(const string &name);
|
||||
|
||||
// The section named |section| in the segment named |segment| claims that
|
||||
// its contents do not lie entirely within the segment.
|
||||
virtual void MisplacedSectionData(const string §ion,
|
||||
const string &segment);
|
||||
|
||||
// The LC_SYMTAB command claims that symbol table contents are located
|
||||
// beyond the end of the file.
|
||||
virtual void MisplacedSymbolTable();
|
||||
|
||||
// An attempt was made to read a Mach-O file of the unsupported
|
||||
// CPU architecture |cpu_type|.
|
||||
virtual void UnsupportedCPUType(cpu_type_t cpu_type);
|
||||
|
||||
private:
|
||||
string filename_;
|
||||
};
|
||||
|
||||
// A handler for sections parsed from a segment. The WalkSegmentSections
|
||||
// member function accepts an instance of this class, and applies it to
|
||||
// each section defined in a given segment.
|
||||
class SectionHandler {
|
||||
public:
|
||||
virtual ~SectionHandler() { }
|
||||
|
||||
// Called to report that the segment's section list contains |section|.
|
||||
// This should return true if the iteration should continue, or false
|
||||
// if it should stop.
|
||||
virtual bool HandleSection(const Section §ion) = 0;
|
||||
};
|
||||
|
||||
// A handler for the load commands in a Mach-O file.
|
||||
class LoadCommandHandler {
|
||||
public:
|
||||
LoadCommandHandler() { }
|
||||
virtual ~LoadCommandHandler() { }
|
||||
|
||||
// When called from WalkLoadCommands, the following handler functions
|
||||
// should return true if they wish to continue iterating over the load
|
||||
// command list, or false if they wish to stop iterating.
|
||||
//
|
||||
// When called from LoadCommandIterator::Handle or Reader::Handle,
|
||||
// these functions' return values are simply passed through to Handle's
|
||||
// caller.
|
||||
//
|
||||
// The definitions provided by this base class simply return true; the
|
||||
// default is to silently ignore sections whose member functions the
|
||||
// subclass doesn't override.
|
||||
|
||||
// COMMAND is load command we don't recognize. We provide only the
|
||||
// command type and a ByteBuffer enclosing the command's data (If we
|
||||
// cannot parse the command type or its size, we call
|
||||
// reporter_->IncompleteLoadCommand instead.)
|
||||
virtual bool UnknownCommand(LoadCommandType type,
|
||||
const ByteBuffer &contents) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment
|
||||
// with the properties given in |segment|.
|
||||
virtual bool SegmentCommand(const Segment &segment) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The load command is LC_SYMTAB. |entries| holds the array of nlist
|
||||
// entries, and |names| holds the strings the entries refer to.
|
||||
virtual bool SymtabCommand(const ByteBuffer &entries,
|
||||
const ByteBuffer &names) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add handler functions for more load commands here as needed.
|
||||
};
|
||||
|
||||
// Create a Mach-O file reader that reports problems to |reporter|.
|
||||
explicit Reader(Reporter *reporter)
|
||||
: reporter_(reporter) { }
|
||||
|
||||
// Read the given data as a Mach-O file. The reader retains pointers
|
||||
// into the data passed, so the data should live as long as the reader
|
||||
// does. On success, return true; on failure, return false.
|
||||
//
|
||||
// At most one of these functions should be invoked once on each Reader
|
||||
// instance.
|
||||
bool Read(const uint8_t *buffer,
|
||||
size_t size,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype);
|
||||
bool Read(const ByteBuffer &buffer,
|
||||
cpu_type_t expected_cpu_type,
|
||||
cpu_subtype_t expected_cpu_subtype) {
|
||||
return Read(buffer.start,
|
||||
buffer.Size(),
|
||||
expected_cpu_type,
|
||||
expected_cpu_subtype);
|
||||
}
|
||||
|
||||
// Return this file's characteristics, as found in the Mach-O header.
|
||||
cpu_type_t cpu_type() const { return cpu_type_; }
|
||||
cpu_subtype_t cpu_subtype() const { return cpu_subtype_; }
|
||||
FileType file_type() const { return file_type_; }
|
||||
FileFlags flags() const { return flags_; }
|
||||
|
||||
// Return true if this is a 64-bit Mach-O file, false if it is a 32-bit
|
||||
// Mach-O file.
|
||||
bool bits_64() const { return bits_64_; }
|
||||
|
||||
// Return true if this is a big-endian Mach-O file, false if it is
|
||||
// little-endian.
|
||||
bool big_endian() const { return big_endian_; }
|
||||
|
||||
// Apply |handler| to each load command in this Mach-O file, stopping when
|
||||
// a handler function returns false. If we encounter a malformed load
|
||||
// command, report it via reporter_ and return false. Return true if all
|
||||
// load commands were parseable and all handlers returned true.
|
||||
bool WalkLoadCommands(LoadCommandHandler *handler) const;
|
||||
|
||||
// Set |segment| to describe the segment named |name|, if present. If
|
||||
// found, |segment|'s byte buffers refer to a subregion of the bytes
|
||||
// passed to Read. If we find the section, return true; otherwise,
|
||||
// return false.
|
||||
bool FindSegment(const string &name, Segment *segment) const;
|
||||
|
||||
// Apply |handler| to each section defined in |segment|. If |handler| returns
|
||||
// false, stop iterating and return false. If all calls to |handler| return
|
||||
// true and we reach the end of the section list, return true.
|
||||
bool WalkSegmentSections(const Segment &segment, SectionHandler *handler)
|
||||
const;
|
||||
|
||||
// Clear |section_map| and then populate it with a map of the sections
|
||||
// in |segment|, from section names to Section structures.
|
||||
// Each Section's contents refer to bytes in |segment|'s contents.
|
||||
// On success, return true; if a problem occurs, report it and return false.
|
||||
bool MapSegmentSections(const Segment &segment, SectionMap *section_map)
|
||||
const;
|
||||
|
||||
private:
|
||||
// Used internally.
|
||||
class SegmentFinder;
|
||||
class SectionMapper;
|
||||
|
||||
// We use this to report problems parsing the file's contents. (WEAK)
|
||||
Reporter *reporter_;
|
||||
|
||||
// The contents of the Mach-O file we're parsing. We do not own the
|
||||
// storage it refers to.
|
||||
ByteBuffer buffer_;
|
||||
|
||||
// True if this file is big-endian.
|
||||
bool big_endian_;
|
||||
|
||||
// True if this file is a 64-bit Mach-O file.
|
||||
bool bits_64_;
|
||||
|
||||
// This file's cpu type and subtype.
|
||||
cpu_type_t cpu_type_; // mach_header[_64].cputype
|
||||
cpu_subtype_t cpu_subtype_; // mach_header[_64].cpusubtype
|
||||
|
||||
// This file's type.
|
||||
FileType file_type_; // mach_header[_64].filetype
|
||||
|
||||
// The region of buffer_ occupied by load commands.
|
||||
ByteBuffer load_commands_;
|
||||
|
||||
// The number of load commands in load_commands_.
|
||||
uint32_t load_command_count_; // mach_header[_64].ncmds
|
||||
|
||||
// This file's header flags.
|
||||
FileFlags flags_;
|
||||
};
|
||||
|
||||
} // namespace mach_o
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // BREAKPAD_COMMON_MAC_MACHO_READER_H_
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -31,43 +31,44 @@
|
|||
//
|
||||
// Author: Dave Camp
|
||||
|
||||
#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)
|
||||
{
|
||||
uc->cmd = NXSwapLong(uc->cmd);
|
||||
uc->cmdsize = NXSwapLong(uc->cmdsize);
|
||||
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)
|
||||
{
|
||||
sg->cmd = NXSwapLong(sg->cmd);
|
||||
sg->cmdsize = NXSwapLong(sg->cmdsize);
|
||||
sg->cmd = ByteSwap(sg->cmd);
|
||||
sg->cmdsize = ByteSwap(sg->cmdsize);
|
||||
|
||||
sg->vmaddr = NXSwapLongLong(sg->vmaddr);
|
||||
sg->vmsize = NXSwapLongLong(sg->vmsize);
|
||||
sg->fileoff = NXSwapLongLong(sg->fileoff);
|
||||
sg->filesize = NXSwapLongLong(sg->filesize);
|
||||
sg->vmaddr = ByteSwap(sg->vmaddr);
|
||||
sg->vmsize = ByteSwap(sg->vmsize);
|
||||
sg->fileoff = ByteSwap(sg->fileoff);
|
||||
sg->filesize = ByteSwap(sg->filesize);
|
||||
|
||||
sg->maxprot = NXSwapLong(sg->maxprot);
|
||||
sg->initprot = NXSwapLong(sg->initprot);
|
||||
sg->nsects = NXSwapLong(sg->nsects);
|
||||
sg->flags = NXSwapLong(sg->flags);
|
||||
sg->maxprot = ByteSwap(sg->maxprot);
|
||||
sg->initprot = ByteSwap(sg->initprot);
|
||||
sg->nsects = ByteSwap(sg->nsects);
|
||||
sg->flags = ByteSwap(sg->flags);
|
||||
}
|
||||
|
||||
void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
|
||||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
mh->magic = NXSwapLong(mh->magic);
|
||||
mh->cputype = NXSwapLong(mh->cputype);
|
||||
mh->cpusubtype = NXSwapLong(mh->cpusubtype);
|
||||
mh->filetype = NXSwapLong(mh->filetype);
|
||||
mh->ncmds = NXSwapLong(mh->ncmds);
|
||||
mh->sizeofcmds = NXSwapLong(mh->sizeofcmds);
|
||||
mh->flags = NXSwapLong(mh->flags);
|
||||
mh->reserved = NXSwapLong(mh->reserved);
|
||||
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);
|
||||
mh->reserved = ByteSwap(mh->reserved);
|
||||
}
|
||||
|
||||
void breakpad_swap_section_64(struct section_64 *s,
|
||||
|
@ -75,15 +76,15 @@ void breakpad_swap_section_64(struct section_64 *s,
|
|||
enum NXByteOrder target_byte_order)
|
||||
{
|
||||
for (uint32_t i = 0; i < nsects; i++) {
|
||||
s[i].addr = NXSwapLongLong(s[i].addr);
|
||||
s[i].size = NXSwapLongLong(s[i].size);
|
||||
s[i].addr = ByteSwap(s[i].addr);
|
||||
s[i].size = ByteSwap(s[i].size);
|
||||
|
||||
s[i].offset = NXSwapLong(s[i].offset);
|
||||
s[i].align = NXSwapLong(s[i].align);
|
||||
s[i].reloff = NXSwapLong(s[i].reloff);
|
||||
s[i].nreloc = NXSwapLong(s[i].nreloc);
|
||||
s[i].flags = NXSwapLong(s[i].flags);
|
||||
s[i].reserved1 = NXSwapLong(s[i].reserved1);
|
||||
s[i].reserved2 = NXSwapLong(s[i].reserved2);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
|
||||
#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
|
||||
|
|
|
@ -43,6 +43,7 @@ extern "C" { // necessary for Leopard
|
|||
#include <unistd.h>
|
||||
}
|
||||
|
||||
#include "common/mac/byteswap.h"
|
||||
#include "common/mac/macho_walker.h"
|
||||
#include "common/mac/macho_utilities.h"
|
||||
|
||||
|
@ -61,20 +62,11 @@ MachoWalker::~MachoWalker() {
|
|||
}
|
||||
|
||||
int MachoWalker::ValidateCPUType(int cpu_type) {
|
||||
// If the user didn't specify, try to use the local architecture. If that
|
||||
// fails, use the base type for the executable.
|
||||
// If the user didn't specify, use the local architecture.
|
||||
if (cpu_type == 0) {
|
||||
const NXArchInfo *arch = NXGetLocalArchInfo();
|
||||
if (arch)
|
||||
cpu_type = arch->cputype;
|
||||
else
|
||||
#if __ppc__
|
||||
cpu_type = CPU_TYPE_POWERPC;
|
||||
#elif __i386__
|
||||
cpu_type = CPU_TYPE_X86;
|
||||
#else
|
||||
#error Unknown architecture -- are you on a PDP-11?
|
||||
#endif
|
||||
assert(arch);
|
||||
cpu_type = arch->cputype;
|
||||
}
|
||||
|
||||
return cpu_type;
|
||||
|
@ -134,7 +126,7 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
|
|||
return false;
|
||||
|
||||
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
|
||||
header_cpu_type = NXSwapInt(header_cpu_type);
|
||||
header_cpu_type = ByteSwap(header_cpu_type);
|
||||
|
||||
if (valid_cpu_type != header_cpu_type)
|
||||
return false;
|
||||
|
|
|
@ -55,10 +55,10 @@ std::string ConvertToString(CFStringRef str) {
|
|||
|
||||
unsigned int IntegerValueAtIndex(string &str, unsigned int idx) {
|
||||
string digits("0123456789"), temp;
|
||||
unsigned int start = 0;
|
||||
unsigned int end;
|
||||
unsigned int found = 0;
|
||||
unsigned int result = 0;
|
||||
size_t start = 0;
|
||||
size_t end;
|
||||
size_t found = 0;
|
||||
size_t result = 0;
|
||||
|
||||
for (; found <= idx; ++found) {
|
||||
end = str.find_first_not_of(digits, start);
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
|
||||
// module.cc: Implement google_breakpad::Module. See module.h.
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include "common/module.h"
|
||||
|
||||
#include "common/linux/module.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
|
@ -38,10 +38,11 @@
|
|||
#ifndef COMMON_LINUX_MODULE_H__
|
||||
#define COMMON_LINUX_MODULE_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
|
@ -153,8 +154,14 @@ class Module {
|
|||
// for functions and lines will be written to the Breakpad symbol
|
||||
// file as offsets from this address. Construction initializes this
|
||||
// module's load address to zero: addresses written to the symbol
|
||||
// file will be the same as they appear in the File and Line
|
||||
// structures.
|
||||
// file will be the same as they appear in the Function, Line, and
|
||||
// StackFrameEntry structures.
|
||||
//
|
||||
// Note that this member function has no effect on addresses stored
|
||||
// in the data added to this module; the Write member function
|
||||
// simply subtracts off the load address from addresses before it
|
||||
// prints them. Only the last load address given before calling
|
||||
// Write is used.
|
||||
void SetLoadAddress(Address load_address);
|
||||
|
||||
// Add FUNCTION to the module.
|
||||
|
@ -223,7 +230,7 @@ class Module {
|
|||
// established by SetLoadAddress.
|
||||
bool Write(FILE *stream);
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
// Report an error that has occurred writing the symbol file, using
|
||||
// errno to find the appropriate cause. Return false.
|
|
@ -31,16 +31,16 @@
|
|||
|
||||
// module_unittest.cc: Unit tests for google_breakpad::Module.
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/module.h"
|
||||
#include "common/module.h"
|
||||
|
||||
using google_breakpad::Module;
|
||||
using std::string;
|
||||
|
@ -140,8 +140,6 @@ TEST(Write, RelativeLoadAddress) {
|
|||
FILE *f = checked_tmpfile();
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||
|
||||
// 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");
|
||||
|
@ -174,6 +172,10 @@ TEST(Write, RelativeLoadAddress) {
|
|||
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(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче