From fd38d48e6d5e56cb66b0fa0f7e25f840a83dac5c Mon Sep 17 00:00:00 2001 From: bryner Date: Mon, 11 Dec 2006 23:22:54 +0000 Subject: Add an abstract interface to SourceLineResolver, and allow any implementation to be used with MinidumpProcessor. The basic SourceLineResolver is now a public interface (#89) git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@83 4c0a9323-5329-0410-9bdc-e9ce6186880e --- Makefile.am | 28 +- Makefile.in | 97 ++-- src/common/windows/pdb_source_line_writer.h | 2 +- .../processor/basic_source_line_resolver.h | 84 +++ src/google_airbag/processor/minidump_processor.h | 5 +- .../processor/source_line_resolver_interface.h | 79 +++ src/google_airbag/processor/stackwalker.h | 14 +- src/processor/basic_source_line_resolver.cc | 561 +++++++++++++++++++++ .../basic_source_line_resolver_unittest.cc | 202 ++++++++ src/processor/minidump_processor.cc | 8 +- src/processor/minidump_processor_unittest.cc | 5 +- src/processor/minidump_stackwalk.cc | 5 +- src/processor/source_line_resolver.cc | 561 --------------------- src/processor/source_line_resolver.h | 98 ---- src/processor/source_line_resolver_unittest.cc | 202 -------- src/processor/stackwalker.cc | 35 +- src/processor/stackwalker_ppc.cc | 5 +- src/processor/stackwalker_ppc.h | 3 +- src/processor/stackwalker_selftest.cc | 7 +- src/processor/stackwalker_x86.cc | 5 +- src/processor/stackwalker_x86.h | 3 +- 21 files changed, 1052 insertions(+), 957 deletions(-) create mode 100644 src/google_airbag/processor/basic_source_line_resolver.h create mode 100644 src/google_airbag/processor/source_line_resolver_interface.h create mode 100644 src/processor/basic_source_line_resolver.cc create mode 100644 src/processor/basic_source_line_resolver_unittest.cc delete mode 100644 src/processor/source_line_resolver.cc delete mode 100644 src/processor/source_line_resolver.h delete mode 100644 src/processor/source_line_resolver_unittest.cc diff --git a/Makefile.am b/Makefile.am index 6f1ca84e..ff45f10a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ lib_LTLIBRARIES = src/libairbag.la src_libairbag_la_SOURCES = \ src/google_airbag/common/airbag_types.h \ src/google_airbag/common/minidump_format.h \ + src/google_airbag/processor/basic_source_line_resolver.h \ src/google_airbag/processor/call_stack.h \ src/google_airbag/processor/code_module.h \ src/google_airbag/processor/code_modules.h \ @@ -68,6 +69,7 @@ src_libairbag_la_SOURCES = \ src/processor/basic_code_module.h \ src/processor/basic_code_modules.cc \ src/processor/basic_code_modules.h \ + src/processor/basic_source_line_resolver.cc \ src/processor/call_stack.cc \ src/processor/contained_range_map.h \ src/processor/contained_range_map-inl.h \ @@ -84,8 +86,6 @@ src_libairbag_la_SOURCES = \ src/processor/scoped_ptr.h \ src/processor/simple_symbol_supplier.cc \ src/processor/simple_symbol_supplier.h \ - src/processor/source_line_resolver.cc \ - src/processor/source_line_resolver.h \ src/processor/stack_frame_info.h \ src/processor/stackwalker.cc \ src/processor/stackwalker_ppc.cc \ @@ -103,12 +103,12 @@ bin_PROGRAMS = \ ## Tests check_PROGRAMS = \ src/processor/address_map_unittest \ + src/processor/basic_source_line_resolver_unittest \ src/processor/contained_range_map_unittest \ src/processor/minidump_processor_unittest \ src/processor/pathname_stripper_unittest \ src/processor/postfix_evaluator_unittest \ - src/processor/range_map_unittest \ - src/processor/source_line_resolver_unittest + src/processor/range_map_unittest if SELFTEST check_PROGRAMS += \ @@ -125,6 +125,11 @@ TESTS_ENVIRONMENT = src_processor_address_map_unittest_SOURCES = \ src/processor/address_map_unittest.cc +src_processor_basic_source_line_resolver_unittest_SOURCES = \ + src/processor/basic_source_line_resolver_unittest.cc +src_processor_basic_source_line_resolver_unittest_LDADD = \ + src/processor/basic_source_line_resolver.lo + src_processor_contained_range_map_unittest_SOURCES = \ src/processor/contained_range_map_unittest.cc @@ -132,14 +137,14 @@ src_processor_minidump_processor_unittest_SOURCES = \ src/processor/minidump_processor_unittest.cc src_processor_minidump_processor_unittest_LDADD = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump_processor.lo \ src/processor/minidump.lo \ src/processor/process_state.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo src_processor_pathname_stripper_unittest_SOURCES = \ src/processor/pathname_stripper_unittest.cc @@ -152,18 +157,13 @@ src_processor_postfix_evaluator_unittest_SOURCES = \ src_processor_range_map_unittest_SOURCES = \ src/processor/range_map_unittest.cc -src_processor_source_line_resolver_unittest_SOURCES = \ - src/processor/source_line_resolver_unittest.cc -src_processor_source_line_resolver_unittest_LDADD = \ - src/processor/source_line_resolver.lo - src_processor_stackwalker_selftest_SOURCES = \ src/processor/stackwalker_selftest.cc src_processor_stackwalker_selftest_LDADD = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump.lo \ - src/processor/source_line_resolver.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ src/processor/stackwalker_x86.lo @@ -182,6 +182,7 @@ src_processor_minidump_stackwalk_SOURCES = \ src/processor/minidump_stackwalk.cc src_processor_minidump_stackwalk_LDADD = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump.lo \ src/processor/minidump_processor.lo \ @@ -190,8 +191,7 @@ src_processor_minidump_stackwalk_LDADD = \ src/processor/simple_symbol_supplier.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo ## Additional files to be included in a source distribution diff --git a/Makefile.in b/Makefile.in index 10d7108a..5ffd7550 100644 --- a/Makefile.in +++ b/Makefile.in @@ -71,13 +71,12 @@ host_triplet = @host@ bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT) \ src/processor/minidump_stackwalk$(EXEEXT) check_PROGRAMS = src/processor/address_map_unittest$(EXEEXT) \ + src/processor/basic_source_line_resolver_unittest$(EXEEXT) \ src/processor/contained_range_map_unittest$(EXEEXT) \ src/processor/minidump_processor_unittest$(EXEEXT) \ src/processor/pathname_stripper_unittest$(EXEEXT) \ src/processor/postfix_evaluator_unittest$(EXEEXT) \ - src/processor/range_map_unittest$(EXEEXT) \ - src/processor/source_line_resolver_unittest$(EXEEXT) \ - $(am__EXEEXT_1) + src/processor/range_map_unittest$(EXEEXT) $(am__EXEEXT_1) @SELFTEST_TRUE@am__append_1 = \ @SELFTEST_TRUE@ src/processor/stackwalker_selftest @@ -111,12 +110,12 @@ LTLIBRARIES = $(lib_LTLIBRARIES) src_libairbag_la_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_src_libairbag_la_OBJECTS = src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo src/processor/minidump.lo \ src/processor/minidump_processor.lo \ src/processor/pathname_stripper.lo \ src/processor/process_state.lo \ src/processor/simple_symbol_supplier.lo \ - src/processor/source_line_resolver.lo \ src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \ src/processor/stackwalker_x86.lo src_libairbag_la_OBJECTS = $(am_src_libairbag_la_OBJECTS) @@ -129,6 +128,11 @@ am_src_processor_address_map_unittest_OBJECTS = \ src_processor_address_map_unittest_OBJECTS = \ $(am_src_processor_address_map_unittest_OBJECTS) src_processor_address_map_unittest_LDADD = $(LDADD) +am_src_processor_basic_source_line_resolver_unittest_OBJECTS = \ + src/processor/basic_source_line_resolver_unittest.$(OBJEXT) +src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS) +src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = \ + src/processor/basic_source_line_resolver.lo am_src_processor_contained_range_map_unittest_OBJECTS = \ src/processor/contained_range_map_unittest.$(OBJEXT) src_processor_contained_range_map_unittest_OBJECTS = \ @@ -146,26 +150,26 @@ src_processor_minidump_processor_unittest_OBJECTS = \ $(am_src_processor_minidump_processor_unittest_OBJECTS) src_processor_minidump_processor_unittest_DEPENDENCIES = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump_processor.lo src/processor/minidump.lo \ src/processor/process_state.lo src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo am_src_processor_minidump_stackwalk_OBJECTS = \ src/processor/minidump_stackwalk.$(OBJEXT) src_processor_minidump_stackwalk_OBJECTS = \ $(am_src_processor_minidump_stackwalk_OBJECTS) src_processor_minidump_stackwalk_DEPENDENCIES = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo src/processor/minidump.lo \ src/processor/minidump_processor.lo \ src/processor/pathname_stripper.lo \ src/processor/process_state.lo \ src/processor/simple_symbol_supplier.lo \ src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo am_src_processor_pathname_stripper_unittest_OBJECTS = \ src/processor/pathname_stripper_unittest.$(OBJEXT) src_processor_pathname_stripper_unittest_OBJECTS = \ @@ -182,20 +186,14 @@ am_src_processor_range_map_unittest_OBJECTS = \ src_processor_range_map_unittest_OBJECTS = \ $(am_src_processor_range_map_unittest_OBJECTS) src_processor_range_map_unittest_LDADD = $(LDADD) -am_src_processor_source_line_resolver_unittest_OBJECTS = \ - src/processor/source_line_resolver_unittest.$(OBJEXT) -src_processor_source_line_resolver_unittest_OBJECTS = \ - $(am_src_processor_source_line_resolver_unittest_OBJECTS) -src_processor_source_line_resolver_unittest_DEPENDENCIES = \ - src/processor/source_line_resolver.lo am_src_processor_stackwalker_selftest_OBJECTS = \ src/processor/stackwalker_selftest.$(OBJEXT) src_processor_stackwalker_selftest_OBJECTS = \ $(am_src_processor_stackwalker_selftest_OBJECTS) src_processor_stackwalker_selftest_DEPENDENCIES = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo src/processor/minidump.lo \ - src/processor/source_line_resolver.lo \ src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \ src/processor/stackwalker_x86.lo SCRIPTS = $(noinst_SCRIPTS) @@ -220,6 +218,7 @@ LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(src_libairbag_la_SOURCES) \ $(src_processor_address_map_unittest_SOURCES) \ + $(src_processor_basic_source_line_resolver_unittest_SOURCES) \ $(src_processor_contained_range_map_unittest_SOURCES) \ $(src_processor_minidump_dump_SOURCES) \ $(src_processor_minidump_processor_unittest_SOURCES) \ @@ -227,10 +226,10 @@ SOURCES = $(src_libairbag_la_SOURCES) \ $(src_processor_pathname_stripper_unittest_SOURCES) \ $(src_processor_postfix_evaluator_unittest_SOURCES) \ $(src_processor_range_map_unittest_SOURCES) \ - $(src_processor_source_line_resolver_unittest_SOURCES) \ $(src_processor_stackwalker_selftest_SOURCES) DIST_SOURCES = $(src_libairbag_la_SOURCES) \ $(src_processor_address_map_unittest_SOURCES) \ + $(src_processor_basic_source_line_resolver_unittest_SOURCES) \ $(src_processor_contained_range_map_unittest_SOURCES) \ $(src_processor_minidump_dump_SOURCES) \ $(src_processor_minidump_processor_unittest_SOURCES) \ @@ -238,7 +237,6 @@ DIST_SOURCES = $(src_libairbag_la_SOURCES) \ $(src_processor_pathname_stripper_unittest_SOURCES) \ $(src_processor_postfix_evaluator_unittest_SOURCES) \ $(src_processor_range_map_unittest_SOURCES) \ - $(src_processor_source_line_resolver_unittest_SOURCES) \ $(src_processor_stackwalker_selftest_SOURCES) dist_docDATA_INSTALL = $(INSTALL_DATA) DATA = $(dist_doc_DATA) @@ -284,7 +282,6 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ -GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -312,9 +309,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -331,30 +331,23 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) -dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ -htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ -localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ -psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ @@ -362,6 +355,7 @@ target_alias = @target_alias@ # This allows #includes to be relative to src/ AM_CPPFLAGS = -I$(top_srcdir)/src +docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) dist_doc_DATA = \ AUTHORS \ COPYING \ @@ -374,6 +368,7 @@ lib_LTLIBRARIES = src/libairbag.la src_libairbag_la_SOURCES = \ src/google_airbag/common/airbag_types.h \ src/google_airbag/common/minidump_format.h \ + src/google_airbag/processor/basic_source_line_resolver.h \ src/google_airbag/processor/call_stack.h \ src/google_airbag/processor/code_module.h \ src/google_airbag/processor/code_modules.h \ @@ -390,6 +385,7 @@ src_libairbag_la_SOURCES = \ src/processor/basic_code_module.h \ src/processor/basic_code_modules.cc \ src/processor/basic_code_modules.h \ + src/processor/basic_source_line_resolver.cc \ src/processor/call_stack.cc \ src/processor/contained_range_map.h \ src/processor/contained_range_map-inl.h \ @@ -406,8 +402,6 @@ src_libairbag_la_SOURCES = \ src/processor/scoped_ptr.h \ src/processor/simple_symbol_supplier.cc \ src/processor/simple_symbol_supplier.h \ - src/processor/source_line_resolver.cc \ - src/processor/source_line_resolver.h \ src/processor/stack_frame_info.h \ src/processor/stackwalker.cc \ src/processor/stackwalker_ppc.cc \ @@ -424,6 +418,12 @@ TESTS_ENVIRONMENT = src_processor_address_map_unittest_SOURCES = \ src/processor/address_map_unittest.cc +src_processor_basic_source_line_resolver_unittest_SOURCES = \ + src/processor/basic_source_line_resolver_unittest.cc + +src_processor_basic_source_line_resolver_unittest_LDADD = \ + src/processor/basic_source_line_resolver.lo + src_processor_contained_range_map_unittest_SOURCES = \ src/processor/contained_range_map_unittest.cc @@ -432,14 +432,14 @@ src_processor_minidump_processor_unittest_SOURCES = \ src_processor_minidump_processor_unittest_LDADD = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump_processor.lo \ src/processor/minidump.lo \ src/processor/process_state.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo src_processor_pathname_stripper_unittest_SOURCES = \ src/processor/pathname_stripper_unittest.cc @@ -453,20 +453,14 @@ src_processor_postfix_evaluator_unittest_SOURCES = \ src_processor_range_map_unittest_SOURCES = \ src/processor/range_map_unittest.cc -src_processor_source_line_resolver_unittest_SOURCES = \ - src/processor/source_line_resolver_unittest.cc - -src_processor_source_line_resolver_unittest_LDADD = \ - src/processor/source_line_resolver.lo - src_processor_stackwalker_selftest_SOURCES = \ src/processor/stackwalker_selftest.cc src_processor_stackwalker_selftest_LDADD = \ src/processor/basic_code_modules.lo \ + src/processor/basic_source_line_resolver.lo \ src/processor/call_stack.lo \ src/processor/minidump.lo \ - src/processor/source_line_resolver.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ src/processor/stackwalker_x86.lo @@ -484,6 +478,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/call_stack.lo \ src/processor/minidump.lo \ src/processor/minidump_processor.lo \ @@ -492,8 +487,7 @@ src_processor_minidump_stackwalk_LDADD = \ src/processor/simple_symbol_supplier.lo \ src/processor/stackwalker.lo \ src/processor/stackwalker_ppc.lo \ - src/processor/stackwalker_x86.lo \ - src/processor/source_line_resolver.lo + src/processor/stackwalker_x86.lo EXTRA_DIST = \ $(SCRIPTS) \ @@ -620,6 +614,9 @@ src/processor/$(DEPDIR)/$(am__dirstamp): @: > src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/basic_code_modules.lo: src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/basic_source_line_resolver.lo: \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/call_stack.lo: src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/minidump.lo: src/processor/$(am__dirstamp) \ @@ -633,8 +630,6 @@ src/processor/process_state.lo: src/processor/$(am__dirstamp) \ src/processor/simple_symbol_supplier.lo: \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) -src/processor/source_line_resolver.lo: src/processor/$(am__dirstamp) \ - src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) src/processor/stackwalker_ppc.lo: src/processor/$(am__dirstamp) \ @@ -694,6 +689,12 @@ src/processor/address_map_unittest.$(OBJEXT): \ src/processor/address_map_unittest$(EXEEXT): $(src_processor_address_map_unittest_OBJECTS) $(src_processor_address_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) @rm -f src/processor/address_map_unittest$(EXEEXT) $(CXXLINK) $(src_processor_address_map_unittest_LDFLAGS) $(src_processor_address_map_unittest_OBJECTS) $(src_processor_address_map_unittest_LDADD) $(LIBS) +src/processor/basic_source_line_resolver_unittest.$(OBJEXT): \ + src/processor/$(am__dirstamp) \ + src/processor/$(DEPDIR)/$(am__dirstamp) +src/processor/basic_source_line_resolver_unittest$(EXEEXT): $(src_processor_basic_source_line_resolver_unittest_OBJECTS) $(src_processor_basic_source_line_resolver_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) + @rm -f src/processor/basic_source_line_resolver_unittest$(EXEEXT) + $(CXXLINK) $(src_processor_basic_source_line_resolver_unittest_LDFLAGS) $(src_processor_basic_source_line_resolver_unittest_OBJECTS) $(src_processor_basic_source_line_resolver_unittest_LDADD) $(LIBS) src/processor/contained_range_map_unittest.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -735,12 +736,6 @@ src/processor/range_map_unittest.$(OBJEXT): \ src/processor/range_map_unittest$(EXEEXT): $(src_processor_range_map_unittest_OBJECTS) $(src_processor_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) @rm -f src/processor/range_map_unittest$(EXEEXT) $(CXXLINK) $(src_processor_range_map_unittest_LDFLAGS) $(src_processor_range_map_unittest_OBJECTS) $(src_processor_range_map_unittest_LDADD) $(LIBS) -src/processor/source_line_resolver_unittest.$(OBJEXT): \ - src/processor/$(am__dirstamp) \ - src/processor/$(DEPDIR)/$(am__dirstamp) -src/processor/source_line_resolver_unittest$(EXEEXT): $(src_processor_source_line_resolver_unittest_OBJECTS) $(src_processor_source_line_resolver_unittest_DEPENDENCIES) src/processor/$(am__dirstamp) - @rm -f src/processor/source_line_resolver_unittest$(EXEEXT) - $(CXXLINK) $(src_processor_source_line_resolver_unittest_LDFLAGS) $(src_processor_source_line_resolver_unittest_OBJECTS) $(src_processor_source_line_resolver_unittest_LDADD) $(LIBS) src/processor/stackwalker_selftest.$(OBJEXT): \ src/processor/$(am__dirstamp) \ src/processor/$(DEPDIR)/$(am__dirstamp) @@ -753,6 +748,9 @@ mostlyclean-compile: -rm -f src/processor/address_map_unittest.$(OBJEXT) -rm -f src/processor/basic_code_modules.$(OBJEXT) -rm -f src/processor/basic_code_modules.lo + -rm -f src/processor/basic_source_line_resolver.$(OBJEXT) + -rm -f src/processor/basic_source_line_resolver.lo + -rm -f src/processor/basic_source_line_resolver_unittest.$(OBJEXT) -rm -f src/processor/call_stack.$(OBJEXT) -rm -f src/processor/call_stack.lo -rm -f src/processor/contained_range_map_unittest.$(OBJEXT) @@ -772,9 +770,6 @@ mostlyclean-compile: -rm -f src/processor/range_map_unittest.$(OBJEXT) -rm -f src/processor/simple_symbol_supplier.$(OBJEXT) -rm -f src/processor/simple_symbol_supplier.lo - -rm -f src/processor/source_line_resolver.$(OBJEXT) - -rm -f src/processor/source_line_resolver.lo - -rm -f src/processor/source_line_resolver_unittest.$(OBJEXT) -rm -f src/processor/stackwalker.$(OBJEXT) -rm -f src/processor/stackwalker.lo -rm -f src/processor/stackwalker_ppc.$(OBJEXT) @@ -788,6 +783,8 @@ distclean-compile: @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.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_source_line_resolver.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/basic_source_line_resolver_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/call_stack.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/contained_range_map_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Plo@am__quote@ @@ -801,8 +798,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/process_state.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/simple_symbol_supplier.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_unittest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_ppc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/stackwalker_selftest.Po@am__quote@ diff --git a/src/common/windows/pdb_source_line_writer.h b/src/common/windows/pdb_source_line_writer.h index a2818263..58c8f5e0 100644 --- a/src/common/windows/pdb_source_line_writer.h +++ b/src/common/windows/pdb_source_line_writer.h @@ -28,7 +28,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // PDBSourceLineWriter uses a pdb file produced by Visual C++ to output -// a line/address map for use with SourceLineResolver. +// a line/address map for use with BasicSourceLineResolver. #ifndef _PDB_SOURCE_LINE_WRITER_H__ #define _PDB_SOURCE_LINE_WRITER_H__ diff --git a/src/google_airbag/processor/basic_source_line_resolver.h b/src/google_airbag/processor/basic_source_line_resolver.h new file mode 100644 index 00000000..c688191a --- /dev/null +++ b/src/google_airbag/processor/basic_source_line_resolver.h @@ -0,0 +1,84 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// BasicSourceLineResolver implements SourceLineResolverInterface, using +// address map files produced by a compatible writer, e.g. PDBSourceLineWriter. + +#ifndef GOOGLE_AIRBAG_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ +#define GOOGLE_AIRBAG_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ + +#include + +#include "google_airbag/processor/source_line_resolver_interface.h" + +namespace google_airbag { + +using std::string; +using __gnu_cxx::hash_map; + +class BasicSourceLineResolver : public SourceLineResolverInterface { + public: + BasicSourceLineResolver(); + virtual ~BasicSourceLineResolver(); + + // SourceLineResolverInterface methods, see source_line_resolver_interface.h + // for more details. + + // Adds a module to this resolver, returning true on success. + // The given map_file is read into memory, and its symbols will be + // retained until the BasicSourceLineResolver is destroyed. + virtual bool LoadModule(const string &module_name, const string &map_file); + + virtual bool HasModule(const string &module_name) const; + + virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const; + + private: + template class MemAddrMap; + struct Line; + struct Function; + struct PublicSymbol; + struct File; + struct HashString { + size_t operator()(const string &s) const; + }; + class Module; + + // All of the modules we've loaded + typedef hash_map ModuleMap; + ModuleMap *modules_; + + // Disallow unwanted copy ctor and assignment operator + BasicSourceLineResolver(const BasicSourceLineResolver&); + void operator=(const BasicSourceLineResolver&); +}; + +} // namespace google_airbag + +#endif // GOOGLE_AIRBAG_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ diff --git a/src/google_airbag/processor/minidump_processor.h b/src/google_airbag/processor/minidump_processor.h index 604eae45..a50d8a79 100644 --- a/src/google_airbag/processor/minidump_processor.h +++ b/src/google_airbag/processor/minidump_processor.h @@ -38,6 +38,7 @@ using std::string; class Minidump; class ProcessState; +class SourceLineResolverInterface; class SymbolSupplier; class MinidumpProcessor { @@ -51,7 +52,8 @@ class MinidumpProcessor { // Initializes this MinidumpProcessor. supplier should be an // implementation of the SymbolSupplier abstract base class. - explicit MinidumpProcessor(SymbolSupplier *supplier); + MinidumpProcessor(SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); ~MinidumpProcessor(); // Processes the minidump file and fills process_state with the result. @@ -84,6 +86,7 @@ class MinidumpProcessor { private: SymbolSupplier *supplier_; + SourceLineResolverInterface *resolver_; }; } // namespace google_airbag diff --git a/src/google_airbag/processor/source_line_resolver_interface.h b/src/google_airbag/processor/source_line_resolver_interface.h new file mode 100644 index 00000000..2afd4d8f --- /dev/null +++ b/src/google_airbag/processor/source_line_resolver_interface.h @@ -0,0 +1,79 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Abstract interface to return function/file/line info for a memory address. + +#ifndef GOOGLE_AIRBAG_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ +#define GOOGLE_AIRBAG_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ + +#include +#include "google_airbag/common/airbag_types.h" + +namespace google_airbag { + +using std::string; + +struct StackFrame; +struct StackFrameInfo; + +class SourceLineResolverInterface { + public: + typedef u_int64_t MemAddr; + + virtual ~SourceLineResolverInterface() {} + + // Adds a module to this resolver, returning true on success. + // + // module_name may be an arbitrary string. Typically, it will be the + // filename of the module, optionally with version identifiers. + // + // map_file should contain line/address mappings for this module. + virtual bool LoadModule(const string &module_name, + const string &map_file) = 0; + + // Returns true if a module with the given name has been loaded. + virtual bool HasModule(const string &module_name) const = 0; + + // Fills in the function_base, function_name, source_file_name, + // and source_line fields of the StackFrame. The instruction and + // module_name fields must already be filled in. Additional debugging + // information, if available, is returned. If the information is not + // available, returns NULL. A NULL return value does not indicate an + // error. The caller takes ownership of any returned StackFrameInfo + // object. + virtual StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const = 0; + + protected: + // SourceLineResolverInterface cannot be instantiated except by subclasses + SourceLineResolverInterface() {} +}; + +} // namespace google_airbag + +#endif // GOOGLE_AIRBAG_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ diff --git a/src/google_airbag/processor/stackwalker.h b/src/google_airbag/processor/stackwalker.h index 70da125e..381b9e29 100644 --- a/src/google_airbag/processor/stackwalker.h +++ b/src/google_airbag/processor/stackwalker.h @@ -50,6 +50,7 @@ class CodeModules; template class linked_ptr; class MemoryRegion; class MinidumpContext; +class SourceLineResolverInterface; struct StackFrame; struct StackFrameInfo; class SymbolSupplier; @@ -73,7 +74,8 @@ class Stackwalker { static Stackwalker* StackwalkerForCPU(MinidumpContext *context, MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier); + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); protected: // memory identifies a MemoryRegion that provides the stack memory @@ -81,10 +83,13 @@ class Stackwalker { // object that is used to look up which code module each stack frame is // associated with. supplier is an optional caller-supplied SymbolSupplier // implementation. If supplier is NULL, source line info will not be - // resolved. + // resolved. resolver is an instance of SourceLineResolverInterface + // (see source_line_resolver_interface.h and basic_source_line_resolver.h). + // If resolver is NULL, source line info will not be resolved. Stackwalker(MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier); + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); // The stack memory to walk. Subclasses will require this region to // get information from the stack. @@ -115,6 +120,9 @@ class Stackwalker { // The optional SymbolSupplier for resolving source line info. SymbolSupplier *supplier_; + + // The SourceLineResolver implementation + SourceLineResolverInterface *resolver_; }; diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc new file mode 100644 index 00000000..a170be6e --- /dev/null +++ b/src/processor/basic_source_line_resolver.cc @@ -0,0 +1,561 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include +#include +#include + +#include "processor/address_map-inl.h" +#include "processor/contained_range_map-inl.h" +#include "processor/range_map-inl.h" + +#include "google_airbag/processor/basic_source_line_resolver.h" +#include "google_airbag/processor/code_module.h" +#include "google_airbag/processor/stack_frame.h" +#include "processor/linked_ptr.h" +#include "processor/scoped_ptr.h" +#include "processor/stack_frame_info.h" + +using std::map; +using std::vector; +using std::make_pair; +using __gnu_cxx::hash; + +namespace google_airbag { + +struct BasicSourceLineResolver::Line { + Line(MemAddr addr, MemAddr code_size, int file_id, int source_line) + : address(addr) + , size(code_size) + , source_file_id(file_id) + , line(source_line) { } + + MemAddr address; + MemAddr size; + int source_file_id; + int line; +}; + +struct BasicSourceLineResolver::Function { + Function(const string &function_name, + MemAddr function_address, + MemAddr code_size, + int set_parameter_size) + : name(function_name), address(function_address), size(code_size), + parameter_size(set_parameter_size) { } + + string name; + MemAddr address; + MemAddr size; + + // The size of parameters passed to this function on the stack. + int parameter_size; + + RangeMap< MemAddr, linked_ptr > lines; +}; + +struct BasicSourceLineResolver::PublicSymbol { + PublicSymbol(const string& set_name, + MemAddr set_address, + int set_parameter_size) + : name(set_name), + address(set_address), + parameter_size(set_parameter_size) {} + + string name; + MemAddr address; + + // If the public symbol is used as a function entry point, parameter_size + // is set to the size of the parameters passed to the funciton on the + // stack, if known. + int parameter_size; +}; + +class BasicSourceLineResolver::Module { + public: + Module(const string &name) : name_(name) { } + + // Loads the given map file, returning true on success. + bool LoadMap(const string &map_file); + + // Looks up the given relative address, and fills the StackFrame struct + // with the result. Additional debugging information, if available, is + // returned. If no additional information is available, returns NULL. + // A NULL return value is not an error. The caller takes ownership of + // any returned StackFrameInfo object. + StackFrameInfo* LookupAddress(StackFrame *frame) const; + + private: + friend class BasicSourceLineResolver; + typedef hash_map FileMap; + + // The types for stack_info_. This is equivalent to MS DIA's + // StackFrameTypeEnum. Each identifies a different type of frame + // information, although all are represented in the symbol file in the + // same format. These are used as indices to the stack_info_ array. + enum StackInfoTypes { + STACK_INFO_FPO = 0, + STACK_INFO_TRAP, // not used here + STACK_INFO_TSS, // not used here + STACK_INFO_STANDARD, + STACK_INFO_FRAME_DATA, + STACK_INFO_LAST, // must be the last sequentially-numbered item + STACK_INFO_UNKNOWN = -1 + }; + + // Splits line into at most max_tokens space-separated tokens, placing + // them in the tokens vector. line is a 0-terminated string that + // optionally ends with a newline character or combination, which will + // be removed. line must not contain any embedded '\n' or '\r' characters. + // If more tokens than max_tokens are present, the final token is placed + // into the vector without splitting it up at all. This modifies line as + // a side effect. Returns true if exactly max_tokens tokens are returned, + // and false if fewer are returned. This is not considered a failure of + // Tokenize, but may be treated as a failure if the caller expects an + // exact, as opposed to maximum, number of tokens. + static bool Tokenize(char *line, int max_tokens, vector *tokens); + + // Parses a file declaration + void ParseFile(char *file_line); + + // Parses a function declaration, returning a new Function object. + Function* ParseFunction(char *function_line); + + // Parses a line declaration, returning a new Line object. + Line* ParseLine(char *line_line); + + // Parses a PUBLIC symbol declaration, storing it in public_symbols_. + // Returns false if an error occurs. + bool ParsePublicSymbol(char *public_line); + + // Parses a stack frame info declaration, storing it in stack_info_. + bool ParseStackInfo(char *stack_info_line); + + string name_; + FileMap files_; + RangeMap< MemAddr, linked_ptr > functions_; + AddressMap< MemAddr, linked_ptr > public_symbols_; + + // Each element in the array is a ContainedRangeMap for a type listed in + // StackInfoTypes. These are split by type because there may be overlaps + // between maps of different types, but some information is only available + // as certain types. + ContainedRangeMap< MemAddr, linked_ptr > + stack_info_[STACK_INFO_LAST]; +}; + +BasicSourceLineResolver::BasicSourceLineResolver() : modules_(new ModuleMap) { +} + +BasicSourceLineResolver::~BasicSourceLineResolver() { + ModuleMap::iterator it; + for (it = modules_->begin(); it != modules_->end(); ++it) { + delete it->second; + } + delete modules_; +} + +bool BasicSourceLineResolver::LoadModule(const string &module_name, + const string &map_file) { + // Make sure we don't already have a module with the given name. + if (modules_->find(module_name) != modules_->end()) { + return false; + } + + Module *module = new Module(module_name); + if (!module->LoadMap(map_file)) { + delete module; + return false; + } + + modules_->insert(make_pair(module_name, module)); + return true; +} + +bool BasicSourceLineResolver::HasModule(const string &module_name) const { + return modules_->find(module_name) != modules_->end(); +} + +StackFrameInfo* BasicSourceLineResolver::FillSourceLineInfo( + StackFrame *frame) const { + if (frame->module) { + ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); + if (it != modules_->end()) { + return it->second->LookupAddress(frame); + } + } + return NULL; +} + +bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) { + FILE *f = fopen(map_file.c_str(), "r"); + if (!f) { + return false; + } + + // TODO(mmentovai): this might not be large enough to handle really long + // lines, which might be present for FUNC lines of highly-templatized + // code. + char buffer[8192]; + Function *cur_func = NULL; + + while (fgets(buffer, sizeof(buffer), f)) { + if (strncmp(buffer, "FILE ", 5) == 0) { + ParseFile(buffer); + } else if (strncmp(buffer, "STACK ", 6) == 0) { + if (!ParseStackInfo(buffer)) { + return false; + } + } else if (strncmp(buffer, "FUNC ", 5) == 0) { + cur_func = ParseFunction(buffer); + if (!cur_func) { + return false; + } + if (!functions_.StoreRange(cur_func->address, cur_func->size, + linked_ptr(cur_func))) { + return false; + } + } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { + // Clear cur_func: public symbols don't contain line number information. + cur_func = NULL; + + if (!ParsePublicSymbol(buffer)) { + return false; + } + } else if (strncmp(buffer, "MODULE ", 7) == 0) { + // Ignore these. They're not of any use to BasicSourceLineResolver, + // which is fed modules by a SymbolSupplier. These lines are present to + // aid other tools in properly placing symbol files so that they can + // be accessed by a SymbolSupplier. + // + // MODULE + } else { + if (!cur_func) { + return false; + } + Line *line = ParseLine(buffer); + if (!line) { + return false; + } + cur_func->lines.StoreRange(line->address, line->size, + linked_ptr(line)); + } + } + + fclose(f); + return true; +} + +StackFrameInfo* BasicSourceLineResolver::Module::LookupAddress( + StackFrame *frame) const { + MemAddr address = frame->instruction - frame->module->base_address(); + + linked_ptr retrieved_info; + // Check for debugging info first, before any possible early returns. + // + // We only know about STACK_INFO_FRAME_DATA and STACK_INFO_FPO. Prefer + // them in this order. STACK_INFO_FRAME_DATA is the newer type that + // includes its own program string. STACK_INFO_FPO is the older type + // corresponding to the FPO_DATA struct. See stackwalker_x86.cc. + if (!stack_info_[STACK_INFO_FRAME_DATA].RetrieveRange(address, + &retrieved_info)) { + stack_info_[STACK_INFO_FPO].RetrieveRange(address, &retrieved_info); + } + + scoped_ptr frame_info; + if (retrieved_info.get()) { + frame_info.reset(new StackFrameInfo()); + frame_info->CopyFrom(*retrieved_info.get()); + } + + // First, look for a matching FUNC range. Use RetrieveNearestRange instead + // of RetrieveRange so that the nearest function can be compared to the + // nearest PUBLIC symbol if the address does not lie within the function. + // Having access to the highest function below address, even when address + // is outside of the function, is useful: if the function is higher than + // the nearest PUBLIC symbol, then it means that the PUBLIC symbols is not + // valid for the address, and no function information should be filled in. + // Using RetrieveNearestRange instead of RetrieveRange means that we need + // to verify that address is within the range before using a FUNC. + // + // If no FUNC containing the address is found, look for the nearest PUBLIC + // symbol, being careful not to use a public symbol at a lower address than + // the nearest FUNC. + int parameter_size = 0; + linked_ptr func; + linked_ptr public_symbol; + MemAddr function_base; + MemAddr function_size; + MemAddr public_address; + if (functions_.RetrieveNearestRange(address, &func, + &function_base, &function_size) && + address >= function_base && address < function_base + function_size) { + parameter_size = func->parameter_size; + + frame->function_name = func->name; + frame->function_base = frame->module->base_address() + function_base; + + linked_ptr line; + MemAddr line_base; + if (func->lines.RetrieveRange(address, &line, &line_base, NULL)) { + FileMap::const_iterator it = files_.find(line->source_file_id); + if (it != files_.end()) { + frame->source_file_name = files_.find(line->source_file_id)->second; + } + frame->source_line = line->line; + frame->source_line_base = frame->module->base_address() + line_base; + } + } else if (public_symbols_.Retrieve(address, + &public_symbol, &public_address) && + (!func.get() || public_address > function_base + function_size)) { + parameter_size = public_symbol->parameter_size; + + frame->function_name = public_symbol->name; + frame->function_base = frame->module->base_address() + public_address; + } else { + // No FUNC or PUBLIC data available. + return frame_info.release(); + } + + if (!frame_info.get()) { + // Even without a relevant STACK line, many functions contain information + // about how much space their parameters consume on the stack. Prefer + // the STACK stuff (above), but if it's not present, take the + // information from the FUNC or PUBLIC line. + frame_info.reset(new StackFrameInfo()); + frame_info->parameter_size = parameter_size; + frame_info->valid |= StackFrameInfo::VALID_PARAMETER_SIZE; + } + + return frame_info.release(); +} + +// static +bool BasicSourceLineResolver::Module::Tokenize(char *line, int max_tokens, + vector *tokens) { + tokens->clear(); + tokens->reserve(max_tokens); + + int remaining = max_tokens; + + // Split tokens on the space character. Look for newlines too to + // strip them out before exhausting max_tokens. + char *save_ptr; + char *token = strtok_r(line, " \r\n", &save_ptr); + while (token && --remaining > 0) { + tokens->push_back(token); + if (remaining > 1) + token = strtok_r(NULL, " \r\n", &save_ptr); + } + + // If there's anything left, just add it as a single token. + if (!remaining > 0) { + if ((token = strtok_r(NULL, "\r\n", &save_ptr))) { + tokens->push_back(token); + } + } + + return tokens->size() == static_cast(max_tokens); +} + +void BasicSourceLineResolver::Module::ParseFile(char *file_line) { + // FILE + file_line += 5; // skip prefix + + vector tokens; + if (!Tokenize(file_line, 2, &tokens)) { + return; + } + + int index = atoi(tokens[0]); + if (index < 0) { + return; + } + + char *filename = tokens[1]; + if (filename) { + files_.insert(make_pair(index, string(filename))); + } +} + +BasicSourceLineResolver::Function* +BasicSourceLineResolver::Module::ParseFunction(char *function_line) { + // FUNC
+ function_line += 5; // skip prefix + + vector tokens; + if (!Tokenize(function_line, 4, &tokens)) { + return NULL; + } + + u_int64_t address = strtoull(tokens[0], NULL, 16); + u_int64_t size = strtoull(tokens[1], NULL, 16); + int stack_param_size = strtoull(tokens[2], NULL, 16); + char *name = tokens[3]; + + return new Function(name, address, size, stack_param_size); +} + +BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine( + char *line_line) { + //
+ vector tokens; + if (!Tokenize(line_line, 4, &tokens)) { + return NULL; + } + + u_int64_t address = strtoull(tokens[0], NULL, 16); + u_int64_t size = strtoull(tokens[1], NULL, 16); + int line_number = atoi(tokens[2]); + int source_file = atoi(tokens[3]); + if (line_number <= 0) { + return NULL; + } + + return new Line(address, size, source_file, line_number); +} + +bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) { + // PUBLIC
+ + // Skip "PUBLIC " prefix. + public_line += 7; + + vector tokens; + if (!Tokenize(public_line, 3, &tokens)) { + return false; + } + + u_int64_t address = strtoull(tokens[0], NULL, 16); + int stack_param_size = strtoull(tokens[1], NULL, 16); + char *name = tokens[2]; + + // A few public symbols show up with an address of 0. This has been seen + // in the dumped output of ntdll.pdb for symbols such as _CIlog, _CIpow, + // RtlDescribeChunkLZNT1, and RtlReserveChunkLZNT1. They would conflict + // with one another if they were allowed into the public_symbols_ map, + // but since the address is obviously invalid, gracefully accept them + // as input without putting them into the map. + if (address == 0) { + return true; + } + + linked_ptr symbol(new PublicSymbol(name, address, + stack_param_size)); + return public_symbols_.Store(address, symbol); +} + +bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { + // STACK WIN + // + // + // + // If has_program_string is 1, the rest of the line is a program string. + // Otherwise, the final token tells whether the stack info indicates that + // a base pointer has been allocated. + // + // Expect has_program_string to be 1 when type is STACK_INFO_FRAME_DATA and + // 0 when type is STACK_INFO_FPO, but don't enforce this. + + // Skip "STACK " prefix. + stack_info_line += 6; + + vector tokens; + if (!Tokenize(stack_info_line, 12, &tokens)) + return false; + + // Only MSVC stack frame info is understood for now. + const char *platform = tokens[0]; + if (strcmp(platform, "WIN") != 0) + return false; + + int type = strtol(tokens[1], NULL, 16); + if (type < 0 || type > STACK_INFO_LAST - 1) + return false; + + u_int64_t rva = strtoull(tokens[2], NULL, 16); + u_int64_t code_size = strtoull(tokens[3], NULL, 16); + u_int32_t prolog_size = strtoul(tokens[4], NULL, 16); + u_int32_t epilog_size = strtoul(tokens[5], NULL, 16); + u_int32_t parameter_size = strtoul(tokens[6], NULL, 16); + u_int32_t saved_register_size = strtoul(tokens[7], NULL, 16); + u_int32_t local_size = strtoul(tokens[8], NULL, 16); + u_int32_t max_stack_size = strtoul(tokens[9], NULL, 16); + int has_program_string = strtoul(tokens[10], NULL, 16); + + const char *program_string = ""; + int allocates_base_pointer = 0; + if (has_program_string) { + program_string = tokens[11]; + } else { + allocates_base_pointer = strtoul(tokens[11], NULL, 16); + } + + // TODO(mmentovai): I wanted to use StoreRange's return value as this + // method's return value, but MSVC infrequently outputs stack info that + // violates the containment rules. This happens with a section of code + // in strncpy_s in test_app.cc (testdata/minidump2). There, problem looks + // like this: + // STACK WIN 4 4242 1a a 0 ... (STACK WIN 4 base size prolog 0 ...) + // STACK WIN 4 4243 2e 9 0 ... + // ContainedRangeMap treats these two blocks as conflicting. In reality, + // when the prolog lengths are taken into account, the actual code of + // these blocks doesn't conflict. However, we can't take the prolog lengths + // into account directly here because we'd wind up with a different set + // of range conflicts when MSVC outputs stack info like this: + // STACK WIN 4 1040 73 33 0 ... + // STACK WIN 4 105a 59 19 0 ... + // because in both of these entries, the beginning of the code after the + // prolog is at 0x1073, and the last byte of contained code is at 0x10b2. + // Perhaps we could get away with storing ranges by rva + prolog_size + // if ContainedRangeMap were modified to allow replacement of + // already-stored values. + + linked_ptr stack_frame_info( + new StackFrameInfo(prolog_size, + epilog_size, + parameter_size, + saved_register_size, + local_size, + max_stack_size, + allocates_base_pointer, + program_string)); + stack_info_[type].StoreRange(rva, code_size, stack_frame_info); + + return true; +} + +size_t BasicSourceLineResolver::HashString::operator()(const string &s) const { + return hash()(s.c_str()); +} + +} // namespace google_airbag diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc new file mode 100644 index 00000000..8ad7183f --- /dev/null +++ b/src/processor/basic_source_line_resolver_unittest.cc @@ -0,0 +1,202 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include "google_airbag/processor/basic_source_line_resolver.h" +#include "google_airbag/processor/code_module.h" +#include "google_airbag/processor/stack_frame.h" +#include "processor/linked_ptr.h" +#include "processor/scoped_ptr.h" +#include "processor/stack_frame_info.h" + +#define ASSERT_TRUE(cond) \ + if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + return false; \ + } + +#define ASSERT_FALSE(cond) ASSERT_TRUE(!(cond)) + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) + +namespace { + +using std::string; +using google_airbag::BasicSourceLineResolver; +using google_airbag::CodeModule; +using google_airbag::linked_ptr; +using google_airbag::scoped_ptr; +using google_airbag::StackFrame; +using google_airbag::StackFrameInfo; + +class TestCodeModule : public CodeModule { + public: + TestCodeModule(string code_file) : code_file_(code_file) {} + virtual ~TestCodeModule() {} + + virtual u_int64_t base_address() const { return 0; } + virtual u_int64_t size() const { return 0x4000; } + virtual string code_file() const { return code_file_; } + virtual string code_identifier() const { return ""; } + virtual string debug_file() const { return ""; } + virtual string debug_identifier() const { return ""; } + virtual string version() const { return ""; } + virtual const CodeModule* Copy() const { + return new TestCodeModule(code_file_); + } + + private: + string code_file_; +}; + +static bool VerifyEmpty(const StackFrame &frame) { + ASSERT_TRUE(frame.function_name.empty()); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + return true; +} + +static void ClearSourceLineInfo(StackFrame *frame) { + frame->function_name.clear(); + frame->module = NULL; + frame->source_file_name.clear(); + frame->source_line = 0; +} + +static bool RunTests() { + string testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata"; + + BasicSourceLineResolver resolver; + ASSERT_TRUE(resolver.LoadModule("module1", testdata_dir + "/module1.out")); + ASSERT_TRUE(resolver.HasModule("module1")); + ASSERT_TRUE(resolver.LoadModule("module2", testdata_dir + "/module2.out")); + ASSERT_TRUE(resolver.HasModule("module2")); + + TestCodeModule module1("module1"); + + StackFrame frame; + frame.instruction = 0x1000; + frame.module = NULL; + scoped_ptr frame_info(resolver.FillSourceLineInfo(&frame)); + ASSERT_FALSE(frame.module); + ASSERT_TRUE(frame.function_name.empty()); + ASSERT_EQ(frame.function_base, 0); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + ASSERT_EQ(frame.source_line_base, 0); + + frame.module = &module1; + frame_info.reset(resolver.FillSourceLineInfo(&frame)); + ASSERT_EQ(frame.function_name, "Function1_1"); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module1"); + ASSERT_EQ(frame.function_base, 0x1000); + ASSERT_EQ(frame.source_file_name, "file1_1.cc"); + ASSERT_EQ(frame.source_line, 44); + ASSERT_EQ(frame.source_line_base, 0x1000); + ASSERT_TRUE(frame_info.get()); + ASSERT_FALSE(frame_info->allocates_base_pointer); + ASSERT_EQ(frame_info->program_string, + "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ ="); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x800; + frame.module = &module1; + frame_info.reset(resolver.FillSourceLineInfo(&frame)); + ASSERT_TRUE(VerifyEmpty(frame)); + ASSERT_FALSE(frame_info.get()); + + frame.instruction = 0x1280; + frame_info.reset(resolver.FillSourceLineInfo(&frame)); + ASSERT_EQ(frame.function_name, "Function1_3"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + ASSERT_TRUE(frame_info.get()); + ASSERT_FALSE(frame_info->allocates_base_pointer); + ASSERT_TRUE(frame_info->program_string.empty()); + + frame.instruction = 0x1380; + frame_info.reset(resolver.FillSourceLineInfo(&frame)); + ASSERT_EQ(frame.function_name, "Function1_4"); + ASSERT_TRUE(frame.source_file_name.empty()); + ASSERT_EQ(frame.source_line, 0); + ASSERT_TRUE(frame_info.get()); + ASSERT_FALSE(frame_info->allocates_base_pointer); + ASSERT_FALSE(frame_info->program_string.empty()); + + TestCodeModule module2("module2"); + + frame.instruction = 0x2181; + frame.module = &module2; + frame_info.reset(resolver.FillSourceLineInfo(&frame)); + ASSERT_EQ(frame.function_name, "Function2_2"); + ASSERT_EQ(frame.function_base, 0x2170); + ASSERT_TRUE(frame.module); + ASSERT_EQ(frame.module->code_file(), "module2"); + ASSERT_EQ(frame.source_file_name, "file2_2.cc"); + ASSERT_EQ(frame.source_line, 21); + ASSERT_EQ(frame.source_line_base, 0x2180); + ASSERT_TRUE(frame_info.get()); + ASSERT_EQ(frame_info->prolog_size, 1); + + frame.instruction = 0x216f; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_1"); + + ClearSourceLineInfo(&frame); + frame.instruction = 0x219f; + frame.module = &module2; + resolver.FillSourceLineInfo(&frame); + ASSERT_TRUE(frame.function_name.empty()); + + frame.instruction = 0x21a0; + frame.module = &module2; + resolver.FillSourceLineInfo(&frame); + ASSERT_EQ(frame.function_name, "Public2_2"); + + ASSERT_FALSE(resolver.LoadModule("module3", + testdata_dir + "/module3_bad.out")); + ASSERT_FALSE(resolver.HasModule("module3")); + ASSERT_FALSE(resolver.LoadModule("module4", + testdata_dir + "/invalid-filename")); + ASSERT_FALSE(resolver.HasModule("module4")); + ASSERT_FALSE(resolver.HasModule("invalid-module")); + return true; +} + +} // namespace + +int main(int argc, char **argv) { + if (!RunTests()) { + return 1; + } + return 0; +} diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index ab027e8a..dd4c7156 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -38,8 +38,9 @@ namespace google_airbag { -MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier) - : supplier_(supplier) { +MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : supplier_(supplier), resolver_(resolver) { } MinidumpProcessor::~MinidumpProcessor() { @@ -164,7 +165,8 @@ MinidumpProcessor::ProcessResult MinidumpProcessor::Process( Stackwalker::StackwalkerForCPU(context, thread_memory, process_state->modules_, - supplier_)); + supplier_, + resolver_)); if (!stackwalker.get()) { return PROCESS_ERROR; } diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index 766c2a30..69a29965 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -31,6 +31,7 @@ // corresponding symbol file, and checks the stack frames for correctness. #include +#include "google_airbag/processor/basic_source_line_resolver.h" #include "google_airbag/processor/call_stack.h" #include "google_airbag/processor/code_module.h" #include "google_airbag/processor/code_modules.h" @@ -43,6 +44,7 @@ namespace { using std::string; +using google_airbag::BasicSourceLineResolver; using google_airbag::CallStack; using google_airbag::CodeModule; using google_airbag::MinidumpProcessor; @@ -93,7 +95,8 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( static bool RunTests() { TestSymbolSupplier supplier; - MinidumpProcessor processor(&supplier); + BasicSourceLineResolver resolver; + MinidumpProcessor processor(&supplier, &resolver); string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") + "/src/processor/testdata/minidump2.dmp"; diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 3c55933d..2bd32d7a 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -36,6 +36,7 @@ #include #include +#include "google_airbag/processor/basic_source_line_resolver.h" #include "google_airbag/processor/call_stack.h" #include "google_airbag/processor/code_module.h" #include "google_airbag/processor/code_modules.h" @@ -50,6 +51,7 @@ namespace { using std::string; +using google_airbag::BasicSourceLineResolver; using google_airbag::CallStack; using google_airbag::CodeModule; using google_airbag::CodeModules; @@ -192,7 +194,8 @@ static bool PrintMinidumpProcess(const string &minidump_file, symbol_supplier.reset(new SimpleSymbolSupplier(symbol_path)); } - MinidumpProcessor minidump_processor(symbol_supplier.get()); + BasicSourceLineResolver resolver; + MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver); // Process the minidump. ProcessState process_state; diff --git a/src/processor/source_line_resolver.cc b/src/processor/source_line_resolver.cc deleted file mode 100644 index 1ebc1bf4..00000000 --- a/src/processor/source_line_resolver.cc +++ /dev/null @@ -1,561 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include - -#include -#include -#include - -#include "processor/address_map-inl.h" -#include "processor/contained_range_map-inl.h" -#include "processor/range_map-inl.h" - -#include "processor/source_line_resolver.h" -#include "google_airbag/processor/code_module.h" -#include "google_airbag/processor/stack_frame.h" -#include "processor/linked_ptr.h" -#include "processor/scoped_ptr.h" -#include "processor/stack_frame_info.h" - -using std::map; -using std::vector; -using std::make_pair; -using __gnu_cxx::hash; - -namespace google_airbag { - -struct SourceLineResolver::Line { - Line(MemAddr addr, MemAddr code_size, int file_id, int source_line) - : address(addr) - , size(code_size) - , source_file_id(file_id) - , line(source_line) { } - - MemAddr address; - MemAddr size; - int source_file_id; - int line; -}; - -struct SourceLineResolver::Function { - Function(const string &function_name, - MemAddr function_address, - MemAddr code_size, - int set_parameter_size) - : name(function_name), address(function_address), size(code_size), - parameter_size(set_parameter_size) { } - - string name; - MemAddr address; - MemAddr size; - - // The size of parameters passed to this function on the stack. - int parameter_size; - - RangeMap< MemAddr, linked_ptr > lines; -}; - -struct SourceLineResolver::PublicSymbol { - PublicSymbol(const string& set_name, - MemAddr set_address, - int set_parameter_size) - : name(set_name), - address(set_address), - parameter_size(set_parameter_size) {} - - string name; - MemAddr address; - - // If the public symbol is used as a function entry point, parameter_size - // is set to the size of the parameters passed to the funciton on the - // stack, if known. - int parameter_size; -}; - -class SourceLineResolver::Module { - public: - Module(const string &name) : name_(name) { } - - // Loads the given map file, returning true on success. - bool LoadMap(const string &map_file); - - // Looks up the given relative address, and fills the StackFrame struct - // with the result. Additional debugging information, if available, is - // returned. If no additional information is available, returns NULL. - // A NULL return value is not an error. The caller takes ownership of - // any returned StackFrameInfo object. - StackFrameInfo* LookupAddress(StackFrame *frame) const; - - private: - friend class SourceLineResolver; - typedef hash_map FileMap; - - // The types for stack_info_. This is equivalent to MS DIA's - // StackFrameTypeEnum. Each identifies a different type of frame - // information, although all are represented in the symbol file in the - // same format. These are used as indices to the stack_info_ array. - enum StackInfoTypes { - STACK_INFO_FPO = 0, - STACK_INFO_TRAP, // not used here - STACK_INFO_TSS, // not used here - STACK_INFO_STANDARD, - STACK_INFO_FRAME_DATA, - STACK_INFO_LAST, // must be the last sequentially-numbered item - STACK_INFO_UNKNOWN = -1 - }; - - // Splits line into at most max_tokens space-separated tokens, placing - // them in the tokens vector. line is a 0-terminated string that - // optionally ends with a newline character or combination, which will - // be removed. line must not contain any embedded '\n' or '\r' characters. - // If more tokens than max_tokens are present, the final token is placed - // into the vector without splitting it up at all. This modifies line as - // a side effect. Returns true if exactly max_tokens tokens are returned, - // and false if fewer are returned. This is not considered a failure of - // Tokenize, but may be treated as a failure if the caller expects an - // exact, as opposed to maximum, number of tokens. - static bool Tokenize(char *line, int max_tokens, vector *tokens); - - // Parses a file declaration - void ParseFile(char *file_line); - - // Parses a function declaration, returning a new Function object. - Function* ParseFunction(char *function_line); - - // Parses a line declaration, returning a new Line object. - Line* ParseLine(char *line_line); - - // Parses a PUBLIC symbol declaration, storing it in public_symbols_. - // Returns false if an error occurs. - bool ParsePublicSymbol(char *public_line); - - // Parses a stack frame info declaration, storing it in stack_info_. - bool ParseStackInfo(char *stack_info_line); - - string name_; - FileMap files_; - RangeMap< MemAddr, linked_ptr > functions_; - AddressMap< MemAddr, linked_ptr > public_symbols_; - - // Each element in the array is a ContainedRangeMap for a type listed in - // StackInfoTypes. These are split by type because there may be overlaps - // between maps of different types, but some information is only available - // as certain types. - ContainedRangeMap< MemAddr, linked_ptr > - stack_info_[STACK_INFO_LAST]; -}; - -SourceLineResolver::SourceLineResolver() : modules_(new ModuleMap) { -} - -SourceLineResolver::~SourceLineResolver() { - ModuleMap::iterator it; - for (it = modules_->begin(); it != modules_->end(); ++it) { - delete it->second; - } - delete modules_; -} - -bool SourceLineResolver::LoadModule(const string &module_name, - const string &map_file) { - // Make sure we don't already have a module with the given name. - if (modules_->find(module_name) != modules_->end()) { - return false; - } - - Module *module = new Module(module_name); - if (!module->LoadMap(map_file)) { - delete module; - return false; - } - - modules_->insert(make_pair(module_name, module)); - return true; -} - -bool SourceLineResolver::HasModule(const string &module_name) const { - return modules_->find(module_name) != modules_->end(); -} - -StackFrameInfo* SourceLineResolver::FillSourceLineInfo( - StackFrame *frame) const { - if (frame->module) { - ModuleMap::const_iterator it = modules_->find(frame->module->code_file()); - if (it != modules_->end()) { - return it->second->LookupAddress(frame); - } - } - return NULL; -} - -bool SourceLineResolver::Module::LoadMap(const string &map_file) { - FILE *f = fopen(map_file.c_str(), "r"); - if (!f) { - return false; - } - - // TODO(mmentovai): this might not be large enough to handle really long - // lines, which might be present for FUNC lines of highly-templatized - // code. - char buffer[8192]; - Function *cur_func = NULL; - - while (fgets(buffer, sizeof(buffer), f)) { - if (strncmp(buffer, "FILE ", 5) == 0) { - ParseFile(buffer); - } else if (strncmp(buffer, "STACK ", 6) == 0) { - if (!ParseStackInfo(buffer)) { - return false; - } - } else if (strncmp(buffer, "FUNC ", 5) == 0) { - cur_func = ParseFunction(buffer); - if (!cur_func) { - return false; - } - if (!functions_.StoreRange(cur_func->address, cur_func->size, - linked_ptr(cur_func))) { - return false; - } - } else if (strncmp(buffer, "PUBLIC ", 7) == 0) { - // Clear cur_func: public symbols don't contain line number information. - cur_func = NULL; - - if (!ParsePublicSymbol(buffer)) { - return false; - } - } else if (strncmp(buffer, "MODULE ", 7) == 0) { - // Ignore these. They're not of any use to SourceLineResolver, which - // is fed modules by a SymbolSupplier. These lines are present to - // aid other tools in properly placing symbol files so that they can - // be accessed by a SymbolSupplier. - // - // MODULE - } else { - if (!cur_func) { - return false; - } - Line *line = ParseLine(buffer); - if (!line) { - return false; - } - cur_func->lines.StoreRange(line->address, line->size, - linked_ptr(line)); - } - } - - fclose(f); - return true; -} - -StackFrameInfo* SourceLineResolver::Module::LookupAddress(StackFrame *frame) - const { - MemAddr address = frame->instruction - frame->module->base_address(); - - linked_ptr retrieved_info; - // Check for debugging info first, before any possible early returns. - // - // We only know about STACK_INFO_FRAME_DATA and STACK_INFO_FPO. Prefer - // them in this order. STACK_INFO_FRAME_DATA is the newer type that - // includes its own program string. STACK_INFO_FPO is the older type - // corresponding to the FPO_DATA struct. See stackwalker_x86.cc. - if (!stack_info_[STACK_INFO_FRAME_DATA].RetrieveRange(address, - &retrieved_info)) { - stack_info_[STACK_INFO_FPO].RetrieveRange(address, &retrieved_info); - } - - scoped_ptr frame_info; - if (retrieved_info.get()) { - frame_info.reset(new StackFrameInfo()); - frame_info->CopyFrom(*retrieved_info.get()); - } - - // First, look for a matching FUNC range. Use RetrieveNearestRange instead - // of RetrieveRange so that the nearest function can be compared to the - // nearest PUBLIC symbol if the address does not lie within the function. - // Having access to the highest function below address, even when address - // is outside of the function, is useful: if the function is higher than - // the nearest PUBLIC symbol, then it means that the PUBLIC symbols is not - // valid for the address, and no function information should be filled in. - // Using RetrieveNearestRange instead of RetrieveRange means that we need - // to verify that address is within the range before using a FUNC. - // - // If no FUNC containing the address is found, look for the nearest PUBLIC - // symbol, being careful not to use a public symbol at a lower address than - // the nearest FUNC. - int parameter_size = 0; - linked_ptr func; - linked_ptr public_symbol; - MemAddr function_base; - MemAddr function_size; - MemAddr public_address; - if (functions_.RetrieveNearestRange(address, &func, - &function_base, &function_size) && - address >= function_base && address < function_base + function_size) { - parameter_size = func->parameter_size; - - frame->function_name = func->name; - frame->function_base = frame->module->base_address() + function_base; - - linked_ptr line; - MemAddr line_base; - if (func->lines.RetrieveRange(address, &line, &line_base, NULL)) { - FileMap::const_iterator it = files_.find(line->source_file_id); - if (it != files_.end()) { - frame->source_file_name = files_.find(line->source_file_id)->second; - } - frame->source_line = line->line; - frame->source_line_base = frame->module->base_address() + line_base; - } - } else if (public_symbols_.Retrieve(address, - &public_symbol, &public_address) && - (!func.get() || public_address > function_base + function_size)) { - parameter_size = public_symbol->parameter_size; - - frame->function_name = public_symbol->name; - frame->function_base = frame->module->base_address() + public_address; - } else { - // No FUNC or PUBLIC data available. - return frame_info.release(); - } - - if (!frame_info.get()) { - // Even without a relevant STACK line, many functions contain information - // about how much space their parameters consume on the stack. Prefer - // the STACK stuff (above), but if it's not present, take the - // information from the FUNC or PUBLIC line. - frame_info.reset(new StackFrameInfo()); - frame_info->parameter_size = parameter_size; - frame_info->valid |= StackFrameInfo::VALID_PARAMETER_SIZE; - } - - return frame_info.release(); -} - -// static -bool SourceLineResolver::Module::Tokenize(char *line, int max_tokens, - vector *tokens) { - tokens->clear(); - tokens->reserve(max_tokens); - - int remaining = max_tokens; - - // Split tokens on the space character. Look for newlines too to - // strip them out before exhausting max_tokens. - char *save_ptr; - char *token = strtok_r(line, " \r\n", &save_ptr); - while (token && --remaining > 0) { - tokens->push_back(token); - if (remaining > 1) - token = strtok_r(NULL, " \r\n", &save_ptr); - } - - // If there's anything left, just add it as a single token. - if (!remaining > 0) { - if ((token = strtok_r(NULL, "\r\n", &save_ptr))) { - tokens->push_back(token); - } - } - - return tokens->size() == static_cast(max_tokens); -} - -void SourceLineResolver::Module::ParseFile(char *file_line) { - // FILE - file_line += 5; // skip prefix - - vector tokens; - if (!Tokenize(file_line, 2, &tokens)) { - return; - } - - int index = atoi(tokens[0]); - if (index < 0) { - return; - } - - char *filename = tokens[1]; - if (filename) { - files_.insert(make_pair(index, string(filename))); - } -} - -SourceLineResolver::Function* SourceLineResolver::Module::ParseFunction( - char *function_line) { - // FUNC
- function_line += 5; // skip prefix - - vector tokens; - if (!Tokenize(function_line, 4, &tokens)) { - return NULL; - } - - u_int64_t address = strtoull(tokens[0], NULL, 16); - u_int64_t size = strtoull(tokens[1], NULL, 16); - int stack_param_size = strtoull(tokens[2], NULL, 16); - char *name = tokens[3]; - - return new Function(name, address, size, stack_param_size); -} - -SourceLineResolver::Line* SourceLineResolver::Module::ParseLine( - char *line_line) { - //
- vector tokens; - if (!Tokenize(line_line, 4, &tokens)) { - return NULL; - } - - u_int64_t address = strtoull(tokens[0], NULL, 16); - u_int64_t size = strtoull(tokens[1], NULL, 16); - int line_number = atoi(tokens[2]); - int source_file = atoi(tokens[3]); - if (line_number <= 0) { - return NULL; - } - - return new Line(address, size, source_file, line_number); -} - -bool SourceLineResolver::Module::ParsePublicSymbol(char *public_line) { - // PUBLIC
- - // Skip "PUBLIC " prefix. - public_line += 7; - - vector tokens; - if (!Tokenize(public_line, 3, &tokens)) { - return false; - } - - u_int64_t address = strtoull(tokens[0], NULL, 16); - int stack_param_size = strtoull(tokens[1], NULL, 16); - char *name = tokens[2]; - - // A few public symbols show up with an address of 0. This has been seen - // in the dumped output of ntdll.pdb for symbols such as _CIlog, _CIpow, - // RtlDescribeChunkLZNT1, and RtlReserveChunkLZNT1. They would conflict - // with one another if they were allowed into the public_symbols_ map, - // but since the address is obviously invalid, gracefully accept them - // as input without putting them into the map. - if (address == 0) { - return true; - } - - linked_ptr symbol(new PublicSymbol(name, address, - stack_param_size)); - return public_symbols_.Store(address, symbol); -} - -bool SourceLineResolver::Module::ParseStackInfo(char *stack_info_line) { - // STACK WIN - // - // - // - // If has_program_string is 1, the rest of the line is a program string. - // Otherwise, the final token tells whether the stack info indicates that - // a base pointer has been allocated. - // - // Expect has_program_string to be 1 when type is STACK_INFO_FRAME_DATA and - // 0 when type is STACK_INFO_FPO, but don't enforce this. - - // Skip "STACK " prefix. - stack_info_line += 6; - - vector tokens; - if (!Tokenize(stack_info_line, 12, &tokens)) - return false; - - // Only MSVC stack frame info is understood for now. - const char *platform = tokens[0]; - if (strcmp(platform, "WIN") != 0) - return false; - - int type = strtol(tokens[1], NULL, 16); - if (type < 0 || type > STACK_INFO_LAST - 1) - return false; - - u_int64_t rva = strtoull(tokens[2], NULL, 16); - u_int64_t code_size = strtoull(tokens[3], NULL, 16); - u_int32_t prolog_size = strtoul(tokens[4], NULL, 16); - u_int32_t epilog_size = strtoul(tokens[5], NULL, 16); - u_int32_t parameter_size = strtoul(tokens[6], NULL, 16); - u_int32_t saved_register_size = strtoul(tokens[7], NULL, 16); - u_int32_t local_size = strtoul(tokens[8], NULL, 16); - u_int32_t max_stack_size = strtoul(tokens[9], NULL, 16); - int has_program_string = strtoul(tokens[10], NULL, 16); - - const char *program_string = ""; - int allocates_base_pointer = 0; - if (has_program_string) { - program_string = tokens[11]; - } else { - allocates_base_pointer = strtoul(tokens[11], NULL, 16); - } - - // TODO(mmentovai): I wanted to use StoreRange's return value as this - // method's return value, but MSVC infrequently outputs stack info that - // violates the containment rules. This happens with a section of code - // in strncpy_s in test_app.cc (testdata/minidump2). There, problem looks - // like this: - // STACK WIN 4 4242 1a a 0 ... (STACK WIN 4 base size prolog 0 ...) - // STACK WIN 4 4243 2e 9 0 ... - // ContainedRangeMap treats these two blocks as conflicting. In reality, - // when the prolog lengths are taken into account, the actual code of - // these blocks doesn't conflict. However, we can't take the prolog lengths - // into account directly here because we'd wind up with a different set - // of range conflicts when MSVC outputs stack info like this: - // STACK WIN 4 1040 73 33 0 ... - // STACK WIN 4 105a 59 19 0 ... - // because in both of these entries, the beginning of the code after the - // prolog is at 0x1073, and the last byte of contained code is at 0x10b2. - // Perhaps we could get away with storing ranges by rva + prolog_size - // if ContainedRangeMap were modified to allow replacement of - // already-stored values. - - linked_ptr stack_frame_info( - new StackFrameInfo(prolog_size, - epilog_size, - parameter_size, - saved_register_size, - local_size, - max_stack_size, - allocates_base_pointer, - program_string)); - stack_info_[type].StoreRange(rva, code_size, stack_frame_info); - - return true; -} - -size_t SourceLineResolver::HashString::operator()(const string &s) const { - return hash()(s.c_str()); -} - -} // namespace google_airbag diff --git a/src/processor/source_line_resolver.h b/src/processor/source_line_resolver.h deleted file mode 100644 index 3e992607..00000000 --- a/src/processor/source_line_resolver.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// SourceLineResolver returns function/file/line info for a memory address. -// It uses address map files produced by a compatible writer, e.g. -// PDBSourceLineWriter. - -#ifndef PROCESSOR_SOURCE_LINE_RESOLVER_H__ -#define PROCESSOR_SOURCE_LINE_RESOLVER_H__ - -#include -#include -#include "google_airbag/common/airbag_types.h" - -namespace google_airbag { - -using std::string; -using __gnu_cxx::hash_map; - -struct StackFrame; -struct StackFrameInfo; - -class SourceLineResolver { - public: - typedef u_int64_t MemAddr; - - SourceLineResolver(); - ~SourceLineResolver(); - - // Adds a module to this resolver, returning true on success. - // - // module_name may be an arbitrary string. Typically, it will be the - // filename of the module, optionally with version identifiers. - // - // map_file should contain line/address mappings for this module. - bool LoadModule(const string &module_name, const string &map_file); - - // Returns true if a module with the given name has been loaded. - bool HasModule(const string &module_name) const; - - // Fills in the function_base, function_name, source_file_name, - // and source_line fields of the StackFrame. The instruction and - // module_name fields must already be filled in. Additional debugging - // information, if available, is returned. If the information is not - // available, returns NULL. A NULL return value does not indicate an - // error. The caller takes ownership of any returned StackFrameInfo - // object. - StackFrameInfo* FillSourceLineInfo(StackFrame *frame) const; - - private: - template class MemAddrMap; - struct Line; - struct Function; - struct PublicSymbol; - struct File; - struct HashString { - size_t operator()(const string &s) const; - }; - class Module; - - // All of the modules we've loaded - typedef hash_map ModuleMap; - ModuleMap *modules_; - - // Disallow unwanted copy ctor and assignment operator - SourceLineResolver(const SourceLineResolver&); - void operator=(const SourceLineResolver&); -}; - -} // namespace google_airbag - -#endif // PROCESSOR_SOURCE_LINE_RESOLVER_H__ diff --git a/src/processor/source_line_resolver_unittest.cc b/src/processor/source_line_resolver_unittest.cc deleted file mode 100644 index 38de9e2c..00000000 --- a/src/processor/source_line_resolver_unittest.cc +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include "processor/source_line_resolver.h" -#include "google_airbag/processor/code_module.h" -#include "google_airbag/processor/stack_frame.h" -#include "processor/linked_ptr.h" -#include "processor/scoped_ptr.h" -#include "processor/stack_frame_info.h" - -#define ASSERT_TRUE(cond) \ - if (!(cond)) { \ - fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ - return false; \ - } - -#define ASSERT_FALSE(cond) ASSERT_TRUE(!(cond)) - -#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) - -namespace { - -using std::string; -using google_airbag::CodeModule; -using google_airbag::linked_ptr; -using google_airbag::scoped_ptr; -using google_airbag::SourceLineResolver; -using google_airbag::StackFrame; -using google_airbag::StackFrameInfo; - -class TestCodeModule : public CodeModule { - public: - TestCodeModule(string code_file) : code_file_(code_file) {} - virtual ~TestCodeModule() {} - - virtual u_int64_t base_address() const { return 0; } - virtual u_int64_t size() const { return 0x4000; } - virtual string code_file() const { return code_file_; } - virtual string code_identifier() const { return ""; } - virtual string debug_file() const { return ""; } - virtual string debug_identifier() const { return ""; } - virtual string version() const { return ""; } - virtual const CodeModule* Copy() const { - return new TestCodeModule(code_file_); - } - - private: - string code_file_; -}; - -static bool VerifyEmpty(const StackFrame &frame) { - ASSERT_TRUE(frame.function_name.empty()); - ASSERT_TRUE(frame.source_file_name.empty()); - ASSERT_EQ(frame.source_line, 0); - return true; -} - -static void ClearSourceLineInfo(StackFrame *frame) { - frame->function_name.clear(); - frame->module = NULL; - frame->source_file_name.clear(); - frame->source_line = 0; -} - -static bool RunTests() { - string testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") + - "/src/processor/testdata"; - - SourceLineResolver resolver; - ASSERT_TRUE(resolver.LoadModule("module1", testdata_dir + "/module1.out")); - ASSERT_TRUE(resolver.HasModule("module1")); - ASSERT_TRUE(resolver.LoadModule("module2", testdata_dir + "/module2.out")); - ASSERT_TRUE(resolver.HasModule("module2")); - - TestCodeModule module1("module1"); - - StackFrame frame; - frame.instruction = 0x1000; - frame.module = NULL; - scoped_ptr frame_info(resolver.FillSourceLineInfo(&frame)); - ASSERT_FALSE(frame.module); - ASSERT_TRUE(frame.function_name.empty()); - ASSERT_EQ(frame.function_base, 0); - ASSERT_TRUE(frame.source_file_name.empty()); - ASSERT_EQ(frame.source_line, 0); - ASSERT_EQ(frame.source_line_base, 0); - - frame.module = &module1; - frame_info.reset(resolver.FillSourceLineInfo(&frame)); - ASSERT_EQ(frame.function_name, "Function1_1"); - ASSERT_TRUE(frame.module); - ASSERT_EQ(frame.module->code_file(), "module1"); - ASSERT_EQ(frame.function_base, 0x1000); - ASSERT_EQ(frame.source_file_name, "file1_1.cc"); - ASSERT_EQ(frame.source_line, 44); - ASSERT_EQ(frame.source_line_base, 0x1000); - ASSERT_TRUE(frame_info.get()); - ASSERT_FALSE(frame_info->allocates_base_pointer); - ASSERT_EQ(frame_info->program_string, - "$eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ ="); - - ClearSourceLineInfo(&frame); - frame.instruction = 0x800; - frame.module = &module1; - frame_info.reset(resolver.FillSourceLineInfo(&frame)); - ASSERT_TRUE(VerifyEmpty(frame)); - ASSERT_FALSE(frame_info.get()); - - frame.instruction = 0x1280; - frame_info.reset(resolver.FillSourceLineInfo(&frame)); - ASSERT_EQ(frame.function_name, "Function1_3"); - ASSERT_TRUE(frame.source_file_name.empty()); - ASSERT_EQ(frame.source_line, 0); - ASSERT_TRUE(frame_info.get()); - ASSERT_FALSE(frame_info->allocates_base_pointer); - ASSERT_TRUE(frame_info->program_string.empty()); - - frame.instruction = 0x1380; - frame_info.reset(resolver.FillSourceLineInfo(&frame)); - ASSERT_EQ(frame.function_name, "Function1_4"); - ASSERT_TRUE(frame.source_file_name.empty()); - ASSERT_EQ(frame.source_line, 0); - ASSERT_TRUE(frame_info.get()); - ASSERT_FALSE(frame_info->allocates_base_pointer); - ASSERT_FALSE(frame_info->program_string.empty()); - - TestCodeModule module2("module2"); - - frame.instruction = 0x2181; - frame.module = &module2; - frame_info.reset(resolver.FillSourceLineInfo(&frame)); - ASSERT_EQ(frame.function_name, "Function2_2"); - ASSERT_EQ(frame.function_base, 0x2170); - ASSERT_TRUE(frame.module); - ASSERT_EQ(frame.module->code_file(), "module2"); - ASSERT_EQ(frame.source_file_name, "file2_2.cc"); - ASSERT_EQ(frame.source_line, 21); - ASSERT_EQ(frame.source_line_base, 0x2180); - ASSERT_TRUE(frame_info.get()); - ASSERT_EQ(frame_info->prolog_size, 1); - - frame.instruction = 0x216f; - resolver.FillSourceLineInfo(&frame); - ASSERT_EQ(frame.function_name, "Public2_1"); - - ClearSourceLineInfo(&frame); - frame.instruction = 0x219f; - frame.module = &module2; - resolver.FillSourceLineInfo(&frame); - ASSERT_TRUE(frame.function_name.empty()); - - frame.instruction = 0x21a0; - frame.module = &module2; - resolver.FillSourceLineInfo(&frame); - ASSERT_EQ(frame.function_name, "Public2_2"); - - ASSERT_FALSE(resolver.LoadModule("module3", - testdata_dir + "/module3_bad.out")); - ASSERT_FALSE(resolver.HasModule("module3")); - ASSERT_FALSE(resolver.LoadModule("module4", - testdata_dir + "/invalid-filename")); - ASSERT_FALSE(resolver.HasModule("module4")); - ASSERT_FALSE(resolver.HasModule("invalid-module")); - return true; -} - -} // namespace - -int main(int argc, char **argv) { - if (!RunTests()) { - return 1; - } - return 0; -} diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index edbe428a..e6a26bb9 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -41,11 +41,11 @@ #include "google_airbag/processor/code_module.h" #include "google_airbag/processor/code_modules.h" #include "google_airbag/processor/minidump.h" +#include "google_airbag/processor/source_line_resolver_interface.h" #include "google_airbag/processor/stack_frame.h" #include "google_airbag/processor/symbol_supplier.h" #include "processor/linked_ptr.h" #include "processor/scoped_ptr.h" -#include "processor/source_line_resolver.h" #include "processor/stack_frame_info.h" #include "processor/stackwalker_ppc.h" #include "processor/stackwalker_x86.h" @@ -54,14 +54,17 @@ namespace google_airbag { Stackwalker::Stackwalker(MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier) - : memory_(memory), modules_(modules), supplier_(supplier) { + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : memory_(memory), + modules_(modules), + supplier_(supplier), + resolver_(resolver) { } bool Stackwalker::Walk(CallStack *stack) { assert(stack); - SourceLineResolver resolver; stack->Clear(); // stack_frame_info parallels the CallStack. The vector is passed to the @@ -88,14 +91,16 @@ bool Stackwalker::Walk(CallStack *stack) { modules_->GetModuleForAddress(frame->instruction); if (module) { frame->module = module; - if (!resolver.HasModule(frame->module->code_file()) && supplier_) { + if (resolver_ && + !resolver_->HasModule(frame->module->code_file()) && + supplier_) { string symbol_file; SymbolSupplier::SymbolResult symbol_result = supplier_->GetSymbolFile(module, &symbol_file); switch (symbol_result) { case SymbolSupplier::FOUND: - resolver.LoadModule(frame->module->code_file(), symbol_file); + resolver_->LoadModule(frame->module->code_file(), symbol_file); break; case SymbolSupplier::NOT_FOUND: break; // nothing to do @@ -103,7 +108,7 @@ bool Stackwalker::Walk(CallStack *stack) { return false; } } - frame_info.reset(resolver.FillSourceLineInfo(frame.get())); + frame_info.reset(resolver_->FillSourceLineInfo(frame.get())); } } @@ -124,22 +129,26 @@ bool Stackwalker::Walk(CallStack *stack) { // static -Stackwalker* Stackwalker::StackwalkerForCPU(MinidumpContext *context, - MemoryRegion *memory, - const CodeModules *modules, - SymbolSupplier *supplier) { +Stackwalker* Stackwalker::StackwalkerForCPU( + MinidumpContext *context, + MemoryRegion *memory, + const CodeModules *modules, + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) { Stackwalker *cpu_stackwalker = NULL; u_int32_t cpu = context->GetContextCPU(); switch (cpu) { case MD_CONTEXT_X86: cpu_stackwalker = new StackwalkerX86(context->GetContextX86(), - memory, modules, supplier); + memory, modules, supplier, + resolver); break; case MD_CONTEXT_PPC: cpu_stackwalker = new StackwalkerPPC(context->GetContextPPC(), - memory, modules, supplier); + memory, modules, supplier, + resolver); break; } diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc index 49b62f8c..ff5243c6 100644 --- a/src/processor/stackwalker_ppc.cc +++ b/src/processor/stackwalker_ppc.cc @@ -45,8 +45,9 @@ namespace google_airbag { StackwalkerPPC::StackwalkerPPC(const MDRawContextPPC *context, MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier) - : Stackwalker(memory, modules, supplier), + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : Stackwalker(memory, modules, supplier, resolver), context_(context) { if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { // This implementation only covers 32-bit ppc CPUs. The limits of the diff --git a/src/processor/stackwalker_ppc.h b/src/processor/stackwalker_ppc.h index bccc9dc2..9901f673 100644 --- a/src/processor/stackwalker_ppc.h +++ b/src/processor/stackwalker_ppc.h @@ -56,7 +56,8 @@ class StackwalkerPPC : public Stackwalker { StackwalkerPPC(const MDRawContextPPC *context, MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier); + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); private: // Implementation of Stackwalker, using ppc context (stack pointer in %r1, diff --git a/src/processor/stackwalker_selftest.cc b/src/processor/stackwalker_selftest.cc index 877a8f3d..e645dd98 100644 --- a/src/processor/stackwalker_selftest.cc +++ b/src/processor/stackwalker_selftest.cc @@ -217,6 +217,7 @@ static u_int32_t GetPC() { static unsigned int CountCallerFrames() __attribute__((noinline)); static unsigned int CountCallerFrames() { SelfMemoryRegion memory; + BasicSourceLineResolver resolver; #if defined(__i386__) MDRawContextX86 context = MDRawContextX86(); @@ -224,13 +225,15 @@ static unsigned int CountCallerFrames() { context.ebp = GetEBP(); context.esp = GetESP(); - StackwalkerX86 stackwalker = StackwalkerX86(&context, &memory, NULL, NULL); + StackwalkerX86 stackwalker = StackwalkerX86(&context, &memory, NULL, NULL, + &resolver); #elif defined(__ppc__) MDRawContextPPC context = MDRawContextPPC(); context.srr0 = GetPC(); context.gpr[1] = GetSP(); - StackwalkerPPC stackwalker = StackwalkerPPC(&context, &memory, NULL, NULL); + StackwalkerPPC stackwalker = StackwalkerPPC(&context, &memory, NULL, NULL, + &resolver); #endif // __i386__ || __ppc__ scoped_ptr stack(stackwalker.Walk()); diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index 1e3390f5..0ee2fbd2 100644 --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -49,8 +49,9 @@ namespace google_airbag { StackwalkerX86::StackwalkerX86(const MDRawContextX86 *context, MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier) - : Stackwalker(memory, modules, supplier), + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver) + : Stackwalker(memory, modules, supplier, resolver), context_(context) { if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { // The x86 is a 32-bit CPU, the limits of the supplied stack are invalid. diff --git a/src/processor/stackwalker_x86.h b/src/processor/stackwalker_x86.h index fe2a7808..f53fc5f7 100644 --- a/src/processor/stackwalker_x86.h +++ b/src/processor/stackwalker_x86.h @@ -57,7 +57,8 @@ class StackwalkerX86 : public Stackwalker { StackwalkerX86(const MDRawContextX86 *context, MemoryRegion *memory, const CodeModules *modules, - SymbolSupplier *supplier); + SymbolSupplier *supplier, + SourceLineResolverInterface *resolver); private: // Implementation of Stackwalker, using x86 context (%ebp, %esp, %eip) and -- cgit v1.2.1