Add some unit tests for Linux WriteSymbolFile

This patch adds synth_elf::{StringTable,SymbolTable,ELF} classes to
produce in-memory ELF files to properly test the Linux symbol dumping
code. It also uses those classes to add some basic tests for
the WriteSymbolFile function.

R=jimb at http://breakpad.appspot.com/277001/show

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@794 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek 2011-07-06 17:05:59 +00:00
parent b2f96f314c
commit 3ca4a120de
16 changed files with 958 additions and 228 deletions

View File

@ -381,8 +381,11 @@ src_common_dumper_unittest_SOURCES = \
src/common/dwarf/dwarf2reader.cc \
src/common/dwarf/dwarf2reader_cfi_unittest.cc \
src/common/linux/dump_symbols.cc \
src/common/linux/dump_symbols_unittest.cc \
src/common/linux/elf_symbols_to_module.cc \
src/common/linux/elf_symbols_to_module_unittest.cc \
src/common/linux/synth_elf.cc \
src/common/linux/synth_elf_unittest.cc \
src/common/linux/file_id.cc \
src/common/linux/file_id_unittest.cc \
src/testing/gtest/src/gtest-all.cc \

View File

@ -451,8 +451,11 @@ am__src_common_dumper_unittest_SOURCES_DIST = \
src/common/dwarf/dwarf2reader.cc \
src/common/dwarf/dwarf2reader_cfi_unittest.cc \
src/common/linux/dump_symbols.cc \
src/common/linux/dump_symbols_unittest.cc \
src/common/linux/elf_symbols_to_module.cc \
src/common/linux/elf_symbols_to_module_unittest.cc \
src/common/linux/synth_elf.cc \
src/common/linux/synth_elf_unittest.cc \
src/common/linux/file_id.cc \
src/common/linux/file_id_unittest.cc \
src/testing/gtest/src/gtest-all.cc \
@ -481,8 +484,11 @@ am__src_common_dumper_unittest_SOURCES_DIST = \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-file_id.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/src_common_dumper_unittest-file_id_unittest.$(OBJEXT) \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/testing/gtest/src/src_common_dumper_unittest-gtest-all.$(OBJEXT) \
@ -1497,8 +1503,11 @@ TESTS_ENVIRONMENT =
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/dwarf/dwarf2reader_cfi_unittest.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/dump_symbols_unittest.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/elf_symbols_to_module_unittest.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/synth_elf_unittest.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/common/linux/file_id_unittest.cc \
@DISABLE_TOOLS_FALSE@@LINUX_HOST_TRUE@ src/testing/gtest/src/gtest-all.cc \
@ -2662,12 +2671,21 @@ src/common/dwarf/src_common_dumper_unittest-dwarf2reader_cfi_unittest.$(OBJEXT):
src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
src/common/linux/src_common_dumper_unittest-file_id.$(OBJEXT): \
src/common/linux/$(am__dirstamp) \
src/common/linux/$(DEPDIR)/$(am__dirstamp)
@ -3150,10 +3168,13 @@ mostlyclean-compile:
-rm -f src/common/linux/guid_creator.$(OBJEXT)
-rm -f src/common/linux/http_upload.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-dump_symbols.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-file_id.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-file_id_unittest.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-synth_elf.$(OBJEXT)
-rm -f src/common/linux/src_common_dumper_unittest-synth_elf_unittest.$(OBJEXT)
-rm -f src/common/md5.$(OBJEXT)
-rm -f src/common/module.$(OBJEXT)
-rm -f src/common/src_client_linux_linux_client_unittest-memory_unittest.$(OBJEXT)
@ -3384,10 +3405,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/guid_creator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/http_upload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/address_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_code_modules.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_source_line_resolver.Po@am__quote@
@ -4077,6 +4101,20 @@ src/common/linux/src_common_dumper_unittest-dump_symbols.obj: src/common/linux/d
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols.obj `if test -f 'src/common/linux/dump_symbols.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols.cc'; fi`
src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o: src/common/linux/dump_symbols_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o `test -f 'src/common/linux/dump_symbols_unittest.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols_unittest.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/dump_symbols_unittest.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.o `test -f 'src/common/linux/dump_symbols_unittest.cc' || echo '$(srcdir)/'`src/common/linux/dump_symbols_unittest.cc
src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj: src/common/linux/dump_symbols_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj `if test -f 'src/common/linux/dump_symbols_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols_unittest.cc'; fi`
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-dump_symbols_unittest.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/dump_symbols_unittest.cc' object='src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-dump_symbols_unittest.obj `if test -f 'src/common/linux/dump_symbols_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/dump_symbols_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/dump_symbols_unittest.cc'; fi`
src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o: src/common/linux/elf_symbols_to_module.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module.o `test -f 'src/common/linux/elf_symbols_to_module.cc' || echo '$(srcdir)/'`src/common/linux/elf_symbols_to_module.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-elf_symbols_to_module.Po
@ -4105,6 +4143,34 @@ src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj:
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-elf_symbols_to_module_unittest.obj `if test -f 'src/common/linux/elf_symbols_to_module_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/elf_symbols_to_module_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/elf_symbols_to_module_unittest.cc'; fi`
src/common/linux/src_common_dumper_unittest-synth_elf.o: src/common/linux/synth_elf.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf.o `test -f 'src/common/linux/synth_elf.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/synth_elf.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf.o `test -f 'src/common/linux/synth_elf.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf.cc
src/common/linux/src_common_dumper_unittest-synth_elf.obj: src/common/linux/synth_elf.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf.obj `if test -f 'src/common/linux/synth_elf.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf.cc'; fi`
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/synth_elf.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf.obj `if test -f 'src/common/linux/synth_elf.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf.cc'; fi`
src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o: src/common/linux/synth_elf_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o `test -f 'src/common/linux/synth_elf_unittest.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf_unittest.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/synth_elf_unittest.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.o `test -f 'src/common/linux/synth_elf_unittest.cc' || echo '$(srcdir)/'`src/common/linux/synth_elf_unittest.cc
src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj: src/common/linux/synth_elf_unittest.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj `if test -f 'src/common/linux/synth_elf_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf_unittest.cc'; fi`
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-synth_elf_unittest.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/common/linux/synth_elf_unittest.cc' object='src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o src/common/linux/src_common_dumper_unittest-synth_elf_unittest.obj `if test -f 'src/common/linux/synth_elf_unittest.cc'; then $(CYGPATH_W) 'src/common/linux/synth_elf_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/src/common/linux/synth_elf_unittest.cc'; fi`
src/common/linux/src_common_dumper_unittest-file_id.o: src/common/linux/file_id.cc
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_common_dumper_unittest_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT src/common/linux/src_common_dumper_unittest-file_id.o -MD -MP -MF src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo -c -o src/common/linux/src_common_dumper_unittest-file_id.o `test -f 'src/common/linux/file_id.cc' || echo '$(srcdir)/'`src/common/linux/file_id.cc
@am__fastdepCXX_TRUE@ $(am__mv) src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Tpo src/common/linux/$(DEPDIR)/src_common_dumper_unittest-file_id.Po

View File

@ -40,6 +40,7 @@
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <algorithm>
#include <set>

View File

@ -34,6 +34,8 @@
#include "common/dwarf_line_to_module.h"
#include <stdio.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
// it until we actually have to deal with DWARF on Windows.

View File

@ -46,6 +46,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <set>
#include <string>
#include <utility>
@ -721,25 +722,32 @@ std::string BaseFileName(const std::string &filename) {
namespace google_breakpad {
bool WriteSymbolFile(const std::string &obj_file,
const std::string &debug_dir, FILE *sym_file) {
MmapWrapper map_wrapper;
ElfW(Ehdr) *elf_header = NULL;
if (!LoadELF(obj_file, &map_wrapper, &elf_header))
// Not explicitly exported, but not static so it can be used in unit tests.
// Ideally obj_file would be const, but internally this code does write
// to some ELF header fields to make its work simpler.
bool WriteSymbolFileInternal(uint8_t* obj_file,
const std::string &obj_filename,
const std::string &debug_dir,
std::ostream &sym_stream) {
ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_file);
if (!IsValidElf(elf_header)) {
fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
return false;
}
unsigned char identifier[16];
google_breakpad::FileID file_id(obj_file.c_str());
if (!file_id.ElfFileIdentifierFromMappedFile(elf_header, identifier)) {
if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
identifier)) {
fprintf(stderr, "%s: unable to generate file identifier\n",
obj_file.c_str());
obj_filename.c_str());
return false;
}
const char *architecture = ElfArchitecture(elf_header);
if (!architecture) {
fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
obj_file.c_str(), elf_header->e_machine);
obj_filename.c_str(), elf_header->e_machine);
return false;
}
@ -748,13 +756,13 @@ bool WriteSymbolFile(const std::string &obj_file,
if (!ElfEndianness(elf_header, &big_endian))
return false;
std::string name = BaseFileName(obj_file);
std::string name = BaseFileName(obj_filename);
std::string os = "Linux";
std::string id = FormatIdentifier(identifier);
LoadSymbolsInfo info(debug_dir);
Module module(name, os, architecture, id);
if (!LoadSymbols(obj_file, big_endian, elf_header, !debug_dir.empty(),
if (!LoadSymbols(obj_filename, big_endian, elf_header, !debug_dir.empty(),
&info, &module)) {
const std::string debuglink_file = info.debuglink_file();
if (debuglink_file.empty())
@ -777,7 +785,7 @@ bool WriteSymbolFile(const std::string &obj_file,
fprintf(stderr, "%s with ELF machine architecture %s does not match "
"%s with ELF architecture %s\n",
debuglink_file.c_str(), debug_architecture,
obj_file.c_str(), architecture);
obj_filename.c_str(), architecture);
return false;
}
@ -786,7 +794,7 @@ bool WriteSymbolFile(const std::string &obj_file,
return false;
if (debug_big_endian != big_endian) {
fprintf(stderr, "%s and %s does not match in endianness\n",
obj_file.c_str(), debuglink_file.c_str());
obj_filename.c_str(), debuglink_file.c_str());
return false;
}
@ -795,10 +803,22 @@ bool WriteSymbolFile(const std::string &obj_file,
return false;
}
}
if (!module.Write(sym_file))
if (!module.Write(sym_stream))
return false;
return true;
}
bool WriteSymbolFile(const std::string &obj_file,
const std::string &debug_dir,
std::ostream &sym_stream) {
MmapWrapper map_wrapper;
ElfW(Ehdr) *elf_header = NULL;
if (!LoadELF(obj_file, &map_wrapper, &elf_header))
return false;
return WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(elf_header),
obj_file, debug_dir, sym_stream);
}
} // namespace google_breakpad

View File

@ -35,19 +35,19 @@
#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__
#define COMMON_LINUX_DUMP_SYMBOLS_H__
#include <stdio.h>
#include <iostream>
#include <string>
namespace google_breakpad {
// Find all the debugging information in OBJ_FILE, an ELF executable
// or shared library, and write it to SYM_FILE in the Breakpad symbol
// or shared library, and write it to SYM_STREAM in the Breakpad symbol
// file format.
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
// then look for the debug file in DEBUG_DIR.
bool WriteSymbolFile(const std::string &obj_file,
const std::string &debug_dir, FILE *sym_file);
const std::string &debug_dir,
std::ostream &sym_stream);
} // namespace google_breakpad

View File

@ -0,0 +1,162 @@
// Copyright (c) 2011 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
// dump_symbols_unittest.cc:
// Unittests for google_breakpad::DumpSymbols
#include <elf.h>
#include <link.h>
#include <stdio.h>
#include <sstream>
#include <string>
#include <vector>
#include "breakpad_googletest_includes.h"
#include "common/linux/synth_elf.h"
namespace google_breakpad {
bool WriteSymbolFileInternal(uint8_t* obj_file,
const std::string &obj_filename,
const std::string &debug_dir,
std::ostream &sym_stream);
}
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
using google_breakpad::WriteSymbolFileInternal;
using std::string;
using std::stringstream;
using std::vector;
using ::testing::Test;
class DumpSymbols : public Test {
public:
void GetElfContents(ELF& elf) {
string contents;
ASSERT_TRUE(elf.GetContents(&contents));
ASSERT_LT(0, contents.size());
elfdata_v.clear();
elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
elfdata = &elfdata_v[0];
}
vector<uint8_t> elfdata_v;
uint8_t* elfdata;
};
TEST_F(DumpSymbols, Invalid) {
Elf32_Ehdr header;
memset(&header, 0, sizeof(header));
stringstream s;
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header),
"foo",
"",
s));
}
// TODO(ted): Fix the dump_symbols code to deal with cross-word-size
// ELF files.
#if __ELF_NATIVE_CLASS == 32
TEST_F(DumpSymbols, SimplePublic32) {
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
// Add a public symbol.
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, 4, table);
syms.AddSymbol("superfunc", (uint32_t)0x1000, (uint32_t)0x10,
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
elf.AddSection(".dynsym", syms,
SHT_DYNSYM, // type
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(Elf32_Sym)); // entsize
elf.Finish();
GetElfContents(elf);
stringstream s;
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
"foo",
"",
s));
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
}
#endif
#if __ELF_NATIVE_CLASS == 64
TEST_F(DumpSymbols, SimplePublic64) {
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
// Add a public symbol.
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, 8, table);
syms.AddSymbol("superfunc", (uint64_t)0x1000, (uint64_t)0x10,
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
SHN_UNDEF + 1);
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
elf.AddSection(".dynsym", syms,
SHT_DYNSYM, // type
SHF_ALLOC, // flags
0, // addr
index, // link
sizeof(Elf64_Sym)); // entsize
elf.Finish();
GetElfContents(elf);
stringstream s;
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
"foo",
"",
s));
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
}
#endif

View File

@ -39,14 +39,15 @@
#include "breakpad_googletest_includes.h"
#include "common/linux/elf_symbols_to_module.h"
#include "common/linux/synth_elf.h"
#include "common/module.h"
#include "common/test_assembler.h"
using google_breakpad::Module;
using google_breakpad::synth_elf::StringTable;
using google_breakpad::test_assembler::Endianness;
using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::kUnsetEndian;
using google_breakpad::test_assembler::Label;
using google_breakpad::test_assembler::Section;
using ::testing::Test;
@ -54,70 +55,6 @@ using ::testing::TestWithParam;
using std::string;
using std::vector;
// String Tables are used in ELF headers, add a class
// for convenience.
class StringTable : public Section {
public:
StringTable(Endianness endianness = kUnsetEndian)
: Section(endianness) {
start() = 0;
empty_string = Add("");
}
// Add the string s to the string table, and return
// a label containing the offset into the string table
// at which it was added.
Label Add(const string& s) {
Label string_label(Here());
AppendCString(s);
return string_label;
}
// All StringTables contain an empty string as their first
// entry.
Label empty_string;
};
class StringTableTest : public Test {
public:
StringTableTest() : table(kLittleEndian) {}
StringTable table;
};
TEST_F(StringTableTest, Empty) {
string contents;
ASSERT_TRUE(table.GetContents(&contents));
const string kExpectedContents = "\0";
EXPECT_EQ(0,
memcmp(kExpectedContents.c_str(), contents.c_str(), table.Size()));
ASSERT_TRUE(table.empty_string.IsKnownConstant());
EXPECT_EQ(0, table.empty_string.Value());
}
TEST_F(StringTableTest, Basic) {
const string s1("table fills with strings");
const string s2("offsets preserved as labels");
const string s3("verified with tests");
const string kExpectedContents =
"\0table fills with strings\0"
"offsets preserved as labels\0"
"verified with tests\0";
Label l1(table.Add(s1));
Label l2(table.Add(s2));
Label l3(table.Add(s3));
string contents;
ASSERT_TRUE(table.GetContents(&contents));
EXPECT_EQ(0,
memcmp(kExpectedContents.c_str(), contents.c_str(), table.Size()));
// empty_string is at zero, other strings start at 1.
ASSERT_TRUE(l1.IsKnownConstant());
EXPECT_EQ(1, l1.Value());
// Each string has an extra byte for a trailing null.
EXPECT_EQ(1 + s1.length() + 1, l2.Value());
EXPECT_EQ(1 + s1.length() + 1 + s2.length() + 1, l3.Value());
}
class ELFSymbolsToModuleTestFixture {
public:
ELFSymbolsToModuleTestFixture(Endianness endianness,

View File

@ -0,0 +1,174 @@
#include "common/linux/synth_elf.h"
#include <assert.h>
#include <elf.h>
#include <stdio.h>
namespace google_breakpad {
namespace synth_elf {
ELF::ELF(uint16_t machine,
uint8_t file_class,
Endianness endianness)
: Section(endianness),
addr_size_(file_class == ELFCLASS64 ? 8 : 4),
program_count_(0),
section_count_(0),
section_header_table_(endianness),
section_header_strings_(endianness) {
// Could add support for more machine types here if needed.
assert(machine == EM_386 ||
machine == EM_X86_64 ||
machine == EM_ARM);
assert(file_class == ELFCLASS32 || file_class == ELFCLASS64);
start() = 0;
// Add ELF header
// e_ident
// EI_MAG0...EI_MAG3
D8(ELFMAG0);
D8(ELFMAG1);
D8(ELFMAG2);
D8(ELFMAG3);
// EI_CLASS
D8(file_class);
// EI_DATA
D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB);
// EI_VERSION
D8(EV_CURRENT);
// EI_OSABI
D8(ELFOSABI_SYSV);
// EI_ABIVERSION
D8(0);
// EI_PAD
Append(7, 0);
assert(Size() == EI_NIDENT);
// e_type
D16(ET_EXEC); //TODO: allow passing ET_DYN?
// e_machine
D16(machine);
// e_version
D32(EV_CURRENT);
// e_entry
Append(endianness, addr_size_, 0);
// e_phoff
Append(endianness, addr_size_, program_header_label_);
// e_shoff
Append(endianness, addr_size_, section_header_label_);
// e_flags
D32(0);
// e_ehsize
D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
// e_phentsize
D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr));
// e_phnum
D16(program_count_label_);
// e_shentsize
D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
// e_shnum
D16(section_count_label_);
// e_shstrndx
D16(section_header_string_index_);
// Add an empty section for SHN_UNDEF.
Section shn_undef;
AddSection("", shn_undef, SHT_NULL);
}
int ELF::AddSection(const string& name, const Section& section,
uint32_t type, uint32_t flags, uint64_t addr,
uint32_t link, uint64_t entsize, uint64_t offset) {
Label offset_label;
Label string_label(section_header_strings_.Add(name));
size_t size = section.Size();
int index = section_count_;
++section_count_;
section_header_table_
// sh_name
.D32(string_label)
// sh_type
.D32(type)
// sh_flags
.Append(endianness(), addr_size_, flags)
// sh_addr
.Append(endianness(), addr_size_, addr)
// sh_offset
.Append(endianness(), addr_size_, offset_label)
// sh_size
.Append(endianness(), addr_size_, size)
// sh_link
.D32(link)
// sh_info
.D32(0)
// sh_addralign
.Append(endianness(), addr_size_, 0)
// sh_entsize
.Append(endianness(), addr_size_, entsize);
// NULL and NOBITS sections have no content, so they
// don't need to be written to the file.
if (type == SHT_NULL) {
offset_label = 0;
} else if (type == SHT_NOBITS) {
offset_label = offset;
} else {
Mark(&offset_label);
Append(section);
Align(4);
}
return index;
}
void ELF::Finish() {
// Add the section header string table at the end.
section_header_string_index_ = section_count_;
//printf(".shstrtab size: %ld\n", section_header_strings_.Size());
AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
//printf("section_count_: %ld, sections_.size(): %ld\n",
// section_count_, sections_.size());
section_count_label_ = section_count_;
program_count_label_ = program_count_;
// TODO: allow adding entries to program header table
program_header_label_ = 0;
// Section header table starts here.
Mark(&section_header_label_);
Append(section_header_table_);
}
SymbolTable::SymbolTable(Endianness endianness,
size_t addr_size,
StringTable& table) : Section(endianness),
addr_size_(addr_size),
table_(table) {
assert(addr_size_ == 4 || addr_size_ == 8);
}
void SymbolTable::AddSymbol(const string& name, uint32_t value,
uint32_t size, unsigned info, uint16_t shndx) {
assert(addr_size_ == 4);
D32(table_.Add(name));
D32(value);
D32(size);
D8(info);
D8(0); // other
D16(shndx);
}
void SymbolTable::AddSymbol(const string& name, uint64_t value,
uint64_t size, unsigned info, uint16_t shndx) {
assert(addr_size_ == 8);
D32(table_.Add(name));
D8(info);
D8(0); // other
D16(shndx);
D64(value);
D64(size);
}
} // namespace synth_elf
} // namespace google_breakpad

View File

@ -0,0 +1,155 @@
// -*- mode: C++ -*-
// Copyright (c) 2011, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
// synth_elf.h: Interface to synth_elf::ELF: fake ELF generator.
#ifndef COMMON_LINUX_SYNTH_ELF_H_
#define COMMON_LINUX_SYNTH_ELF_H_
#include "common/test_assembler.h"
#include <list>
#include <map>
#include <string>
#include <utility>
namespace google_breakpad {
namespace synth_elf {
using std::list;
using std::map;
using std::pair;
using std::string;
using test_assembler::Endianness;
using test_assembler::kLittleEndian;
using test_assembler::kUnsetEndian;
using test_assembler::Label;
using test_assembler::Section;
// String tables are common in ELF headers, so subclass Section
// to make them easy to generate.
class StringTable : public Section {
public:
StringTable(Endianness endianness = kUnsetEndian)
: Section(endianness) {
start() = 0;
empty_string = Add("");
}
// Add the string s to the string table, and return
// a label containing the offset into the string table
// at which it was added.
Label Add(const string& s) {
if (strings_.find(s) != strings_.end())
return strings_[s];
Label string_label(Here());
AppendCString(s);
strings_[s] = string_label;
return string_label;
}
// All StringTables contain an empty string as their first
// entry.
Label empty_string;
// Avoid inserting duplicate strings.
map<string,Label> strings_;
};
// A Section representing an entire ELF file.
class ELF : public Section {
public:
ELF(uint16_t machine, // EM_386, etc
uint8_t file_class, // ELFCLASS{32,64}
Endianness endianness = kLittleEndian);
// Add the Section section to the section header table and append it
// to the file. Returns the index of the section in the section
// header table.
int AddSection(const string& name, const Section& section,
uint32_t type, uint32_t flags = 0, uint64_t addr = 0,
uint32_t link = 0, uint64_t entsize = 0, uint64_t offset = 0);
// Write out all data. GetContents may be used after this.
void Finish();
private:
// Size of an address, in bytes.
const size_t addr_size_;
// Offset to the program header table.
Label program_header_label_;
// Number of entries in the program header table.
int program_count_;
Label program_count_label_;
// Offset to the section header table.
Label section_header_label_;
// Number of entries in the section header table.
int section_count_;
Label section_count_label_;
// The section header table itself.
Section section_header_table_;
// Index of the section header string table in the section
// header table.
Label section_header_string_index_;
// Section containing the names of section header table entries.
StringTable section_header_strings_;
};
// A class to build .symtab or .dynsym sections.
class SymbolTable : public Section {
public:
// table is the StringTable that contains symbol names. The caller
// must ensure that it remains alive for the life of the
// SymbolTable.
SymbolTable(Endianness endianness, size_t addr_size, StringTable& table);
// Add an Elf32_Sym.
void AddSymbol(const string& name, uint32_t value,
uint32_t size, unsigned info, uint16_t shndx);
// Add an Elf64_Sym.
void AddSymbol(const string& name, uint64_t value,
uint64_t size, unsigned info, uint16_t shndx);
private:
size_t addr_size_;
StringTable& table_;
};
} // namespace synth_elf
} // namespace google_breakpad
#endif // COMMON_LINUX_SYNTH_ELF_H_

View File

@ -0,0 +1,265 @@
// Copyright (c) 2011 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
// synth_elf_unittest.cc:
// Unittests for google_breakpad::synth_elf::ELF
#include <elf.h>
#include "breakpad_googletest_includes.h"
#include "common/linux/synth_elf.h"
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable;
using google_breakpad::test_assembler::Endianness;
using google_breakpad::test_assembler::kBigEndian;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Label;
using std::string;
using ::testing::Test;
class StringTableTest : public Test {
public:
StringTableTest() : table(kLittleEndian) {}
StringTable table;
};
TEST_F(StringTableTest, Empty) {
EXPECT_EQ(1, table.Size());
string contents;
ASSERT_TRUE(table.GetContents(&contents));
const char* kExpectedContents = "\0";
EXPECT_EQ(0, memcmp(kExpectedContents,
contents.c_str(),
contents.size()));
ASSERT_TRUE(table.empty_string.IsKnownConstant());
EXPECT_EQ(0, table.empty_string.Value());
}
TEST_F(StringTableTest, Basic) {
const string s1("table fills with strings");
const string s2("offsets preserved as labels");
const string s3("verified with tests");
const char* kExpectedContents =
"\0table fills with strings\0"
"offsets preserved as labels\0"
"verified with tests\0";
Label l1(table.Add(s1));
Label l2(table.Add(s2));
Label l3(table.Add(s3));
string contents;
ASSERT_TRUE(table.GetContents(&contents));
EXPECT_EQ(0, memcmp(kExpectedContents,
contents.c_str(),
contents.size()));
// empty_string is at zero, other strings start at 1.
ASSERT_TRUE(l1.IsKnownConstant());
EXPECT_EQ(1, l1.Value());
// Each string has an extra byte for a trailing null.
EXPECT_EQ(1 + s1.length() + 1, l2.Value());
EXPECT_EQ(1 + s1.length() + 1 + s2.length() + 1, l3.Value());
}
TEST_F(StringTableTest, Duplicates) {
const string s1("string 1");
const string s2("string 2");
const string s3("");
const char* kExpectedContents = "\0string 1\0string 2\0";
Label l1(table.Add(s1));
Label l2(table.Add(s2));
// Adding strings twice should return the same Label.
Label l3(table.Add(s3));
Label l4(table.Add(s2));
string contents;
ASSERT_TRUE(table.GetContents(&contents));
EXPECT_EQ(0, memcmp(kExpectedContents,
contents.c_str(),
contents.size()));
EXPECT_EQ(0, table.empty_string.Value());
EXPECT_EQ(table.empty_string.Value(), l3.Value());
EXPECT_EQ(l2.Value(), l4.Value());
}
class SymbolTableTest : public Test {};
TEST_F(SymbolTableTest, Simple32) {
StringTable table(kLittleEndian);
SymbolTable syms(kLittleEndian, 4, table);
const string kFuncName1 = "superfunc";
const uint32_t kFuncAddr1 = 0x10001000;
const uint32_t kFuncSize1 = 0x10;
const string kFuncName2 = "awesomefunc";
const uint32_t kFuncAddr2 = 0x20002000;
const uint32_t kFuncSize2 = 0x2f;
const string kFuncName3 = "megafunc";
const uint32_t kFuncAddr3 = 0x30003000;
const uint32_t kFuncSize3 = 0x3c;
syms.AddSymbol(kFuncName1, kFuncAddr1, kFuncSize1,
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
SHN_UNDEF + 1);
syms.AddSymbol(kFuncName2, kFuncAddr2, kFuncSize2,
ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
SHN_UNDEF + 2);
syms.AddSymbol(kFuncName3, kFuncAddr3, kFuncSize3,
ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
SHN_UNDEF + 3);
const char kExpectedStringTable[] = "\0superfunc\0awesomefunc\0megafunc";
const size_t kExpectedStringTableSize = sizeof(kExpectedStringTable);
EXPECT_EQ(kExpectedStringTableSize, table.Size());
string table_contents;
table.GetContents(&table_contents);
EXPECT_EQ(0, memcmp(kExpectedStringTable,
table_contents.c_str(),
table_contents.size()));
const uint8_t kExpectedSymbolContents[] = {
// Symbol 1
0x01, 0x00, 0x00, 0x00, // name
0x00, 0x10, 0x00, 0x10, // value
0x10, 0x00, 0x00, 0x00, // size
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), // info
0x00, // other
0x01, 0x00, // shndx
// Symbol 2
0x0B, 0x00, 0x00, 0x00, // name
0x00, 0x20, 0x00, 0x20, // value
0x2f, 0x00, 0x00, 0x00, // size
ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info
0x00, // other
0x02, 0x00, // shndx
// Symbol 3
0x17, 0x00, 0x00, 0x00, // name
0x00, 0x30, 0x00, 0x30, // value
0x3c, 0x00, 0x00, 0x00, // size
ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info
0x00, // other
0x03, 0x00, // shndx
};
const size_t kExpectedSymbolSize = sizeof(kExpectedSymbolContents);
EXPECT_EQ(kExpectedSymbolSize, syms.Size());
string symbol_contents;
syms.GetContents(&symbol_contents);
EXPECT_EQ(0, memcmp(kExpectedSymbolContents,
symbol_contents.c_str(),
symbol_contents.size()));
}
class BasicElf : public Test {};
// Doesn't seem worthwhile writing the tests to be endian-independent
// when they're unlikely to ever be run on big-endian systems.
#if defined(__i386__) || defined(__x86_64__)
TEST_F(BasicElf, EmptyLE32) {
const size_t kStringTableSize = sizeof("\0.shstrtab");
const size_t kStringTableAlign = 4 - kStringTableSize % 4;
const size_t kExpectedSize = sizeof(Elf32_Ehdr) +
// Two sections, SHT_NULL + the section header string table.
2 * sizeof(Elf32_Shdr) +
kStringTableSize + kStringTableAlign;
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
elf.Finish();
EXPECT_EQ(kExpectedSize, elf.Size());
string contents;
ASSERT_TRUE(elf.GetContents(&contents));
ASSERT_EQ(kExpectedSize, contents.size());
const Elf32_Ehdr* header =
reinterpret_cast<const Elf32_Ehdr*>(contents.data());
const uint8_t kIdent[] = {
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
0, 0, 0, 0, 0, 0, 0, 0
};
EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent)));
EXPECT_EQ(ET_EXEC, header->e_type);
EXPECT_EQ(EM_386, header->e_machine);
EXPECT_EQ(EV_CURRENT, header->e_version);
EXPECT_EQ(0, header->e_entry);
EXPECT_EQ(0, header->e_phoff);
EXPECT_EQ(sizeof(Elf32_Ehdr) + kStringTableSize + kStringTableAlign,
header->e_shoff);
EXPECT_EQ(0, header->e_flags);
EXPECT_EQ(sizeof(Elf32_Ehdr), header->e_ehsize);
EXPECT_EQ(sizeof(Elf32_Phdr), header->e_phentsize);
EXPECT_EQ(0, header->e_phnum);
EXPECT_EQ(sizeof(Elf32_Shdr), header->e_shentsize);
EXPECT_EQ(2, header->e_shnum);
EXPECT_EQ(1, header->e_shstrndx);
}
TEST_F(BasicElf, EmptyLE64) {
const size_t kStringTableSize = sizeof("\0.shstrtab");
const size_t kStringTableAlign = 4 - kStringTableSize % 4;
const size_t kExpectedSize = sizeof(Elf64_Ehdr) +
// Two sections, SHT_NULL + the section header string table.
2 * sizeof(Elf64_Shdr) +
kStringTableSize + kStringTableAlign;
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
elf.Finish();
EXPECT_EQ(kExpectedSize, elf.Size());
string contents;
ASSERT_TRUE(elf.GetContents(&contents));
ASSERT_EQ(kExpectedSize, contents.size());
const Elf64_Ehdr* header =
reinterpret_cast<const Elf64_Ehdr*>(contents.data());
const uint8_t kIdent[] = {
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
0, 0, 0, 0, 0, 0, 0, 0
};
EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent)));
EXPECT_EQ(ET_EXEC, header->e_type);
EXPECT_EQ(EM_X86_64, header->e_machine);
EXPECT_EQ(EV_CURRENT, header->e_version);
EXPECT_EQ(0, header->e_entry);
EXPECT_EQ(0, header->e_phoff);
EXPECT_EQ(sizeof(Elf64_Ehdr) + kStringTableSize + kStringTableAlign,
header->e_shoff);
EXPECT_EQ(0, header->e_flags);
EXPECT_EQ(sizeof(Elf64_Ehdr), header->e_ehsize);
EXPECT_EQ(sizeof(Elf64_Phdr), header->e_phentsize);
EXPECT_EQ(0, header->e_phnum);
EXPECT_EQ(sizeof(Elf64_Shdr), header->e_shentsize);
EXPECT_EQ(2, header->e_shnum);
EXPECT_EQ(1, header->e_shstrndx);
}
#endif // defined(__i386__) || defined(__x86_64__)

View File

@ -35,10 +35,18 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
namespace google_breakpad {
using std::dec;
using std::endl;
using std::hex;
Module::Module(const string &name, const string &os,
const string &architecture, const string &id) :
name_(name),
@ -182,22 +190,20 @@ bool Module::ReportError() {
return false;
}
bool Module::WriteRuleMap(const RuleMap &rule_map, FILE *stream) {
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
for (RuleMap::const_iterator it = rule_map.begin();
it != rule_map.end(); it++) {
if (it != rule_map.begin() &&
0 > putc(' ', stream))
return false;
if (0 > fprintf(stream, "%s: %s", it->first.c_str(), it->second.c_str()))
return false;
if (it != rule_map.begin())
stream << ' ';
stream << it->first << ": " << it->second;
}
return true;
return stream.good();
}
bool Module::Write(FILE *stream) {
if (0 > fprintf(stream, "MODULE %s %s %s %s\n",
os_.c_str(), architecture_.c_str(), id_.c_str(),
name_.c_str()))
bool Module::Write(std::ostream &stream) {
stream << "MODULE " << os_ << " " << architecture_ << " "
<< id_ << " " << name_ << endl;
if (!stream.good())
return ReportError();
AssignSourceIds();
@ -207,8 +213,8 @@ bool Module::Write(FILE *stream) {
file_it != files_.end(); file_it++) {
File *file = file_it->second;
if (file->source_id >= 0) {
if (0 > fprintf(stream, "FILE %d %s\n",
file->source_id, file->name.c_str()))
stream << "FILE " << file->source_id << " " << file->name << endl;
if (!stream.good())
return ReportError();
}
}
@ -217,29 +223,35 @@ bool Module::Write(FILE *stream) {
for (FunctionSet::const_iterator func_it = functions_.begin();
func_it != functions_.end(); func_it++) {
Function *func = *func_it;
if (0 > fprintf(stream, "FUNC %llx %llx %llx %s\n",
(unsigned long long) (func->address - load_address_),
(unsigned long long) func->size,
(unsigned long long) func->parameter_size,
func->name.c_str()))
stream << "FUNC " << hex
<< (func->address - load_address_) << " "
<< func->size << " "
<< func->parameter_size << " "
<< func->name << dec << endl;
if (!stream.good())
return ReportError();
for (vector<Line>::iterator line_it = func->lines.begin();
line_it != func->lines.end(); line_it++)
if (0 > fprintf(stream, "%llx %llx %d %d\n",
(unsigned long long) (line_it->address - load_address_),
(unsigned long long) line_it->size,
line_it->number,
line_it->file->source_id))
line_it != func->lines.end(); line_it++) {
stream << hex
<< (line_it->address - load_address_) << " "
<< line_it->size << " "
<< dec
<< line_it->number << " "
<< line_it->file->source_id << endl;
if (!stream.good())
return ReportError();
}
}
// Write out 'PUBLIC' records.
for (ExternSet::const_iterator extern_it = externs_.begin();
extern_it != externs_.end(); extern_it++) {
Extern *ext = *extern_it;
if (0 > fprintf(stream, "PUBLIC %llx 0 %s\n",
(unsigned long long) (ext->address - load_address_),
ext->name.c_str()))
stream << "PUBLIC " << hex
<< (ext->address - load_address_) << " 0 "
<< ext->name << dec << endl;
if (!stream.good())
return ReportError();
}
@ -248,21 +260,25 @@ bool Module::Write(FILE *stream) {
for (frame_it = stack_frame_entries_.begin();
frame_it != stack_frame_entries_.end(); frame_it++) {
StackFrameEntry *entry = *frame_it;
if (0 > fprintf(stream, "STACK CFI INIT %llx %llx ",
(unsigned long long) entry->address - load_address_,
(unsigned long long) entry->size)
|| !WriteRuleMap(entry->initial_rules, stream)
|| 0 > putc('\n', stream))
stream << "STACK CFI INIT " << hex
<< (entry->address - load_address_) << " "
<< entry->size << " " << dec;
if (!stream.good()
|| !WriteRuleMap(entry->initial_rules, stream))
return ReportError();
stream << endl;
// Write out this entry's delta rules as 'STACK CFI' records.
for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
delta_it != entry->rule_changes.end(); delta_it++) {
if (0 > fprintf(stream, "STACK CFI %llx ",
(unsigned long long) delta_it->first - load_address_)
|| !WriteRuleMap(delta_it->second, stream)
|| 0 > putc('\n', stream))
stream << "STACK CFI " << hex
<< (delta_it->first - load_address_) << " " << dec;
if (!stream.good()
|| !WriteRuleMap(delta_it->second, stream))
return ReportError();
stream << endl;
}
}

View File

@ -38,8 +38,7 @@
#ifndef COMMON_LINUX_MODULE_H__
#define COMMON_LINUX_MODULE_H__
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <string>
@ -264,7 +263,7 @@ class Module {
// - the functions added via AddFunctions, each with its lines.
// Addresses in the output are all relative to the load address
// established by SetLoadAddress.
bool Write(FILE *stream);
bool Write(std::ostream &stream);
private:
@ -275,7 +274,7 @@ class Module {
// Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI'
// records, without a final newline. Return true if all goes well;
// if an error occurs, return false, and leave errno set.
static bool WriteRuleMap(const RuleMap &rule_map, FILE *stream);
static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream);
// Module header entries.
string name_, os_, architecture_, id_;

View File

@ -37,6 +37,7 @@
#include <string.h>
#include <algorithm>
#include <sstream>
#include <string>
#include "breakpad_googletest_includes.h"
@ -44,53 +45,10 @@
using google_breakpad::Module;
using std::string;
using std::stringstream;
using std::vector;
using testing::ContainerEq;
// Return a FILE * referring to a temporary file that will be deleted
// automatically when the stream is closed or the program exits.
static FILE *checked_tmpfile() {
FILE *f = tmpfile();
if (!f) {
fprintf(stderr, "error creating temporary file: %s\n", strerror(errno));
exit(1);
}
return f;
}
// Read from STREAM until end of file, and return the contents as a
// string.
static string checked_read(FILE *stream) {
string contents;
int c;
while ((c = getc(stream)) != EOF)
contents.push_back(c);
if (ferror(stream)) {
fprintf(stderr, "error reading temporary file contents: %s\n",
strerror(errno));
exit(1);
}
return contents;
}
// Apply 'fflush' to STREAM, and check for errors.
static void checked_fflush(FILE *stream) {
if (fflush(stream) == EOF) {
fprintf(stderr, "error flushing temporary file stream: %s\n",
strerror(errno));
exit(1);
}
}
// Apply 'fclose' to STREAM, and check for errors.
static void checked_fclose(FILE *stream) {
if (fclose(stream) == EOF) {
fprintf(stderr, "error closing temporary file stream: %s\n",
strerror(errno));
exit(1);
}
}
static Module::Function *generate_duplicate_function(const string &name) {
const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL;
const Module::Address DUP_SIZE = 0x200b26e605f99071LL;
@ -110,19 +68,16 @@ static Module::Function *generate_duplicate_function(const string &name) {
#define MODULE_ID "id-string"
TEST(Write, Header) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
contents.c_str());
}
TEST(Write, OneLineFunc) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
Module::File *file = m.FindFile("file_name.cc");
@ -136,11 +91,8 @@ TEST(Write, OneLineFunc) {
function->lines.push_back(line);
m.AddFunction(function);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 file_name.cc\n"
"FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a"
@ -150,7 +102,7 @@ TEST(Write, OneLineFunc) {
}
TEST(Write, RelativeLoadAddress) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Some source files. We will expect to see them in lexicographic order.
@ -189,11 +141,8 @@ TEST(Write, RelativeLoadAddress) {
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename-a.cc\n"
"FILE 1 filename-b.cc\n"
@ -247,12 +196,9 @@ TEST(Write, OmitUnusedFiles) {
EXPECT_STREQ("filename3", vec[2]->name.c_str());
EXPECT_NE(-1, vec[2]->source_id);
FILE *f = checked_tmpfile();
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
stringstream s;
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename1\n"
"FILE 1 filename3\n"
@ -264,7 +210,7 @@ TEST(Write, OmitUnusedFiles) {
}
TEST(Construct, AddFunctions) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two functions.
@ -287,11 +233,8 @@ TEST(Construct, AddFunctions) {
m.AddFunctions(vec.begin(), vec.end());
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
" _and_void\n"
@ -308,7 +251,7 @@ TEST(Construct, AddFunctions) {
}
TEST(Construct, AddFrames) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// First STACK CFI entry, with no initial rules or deltas.
@ -342,11 +285,8 @@ TEST(Construct, AddFrames) {
m.AddStackFrameEntry(entry3);
// Check that Write writes STACK CFI records properly.
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
"STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407"
@ -411,7 +351,7 @@ TEST(Construct, UniqueFiles) {
}
TEST(Construct, DuplicateFunctions) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two functions.
@ -421,11 +361,8 @@ TEST(Construct, DuplicateFunctions) {
m.AddFunction(function1);
m.AddFunction(function2);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
" _without_form\n",
@ -433,7 +370,7 @@ TEST(Construct, DuplicateFunctions) {
}
TEST(Construct, FunctionsWithSameAddress) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two functions.
@ -443,11 +380,8 @@ TEST(Construct, FunctionsWithSameAddress) {
m.AddFunction(function1);
m.AddFunction(function2);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
" _and_void\n"
@ -459,7 +393,7 @@ TEST(Construct, FunctionsWithSameAddress) {
// Externs should be written out as PUBLIC records, sorted by
// address.
TEST(Construct, Externs) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two externs.
@ -473,11 +407,8 @@ TEST(Construct, Externs) {
m.AddExtern(extern1);
m.AddExtern(extern2);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
MODULE_ID " " MODULE_NAME "\n"
@ -489,7 +420,7 @@ TEST(Construct, Externs) {
// Externs with the same address should only keep the first entry
// added.
TEST(Construct, DuplicateExterns) {
FILE *f = checked_tmpfile();
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
// Two externs.
@ -503,11 +434,8 @@ TEST(Construct, DuplicateExterns) {
m.AddExtern(extern1);
m.AddExtern(extern2);
m.Write(f);
checked_fflush(f);
rewind(f);
string contents = checked_read(f);
checked_fclose(f);
m.Write(s);
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
MODULE_ID " " MODULE_NAME "\n"

View File

@ -34,6 +34,7 @@
#include <assert.h>
#include <cxxabi.h>
#include <stdarg.h>
#include <stdio.h>
#include <algorithm>

View File

@ -27,6 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <stdio.h>
#include <string>
@ -46,7 +47,7 @@ int main(int argc, char **argv) {
if (argc == 3)
debug_dir = argv[2];
if (!WriteSymbolFile(binary, debug_dir, stdout)) {
if (!WriteSymbolFile(binary, debug_dir, std::cout)) {
fprintf(stderr, "Failed to write symbol file.\n");
return 1;
}