mirror of
				https://github.com/yuzu-emu/breakpad.git
				synced 2025-11-04 11:44:59 +00:00 
			
		
		
		
	Module API (#32). r=waylonis, bryner
- Introduces a standard API for dealing with modules. MinidumpModule is now a concrete implementation of this API. Code may interact with single modules using the CodeModule interface, and collections of modules using its container, the CodeModules interface. - CodeModule is used directly by SymbolSupplier implementations and SourceLineResolver. Reliance on the specific implementation in MinidumpModule has been eliminated. - Module lists are now added to ProcessState objects. Module references in each stack frame are now pointers to objects in these module lists. - The sample minidump_stackwalk tool prints the module list after printing all threads' stacks. http://groups.google.com/group/airbag-dev/browse_frm/thread/a9c0550edde54cf8 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@74 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
		
							parent
							
								
									ed61ae0bbd
								
							
						
					
					
						commit
						db3342a10e
					
				
							
								
								
									
										47
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								Makefile.am
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -53,6 +53,8 @@ src_libairbag_la_SOURCES = \
 | 
			
		|||
	src/google_airbag/common/airbag_types.h \
 | 
			
		||||
	src/google_airbag/common/minidump_format.h \
 | 
			
		||||
	src/google_airbag/processor/call_stack.h \
 | 
			
		||||
	src/google_airbag/processor/code_module.h \
 | 
			
		||||
	src/google_airbag/processor/code_modules.h \
 | 
			
		||||
	src/google_airbag/processor/memory_region.h \
 | 
			
		||||
	src/google_airbag/processor/minidump.h \
 | 
			
		||||
	src/google_airbag/processor/minidump_processor.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +65,9 @@ src_libairbag_la_SOURCES = \
 | 
			
		|||
	src/google_airbag/processor/symbol_supplier.h \
 | 
			
		||||
	src/processor/address_map.h \
 | 
			
		||||
	src/processor/address_map-inl.h \
 | 
			
		||||
	src/processor/basic_code_module.h \
 | 
			
		||||
	src/processor/basic_code_modules.cc \
 | 
			
		||||
	src/processor/basic_code_modules.h \
 | 
			
		||||
	src/processor/call_stack.cc \
 | 
			
		||||
	src/processor/contained_range_map.h \
 | 
			
		||||
	src/processor/contained_range_map-inl.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +131,7 @@ src_processor_contained_range_map_unittest_SOURCES = \
 | 
			
		|||
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/call_stack.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +160,7 @@ src_processor_source_line_resolver_unittest_LDADD = \
 | 
			
		|||
src_processor_stackwalker_selftest_SOURCES = \
 | 
			
		||||
	src/processor/stackwalker_selftest.cc
 | 
			
		||||
src_processor_stackwalker_selftest_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/call_stack.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
	src/processor/source_line_resolver.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -168,11 +175,13 @@ noinst_SCRIPTS = $(check_SCRIPTS)
 | 
			
		|||
src_processor_minidump_dump_SOURCES = \
 | 
			
		||||
	src/processor/minidump_dump.cc
 | 
			
		||||
src_processor_minidump_dump_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/minidump.lo
 | 
			
		||||
 | 
			
		||||
src_processor_minidump_stackwalk_SOURCES = \
 | 
			
		||||
	src/processor/minidump_stackwalk.cc
 | 
			
		||||
src_processor_minidump_stackwalk_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/call_stack.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -186,16 +195,44 @@ src_processor_minidump_stackwalk_LDADD = \
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
## Additional files to be included in a source distribution
 | 
			
		||||
##
 | 
			
		||||
## find src/client src/common src/processor/testdata src/tools \
 | 
			
		||||
##     -type f \! -wholename '*/.svn*' -print | sort
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
	$(SCRIPTS) \
 | 
			
		||||
	src/processor/testdata/minidump1.dmp \
 | 
			
		||||
	src/processor/testdata/minidump1.out \
 | 
			
		||||
	src/processor/testdata/minidump1.stack.out \
 | 
			
		||||
	src/client/minidump_file_writer.cc \
 | 
			
		||||
	src/client/minidump_file_writer.h \
 | 
			
		||||
	src/client/minidump_file_writer-inl.h \
 | 
			
		||||
	src/client/windows/airbag_client.sln \
 | 
			
		||||
	src/client/windows/handler/exception_handler.cc \
 | 
			
		||||
	src/client/windows/handler/exception_handler.h \
 | 
			
		||||
	src/client/windows/handler/exception_handler.vcproj \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.cc \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.h \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.vcproj \
 | 
			
		||||
	src/common/windows/guid_string.cc \
 | 
			
		||||
	src/common/windows/guid_string.h \
 | 
			
		||||
	src/common/windows/http_upload.cc \
 | 
			
		||||
	src/common/windows/http_upload.h \
 | 
			
		||||
	src/common/windows/pdb_source_line_writer.cc \
 | 
			
		||||
	src/common/windows/pdb_source_line_writer.h \
 | 
			
		||||
	src/common/windows/string_utils-inl.h \
 | 
			
		||||
	src/processor/testdata/minidump2.dmp \
 | 
			
		||||
	src/processor/testdata/minidump2.sym \
 | 
			
		||||
	src/processor/testdata/minidump2.dump.out \
 | 
			
		||||
	src/processor/testdata/minidump2.stackwalk.out \
 | 
			
		||||
	src/processor/testdata/module1.out \
 | 
			
		||||
	src/processor/testdata/module2.out \
 | 
			
		||||
	src/processor/testdata/module3_bad.out
 | 
			
		||||
	src/processor/testdata/module3_bad.out \
 | 
			
		||||
	src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym \
 | 
			
		||||
	src/processor/testdata/symbols/test_app.pdb/8DDB7E9A365748938D6EB08B1DCA31AA1/test_app.sym \
 | 
			
		||||
	src/processor/testdata/test_app.cc \
 | 
			
		||||
	src/tools/windows/dump_syms/dump_syms.cc \
 | 
			
		||||
	src/tools/windows/dump_syms/dump_syms.vcproj \
 | 
			
		||||
	src/tools/windows/dump_syms/run_regtest.sh \
 | 
			
		||||
	src/tools/windows/dump_syms/testdata/dump_syms_regtest.out \
 | 
			
		||||
	src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \
 | 
			
		||||
	src/tools/windows/symupload/symupload.cc \
 | 
			
		||||
	src/tools/windows/symupload/symupload.vcproj
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Additional rules
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								Makefile.in
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								Makefile.in
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -110,8 +110,9 @@ libLTLIBRARIES_INSTALL = $(INSTALL)
 | 
			
		|||
LTLIBRARIES = $(lib_LTLIBRARIES)
 | 
			
		||||
src_libairbag_la_LIBADD =
 | 
			
		||||
am__dirstamp = $(am__leading_dot)dirstamp
 | 
			
		||||
am_src_libairbag_la_OBJECTS = src/processor/call_stack.lo \
 | 
			
		||||
	src/processor/minidump.lo src/processor/minidump_processor.lo \
 | 
			
		||||
am_src_libairbag_la_OBJECTS = src/processor/basic_code_modules.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 \
 | 
			
		||||
| 
						 | 
				
			
			@ -137,12 +138,14 @@ am_src_processor_minidump_dump_OBJECTS =  \
 | 
			
		|||
	src/processor/minidump_dump.$(OBJEXT)
 | 
			
		||||
src_processor_minidump_dump_OBJECTS =  \
 | 
			
		||||
	$(am_src_processor_minidump_dump_OBJECTS)
 | 
			
		||||
src_processor_minidump_dump_DEPENDENCIES = src/processor/minidump.lo
 | 
			
		||||
src_processor_minidump_dump_DEPENDENCIES =  \
 | 
			
		||||
	src/processor/basic_code_modules.lo src/processor/minidump.lo
 | 
			
		||||
am_src_processor_minidump_processor_unittest_OBJECTS =  \
 | 
			
		||||
	src/processor/minidump_processor_unittest.$(OBJEXT)
 | 
			
		||||
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/call_stack.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo src/processor/minidump.lo \
 | 
			
		||||
	src/processor/process_state.lo src/processor/stackwalker.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +157,7 @@ am_src_processor_minidump_stackwalk_OBJECTS =  \
 | 
			
		|||
src_processor_minidump_stackwalk_OBJECTS =  \
 | 
			
		||||
	$(am_src_processor_minidump_stackwalk_OBJECTS)
 | 
			
		||||
src_processor_minidump_stackwalk_DEPENDENCIES =  \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/call_stack.lo src/processor/minidump.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo \
 | 
			
		||||
	src/processor/pathname_stripper.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -189,6 +193,7 @@ am_src_processor_stackwalker_selftest_OBJECTS =  \
 | 
			
		|||
src_processor_stackwalker_selftest_OBJECTS =  \
 | 
			
		||||
	$(am_src_processor_stackwalker_selftest_OBJECTS)
 | 
			
		||||
src_processor_stackwalker_selftest_DEPENDENCIES =  \
 | 
			
		||||
	src/processor/basic_code_modules.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 \
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +375,8 @@ src_libairbag_la_SOURCES = \
 | 
			
		|||
	src/google_airbag/common/airbag_types.h \
 | 
			
		||||
	src/google_airbag/common/minidump_format.h \
 | 
			
		||||
	src/google_airbag/processor/call_stack.h \
 | 
			
		||||
	src/google_airbag/processor/code_module.h \
 | 
			
		||||
	src/google_airbag/processor/code_modules.h \
 | 
			
		||||
	src/google_airbag/processor/memory_region.h \
 | 
			
		||||
	src/google_airbag/processor/minidump.h \
 | 
			
		||||
	src/google_airbag/processor/minidump_processor.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -380,6 +387,9 @@ src_libairbag_la_SOURCES = \
 | 
			
		|||
	src/google_airbag/processor/symbol_supplier.h \
 | 
			
		||||
	src/processor/address_map.h \
 | 
			
		||||
	src/processor/address_map-inl.h \
 | 
			
		||||
	src/processor/basic_code_module.h \
 | 
			
		||||
	src/processor/basic_code_modules.cc \
 | 
			
		||||
	src/processor/basic_code_modules.h \
 | 
			
		||||
	src/processor/call_stack.cc \
 | 
			
		||||
	src/processor/contained_range_map.h \
 | 
			
		||||
	src/processor/contained_range_map-inl.h \
 | 
			
		||||
| 
						 | 
				
			
			@ -421,6 +431,7 @@ 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/call_stack.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -452,6 +463,7 @@ src_processor_stackwalker_selftest_SOURCES = \
 | 
			
		|||
	src/processor/stackwalker_selftest.cc
 | 
			
		||||
 | 
			
		||||
src_processor_stackwalker_selftest_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/call_stack.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
	src/processor/source_line_resolver.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -464,12 +476,14 @@ src_processor_minidump_dump_SOURCES = \
 | 
			
		|||
	src/processor/minidump_dump.cc
 | 
			
		||||
 | 
			
		||||
src_processor_minidump_dump_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/minidump.lo
 | 
			
		||||
 | 
			
		||||
src_processor_minidump_stackwalk_SOURCES = \
 | 
			
		||||
	src/processor/minidump_stackwalk.cc
 | 
			
		||||
 | 
			
		||||
src_processor_minidump_stackwalk_LDADD = \
 | 
			
		||||
	src/processor/basic_code_modules.lo \
 | 
			
		||||
	src/processor/call_stack.lo \
 | 
			
		||||
	src/processor/minidump.lo \
 | 
			
		||||
	src/processor/minidump_processor.lo \
 | 
			
		||||
| 
						 | 
				
			
			@ -483,14 +497,39 @@ src_processor_minidump_stackwalk_LDADD = \
 | 
			
		|||
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
	$(SCRIPTS) \
 | 
			
		||||
	src/processor/testdata/minidump1.dmp \
 | 
			
		||||
	src/processor/testdata/minidump1.out \
 | 
			
		||||
	src/processor/testdata/minidump1.stack.out \
 | 
			
		||||
	src/client/minidump_file_writer.cc \
 | 
			
		||||
	src/client/minidump_file_writer.h \
 | 
			
		||||
	src/client/minidump_file_writer-inl.h \
 | 
			
		||||
	src/client/windows/airbag_client.sln \
 | 
			
		||||
	src/client/windows/handler/exception_handler.cc \
 | 
			
		||||
	src/client/windows/handler/exception_handler.h \
 | 
			
		||||
	src/client/windows/handler/exception_handler.vcproj \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.cc \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.h \
 | 
			
		||||
	src/client/windows/sender/crash_report_sender.vcproj \
 | 
			
		||||
	src/common/windows/guid_string.cc \
 | 
			
		||||
	src/common/windows/guid_string.h \
 | 
			
		||||
	src/common/windows/http_upload.cc \
 | 
			
		||||
	src/common/windows/http_upload.h \
 | 
			
		||||
	src/common/windows/pdb_source_line_writer.cc \
 | 
			
		||||
	src/common/windows/pdb_source_line_writer.h \
 | 
			
		||||
	src/common/windows/string_utils-inl.h \
 | 
			
		||||
	src/processor/testdata/minidump2.dmp \
 | 
			
		||||
	src/processor/testdata/minidump2.sym \
 | 
			
		||||
	src/processor/testdata/minidump2.dump.out \
 | 
			
		||||
	src/processor/testdata/minidump2.stackwalk.out \
 | 
			
		||||
	src/processor/testdata/module1.out \
 | 
			
		||||
	src/processor/testdata/module2.out \
 | 
			
		||||
	src/processor/testdata/module3_bad.out
 | 
			
		||||
	src/processor/testdata/module3_bad.out \
 | 
			
		||||
	src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym \
 | 
			
		||||
	src/processor/testdata/symbols/test_app.pdb/8DDB7E9A365748938D6EB08B1DCA31AA1/test_app.sym \
 | 
			
		||||
	src/processor/testdata/test_app.cc \
 | 
			
		||||
	src/tools/windows/dump_syms/dump_syms.cc \
 | 
			
		||||
	src/tools/windows/dump_syms/dump_syms.vcproj \
 | 
			
		||||
	src/tools/windows/dump_syms/run_regtest.sh \
 | 
			
		||||
	src/tools/windows/dump_syms/testdata/dump_syms_regtest.out \
 | 
			
		||||
	src/tools/windows/dump_syms/testdata/dump_syms_regtest.pdb \
 | 
			
		||||
	src/tools/windows/symupload/symupload.cc \
 | 
			
		||||
	src/tools/windows/symupload/symupload.vcproj
 | 
			
		||||
 | 
			
		||||
all: all-am
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -579,6 +618,8 @@ src/processor/$(am__dirstamp):
 | 
			
		|||
src/processor/$(DEPDIR)/$(am__dirstamp):
 | 
			
		||||
	@$(mkdir_p) src/processor/$(DEPDIR)
 | 
			
		||||
	@: > src/processor/$(DEPDIR)/$(am__dirstamp)
 | 
			
		||||
src/processor/basic_code_modules.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) \
 | 
			
		||||
| 
						 | 
				
			
			@ -710,6 +751,8 @@ src/processor/stackwalker_selftest$(EXEEXT): $(src_processor_stackwalker_selftes
 | 
			
		|||
mostlyclean-compile:
 | 
			
		||||
	-rm -f *.$(OBJEXT)
 | 
			
		||||
	-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/call_stack.$(OBJEXT)
 | 
			
		||||
	-rm -f src/processor/call_stack.lo
 | 
			
		||||
	-rm -f src/processor/contained_range_map_unittest.$(OBJEXT)
 | 
			
		||||
| 
						 | 
				
			
			@ -744,6 +787,7 @@ distclean-compile:
 | 
			
		|||
	-rm -f *.tab.c
 | 
			
		||||
 | 
			
		||||
@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)/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@
 | 
			
		||||
| 
						 | 
				
			
			@ -941,7 +985,7 @@ check-TESTS: $(TESTS)
 | 
			
		|||
distdir: $(DISTFILES)
 | 
			
		||||
	$(am__remove_distdir)
 | 
			
		||||
	mkdir $(distdir)
 | 
			
		||||
	$(mkdir_p) $(distdir)/autotools $(distdir)/src $(distdir)/src/processor $(distdir)/src/processor/testdata
 | 
			
		||||
	$(mkdir_p) $(distdir)/autotools $(distdir)/src $(distdir)/src/client $(distdir)/src/client/windows $(distdir)/src/client/windows/handler $(distdir)/src/client/windows/sender $(distdir)/src/common/windows $(distdir)/src/processor $(distdir)/src/processor/testdata $(distdir)/src/processor/testdata/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542 $(distdir)/src/processor/testdata/symbols/test_app.pdb/8DDB7E9A365748938D6EB08B1DCA31AA1 $(distdir)/src/tools/windows/dump_syms $(distdir)/src/tools/windows/dump_syms/testdata $(distdir)/src/tools/windows/symupload
 | 
			
		||||
	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
 | 
			
		||||
	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
 | 
			
		||||
	list='$(DISTFILES)'; for file in $$list; do \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								aclocal.m4
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -7061,6 +7061,23 @@ AC_DEFUN([_AM_SET_OPTIONS],
 | 
			
		|||
AC_DEFUN([_AM_IF_OPTION],
 | 
			
		||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
 | 
			
		||||
#
 | 
			
		||||
# This file is free software; the Free Software Foundation
 | 
			
		||||
# gives unlimited permission to copy and/or distribute it,
 | 
			
		||||
# with or without modifications, as long as this notice is preserved.
 | 
			
		||||
 | 
			
		||||
# AM_RUN_LOG(COMMAND)
 | 
			
		||||
# -------------------
 | 
			
		||||
# Run COMMAND, save the exit status in ac_status, and log it.
 | 
			
		||||
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
 | 
			
		||||
AC_DEFUN([AM_RUN_LOG],
 | 
			
		||||
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
 | 
			
		||||
   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
 | 
			
		||||
   (exit $ac_status); }])
 | 
			
		||||
 | 
			
		||||
# Check to make sure that the build environment is sane.    -*- Autoconf -*-
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										129
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										129
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -2375,7 +2375,88 @@ INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
 | 
			
		|||
 | 
			
		||||
AMTAR=${AMTAR-"${am_missing_run}tar"}
 | 
			
		||||
 | 
			
		||||
am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
 | 
			
		||||
 | 
			
		||||
{ echo "$as_me:$LINENO: checking how to create a ustar tar archive" >&5
 | 
			
		||||
echo $ECHO_N "checking how to create a ustar tar archive... $ECHO_C" >&6; }
 | 
			
		||||
# Loop over all known methods to create a tar archive until one works.
 | 
			
		||||
_am_tools='gnutar plaintar pax cpio none'
 | 
			
		||||
_am_tools=${am_cv_prog_tar_ustar-$_am_tools}
 | 
			
		||||
# Do not fold the above two line into one, because Tru64 sh and
 | 
			
		||||
# Solaris sh will not grok spaces in the rhs of `-'.
 | 
			
		||||
for _am_tool in $_am_tools
 | 
			
		||||
do
 | 
			
		||||
  case $_am_tool in
 | 
			
		||||
  gnutar)
 | 
			
		||||
    for _am_tar in tar gnutar gtar;
 | 
			
		||||
    do
 | 
			
		||||
      { echo "$as_me:$LINENO: $_am_tar --version" >&5
 | 
			
		||||
   ($_am_tar --version) >&5 2>&5
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
 | 
			
		||||
   (exit $ac_status); } && break
 | 
			
		||||
    done
 | 
			
		||||
    am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"'
 | 
			
		||||
    am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"'
 | 
			
		||||
    am__untar="$_am_tar -xf -"
 | 
			
		||||
    ;;
 | 
			
		||||
  plaintar)
 | 
			
		||||
    # Must skip GNU tar: if it does not support --format= it doesn't create
 | 
			
		||||
    # ustar tarball either.
 | 
			
		||||
    (tar --version) >/dev/null 2>&1 && continue
 | 
			
		||||
    am__tar='tar chf - "$$tardir"'
 | 
			
		||||
    am__tar_='tar chf - "$tardir"'
 | 
			
		||||
    am__untar='tar xf -'
 | 
			
		||||
    ;;
 | 
			
		||||
  pax)
 | 
			
		||||
    am__tar='pax -L -x ustar -w "$$tardir"'
 | 
			
		||||
    am__tar_='pax -L -x ustar -w "$tardir"'
 | 
			
		||||
    am__untar='pax -r'
 | 
			
		||||
    ;;
 | 
			
		||||
  cpio)
 | 
			
		||||
    am__tar='find "$$tardir" -print | cpio -o -H ustar -L'
 | 
			
		||||
    am__tar_='find "$tardir" -print | cpio -o -H ustar -L'
 | 
			
		||||
    am__untar='cpio -i -H ustar -d'
 | 
			
		||||
    ;;
 | 
			
		||||
  none)
 | 
			
		||||
    am__tar=false
 | 
			
		||||
    am__tar_=false
 | 
			
		||||
    am__untar=false
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  # If the value was cached, stop now.  We just wanted to have am__tar
 | 
			
		||||
  # and am__untar set.
 | 
			
		||||
  test -n "${am_cv_prog_tar_ustar}" && break
 | 
			
		||||
 | 
			
		||||
  # tar/untar a dummy directory, and stop if the command works
 | 
			
		||||
  rm -rf conftest.dir
 | 
			
		||||
  mkdir conftest.dir
 | 
			
		||||
  echo GrepMe > conftest.dir/file
 | 
			
		||||
  { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5
 | 
			
		||||
   (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
 | 
			
		||||
   (exit $ac_status); }
 | 
			
		||||
  rm -rf conftest.dir
 | 
			
		||||
  if test -s conftest.tar; then
 | 
			
		||||
    { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5
 | 
			
		||||
   ($am__untar <conftest.tar) >&5 2>&5
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
 | 
			
		||||
   (exit $ac_status); }
 | 
			
		||||
    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
 | 
			
		||||
  fi
 | 
			
		||||
done
 | 
			
		||||
rm -rf conftest.dir
 | 
			
		||||
 | 
			
		||||
if test "${am_cv_prog_tar_ustar+set}" = set; then
 | 
			
		||||
  echo $ECHO_N "(cached) $ECHO_C" >&6
 | 
			
		||||
else
 | 
			
		||||
  am_cv_prog_tar_ustar=$_am_tool
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
{ echo "$as_me:$LINENO: result: $am_cv_prog_tar_ustar" >&5
 | 
			
		||||
echo "${ECHO_T}$am_cv_prog_tar_ustar" >&6; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5154,7 +5235,7 @@ ia64-*-hpux*)
 | 
			
		|||
  ;;
 | 
			
		||||
*-*-irix6*)
 | 
			
		||||
  # Find out which ABI we are using.
 | 
			
		||||
  echo '#line 5157 "configure"' > conftest.$ac_ext
 | 
			
		||||
  echo '#line 5238 "configure"' > conftest.$ac_ext
 | 
			
		||||
  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
 | 
			
		||||
  (eval $ac_compile) 2>&5
 | 
			
		||||
  ac_status=$?
 | 
			
		||||
| 
						 | 
				
			
			@ -7319,11 +7400,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:7322: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:7403: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:7326: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:7407: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -7587,11 +7668,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:7590: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:7671: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:7594: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:7675: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -7691,11 +7772,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:7694: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:7775: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>out/conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat out/conftest.err >&5
 | 
			
		||||
   echo "$as_me:7698: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:7779: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
 | 
			
		||||
   then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
| 
						 | 
				
			
			@ -10143,7 +10224,7 @@ else
 | 
			
		|||
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
 | 
			
		||||
  lt_status=$lt_dlunknown
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 10146 "configure"
 | 
			
		||||
#line 10227 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
 | 
			
		||||
#if HAVE_DLFCN_H
 | 
			
		||||
| 
						 | 
				
			
			@ -10243,7 +10324,7 @@ else
 | 
			
		|||
  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
 | 
			
		||||
  lt_status=$lt_dlunknown
 | 
			
		||||
  cat > conftest.$ac_ext <<EOF
 | 
			
		||||
#line 10246 "configure"
 | 
			
		||||
#line 10327 "configure"
 | 
			
		||||
#include "confdefs.h"
 | 
			
		||||
 | 
			
		||||
#if HAVE_DLFCN_H
 | 
			
		||||
| 
						 | 
				
			
			@ -12611,11 +12692,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:12614: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:12695: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:12618: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:12699: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -12715,11 +12796,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:12718: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:12799: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>out/conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat out/conftest.err >&5
 | 
			
		||||
   echo "$as_me:12722: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:12803: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
 | 
			
		||||
   then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
| 
						 | 
				
			
			@ -14285,11 +14366,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:14288: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:14369: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:14292: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:14373: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -14389,11 +14470,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:14392: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:14473: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>out/conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat out/conftest.err >&5
 | 
			
		||||
   echo "$as_me:14396: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:14477: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
 | 
			
		||||
   then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
| 
						 | 
				
			
			@ -16619,11 +16700,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:16622: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:16703: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:16626: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:16707: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -16887,11 +16968,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:16890: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:16971: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat conftest.err >&5
 | 
			
		||||
   echo "$as_me:16894: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:16975: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s "$ac_outfile"; then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
     # So say no if there are warnings other than the usual output.
 | 
			
		||||
| 
						 | 
				
			
			@ -16991,11 +17072,11 @@ else
 | 
			
		|||
   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
 | 
			
		||||
   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
 | 
			
		||||
   -e 's:$: $lt_compiler_flag:'`
 | 
			
		||||
   (eval echo "\"\$as_me:16994: $lt_compile\"" >&5)
 | 
			
		||||
   (eval echo "\"\$as_me:17075: $lt_compile\"" >&5)
 | 
			
		||||
   (eval "$lt_compile" 2>out/conftest.err)
 | 
			
		||||
   ac_status=$?
 | 
			
		||||
   cat out/conftest.err >&5
 | 
			
		||||
   echo "$as_me:16998: \$? = $ac_status" >&5
 | 
			
		||||
   echo "$as_me:17079: \$? = $ac_status" >&5
 | 
			
		||||
   if (exit $ac_status) && test -s out/conftest2.$ac_objext
 | 
			
		||||
   then
 | 
			
		||||
     # The compiler can only warn and ignore the option if not recognized
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ dnl Sanity check: the argument is just a file that should exist.
 | 
			
		|||
AC_CONFIG_SRCDIR(README)
 | 
			
		||||
AC_CONFIG_AUX_DIR(autotools)
 | 
			
		||||
 | 
			
		||||
AM_INIT_AUTOMAKE(subdir-objects)
 | 
			
		||||
AM_INIT_AUTOMAKE(subdir-objects tar-ustar)
 | 
			
		||||
AM_CONFIG_HEADER(src/config.h)
 | 
			
		||||
 | 
			
		||||
AC_PROG_CC
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										93
									
								
								src/google_airbag/processor/code_module.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/google_airbag/processor/code_module.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
// 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.
 | 
			
		||||
 | 
			
		||||
// code_module.h: Carries information about code modules that are loaded
 | 
			
		||||
// into a process.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#ifndef GOOGLE_AIRBAG_PROCESSOR_CODE_MODULE_H__
 | 
			
		||||
#define GOOGLE_AIRBAG_PROCESSOR_CODE_MODULE_H__
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
class CodeModule {
 | 
			
		||||
 public:
 | 
			
		||||
  virtual ~CodeModule() {}
 | 
			
		||||
 | 
			
		||||
  // The base address of this code module as it was loaded by the process.
 | 
			
		||||
  // (u_int64_t)-1 on error.
 | 
			
		||||
  virtual u_int64_t base_address() const = 0;
 | 
			
		||||
 | 
			
		||||
  // The size of the code module.  0 on error.
 | 
			
		||||
  virtual u_int64_t size() const = 0;
 | 
			
		||||
 | 
			
		||||
  // The path or file name that the code module was loaded from.  Empty on
 | 
			
		||||
  // error.
 | 
			
		||||
  virtual string code_file() const = 0;
 | 
			
		||||
 | 
			
		||||
  // An identifying string used to discriminate between multiple versions and
 | 
			
		||||
  // builds of the same code module.  This may contain a uuid, timestamp,
 | 
			
		||||
  // version number, or any combination of this or other information, in an
 | 
			
		||||
  // implementation-defined format.  Empty on error.
 | 
			
		||||
  virtual string code_identifier() const = 0;
 | 
			
		||||
 | 
			
		||||
  // The filename containing debugging information associated with the code
 | 
			
		||||
  // module.  If debugging information is stored in a file separate from the
 | 
			
		||||
  // code module itself (as is the case when .pdb or .dSYM files are used),
 | 
			
		||||
  // this will be different from code_file.  If debugging information is
 | 
			
		||||
  // stored in the code module itself (possibly prior to stripping), this
 | 
			
		||||
  // will be the same as code_file.  Empty on error.
 | 
			
		||||
  virtual string debug_file() const = 0;
 | 
			
		||||
 | 
			
		||||
  // An identifying string similar to code_identifier, but identifies a
 | 
			
		||||
  // specific version and build of the associated debug file.  This may be
 | 
			
		||||
  // the same as code_identifier when the debug_file and code_file are
 | 
			
		||||
  // identical or when the same identifier is used to identify distinct
 | 
			
		||||
  // debug and code files.
 | 
			
		||||
  virtual string debug_identifier() const = 0;
 | 
			
		||||
 | 
			
		||||
  // A human-readable representation of the code module's version.  Empty on
 | 
			
		||||
  // error.
 | 
			
		||||
  virtual string version() const = 0;
 | 
			
		||||
 | 
			
		||||
  // Creates a new copy of this CodeModule object, which the caller takes
 | 
			
		||||
  // ownership of.  The new CodeModule may be of a different concrete class
 | 
			
		||||
  // than the CodeModule being copied, but will behave identically to the
 | 
			
		||||
  // copied CodeModule as far as the CodeModule interface is concerned.
 | 
			
		||||
  virtual const CodeModule* Copy() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
 | 
			
		||||
#endif  // GOOGLE_AIRBAG_PROCESSOR_CODE_MODULE_H__
 | 
			
		||||
							
								
								
									
										98
									
								
								src/google_airbag/processor/code_modules.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/google_airbag/processor/code_modules.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,98 @@
 | 
			
		|||
// 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.
 | 
			
		||||
 | 
			
		||||
// code_modules.h: Contains all of the CodeModule objects that were loaded
 | 
			
		||||
// into a single process.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#ifndef GOOGLE_AIRBAG_PROCESSOR_CODE_MODULES_H__
 | 
			
		||||
#define GOOGLE_AIRBAG_PROCESSOR_CODE_MODULES_H__
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/common/airbag_types.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
class CodeModule;
 | 
			
		||||
 | 
			
		||||
class CodeModules {
 | 
			
		||||
 public:
 | 
			
		||||
  virtual ~CodeModules() {}
 | 
			
		||||
 | 
			
		||||
  // The number of contained CodeModule objects.
 | 
			
		||||
  virtual unsigned int module_count() const = 0;
 | 
			
		||||
 | 
			
		||||
  // Random access to modules.  Returns the module whose code is present
 | 
			
		||||
  // at the address indicated by |address|.  If no module is present at this
 | 
			
		||||
  // address, returns NULL.  Ownership of the returned CodeModule is retained
 | 
			
		||||
  // by the CodeModules object; pointers returned by this method are valid for
 | 
			
		||||
  // comparison with pointers returned by the other Get methods.
 | 
			
		||||
  virtual const CodeModule* GetModuleForAddress(u_int64_t address) const = 0;
 | 
			
		||||
 | 
			
		||||
  // Returns the module corresponding to the main executable.  If there is
 | 
			
		||||
  // no main executable, returns NULL.  Ownership of the returned CodeModule
 | 
			
		||||
  // is retained by the CodeModules object; pointers returned by this method
 | 
			
		||||
  // are valid for comparison with pointers returned by the other Get
 | 
			
		||||
  // methods.
 | 
			
		||||
  virtual const CodeModule* GetMainModule() const = 0;
 | 
			
		||||
 | 
			
		||||
  // Sequential access to modules.  A sequence number of 0 corresponds to the
 | 
			
		||||
  // module residing lowest in memory.  If the sequence number is out of
 | 
			
		||||
  // range, returns NULL.  Ownership of the returned CodeModule is retained
 | 
			
		||||
  // by the CodeModules object; pointers returned by this method are valid for
 | 
			
		||||
  // comparison with pointers returned by the other Get methods.
 | 
			
		||||
  virtual const CodeModule* GetModuleAtSequence(
 | 
			
		||||
      unsigned int sequence) const = 0;
 | 
			
		||||
 | 
			
		||||
  // Sequential access to modules.  This is similar to GetModuleAtSequence,
 | 
			
		||||
  // except no ordering requirement is enforced.  A CodeModules implementation
 | 
			
		||||
  // may return CodeModule objects from GetModuleAtIndex in any order it
 | 
			
		||||
  // wishes, provided that the order remain the same throughout the life of
 | 
			
		||||
  // the CodeModules object.  Typically, GetModuleAtIndex would be used by
 | 
			
		||||
  // a caller to enumerate all CodeModule objects quickly when the enumeration
 | 
			
		||||
  // does not require any ordering.  If the index argument is out of range,
 | 
			
		||||
  // returns NULL.  Ownership of the returned CodeModule is retained by
 | 
			
		||||
  // the CodeModules object; pointers returned by this method are valid for
 | 
			
		||||
  // comparison with pointers returned by the other Get methods.
 | 
			
		||||
  virtual const CodeModule* GetModuleAtIndex(unsigned int index) const = 0;
 | 
			
		||||
 | 
			
		||||
  // Creates a new copy of this CodeModules object, which the caller takes
 | 
			
		||||
  // ownership of.  The new object will also contain copies of the existing
 | 
			
		||||
  // object's child CodeModule objects.  The new CodeModules object may be of
 | 
			
		||||
  // a different concrete class than the object being copied, but will behave
 | 
			
		||||
  // identically to the copied object as far as the CodeModules and CodeModule
 | 
			
		||||
  // interfaces are concerned, except that the order that GetModuleAtIndex
 | 
			
		||||
  // returns objects in may differ between a copy and the original CodeModules
 | 
			
		||||
  // object.
 | 
			
		||||
  virtual const CodeModules* Copy() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
 | 
			
		||||
#endif  // GOOGLE_AIRBAG_PROCESSOR_CODE_MODULES_H__
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +85,8 @@
 | 
			
		|||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/common/minidump_format.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
#include "google_airbag/processor/memory_region.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +164,7 @@ class MinidumpStream : public MinidumpObject {
 | 
			
		|||
// user wants).
 | 
			
		||||
class MinidumpContext : public MinidumpStream {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpContext();
 | 
			
		||||
  virtual ~MinidumpContext();
 | 
			
		||||
 | 
			
		||||
  // Returns an MD_CONTEXT_* value such as MD_CONTEXT_X86 or MD_CONTEXT_PPC
 | 
			
		||||
  // identifying the CPU type that the context was collected from.  The
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +219,7 @@ class MinidumpContext : public MinidumpStream {
 | 
			
		|||
class MinidumpMemoryRegion : public MinidumpObject,
 | 
			
		||||
                             public MemoryRegion {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpMemoryRegion();
 | 
			
		||||
  virtual ~MinidumpMemoryRegion();
 | 
			
		||||
 | 
			
		||||
  // Returns a pointer to the base of the memory region.  Returns the
 | 
			
		||||
  // cached value if available, otherwise, reads the minidump file and
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +274,7 @@ class MinidumpMemoryRegion : public MinidumpObject,
 | 
			
		|||
// provided here.
 | 
			
		||||
class MinidumpThread : public MinidumpObject {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpThread();
 | 
			
		||||
  virtual ~MinidumpThread();
 | 
			
		||||
 | 
			
		||||
  const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; }
 | 
			
		||||
  MinidumpMemoryRegion* GetMemory();
 | 
			
		||||
| 
						 | 
				
			
			@ -308,7 +310,7 @@ class MinidumpThread : public MinidumpObject {
 | 
			
		|||
// a process.
 | 
			
		||||
class MinidumpThreadList : public MinidumpStream {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpThreadList();
 | 
			
		||||
  virtual ~MinidumpThreadList();
 | 
			
		||||
 | 
			
		||||
  unsigned int thread_count() const { return valid_ ? thread_count_ : 0; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -346,19 +348,24 @@ class MinidumpThreadList : public MinidumpStream {
 | 
			
		|||
// code modules.  Access is provided to various data referenced indirectly
 | 
			
		||||
// by MDRawModule, such as the module's name and a specification for where
 | 
			
		||||
// to locate debugging information for the module.
 | 
			
		||||
class MinidumpModule : public MinidumpObject {
 | 
			
		||||
class MinidumpModule : public MinidumpObject,
 | 
			
		||||
                       public CodeModule {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpModule();
 | 
			
		||||
  virtual ~MinidumpModule();
 | 
			
		||||
 | 
			
		||||
  const MDRawModule* module() const { return valid_ ? &module_ : NULL; }
 | 
			
		||||
  u_int64_t base_address() const {
 | 
			
		||||
 | 
			
		||||
  // CodeModule implementation
 | 
			
		||||
  virtual u_int64_t base_address() const {
 | 
			
		||||
    return valid_ ? module_.base_of_image : static_cast<u_int64_t>(-1);
 | 
			
		||||
  }
 | 
			
		||||
  u_int32_t size() const { return valid_ ? module_.size_of_image : 0; }
 | 
			
		||||
 | 
			
		||||
  // The name of the file containing this module's code (exe, dll, so,
 | 
			
		||||
  // dylib).
 | 
			
		||||
  const string* GetName();
 | 
			
		||||
  virtual u_int64_t size() const { return valid_ ? module_.size_of_image : 0; }
 | 
			
		||||
  virtual string code_file() const;
 | 
			
		||||
  virtual string code_identifier() const;
 | 
			
		||||
  virtual string debug_file() const;
 | 
			
		||||
  virtual string debug_identifier() const;
 | 
			
		||||
  virtual string version() const;
 | 
			
		||||
  virtual const CodeModule* Copy() const;
 | 
			
		||||
 | 
			
		||||
  // The CodeView record, which contains information to locate the module's
 | 
			
		||||
  // debugging information (pdb).  This is returned as u_int8_t* because
 | 
			
		||||
| 
						 | 
				
			
			@ -372,12 +379,6 @@ class MinidumpModule : public MinidumpObject {
 | 
			
		|||
  // field is not expected to be present.
 | 
			
		||||
  const MDImageDebugMisc* GetMiscRecord();
 | 
			
		||||
 | 
			
		||||
  // The filename of the file containing debugging information for this
 | 
			
		||||
  // module.  This data is supplied by the CodeView record, if present, or
 | 
			
		||||
  // the miscellaneous debug record.  As such, it will reference either a
 | 
			
		||||
  // pdb or dbg file.
 | 
			
		||||
  const string* GetDebugFilename();
 | 
			
		||||
 | 
			
		||||
  // Print a human-readable representation of the object to stdout.
 | 
			
		||||
  void Print();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -392,6 +393,21 @@ class MinidumpModule : public MinidumpObject {
 | 
			
		|||
  // MinidumpModuleList handles that directly.
 | 
			
		||||
  bool Read();
 | 
			
		||||
 | 
			
		||||
  // Reads indirectly-referenced data, including the module name, CodeView
 | 
			
		||||
  // record, and miscellaneous debugging record.  This is necessary to allow
 | 
			
		||||
  // MinidumpModuleList to fully construct MinidumpModule objects without
 | 
			
		||||
  // requiring seeks to read a contiguous set of MinidumpModule objects.
 | 
			
		||||
  // All auxiliary data should be available when Read is called, in order to
 | 
			
		||||
  // allow the CodeModule getters to be const methods.
 | 
			
		||||
  bool ReadAuxiliaryData();
 | 
			
		||||
 | 
			
		||||
  // True after a successful Read.  This is different from valid_, which is
 | 
			
		||||
  // not set true until ReadAuxiliaryData also completes successfully.
 | 
			
		||||
  // module_valid_ is only used by ReadAuxiliaryData and the functions it
 | 
			
		||||
  // calls to determine whether the object is ready for auxiliary data to 
 | 
			
		||||
  // be read.
 | 
			
		||||
  bool              module_valid_;
 | 
			
		||||
 | 
			
		||||
  MDRawModule       module_;
 | 
			
		||||
 | 
			
		||||
  // Cached module name.
 | 
			
		||||
| 
						 | 
				
			
			@ -407,9 +423,6 @@ class MinidumpModule : public MinidumpObject {
 | 
			
		|||
  // because the structure contains a variable-sized string and its exact
 | 
			
		||||
  // size cannot be known until it is processed.
 | 
			
		||||
  vector<u_int8_t>* misc_record_;
 | 
			
		||||
 | 
			
		||||
  // Cached debug filename.
 | 
			
		||||
  const string*     debug_filename_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -417,18 +430,21 @@ class MinidumpModule : public MinidumpObject {
 | 
			
		|||
// in the form of MinidumpModules.  It maintains a map of these modules
 | 
			
		||||
// so that it may easily provide a code module corresponding to a specific
 | 
			
		||||
// address.
 | 
			
		||||
class MinidumpModuleList : public MinidumpStream {
 | 
			
		||||
class MinidumpModuleList : public MinidumpStream,
 | 
			
		||||
                           public CodeModules {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpModuleList();
 | 
			
		||||
  virtual ~MinidumpModuleList();
 | 
			
		||||
 | 
			
		||||
  unsigned int module_count() const { return valid_ ? module_count_ : 0; }
 | 
			
		||||
 | 
			
		||||
  // Sequential access to modules.
 | 
			
		||||
  MinidumpModule* GetModuleAtIndex(unsigned int index) const;
 | 
			
		||||
 | 
			
		||||
  // Random access to modules.  Returns the module whose code is present
 | 
			
		||||
  // at the address identified by address.
 | 
			
		||||
  MinidumpModule* GetModuleForAddress(u_int64_t address);
 | 
			
		||||
  // CodeModules implementation.
 | 
			
		||||
  virtual unsigned int module_count() const {
 | 
			
		||||
    return valid_ ? module_count_ : 0;
 | 
			
		||||
  }
 | 
			
		||||
  virtual const MinidumpModule* GetModuleForAddress(u_int64_t address) const;
 | 
			
		||||
  virtual const MinidumpModule* GetMainModule() const;
 | 
			
		||||
  virtual const MinidumpModule* GetModuleAtSequence(
 | 
			
		||||
      unsigned int sequence) const;
 | 
			
		||||
  virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const;
 | 
			
		||||
  virtual const CodeModules* Copy() const;
 | 
			
		||||
 | 
			
		||||
  // Print a human-readable representation of the object to stdout.
 | 
			
		||||
  void Print();
 | 
			
		||||
| 
						 | 
				
			
			@ -463,7 +479,7 @@ class MinidumpModuleList : public MinidumpStream {
 | 
			
		|||
// memory minidumps contain all of a process' mapped memory.
 | 
			
		||||
class MinidumpMemoryList : public MinidumpStream {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpMemoryList();
 | 
			
		||||
  virtual ~MinidumpMemoryList();
 | 
			
		||||
 | 
			
		||||
  unsigned int region_count() const { return valid_ ? region_count_ : 0; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +528,7 @@ class MinidumpMemoryList : public MinidumpStream {
 | 
			
		|||
// the exception occurred.
 | 
			
		||||
class MinidumpException : public MinidumpStream {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpException();
 | 
			
		||||
  virtual ~MinidumpException();
 | 
			
		||||
 | 
			
		||||
  const MDRawExceptionStream* exception() const {
 | 
			
		||||
    return valid_ ? &exception_ : NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +563,7 @@ class MinidumpException : public MinidumpStream {
 | 
			
		|||
// the system on which the minidump was generated.  See also MinidumpMiscInfo.
 | 
			
		||||
class MinidumpSystemInfo : public MinidumpStream {
 | 
			
		||||
 public:
 | 
			
		||||
  ~MinidumpSystemInfo();
 | 
			
		||||
  virtual ~MinidumpSystemInfo();
 | 
			
		||||
 | 
			
		||||
  const MDRawSystemInfo* system_info() const {
 | 
			
		||||
    return valid_ ? &system_info_ : NULL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,7 @@ using std::string;
 | 
			
		|||
using std::vector;
 | 
			
		||||
 | 
			
		||||
class CallStack;
 | 
			
		||||
class CodeModules;
 | 
			
		||||
 | 
			
		||||
class ProcessState {
 | 
			
		||||
 public:
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +59,7 @@ class ProcessState {
 | 
			
		|||
  string os_version() const { return os_version_; }
 | 
			
		||||
  string cpu() const { return cpu_; }
 | 
			
		||||
  string cpu_info() const { return cpu_info_; }
 | 
			
		||||
  const CodeModules* modules() const { return modules_; }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  // MinidumpProcessor is responsible for building ProcessState objects.
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +68,7 @@ class ProcessState {
 | 
			
		|||
  // Disallow instantiation other than by friends.
 | 
			
		||||
  ProcessState() : crashed_(false), crash_reason_(), crash_address_(0),
 | 
			
		||||
                   requesting_thread_(-1), threads_(), os_(), os_version_(),
 | 
			
		||||
                   cpu_(), cpu_info_() {}
 | 
			
		||||
                   cpu_(), cpu_info_(), modules_(NULL) {}
 | 
			
		||||
 | 
			
		||||
  // True if the process crashed, false if the dump was produced outside
 | 
			
		||||
  // of an exception handler.
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +122,10 @@ class ProcessState {
 | 
			
		|||
  // present in the dump, or additional identifying information is not
 | 
			
		||||
  // defined for the CPU family, this field will be empty.
 | 
			
		||||
  string cpu_info_;
 | 
			
		||||
 | 
			
		||||
  // The modules that were loaded into the process represented by the
 | 
			
		||||
  // ProcessState.
 | 
			
		||||
  const CodeModules *modules_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,15 +35,16 @@
 | 
			
		|||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
class CodeModule;
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
struct StackFrame {
 | 
			
		||||
  StackFrame()
 | 
			
		||||
      : instruction(),
 | 
			
		||||
        module_base(),
 | 
			
		||||
        module_name(),
 | 
			
		||||
        function_base(),
 | 
			
		||||
        module(NULL),
 | 
			
		||||
        function_name(),
 | 
			
		||||
        function_base(),
 | 
			
		||||
        source_file_name(),
 | 
			
		||||
        source_line(),
 | 
			
		||||
        source_line_base() {}
 | 
			
		||||
| 
						 | 
				
			
			@ -56,19 +57,16 @@ struct StackFrame {
 | 
			
		|||
  // but may not necessarily point to the exact beginning of that instruction.
 | 
			
		||||
  u_int64_t instruction;
 | 
			
		||||
 | 
			
		||||
  // The base address of the module.
 | 
			
		||||
  u_int64_t module_base;
 | 
			
		||||
 | 
			
		||||
  // The module in which the instruction resides.
 | 
			
		||||
  string module_name;
 | 
			
		||||
  const CodeModule *module;
 | 
			
		||||
 | 
			
		||||
  // The function name, may be omitted if debug symbols are not available.
 | 
			
		||||
  string function_name;
 | 
			
		||||
 | 
			
		||||
  // The start address of the function, may be omitted if debug symbols
 | 
			
		||||
  // are not available.
 | 
			
		||||
  u_int64_t function_base;
 | 
			
		||||
 | 
			
		||||
  // The function name, may be omitted if debug symbols are not available.
 | 
			
		||||
  string function_name;
 | 
			
		||||
 | 
			
		||||
  // The source file name, may be omitted if debug symbols are not available.
 | 
			
		||||
  string source_file_name;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,10 +46,10 @@
 | 
			
		|||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
class CallStack;
 | 
			
		||||
class CodeModules;
 | 
			
		||||
template<typename T> class linked_ptr;
 | 
			
		||||
class MemoryRegion;
 | 
			
		||||
class MinidumpContext;
 | 
			
		||||
class MinidumpModuleList;
 | 
			
		||||
struct StackFrame;
 | 
			
		||||
struct StackFrameInfo;
 | 
			
		||||
class SymbolSupplier;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,18 +71,18 @@ class Stackwalker {
 | 
			
		|||
  // argument.  If no suitable concrete subclass exists, returns NULL.
 | 
			
		||||
  static Stackwalker* StackwalkerForCPU(MinidumpContext *context,
 | 
			
		||||
                                        MemoryRegion *memory,
 | 
			
		||||
                                        MinidumpModuleList *modules,
 | 
			
		||||
                                        const CodeModules *modules,
 | 
			
		||||
                                        SymbolSupplier *supplier);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  // memory identifies a MemoryRegion that provides the stack memory
 | 
			
		||||
  // for the stack to walk.  modules, if non-NULL, is a MinidumpModuleList
 | 
			
		||||
  // that is used to look up which code module each stack frame is
 | 
			
		||||
  // for the stack to walk.  modules, if non-NULL, is a CodeModules
 | 
			
		||||
  // 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.
 | 
			
		||||
  Stackwalker(MemoryRegion *memory,
 | 
			
		||||
              MinidumpModuleList *modules,
 | 
			
		||||
              const CodeModules *modules,
 | 
			
		||||
              SymbolSupplier *supplier);
 | 
			
		||||
 | 
			
		||||
  // The stack memory to walk.  Subclasses will require this region to
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ class Stackwalker {
 | 
			
		|||
 | 
			
		||||
  // A list of modules, for populating each StackFrame's module information.
 | 
			
		||||
  // This field is optional and may be NULL.
 | 
			
		||||
  MinidumpModuleList *modules_;
 | 
			
		||||
  const CodeModules *modules_;
 | 
			
		||||
 | 
			
		||||
  // The optional SymbolSupplier for resolving source line info.
 | 
			
		||||
  SymbolSupplier *supplier_;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,14 +38,14 @@
 | 
			
		|||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
class MinidumpModule;
 | 
			
		||||
class CodeModule;
 | 
			
		||||
 | 
			
		||||
class SymbolSupplier {
 | 
			
		||||
 public:
 | 
			
		||||
  virtual ~SymbolSupplier() {}
 | 
			
		||||
 | 
			
		||||
  // Returns the path to the symbol file for the given module.
 | 
			
		||||
  virtual string GetSymbolFile(MinidumpModule *module) = 0;
 | 
			
		||||
  virtual string GetSymbolFile(const CodeModule *module) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										95
									
								
								src/processor/basic_code_module.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/processor/basic_code_module.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
// 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.
 | 
			
		||||
 | 
			
		||||
// basic_code_module.h: Carries information about code modules that are loaded
 | 
			
		||||
// into a process.
 | 
			
		||||
//
 | 
			
		||||
// This is a basic concrete implementation of CodeModule.  It cannot be
 | 
			
		||||
// instantiated directly, only based on other objects that implement
 | 
			
		||||
// the CodeModule interface.  It exists to provide a CodeModule implementation
 | 
			
		||||
// a place to store information when the life of the original object (such as
 | 
			
		||||
// a MinidumpModule) cannot be guaranteed.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#ifndef PROCESSOR_BASIC_CODE_MODULE_H__
 | 
			
		||||
#define PROCESSOR_BASIC_CODE_MODULE_H__
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
class BasicCodeModule : public CodeModule {
 | 
			
		||||
 public:
 | 
			
		||||
  // Creates a new BasicCodeModule given any existing CodeModule
 | 
			
		||||
  // implementation.  This is useful to make a copy of the data relevant to
 | 
			
		||||
  // the CodeModule interface without requiring all of the resources that
 | 
			
		||||
  // other CodeModule implementations may require.
 | 
			
		||||
  explicit BasicCodeModule(const CodeModule *that)
 | 
			
		||||
      : base_address_(that->base_address()),
 | 
			
		||||
        size_(that->size()),
 | 
			
		||||
        code_file_(that->code_file()),
 | 
			
		||||
        code_identifier_(that->code_identifier()),
 | 
			
		||||
        debug_file_(that->debug_file()),
 | 
			
		||||
        debug_identifier_(that->debug_identifier()),
 | 
			
		||||
        version_(that->version()) {}
 | 
			
		||||
  virtual ~BasicCodeModule() {}
 | 
			
		||||
 | 
			
		||||
  // See code_module.h for descriptions of these methods and the associated
 | 
			
		||||
  // members.
 | 
			
		||||
  virtual u_int64_t base_address() const { return base_address_; }
 | 
			
		||||
  virtual u_int64_t size() const { return size_; }
 | 
			
		||||
  virtual string code_file() const { return code_file_; }
 | 
			
		||||
  virtual string code_identifier() const { return code_identifier_; }
 | 
			
		||||
  virtual string debug_file() const { return debug_file_; }
 | 
			
		||||
  virtual string debug_identifier() const { return debug_identifier_; }
 | 
			
		||||
  virtual string version() const { return version_; }
 | 
			
		||||
  virtual const CodeModule* Copy() const { return new BasicCodeModule(this); }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  u_int64_t base_address_;
 | 
			
		||||
  u_int64_t size_;
 | 
			
		||||
  string code_file_;
 | 
			
		||||
  string code_identifier_;
 | 
			
		||||
  string debug_file_;
 | 
			
		||||
  string debug_identifier_;
 | 
			
		||||
  string version_;
 | 
			
		||||
 | 
			
		||||
  // Disallow copy constructor and assignment operator.
 | 
			
		||||
  BasicCodeModule(const BasicCodeModule &that);
 | 
			
		||||
  void operator=(const BasicCodeModule &that);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
 | 
			
		||||
#endif  // PROCESSOR_BASIC_CODE_MODULE_H__
 | 
			
		||||
							
								
								
									
										112
									
								
								src/processor/basic_code_modules.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/processor/basic_code_modules.cc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,112 @@
 | 
			
		|||
// 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.
 | 
			
		||||
 | 
			
		||||
// basic_code_modules.cc: Contains all of the CodeModule objects that
 | 
			
		||||
// were loaded into a single process.
 | 
			
		||||
//
 | 
			
		||||
// See basic_code_modules.h for documentation.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
#include "processor/basic_code_modules.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "processor/linked_ptr.h"
 | 
			
		||||
#include "processor/range_map-inl.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
BasicCodeModules::BasicCodeModules(const CodeModules *that)
 | 
			
		||||
    : main_address_(0),
 | 
			
		||||
      map_(new RangeMap<u_int64_t, linked_ptr<const CodeModule> >()) {
 | 
			
		||||
  assert(that);
 | 
			
		||||
 | 
			
		||||
  const CodeModule *main_module = that->GetMainModule();
 | 
			
		||||
  if (main_module)
 | 
			
		||||
    main_address_ = main_module->base_address();
 | 
			
		||||
 | 
			
		||||
  unsigned int count = that->module_count();
 | 
			
		||||
  for (unsigned int module_sequence = 0;
 | 
			
		||||
       module_sequence < count;
 | 
			
		||||
       ++module_sequence) {
 | 
			
		||||
    // Make a copy of the module and insert it into the map.  Use
 | 
			
		||||
    // GetModuleAtIndex because ordering is unimportant when slurping the
 | 
			
		||||
    // entire list, and GetModuleAtIndex may be faster than
 | 
			
		||||
    // GetModuleAtSequence.
 | 
			
		||||
    const CodeModule *module = that->GetModuleAtIndex(module_sequence)->Copy();
 | 
			
		||||
    map_->StoreRange(module->base_address(), module->size(),
 | 
			
		||||
                     linked_ptr<const CodeModule>(module));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BasicCodeModules::~BasicCodeModules() {
 | 
			
		||||
  delete map_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int BasicCodeModules::module_count() const {
 | 
			
		||||
  return map_->GetCount();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CodeModule* BasicCodeModules::GetModuleForAddress(
 | 
			
		||||
    u_int64_t address) const {
 | 
			
		||||
  linked_ptr<const CodeModule> module;
 | 
			
		||||
  if (!map_->RetrieveRange(address, &module, NULL, NULL))
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return module.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CodeModule* BasicCodeModules::GetMainModule() const {
 | 
			
		||||
  return GetModuleForAddress(main_address_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CodeModule* BasicCodeModules::GetModuleAtSequence(
 | 
			
		||||
    unsigned int sequence) const {
 | 
			
		||||
  linked_ptr<const CodeModule> module;
 | 
			
		||||
  if (!map_->RetrieveRangeAtIndex(sequence, &module, NULL, NULL))
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return module.get();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CodeModule* BasicCodeModules::GetModuleAtIndex(
 | 
			
		||||
    unsigned int index) const {
 | 
			
		||||
  // This class stores everything in a RangeMap, without any more-efficient
 | 
			
		||||
  // way to walk the list of CodeModule objects.  Implement GetModuleAtIndex
 | 
			
		||||
  // using GetModuleAtSequence, which meets all of the requirements, and
 | 
			
		||||
  // in addition, guarantees ordering.
 | 
			
		||||
  return GetModuleAtSequence(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CodeModules* BasicCodeModules::Copy() const {
 | 
			
		||||
  return new BasicCodeModules(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
							
								
								
									
										85
									
								
								src/processor/basic_code_modules.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/processor/basic_code_modules.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,85 @@
 | 
			
		|||
// Copyright (c) 2006, Google Inc.
 | 
			
		||||
// All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are
 | 
			
		||||
// met:
 | 
			
		||||
//
 | 
			
		||||
//     * Redistributions of source code must retain the above copyright
 | 
			
		||||
// notice, this list of conditions and the following disclaimer.
 | 
			
		||||
//     * Redistributions in binary form must reproduce the above
 | 
			
		||||
// copyright notice, this list of conditions and the following disclaimer
 | 
			
		||||
// in the documentation and/or other materials provided with the
 | 
			
		||||
// distribution.
 | 
			
		||||
//     * Neither the name of Google Inc. nor the names of its
 | 
			
		||||
// contributors may be used to endorse or promote products derived from
 | 
			
		||||
// this software without specific prior written permission.
 | 
			
		||||
//
 | 
			
		||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
// basic_code_modules.h: Contains all of the CodeModule objects that
 | 
			
		||||
// were loaded into a single process.
 | 
			
		||||
//
 | 
			
		||||
// This is a basic concrete implementation of CodeModules.  It cannot be
 | 
			
		||||
// instantiated directly, only based on other objects that implement
 | 
			
		||||
// the CodeModules interface.  It exists to provide a CodeModules
 | 
			
		||||
// implementation a place to store information when the life of the original
 | 
			
		||||
// object (such as a MinidumpModuleList) cannot be guaranteed.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#ifndef PROCESSOR_BASIC_CODE_MODULES_H__
 | 
			
		||||
#define PROCESSOR_BASIC_CODE_MODULES_H__
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
template<typename T> class linked_ptr;
 | 
			
		||||
template<typename AddressType, typename EntryType> class RangeMap;
 | 
			
		||||
 | 
			
		||||
class BasicCodeModules : public CodeModules {
 | 
			
		||||
 public:
 | 
			
		||||
  // Creates a new BasicCodeModules object given any existing CodeModules
 | 
			
		||||
  // implementation.  This is useful to make a copy of the data relevant to
 | 
			
		||||
  // the CodeModules and CodeModule interfaces without requiring all of the
 | 
			
		||||
  // resources that other implementations may require.  A copy will be
 | 
			
		||||
  // made of each contained CodeModule using CodeModule::Copy.
 | 
			
		||||
  explicit BasicCodeModules(const CodeModules *that);
 | 
			
		||||
 | 
			
		||||
  virtual ~BasicCodeModules();
 | 
			
		||||
 | 
			
		||||
  // See code_modules.h for descriptions of these methods.
 | 
			
		||||
  virtual unsigned int module_count() const;
 | 
			
		||||
  virtual const CodeModule* GetModuleForAddress(u_int64_t address) const;
 | 
			
		||||
  virtual const CodeModule* GetMainModule() const;
 | 
			
		||||
  virtual const CodeModule* GetModuleAtSequence(unsigned int sequence) const;
 | 
			
		||||
  virtual const CodeModule* GetModuleAtIndex(unsigned int index) const;
 | 
			
		||||
  virtual const CodeModules* Copy() const;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  // The base address of the main module.
 | 
			
		||||
  u_int64_t main_address_;
 | 
			
		||||
 | 
			
		||||
  // The map used to contain each CodeModule, keyed by each CodeModule's
 | 
			
		||||
  // address range.
 | 
			
		||||
  RangeMap<u_int64_t, linked_ptr<const CodeModule> > *map_;
 | 
			
		||||
 | 
			
		||||
  // Disallow copy constructor and assignment operator.
 | 
			
		||||
  BasicCodeModules(const BasicCodeModules &that);
 | 
			
		||||
  void operator=(const BasicCodeModules &that);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
 | 
			
		||||
#endif  // PROCESSOR_BASIC_CODE_MODULES_H__
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +54,8 @@ typedef SSIZE_T ssize_t;
 | 
			
		|||
#include "processor/range_map-inl.h"
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "processor/basic_code_module.h"
 | 
			
		||||
#include "processor/basic_code_modules.h"
 | 
			
		||||
#include "processor/scoped_ptr.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -999,11 +1001,11 @@ void MinidumpThreadList::Print() {
 | 
			
		|||
 | 
			
		||||
MinidumpModule::MinidumpModule(Minidump* minidump)
 | 
			
		||||
    : MinidumpObject(minidump),
 | 
			
		||||
      module_valid_(false),
 | 
			
		||||
      module_(),
 | 
			
		||||
      name_(NULL),
 | 
			
		||||
      cv_record_(NULL),
 | 
			
		||||
      misc_record_(NULL),
 | 
			
		||||
      debug_filename_(NULL) {
 | 
			
		||||
      misc_record_(NULL) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1011,7 +1013,6 @@ MinidumpModule::~MinidumpModule() {
 | 
			
		|||
  delete name_;
 | 
			
		||||
  delete cv_record_;
 | 
			
		||||
  delete misc_record_;
 | 
			
		||||
  delete debug_filename_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,9 +1024,8 @@ bool MinidumpModule::Read() {
 | 
			
		|||
  cv_record_ = NULL;
 | 
			
		||||
  delete misc_record_;
 | 
			
		||||
  misc_record_ = NULL;
 | 
			
		||||
  delete debug_filename_;
 | 
			
		||||
  debug_filename_ = NULL;
 | 
			
		||||
 | 
			
		||||
  module_valid_ = false;
 | 
			
		||||
  valid_ = false;
 | 
			
		||||
 | 
			
		||||
  if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE))
 | 
			
		||||
| 
						 | 
				
			
			@ -1062,24 +1062,239 @@ bool MinidumpModule::Read() {
 | 
			
		|||
  if (module_.size_of_image == 0 || high_address < module_.base_of_image)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  module_valid_ = true;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MinidumpModule::ReadAuxiliaryData() {
 | 
			
		||||
  if (!module_valid_)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  // Each module must have a name.
 | 
			
		||||
  name_ = minidump_->ReadString(module_.module_name_rva);
 | 
			
		||||
  if (!name_)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  // CodeView and miscellaneous debug records are only required if the
 | 
			
		||||
  // module indicates that they exist.
 | 
			
		||||
  if (module_.cv_record.data_size && !GetCVRecord())
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  if (module_.misc_record.data_size && !GetMiscRecord())
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  valid_ = true;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const string* MinidumpModule::GetName() {
 | 
			
		||||
string MinidumpModule::code_file() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  if (!name_)
 | 
			
		||||
    name_ = minidump_->ReadString(module_.module_name_rva);
 | 
			
		||||
  return *name_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  return name_;
 | 
			
		||||
 | 
			
		||||
string MinidumpModule::code_identifier() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
 | 
			
		||||
  if (!minidump_system_info)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
 | 
			
		||||
  if (!raw_system_info)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  string identifier;
 | 
			
		||||
 | 
			
		||||
  switch (raw_system_info->platform_id) {
 | 
			
		||||
    case MD_OS_WIN32_NT:
 | 
			
		||||
    case MD_OS_WIN32_WINDOWS: {
 | 
			
		||||
      char identifier_string[17];
 | 
			
		||||
      snprintf(identifier_string, sizeof(identifier_string), "%08x%x",
 | 
			
		||||
               module_.time_date_stamp, module_.size_of_image);
 | 
			
		||||
      identifier = identifier_string;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    case MD_OS_MAC_OS_X: {
 | 
			
		||||
      // TODO(mmentovai): support uuid extension if present, otherwise fall
 | 
			
		||||
      // back to version (from LC_ID_DYLIB?), otherwise fall back to something
 | 
			
		||||
      // else.
 | 
			
		||||
      identifier = "id";
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    default: {
 | 
			
		||||
      // Without knowing what OS generated the dump, we can't generate a good
 | 
			
		||||
      // identifier.  Return an empty string, signalling failure.
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return identifier;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
string MinidumpModule::debug_file() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  string file;
 | 
			
		||||
  // Prefer the CodeView record if present.
 | 
			
		||||
  const MDCVInfoPDB70* cv_record_70 =
 | 
			
		||||
      reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
 | 
			
		||||
  if (cv_record_70) {
 | 
			
		||||
    if (cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE) {
 | 
			
		||||
      // GetCVRecord guarantees pdb_file_name is null-terminated.
 | 
			
		||||
      file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
 | 
			
		||||
    } else if (cv_record_70->cv_signature == MD_CVINFOPDB20_SIGNATURE) {
 | 
			
		||||
      // It's actually a MDCVInfoPDB20 structure.
 | 
			
		||||
      const MDCVInfoPDB20* cv_record_20 =
 | 
			
		||||
          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
 | 
			
		||||
 | 
			
		||||
      // GetCVRecord guarantees pdb_file_name is null-terminated.
 | 
			
		||||
      file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If there's a CodeView record but it doesn't match a known signature,
 | 
			
		||||
    // try the miscellaneous record - but it's suspicious because
 | 
			
		||||
    // GetCVRecord shouldn't have accepted a CodeView record that doesn't
 | 
			
		||||
    // match a known signature.
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (file.empty()) {
 | 
			
		||||
    // No usable CodeView record.  Try the miscellaneous debug record.
 | 
			
		||||
    const MDImageDebugMisc* misc_record =
 | 
			
		||||
        reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
 | 
			
		||||
    if (misc_record) {
 | 
			
		||||
      if (!misc_record->unicode) {
 | 
			
		||||
        // If it's not Unicode, just stuff it into the string.  It's unclear
 | 
			
		||||
        // if misc_record->data is 0-terminated, so use an explicit size.
 | 
			
		||||
        file = string(
 | 
			
		||||
            reinterpret_cast<const char*>(misc_record->data),
 | 
			
		||||
            module_.misc_record.data_size - sizeof(MDImageDebugMisc));
 | 
			
		||||
      } else {
 | 
			
		||||
        // There's a misc_record but it encodes the debug filename in UTF-16.
 | 
			
		||||
        // (Actually, because miscellaneous records are so old, it's probably
 | 
			
		||||
        // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
 | 
			
		||||
        // that this method (and all other methods in the Minidump family)
 | 
			
		||||
        // return.
 | 
			
		||||
 | 
			
		||||
        unsigned int bytes =
 | 
			
		||||
            module_.misc_record.data_size - sizeof(MDImageDebugMisc);
 | 
			
		||||
        if (bytes % 2 == 0) {
 | 
			
		||||
          unsigned int utf16_words = bytes / 2;
 | 
			
		||||
 | 
			
		||||
          // UTF16ToUTF8 expects a vector<u_int16_t>, so create a temporary one
 | 
			
		||||
          // and copy the UTF-16 data into it.
 | 
			
		||||
          vector<u_int16_t> string_utf16(utf16_words);
 | 
			
		||||
          if (utf16_words)
 | 
			
		||||
            memcpy(&string_utf16[0], &misc_record->data, bytes);
 | 
			
		||||
 | 
			
		||||
          // GetMiscRecord already byte-swapped the data[] field if it contains
 | 
			
		||||
          // UTF-16, so pass false as the swap argument.
 | 
			
		||||
          scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
 | 
			
		||||
          file = *new_file;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return file;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
string MinidumpModule::debug_identifier() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  string identifier;
 | 
			
		||||
 | 
			
		||||
  // Use the CodeView record if present.
 | 
			
		||||
  const MDCVInfoPDB70* cv_record_70 =
 | 
			
		||||
      reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
 | 
			
		||||
  if (cv_record_70) {
 | 
			
		||||
    if (cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE) {
 | 
			
		||||
      char identifier_string[41];
 | 
			
		||||
      snprintf(identifier_string, sizeof(identifier_string),
 | 
			
		||||
               "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%X",
 | 
			
		||||
               cv_record_70->signature.data1,
 | 
			
		||||
               cv_record_70->signature.data2,
 | 
			
		||||
               cv_record_70->signature.data3,
 | 
			
		||||
               cv_record_70->signature.data4[0],
 | 
			
		||||
               cv_record_70->signature.data4[1],
 | 
			
		||||
               cv_record_70->signature.data4[2],
 | 
			
		||||
               cv_record_70->signature.data4[3],
 | 
			
		||||
               cv_record_70->signature.data4[4],
 | 
			
		||||
               cv_record_70->signature.data4[5],
 | 
			
		||||
               cv_record_70->signature.data4[6],
 | 
			
		||||
               cv_record_70->signature.data4[7],
 | 
			
		||||
               cv_record_70->age);
 | 
			
		||||
      identifier = identifier_string;
 | 
			
		||||
    } else if (cv_record_70->cv_signature == MD_CVINFOPDB20_SIGNATURE) {
 | 
			
		||||
      // It's actually a MDCVInfoPDB20 structure.
 | 
			
		||||
      const MDCVInfoPDB20* cv_record_20 =
 | 
			
		||||
          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
 | 
			
		||||
 | 
			
		||||
      char identifier_string[17];
 | 
			
		||||
      snprintf(identifier_string, sizeof(identifier_string),
 | 
			
		||||
               "%08x%x", cv_record_20->signature, cv_record_20->age);
 | 
			
		||||
      identifier = identifier_string;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO(mmentovai): if there's no CodeView record, there might be a
 | 
			
		||||
  // miscellaneous debug record.  It only carries a filename, though, and no
 | 
			
		||||
  // identifier.  I'm not sure what the right thing to do for the identifier
 | 
			
		||||
  // is in that case, but I don't expect to find many modules without a
 | 
			
		||||
  // CodeView record (or some other Airbag extension structure in place of
 | 
			
		||||
  // a CodeView record).  Treat it as an error (empty identifier) for now.
 | 
			
		||||
 | 
			
		||||
  // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
 | 
			
		||||
 | 
			
		||||
  return identifier;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
string MinidumpModule::version() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  string version;
 | 
			
		||||
 | 
			
		||||
  if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
 | 
			
		||||
      module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
 | 
			
		||||
    char version_string[24];
 | 
			
		||||
    snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
 | 
			
		||||
             module_.version_info.file_version_hi >> 16,
 | 
			
		||||
             module_.version_info.file_version_hi & 0xffff,
 | 
			
		||||
             module_.version_info.file_version_lo >> 16,
 | 
			
		||||
             module_.version_info.file_version_lo & 0xffff);
 | 
			
		||||
    version = version_string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // TODO(mmentovai): possibly support other struct types in place of
 | 
			
		||||
  // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
 | 
			
		||||
  // a different structure that better represents versioning facilities on
 | 
			
		||||
  // Mac OS X and Linux, instead of forcing them to adhere to the dotted
 | 
			
		||||
  // quad of 16-bit ints that Windows uses.
 | 
			
		||||
 | 
			
		||||
  return version;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const CodeModule* MinidumpModule::Copy() const {
 | 
			
		||||
  return new BasicCodeModule(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const u_int8_t* MinidumpModule::GetCVRecord() {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
  if (!module_valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  if (!cv_record_) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,7 +1372,7 @@ const u_int8_t* MinidumpModule::GetCVRecord() {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
const MDImageDebugMisc* MinidumpModule::GetMiscRecord() {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
  if (!module_valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  if (!misc_record_) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1216,83 +1431,6 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This method will perform no allocation-size checking on its own; it relies
 | 
			
		||||
// on GetCVRecord() and GetMiscRecord() to have made the determination that
 | 
			
		||||
// the necessary structures aren't oversized.
 | 
			
		||||
const string* MinidumpModule::GetDebugFilename() {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  if (!debug_filename_) {
 | 
			
		||||
    // Prefer the CodeView record if present.
 | 
			
		||||
    const MDCVInfoPDB70* cv_record_70 =
 | 
			
		||||
        reinterpret_cast<const MDCVInfoPDB70*>(GetCVRecord());
 | 
			
		||||
    if (cv_record_70) {
 | 
			
		||||
      if (cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE) {
 | 
			
		||||
        // GetCVRecord guarantees pdb_file_name is null-terminated.
 | 
			
		||||
        debug_filename_ = new string(
 | 
			
		||||
            reinterpret_cast<const char*>(cv_record_70->pdb_file_name));
 | 
			
		||||
 | 
			
		||||
        return debug_filename_;
 | 
			
		||||
      } else if (cv_record_70->cv_signature == MD_CVINFOPDB20_SIGNATURE) {
 | 
			
		||||
        // It's actually a MDCVInfoPDB20 structure.
 | 
			
		||||
        const MDCVInfoPDB20* cv_record_20 =
 | 
			
		||||
            reinterpret_cast<const MDCVInfoPDB20*>(cv_record_70);
 | 
			
		||||
 | 
			
		||||
        // GetCVRecord guarantees pdb_file_name is null-terminated.
 | 
			
		||||
        debug_filename_ = new string(
 | 
			
		||||
            reinterpret_cast<const char*>(cv_record_20->pdb_file_name));
 | 
			
		||||
 | 
			
		||||
        return debug_filename_;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // If there's a CodeView record but it doesn't match either of those
 | 
			
		||||
      // signatures, try the miscellaneous record - but it's suspicious because
 | 
			
		||||
      // GetCVRecord shouldn't have returned a CodeView record that doesn't
 | 
			
		||||
      // match either signature.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // No usable CodeView record.  Try the miscellaneous debug record.
 | 
			
		||||
    const MDImageDebugMisc* misc_record = GetMiscRecord();
 | 
			
		||||
    if (!misc_record)
 | 
			
		||||
      return NULL;
 | 
			
		||||
 | 
			
		||||
    if (!misc_record->unicode) {
 | 
			
		||||
      // If it's not Unicode, just stuff it into the string.  It's unclear
 | 
			
		||||
      // if misc_record->data is 0-terminated, so use an explicit size.
 | 
			
		||||
      debug_filename_ = new string(
 | 
			
		||||
          reinterpret_cast<const char*>(misc_record->data),
 | 
			
		||||
          module_.misc_record.data_size - sizeof(MDImageDebugMisc));
 | 
			
		||||
 | 
			
		||||
      return debug_filename_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // There's a misc_record but it encodes the debug filename in UTF-16.
 | 
			
		||||
    // (Actually, because miscellaneous records are so old, it's probably
 | 
			
		||||
    // UCS-2.)  Convert it to UTF-8 for congruity with the other strings that
 | 
			
		||||
    // this method (and all other methods in the Minidump family) return.
 | 
			
		||||
 | 
			
		||||
    unsigned int bytes =
 | 
			
		||||
        module_.misc_record.data_size - sizeof(MDImageDebugMisc);
 | 
			
		||||
    if (bytes % 2 != 0)
 | 
			
		||||
      return NULL;
 | 
			
		||||
    unsigned int utf16_words = bytes / 2;
 | 
			
		||||
 | 
			
		||||
    // UTF16ToUTF8 expects a vector<u_int16_t>, so create a temporary one and
 | 
			
		||||
    // copy the UTF-16 data into it.
 | 
			
		||||
    vector<u_int16_t> string_utf16(utf16_words);
 | 
			
		||||
    if (utf16_words)
 | 
			
		||||
      memcpy(&string_utf16[0], &misc_record->data, bytes);
 | 
			
		||||
 | 
			
		||||
    // GetMiscRecord already byte-swapped the data[] field if it contains
 | 
			
		||||
    // UTF-16, so pass false as the swap argument.
 | 
			
		||||
    debug_filename_ = UTF16ToUTF8(string_utf16, false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return debug_filename_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MinidumpModule::Print() {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1340,11 +1478,9 @@ void MinidumpModule::Print() {
 | 
			
		|||
  printf("  misc_record.rva                 = 0x%x\n",
 | 
			
		||||
         module_.misc_record.rva);
 | 
			
		||||
 | 
			
		||||
  const char* module_name = GetName()->c_str();
 | 
			
		||||
  if (module_name)
 | 
			
		||||
    printf("  (module_name)                   = \"%s\"\n", module_name);
 | 
			
		||||
  else
 | 
			
		||||
    printf("  (module_name)                   = (null)\n");
 | 
			
		||||
  printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
 | 
			
		||||
  printf("  (code_identifier)               = \"%s\"\n",
 | 
			
		||||
         code_identifier().c_str());
 | 
			
		||||
 | 
			
		||||
  const MDCVInfoPDB70* cv_record =
 | 
			
		||||
      reinterpret_cast<const MDCVInfoPDB70*>(GetCVRecord());
 | 
			
		||||
| 
						 | 
				
			
			@ -1405,13 +1541,10 @@ void MinidumpModule::Print() {
 | 
			
		|||
    printf("  (misc_record)                   = (null)\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const string* debug_filename = GetDebugFilename();
 | 
			
		||||
  if (debug_filename) {
 | 
			
		||||
    printf("  (debug_filename)                = \"%s\"\n",
 | 
			
		||||
           debug_filename->c_str());
 | 
			
		||||
  } else {
 | 
			
		||||
    printf("  (debug_filename)                = (null)\n");
 | 
			
		||||
  }
 | 
			
		||||
  printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
 | 
			
		||||
  printf("  (debug_identifier)              = \"%s\"\n",
 | 
			
		||||
         debug_identifier().c_str());
 | 
			
		||||
  printf("  (version)                       = \"%s\"\n", version().c_str());
 | 
			
		||||
  printf("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1471,6 +1604,20 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
 | 
			
		|||
      // Assume that the file offset is correct after the last read.
 | 
			
		||||
      if (!module->Read())
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Loop through the module list once more to read additional data and
 | 
			
		||||
    // build the range map.  This is done in a second pass because
 | 
			
		||||
    // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
 | 
			
		||||
    // included in the loop above, additional seeks would be needed where
 | 
			
		||||
    // none are now to read contiguous data.
 | 
			
		||||
    for (unsigned int module_index = 0;
 | 
			
		||||
         module_index < module_count;
 | 
			
		||||
         ++module_index) {
 | 
			
		||||
      MinidumpModule* module = &(*modules)[module_index];
 | 
			
		||||
 | 
			
		||||
      if (!module->ReadAuxiliaryData())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
      u_int64_t base_address = module->base_address();
 | 
			
		||||
      u_int64_t module_size = module->size();
 | 
			
		||||
| 
						 | 
				
			
			@ -1491,16 +1638,8 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MinidumpModule* MinidumpModuleList::GetModuleAtIndex(unsigned int index)
 | 
			
		||||
    const {
 | 
			
		||||
  if (!valid_ || index >= module_count_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return &(*modules_)[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MinidumpModule* MinidumpModuleList::GetModuleForAddress(u_int64_t address) {
 | 
			
		||||
const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
 | 
			
		||||
    u_int64_t address) const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1512,6 +1651,43 @@ MinidumpModule* MinidumpModuleList::GetModuleForAddress(u_int64_t address) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const MinidumpModule* MinidumpModuleList::GetMainModule() const {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  // The main code module is the first one present in a minidump file's
 | 
			
		||||
  // MDRawModuleList.
 | 
			
		||||
  return GetModuleAtSequence(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
 | 
			
		||||
    unsigned int sequence) const {
 | 
			
		||||
  if (!valid_ || sequence >= module_count_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  unsigned int module_index;
 | 
			
		||||
  if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL))
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return GetModuleAtIndex(module_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
 | 
			
		||||
    unsigned int index) const {
 | 
			
		||||
  if (!valid_ || index >= module_count_)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  return &(*modules_)[index];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const CodeModules* MinidumpModuleList::Copy() const {
 | 
			
		||||
  return new BasicCodeModules(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MinidumpModuleList::Print() {
 | 
			
		||||
  if (!valid_)
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,14 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
 | 
			
		|||
        &dump, &process_state->crash_address_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  MinidumpModuleList *module_list = dump.GetModuleList();
 | 
			
		||||
 | 
			
		||||
  // Put a copy of the module list into ProcessState object.  This is not
 | 
			
		||||
  // necessarily a MinidumpModuleList, but it adheres to the CodeModules
 | 
			
		||||
  // interface, which is all that ProcessState needs to expose.
 | 
			
		||||
  if (module_list)
 | 
			
		||||
    process_state->modules_ = module_list->Copy();
 | 
			
		||||
 | 
			
		||||
  MinidumpThreadList *threads = dump.GetThreadList();
 | 
			
		||||
  if (!threads) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -137,10 +145,18 @@ ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
 | 
			
		|||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Use process_state->modules_ instead of module_list, because the
 | 
			
		||||
    // |modules| argument will be used to populate the |module| fields in
 | 
			
		||||
    // the returned StackFrame objects, which will be placed into the
 | 
			
		||||
    // returned ProcessState object.  module_list's lifetime is only as
 | 
			
		||||
    // long as the Minidump object: it will be deleted when this function
 | 
			
		||||
    // returns.  process_state->modules_ is owned by the ProcessState object
 | 
			
		||||
    // (just like the StackFrame objects), and is much more suitable for this
 | 
			
		||||
    // task.
 | 
			
		||||
    scoped_ptr<Stackwalker> stackwalker(
 | 
			
		||||
        Stackwalker::StackwalkerForCPU(context,
 | 
			
		||||
                                       thread_memory,
 | 
			
		||||
                                       dump.GetModuleList(),
 | 
			
		||||
                                       process_state->modules_,
 | 
			
		||||
                                       supplier_));
 | 
			
		||||
    if (!stackwalker.get()) {
 | 
			
		||||
      return NULL;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,8 @@
 | 
			
		|||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
#include "google_airbag/processor/minidump_processor.h"
 | 
			
		||||
#include "google_airbag/processor/process_state.h"
 | 
			
		||||
#include "google_airbag/processor/stack_frame.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +44,7 @@ namespace {
 | 
			
		|||
 | 
			
		||||
using std::string;
 | 
			
		||||
using google_airbag::CallStack;
 | 
			
		||||
using google_airbag::MinidumpModule;
 | 
			
		||||
using google_airbag::CodeModule;
 | 
			
		||||
using google_airbag::MinidumpProcessor;
 | 
			
		||||
using google_airbag::ProcessState;
 | 
			
		||||
using google_airbag::scoped_ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,15 +56,17 @@ using google_airbag::SymbolSupplier;
 | 
			
		|||
    return false; \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#define ASSERT_FALSE(cond) ASSERT_TRUE(!(cond))
 | 
			
		||||
 | 
			
		||||
#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2))
 | 
			
		||||
 | 
			
		||||
class TestSymbolSupplier : public SymbolSupplier {
 | 
			
		||||
 public:
 | 
			
		||||
  virtual string GetSymbolFile(MinidumpModule *module);
 | 
			
		||||
  virtual string GetSymbolFile(const CodeModule *module);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module) {
 | 
			
		||||
  if (*(module->GetName()) == "c:\\test_app.exe") {
 | 
			
		||||
string TestSymbolSupplier::GetSymbolFile(const CodeModule *module) {
 | 
			
		||||
  if (module && module->code_file() == "c:\\test_app.exe") {
 | 
			
		||||
    // The funny-looking pathname is so that the symbol file can also be
 | 
			
		||||
    // reached by a SimpleSymbolSupplier.
 | 
			
		||||
    return string(getenv("srcdir") ? getenv("srcdir") : ".") +
 | 
			
		||||
| 
						 | 
				
			
			@ -92,38 +95,54 @@ static bool RunTests() {
 | 
			
		|||
  ASSERT_EQ(state->crash_address(), 0x45);
 | 
			
		||||
  ASSERT_EQ(state->threads()->size(), 1);
 | 
			
		||||
  ASSERT_EQ(state->requesting_thread(), 0);
 | 
			
		||||
 | 
			
		||||
  CallStack *stack = state->threads()->at(0);
 | 
			
		||||
  ASSERT_TRUE(stack);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->size(), 4);
 | 
			
		||||
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->module_base, 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->module_name, "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(0)->module);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->function_name, "CrashFunction()");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(0)->source_line, 51);
 | 
			
		||||
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->module_base, 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->module_name, "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(1)->module);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->module->base_address(), 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->module->code_file(), "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->function_name, "main");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->source_file_name, "c:\\test_app.cc");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(1)->source_line, 56);
 | 
			
		||||
 | 
			
		||||
  // This comes from the CRT
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->module_base, 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->module_name, "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(2)->module);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->module->base_address(), 0x400000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->module->code_file(), "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->function_name, "__tmainCRTStartup");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->source_file_name,
 | 
			
		||||
            "f:\\rtm\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c");
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(2)->source_line, 318);
 | 
			
		||||
 | 
			
		||||
  // No debug info available for kernel32.dll
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(3)->module_base, 0x7c800000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(3)->module_name,
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(3)->module);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(3)->module->base_address(), 0x7c800000);
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(3)->module->code_file(),
 | 
			
		||||
            "C:\\WINDOWS\\system32\\kernel32.dll");
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(3)->function_name.empty());
 | 
			
		||||
  ASSERT_TRUE(stack->frames()->at(3)->source_file_name.empty());
 | 
			
		||||
  ASSERT_EQ(stack->frames()->at(3)->source_line, 0);
 | 
			
		||||
 | 
			
		||||
  ASSERT_EQ(state->modules()->module_count(), 13);
 | 
			
		||||
  ASSERT_TRUE(state->modules()->GetMainModule());
 | 
			
		||||
  ASSERT_EQ(state->modules()->GetMainModule()->code_file(), "c:\\test_app.exe");
 | 
			
		||||
  ASSERT_FALSE(state->modules()->GetModuleForAddress(0));
 | 
			
		||||
  ASSERT_EQ(state->modules()->GetMainModule(),
 | 
			
		||||
            state->modules()->GetModuleForAddress(0x400000));
 | 
			
		||||
  ASSERT_EQ(state->modules()->GetModuleForAddress(0x7c801234)->debug_file(),
 | 
			
		||||
            "kernel32.pdb");
 | 
			
		||||
  ASSERT_EQ(state->modules()->GetModuleForAddress(0x77d43210)->version(),
 | 
			
		||||
            "5.1.2600.2622");
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,8 @@
 | 
			
		|||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/minidump_processor.h"
 | 
			
		||||
#include "google_airbag/processor/process_state.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +51,8 @@ namespace {
 | 
			
		|||
 | 
			
		||||
using std::string;
 | 
			
		||||
using google_airbag::CallStack;
 | 
			
		||||
using google_airbag::CodeModule;
 | 
			
		||||
using google_airbag::CodeModules;
 | 
			
		||||
using google_airbag::MinidumpModule;
 | 
			
		||||
using google_airbag::MinidumpProcessor;
 | 
			
		||||
using google_airbag::PathnameStripper;
 | 
			
		||||
| 
						 | 
				
			
			@ -90,8 +94,8 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
 | 
			
		|||
    const StackFrame *frame = stack->frames()->at(frame_index);
 | 
			
		||||
    printf("%2d  ", frame_index);
 | 
			
		||||
 | 
			
		||||
    if (!frame->module_name.empty()) {
 | 
			
		||||
      printf("%s", PathnameStripper::File(frame->module_name).c_str());
 | 
			
		||||
    if (frame->module) {
 | 
			
		||||
      printf("%s", PathnameStripper::File(frame->module->code_file()).c_str());
 | 
			
		||||
      if (!frame->function_name.empty()) {
 | 
			
		||||
        printf("!%s", frame->function_name.c_str());
 | 
			
		||||
        if (!frame->source_file_name.empty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +108,7 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
 | 
			
		|||
          printf(" + 0x%llx", frame->instruction - frame->function_base);
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        printf(" + 0x%llx", frame->instruction - frame->module_base);
 | 
			
		||||
        printf(" + 0x%llx", frame->instruction - frame->module->base_address());
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      printf("0x%llx", frame->instruction);
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +151,29 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void PrintModules(const CodeModules *modules) {
 | 
			
		||||
  if (!modules)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  printf("\n");
 | 
			
		||||
  printf("Loaded modules:\n");
 | 
			
		||||
 | 
			
		||||
  u_int64_t main_address = modules->GetMainModule()->base_address();
 | 
			
		||||
 | 
			
		||||
  unsigned int module_count = modules->module_count();
 | 
			
		||||
  for (unsigned int module_sequence = 0;
 | 
			
		||||
       module_sequence < module_count;
 | 
			
		||||
       ++module_sequence) {
 | 
			
		||||
    const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
 | 
			
		||||
    u_int64_t base_address = module->base_address();
 | 
			
		||||
    printf("0x%08llx - 0x%08llx  %s  %s%s\n",
 | 
			
		||||
           base_address, base_address + module->size() - 1,
 | 
			
		||||
           PathnameStripper::File(module->code_file()).c_str(),
 | 
			
		||||
           module->version().empty() ? "???" : module->version().c_str(),
 | 
			
		||||
           module->base_address() == main_address ? "  (main)" : "");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Processes |minidump_file| using MinidumpProcessor.  |symbol_path|, if
 | 
			
		||||
// non-empty, is the base directory of a symbol storage area, laid out in
 | 
			
		||||
// the format required by SimpleSymbolSupplier.  If such a storage area
 | 
			
		||||
| 
						 | 
				
			
			@ -217,6 +244,8 @@ static bool PrintMinidumpProcess(const string &minidump_file,
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  PrintModules(process_state->modules());
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,31 @@
 | 
			
		|||
// Copyright (C) 2006 Google Inc.
 | 
			
		||||
// Copyright (c) 2006, Google Inc.
 | 
			
		||||
// All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are
 | 
			
		||||
// met:
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//     * 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.
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// postfix_evaluator_unittest.cc: Unit tests for PostfixEvaluator.
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,7 @@
 | 
			
		|||
 | 
			
		||||
#include "google_airbag/processor/process_state.h"
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +45,8 @@ ProcessState::~ProcessState() {
 | 
			
		|||
       ++iterator) {
 | 
			
		||||
    delete *iterator;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  delete modules_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace google_airbag
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,6 +141,35 @@ bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename AddressType, typename EntryType>
 | 
			
		||||
bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
 | 
			
		||||
    int index, EntryType *entry,
 | 
			
		||||
    AddressType *entry_base, AddressType *entry_size) const {
 | 
			
		||||
  if (!entry || index >= GetCount())
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  // Walk through the map.  Although it's ordered, it's not a vector, so it
 | 
			
		||||
  // can't be addressed directly by index.
 | 
			
		||||
  MapConstIterator iterator = map_.begin();
 | 
			
		||||
  for (int this_index = 0; this_index < index; ++this_index)
 | 
			
		||||
    ++iterator;
 | 
			
		||||
 | 
			
		||||
  *entry = iterator->second.entry();
 | 
			
		||||
  if (entry_base)
 | 
			
		||||
    *entry_base = iterator->first;
 | 
			
		||||
  if (entry_size)
 | 
			
		||||
    *entry_size = iterator->first - iterator->second.base() + 1;
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename AddressType, typename EntryType>
 | 
			
		||||
int RangeMap<AddressType, EntryType>::GetCount() const {
 | 
			
		||||
  return map_.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename AddressType, typename EntryType>
 | 
			
		||||
void RangeMap<AddressType, EntryType>::Clear() {
 | 
			
		||||
  map_.clear();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,20 @@ class RangeMap {
 | 
			
		|||
                            AddressType *entry_base, AddressType *entry_size)
 | 
			
		||||
                            const;
 | 
			
		||||
 | 
			
		||||
  // Treating all ranges as a list ordered by the address spaces that they
 | 
			
		||||
  // occupy, locates the range at the index specified by index.  Returns
 | 
			
		||||
  // false if index is larger than the number of ranges stored, or if another
 | 
			
		||||
  // parameter error occurs.  entry_base and entry_size, if non-NULL, are set
 | 
			
		||||
  // to the base and size of the entry's range.
 | 
			
		||||
  //
 | 
			
		||||
  // RetrieveRangeAtIndex is not optimized for speedy operation.
 | 
			
		||||
  bool RetrieveRangeAtIndex(int index, EntryType *entry,
 | 
			
		||||
                            AddressType *entry_base, AddressType *entry_size)
 | 
			
		||||
                            const;
 | 
			
		||||
 | 
			
		||||
  // Returns the number of ranges stored in the RangeMap.
 | 
			
		||||
  int GetCount() const;
 | 
			
		||||
 | 
			
		||||
  // Empties the range map, restoring it to the state it was when it was
 | 
			
		||||
  // initially created.
 | 
			
		||||
  void Clear();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -243,6 +243,71 @@ static bool RetrieveTest(TestMap *range_map, const RangeTest *range_test) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Test RetrieveRangeAtIndex, which is supposed to return objects in order
 | 
			
		||||
// according to their addresses.  This test is performed by looping through
 | 
			
		||||
// the map, calling RetrieveRangeAtIndex for all possible indices in sequence,
 | 
			
		||||
// and verifying that each call returns a different object than the previous
 | 
			
		||||
// call, and that ranges are returned with increasing base addresses.  Returns
 | 
			
		||||
// false if the test fails.
 | 
			
		||||
static bool RetrieveIndexTest(TestMap *range_map, int set) {
 | 
			
		||||
  linked_ptr<CountedObject> object;
 | 
			
		||||
  CountedObject *last_object = NULL;
 | 
			
		||||
  AddressType last_base = 0;
 | 
			
		||||
 | 
			
		||||
  int object_count = range_map->GetCount();
 | 
			
		||||
  for (int object_index = 0; object_index < object_count; ++object_index) {
 | 
			
		||||
    AddressType base;
 | 
			
		||||
    if (!range_map->RetrieveRangeAtIndex(object_index, &object, &base, NULL)) {
 | 
			
		||||
      fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, "
 | 
			
		||||
              "expected success, observed failure\n",
 | 
			
		||||
              set, object_index);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!object.get()) {
 | 
			
		||||
      fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, "
 | 
			
		||||
              "expected object, observed NULL\n",
 | 
			
		||||
              set, object_index);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // It's impossible to do these comparisons unless there's a previous
 | 
			
		||||
    // object to compare against.
 | 
			
		||||
    if (last_object) {
 | 
			
		||||
      // The object must be different from the last one.
 | 
			
		||||
      if (object->id() == last_object->id()) {
 | 
			
		||||
        fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, "
 | 
			
		||||
                "expected different objects, observed same objects (%d)\n",
 | 
			
		||||
                set, object_index, object->id());
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Each object must have a base greater than the previous object's base.
 | 
			
		||||
      if (base <= last_base) {
 | 
			
		||||
        fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d, "
 | 
			
		||||
                "expected different bases, observed same bases (%d)\n",
 | 
			
		||||
                set, object_index, base);
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    last_object = object.get();
 | 
			
		||||
    last_base = base;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Make sure that RetrieveRangeAtIndex doesn't allow lookups at indices that
 | 
			
		||||
  // are too high.
 | 
			
		||||
  if (range_map->RetrieveRangeAtIndex(object_count, &object, NULL, NULL)) {
 | 
			
		||||
    fprintf(stderr, "FAILED: RetrieveRangeAtIndex set %d index %d (too large), "
 | 
			
		||||
            "expected failure, observed success\n",
 | 
			
		||||
            set, object_count);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// RunTests runs a series of test sets.
 | 
			
		||||
static bool RunTests() {
 | 
			
		||||
  // These tests will be run sequentially.  The first set of tests exercises
 | 
			
		||||
| 
						 | 
				
			
			@ -373,6 +438,15 @@ static bool RunTests() {
 | 
			
		|||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The RangeMap's own count of objects should also match.
 | 
			
		||||
    if (range_map->GetCount() != stored_count) {
 | 
			
		||||
      fprintf(stderr, "FAILED: stored object count doesn't match GetCount, "
 | 
			
		||||
              "expected %d, observed %d\n",
 | 
			
		||||
              stored_count, range_map->GetCount());
 | 
			
		||||
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Run the RetrieveRange test
 | 
			
		||||
    for (unsigned int range_test_index = 0;
 | 
			
		||||
         range_test_index < range_test_count;
 | 
			
		||||
| 
						 | 
				
			
			@ -382,6 +456,9 @@ static bool RunTests() {
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!RetrieveIndexTest(range_map.get(), range_test_set_index))
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
    // Clear the map between test sets.  If this is the final test set,
 | 
			
		||||
    // delete the map instead to test destruction.
 | 
			
		||||
    if (range_test_set_index < range_test_set_count - 1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,61 +34,45 @@
 | 
			
		|||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
#include "processor/simple_symbol_supplier.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "processor/pathname_stripper.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
string SimpleSymbolSupplier::GetSymbolFileAtPath(MinidumpModule *module,
 | 
			
		||||
string SimpleSymbolSupplier::GetSymbolFileAtPath(const CodeModule *module,
 | 
			
		||||
                                                 const string &root_path) {
 | 
			
		||||
  // For now, only support modules that have GUIDs - which means
 | 
			
		||||
  // MDCVInfoPDB70.
 | 
			
		||||
 | 
			
		||||
  if (!module)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  const MDCVInfoPDB70 *cv_record =
 | 
			
		||||
      reinterpret_cast<const MDCVInfoPDB70*>(module->GetCVRecord());
 | 
			
		||||
  if (!cv_record)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  if (cv_record->cv_signature != MD_CVINFOPDB70_SIGNATURE)
 | 
			
		||||
    return "";
 | 
			
		||||
 | 
			
		||||
  // Start with the base path.
 | 
			
		||||
  string path = root_path;
 | 
			
		||||
 | 
			
		||||
  // Append the pdb file name as a directory name.
 | 
			
		||||
  // Append the debug (pdb) file name as a directory name.
 | 
			
		||||
  path.append("/");
 | 
			
		||||
  string pdb_file_name = PathnameStripper::File(
 | 
			
		||||
      reinterpret_cast<const char *>(cv_record->pdb_file_name));
 | 
			
		||||
  path.append(pdb_file_name);
 | 
			
		||||
  string debug_file_name = PathnameStripper::File(module->debug_file());
 | 
			
		||||
  if (debug_file_name.empty())
 | 
			
		||||
    return "";
 | 
			
		||||
  path.append(debug_file_name);
 | 
			
		||||
 | 
			
		||||
  // Append the uuid and age as a directory name.
 | 
			
		||||
  // Append the identifier as a directory name.
 | 
			
		||||
  path.append("/");
 | 
			
		||||
  char uuid_age_string[43];
 | 
			
		||||
  snprintf(uuid_age_string, sizeof(uuid_age_string),
 | 
			
		||||
           "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%X",
 | 
			
		||||
           cv_record->signature.data1, cv_record->signature.data2,
 | 
			
		||||
           cv_record->signature.data3,
 | 
			
		||||
           cv_record->signature.data4[0], cv_record->signature.data4[1],
 | 
			
		||||
           cv_record->signature.data4[2], cv_record->signature.data4[3],
 | 
			
		||||
           cv_record->signature.data4[4], cv_record->signature.data4[5],
 | 
			
		||||
           cv_record->signature.data4[6], cv_record->signature.data4[7],
 | 
			
		||||
           cv_record->age);
 | 
			
		||||
  path.append(uuid_age_string);
 | 
			
		||||
  string identifier = module->debug_identifier();
 | 
			
		||||
  if (identifier.empty())
 | 
			
		||||
    return "";
 | 
			
		||||
  path.append(identifier);
 | 
			
		||||
 | 
			
		||||
  // Transform the pdb file name into one ending in .sym.  If the existing
 | 
			
		||||
  // Transform the debug file name into one ending in .sym.  If the existing
 | 
			
		||||
  // name ends in .pdb, strip the .pdb.  Otherwise, add .sym to the non-.pdb
 | 
			
		||||
  // name.
 | 
			
		||||
  path.append("/");
 | 
			
		||||
  string pdb_file_extension = pdb_file_name.substr(pdb_file_name.size() - 4);
 | 
			
		||||
  transform(pdb_file_extension.begin(), pdb_file_extension.end(),
 | 
			
		||||
            pdb_file_extension.begin(), tolower);
 | 
			
		||||
  if (pdb_file_extension == ".pdb") {
 | 
			
		||||
    path.append(pdb_file_name.substr(0, pdb_file_name.size() - 4));
 | 
			
		||||
  string debug_file_extension =
 | 
			
		||||
      debug_file_name.substr(debug_file_name.size() - 4);
 | 
			
		||||
  transform(debug_file_extension.begin(), debug_file_extension.end(),
 | 
			
		||||
            debug_file_extension.begin(), tolower);
 | 
			
		||||
  if (debug_file_extension == ".pdb") {
 | 
			
		||||
    path.append(debug_file_name.substr(0, debug_file_name.size() - 4));
 | 
			
		||||
  } else {
 | 
			
		||||
    path.append(pdb_file_name);
 | 
			
		||||
    path.append(debug_file_name);
 | 
			
		||||
  }
 | 
			
		||||
  path.append(".sym");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,14 +33,16 @@
 | 
			
		|||
// that stores symbol files in a filesystem tree.  A SimpleSymbolSupplier is
 | 
			
		||||
// created with a base directory, which is the root for all symbol files.
 | 
			
		||||
// Each symbol file contained therien has a directory entry in the base
 | 
			
		||||
// directory with a name identical to the corresponding pdb file.  Within
 | 
			
		||||
// each of these directories, there are subdirectories named for the uuid and
 | 
			
		||||
// age of each pdb file.  The uuid is presented in hexadecimal form, with
 | 
			
		||||
// uppercase characters and no dashes.  The age is appended to it in
 | 
			
		||||
// hexadecimal form, without any separators.  Within that subdirectory,
 | 
			
		||||
// directory with a name identical to the corresponding debugging file (pdb).
 | 
			
		||||
// Within each of these directories, there are subdirectories named for the
 | 
			
		||||
// debugging file's identifier.  For recent pdb files, this is a concatenation
 | 
			
		||||
// of the pdb's uuid and age, presented in hexadecimal form, using uppercase
 | 
			
		||||
// characters and no dashes or separators.  Within that subdirectory,
 | 
			
		||||
// SimpleSymbolSupplier expects to find the symbol file, which is named
 | 
			
		||||
// identically to the pdb file, but with a .sym extension.  This sample
 | 
			
		||||
// hierarchy is rooted at the "symbols" base directory:
 | 
			
		||||
// identically to the debug file, but with a .sym extension.  If the original
 | 
			
		||||
// debug file had a name ending in .pdb, the .pdb extension will be replaced
 | 
			
		||||
// with .sym.  This sample hierarchy is rooted at the "symbols" base
 | 
			
		||||
// directory:
 | 
			
		||||
//
 | 
			
		||||
// symbols
 | 
			
		||||
// symbols/test_app.pdb
 | 
			
		||||
| 
						 | 
				
			
			@ -59,9 +61,11 @@
 | 
			
		|||
// SimpleSymbolServer, provided that the pdb files are transformed to dumped
 | 
			
		||||
// format using a tool such as dump_syms, and given a .sym extension.
 | 
			
		||||
//
 | 
			
		||||
// SimpleSymbolSupplier presently only supports symbol files that have
 | 
			
		||||
// the MSVC 7.0 CodeView record format.  See MDCVInfoPDB70 in
 | 
			
		||||
// minidump_format.h.
 | 
			
		||||
// SimpleSymbolSupplier supports any debugging file which can be identified
 | 
			
		||||
// by a CodeModule object's debug_file and debug_identifier accessors.  The
 | 
			
		||||
// expected ultimate source of these CodeModule objects are MinidumpModule
 | 
			
		||||
// objects; it is this class that is responsible for assigning appropriate
 | 
			
		||||
// values for debug_file and debug_identifier.
 | 
			
		||||
//
 | 
			
		||||
// Author: Mark Mentovai
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +80,7 @@ namespace google_airbag {
 | 
			
		|||
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
class MinidumpModule;
 | 
			
		||||
class CodeModule;
 | 
			
		||||
 | 
			
		||||
class SimpleSymbolSupplier : public SymbolSupplier {
 | 
			
		||||
 public:
 | 
			
		||||
| 
						 | 
				
			
			@ -88,12 +92,13 @@ class SimpleSymbolSupplier : public SymbolSupplier {
 | 
			
		|||
 | 
			
		||||
  // Returns the path to the symbol file for the given module.  See the
 | 
			
		||||
  // description above.
 | 
			
		||||
  virtual string GetSymbolFile(MinidumpModule *module) {
 | 
			
		||||
  virtual string GetSymbolFile(const CodeModule *module) {
 | 
			
		||||
    return GetSymbolFileAtPath(module, path_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  string GetSymbolFileAtPath(MinidumpModule *module, const string &root_path);
 | 
			
		||||
  string GetSymbolFileAtPath(const CodeModule *module,
 | 
			
		||||
                             const string &root_path);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  string path_;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,7 @@
 | 
			
		|||
#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"
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +112,7 @@ class SourceLineResolver::Module {
 | 
			
		|||
  // 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(MemAddr address, StackFrame *frame) const;
 | 
			
		||||
  StackFrameInfo* LookupAddress(StackFrame *frame) const;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  friend class SourceLineResolver;
 | 
			
		||||
| 
						 | 
				
			
			@ -206,10 +207,11 @@ bool SourceLineResolver::HasModule(const string &module_name) const {
 | 
			
		|||
 | 
			
		||||
StackFrameInfo* SourceLineResolver::FillSourceLineInfo(
 | 
			
		||||
    StackFrame *frame) const {
 | 
			
		||||
  ModuleMap::const_iterator it = modules_->find(frame->module_name);
 | 
			
		||||
  if (it != modules_->end()) {
 | 
			
		||||
    return it->second->LookupAddress(frame->instruction - frame->module_base,
 | 
			
		||||
                                     frame);
 | 
			
		||||
  if (frame->module) {
 | 
			
		||||
    ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
 | 
			
		||||
    if (it != modules_->end()) {
 | 
			
		||||
      return it->second->LookupAddress(frame);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -273,8 +275,10 @@ bool SourceLineResolver::Module::LoadMap(const string &map_file) {
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StackFrameInfo* SourceLineResolver::Module::LookupAddress(
 | 
			
		||||
    MemAddr address, StackFrame *frame) const {
 | 
			
		||||
StackFrameInfo* SourceLineResolver::Module::LookupAddress(StackFrame *frame)
 | 
			
		||||
    const {
 | 
			
		||||
  MemAddr address = frame->instruction - frame->module->base_address();
 | 
			
		||||
 | 
			
		||||
  linked_ptr<StackFrameInfo> retrieved_info;
 | 
			
		||||
  // Check for debugging info first, before any possible early returns.
 | 
			
		||||
  //
 | 
			
		||||
| 
						 | 
				
			
			@ -318,7 +322,7 @@ StackFrameInfo* SourceLineResolver::Module::LookupAddress(
 | 
			
		|||
    parameter_size = func->parameter_size;
 | 
			
		||||
 | 
			
		||||
    frame->function_name = func->name;
 | 
			
		||||
    frame->function_base = frame->module_base + function_base;
 | 
			
		||||
    frame->function_base = frame->module->base_address() + function_base;
 | 
			
		||||
 | 
			
		||||
    linked_ptr<Line> line;
 | 
			
		||||
    MemAddr line_base;
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +332,7 @@ StackFrameInfo* SourceLineResolver::Module::LookupAddress(
 | 
			
		|||
        frame->source_file_name = files_.find(line->source_file_id)->second;
 | 
			
		||||
      }
 | 
			
		||||
      frame->source_line = line->line;
 | 
			
		||||
      frame->source_line_base = frame->module_base + line_base;
 | 
			
		||||
      frame->source_line_base = frame->module->base_address() + line_base;
 | 
			
		||||
    }
 | 
			
		||||
  } else if (public_symbols_.Retrieve(address,
 | 
			
		||||
                                      &public_symbol, &public_address) &&
 | 
			
		||||
| 
						 | 
				
			
			@ -336,7 +340,7 @@ StackFrameInfo* SourceLineResolver::Module::LookupAddress(
 | 
			
		|||
    parameter_size = public_symbol->parameter_size;
 | 
			
		||||
 | 
			
		||||
    frame->function_name = public_symbol->name;
 | 
			
		||||
    frame->function_base = frame->module_base + public_address;
 | 
			
		||||
    frame->function_base = frame->module->base_address() + public_address;
 | 
			
		||||
  } else {
 | 
			
		||||
    // No FUNC or PUBLIC data available.
 | 
			
		||||
    return frame_info.release();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@
 | 
			
		|||
#include <cstdio>
 | 
			
		||||
#include <string>
 | 
			
		||||
#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"
 | 
			
		||||
| 
						 | 
				
			
			@ -48,12 +49,33 @@
 | 
			
		|||
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());
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +85,7 @@ static bool VerifyEmpty(const StackFrame &frame) {
 | 
			
		|||
 | 
			
		||||
static void ClearSourceLineInfo(StackFrame *frame) {
 | 
			
		||||
  frame->function_name.clear();
 | 
			
		||||
  frame->module = NULL;
 | 
			
		||||
  frame->source_file_name.clear();
 | 
			
		||||
  frame->source_line = 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -77,13 +100,28 @@ static bool RunTests() {
 | 
			
		|||
  ASSERT_TRUE(resolver.LoadModule("module2", testdata_dir + "/module2.out"));
 | 
			
		||||
  ASSERT_TRUE(resolver.HasModule("module2"));
 | 
			
		||||
 | 
			
		||||
  TestCodeModule module1("module1");
 | 
			
		||||
 | 
			
		||||
  StackFrame frame;
 | 
			
		||||
  frame.instruction = 0x1000;
 | 
			
		||||
  frame.module_name = "module1";
 | 
			
		||||
  frame.module = NULL;
 | 
			
		||||
  scoped_ptr<StackFrameInfo> 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,
 | 
			
		||||
| 
						 | 
				
			
			@ -91,6 +129,7 @@ static bool RunTests() {
 | 
			
		|||
 | 
			
		||||
  ClearSourceLineInfo(&frame);
 | 
			
		||||
  frame.instruction = 0x800;
 | 
			
		||||
  frame.module = &module1;
 | 
			
		||||
  frame_info.reset(resolver.FillSourceLineInfo(&frame));
 | 
			
		||||
  ASSERT_TRUE(VerifyEmpty(frame));
 | 
			
		||||
  ASSERT_FALSE(frame_info.get());
 | 
			
		||||
| 
						 | 
				
			
			@ -113,28 +152,33 @@ static bool RunTests() {
 | 
			
		|||
  ASSERT_FALSE(frame_info->allocates_base_pointer);
 | 
			
		||||
  ASSERT_FALSE(frame_info->program_string.empty());
 | 
			
		||||
 | 
			
		||||
  frame.instruction = 0x2180;
 | 
			
		||||
  frame.module_name = "module2";
 | 
			
		||||
  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;
 | 
			
		||||
  frame.module_name = "module2";
 | 
			
		||||
  resolver.FillSourceLineInfo(&frame);
 | 
			
		||||
  ASSERT_EQ(frame.function_name, "Public2_1");
 | 
			
		||||
 | 
			
		||||
  ClearSourceLineInfo(&frame);
 | 
			
		||||
  frame.instruction = 0x219f;
 | 
			
		||||
  frame.module_name = "module2";
 | 
			
		||||
  frame.module = &module2;
 | 
			
		||||
  resolver.FillSourceLineInfo(&frame);
 | 
			
		||||
  ASSERT_TRUE(frame.function_name.empty());
 | 
			
		||||
 | 
			
		||||
  frame.instruction = 0x21a0;
 | 
			
		||||
  frame.module_name = "module2";
 | 
			
		||||
  frame.module = &module2;
 | 
			
		||||
  resolver.FillSourceLineInfo(&frame);
 | 
			
		||||
  ASSERT_EQ(frame.function_name, "Public2_2");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,8 @@
 | 
			
		|||
 | 
			
		||||
#include "google_airbag/processor/stackwalker.h"
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/code_module.h"
 | 
			
		||||
#include "google_airbag/processor/code_modules.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/stack_frame.h"
 | 
			
		||||
#include "google_airbag/processor/symbol_supplier.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +51,7 @@
 | 
			
		|||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Stackwalker::Stackwalker(MemoryRegion *memory, MinidumpModuleList *modules,
 | 
			
		||||
Stackwalker::Stackwalker(MemoryRegion *memory, const CodeModules *modules,
 | 
			
		||||
                         SymbolSupplier *supplier)
 | 
			
		||||
    : memory_(memory), modules_(modules), supplier_(supplier) {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -80,15 +82,14 @@ CallStack* Stackwalker::Walk() {
 | 
			
		|||
 | 
			
		||||
    // Resolve the module information, if a module map was provided.
 | 
			
		||||
    if (modules_) {
 | 
			
		||||
      MinidumpModule *module =
 | 
			
		||||
      const CodeModule *module =
 | 
			
		||||
          modules_->GetModuleForAddress(frame->instruction);
 | 
			
		||||
      if (module) {
 | 
			
		||||
        frame->module_name = *(module->GetName());
 | 
			
		||||
        frame->module_base = module->base_address();
 | 
			
		||||
        if (!resolver.HasModule(frame->module_name) && supplier_) {
 | 
			
		||||
        frame->module = module;
 | 
			
		||||
        if (!resolver.HasModule(frame->module->code_file()) && supplier_) {
 | 
			
		||||
          string symbol_file = supplier_->GetSymbolFile(module);
 | 
			
		||||
          if (!symbol_file.empty()) {
 | 
			
		||||
            resolver.LoadModule(frame->module_name, symbol_file);
 | 
			
		||||
            resolver.LoadModule(frame->module->code_file(), symbol_file);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        frame_info.reset(resolver.FillSourceLineInfo(frame.get()));
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +115,7 @@ CallStack* Stackwalker::Walk() {
 | 
			
		|||
// static
 | 
			
		||||
Stackwalker* Stackwalker::StackwalkerForCPU(MinidumpContext *context,
 | 
			
		||||
                                            MemoryRegion *memory,
 | 
			
		||||
                                            MinidumpModuleList *modules,
 | 
			
		||||
                                            const CodeModules *modules,
 | 
			
		||||
                                            SymbolSupplier *supplier) {
 | 
			
		||||
  Stackwalker *cpu_stackwalker = NULL;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@
 | 
			
		|||
 | 
			
		||||
#include "processor/stackwalker_ppc.h"
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/memory_region.h"
 | 
			
		||||
#include "google_airbag/processor/stack_frame_cpu.h"
 | 
			
		||||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ namespace google_airbag {
 | 
			
		|||
 | 
			
		||||
StackwalkerPPC::StackwalkerPPC(const MDRawContextPPC *context,
 | 
			
		||||
                               MemoryRegion *memory,
 | 
			
		||||
                               MinidumpModuleList *modules,
 | 
			
		||||
                               const CodeModules *modules,
 | 
			
		||||
                               SymbolSupplier *supplier)
 | 
			
		||||
    : Stackwalker(memory, modules, supplier),
 | 
			
		||||
      context_(context) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,19 +45,17 @@
 | 
			
		|||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
class MinidumpContext;
 | 
			
		||||
class MinidumpModuleList;
 | 
			
		||||
 | 
			
		||||
class CodeModules;
 | 
			
		||||
 | 
			
		||||
class StackwalkerPPC : public Stackwalker {
 | 
			
		||||
 public:
 | 
			
		||||
  // context is a MinidumpContext object that gives access to ppc-specific
 | 
			
		||||
  // context is a ppc context object that gives access to ppc-specific
 | 
			
		||||
  // register state corresponding to the innermost called frame to be
 | 
			
		||||
  // included in the stack.  The other arguments are passed directly through
 | 
			
		||||
  // to the base Stackwalker constructor.
 | 
			
		||||
  StackwalkerPPC(const MDRawContextPPC *context,
 | 
			
		||||
                 MemoryRegion *memory,
 | 
			
		||||
                 MinidumpModuleList *modules,
 | 
			
		||||
                 const CodeModules *modules,
 | 
			
		||||
                 SymbolSupplier *supplier);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,31 @@
 | 
			
		|||
// Copyright (C) 2006 Google Inc.
 | 
			
		||||
// Copyright (c) 2006, Google Inc.
 | 
			
		||||
// All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
// Redistribution and use in source and binary forms, with or without
 | 
			
		||||
// modification, are permitted provided that the following conditions are
 | 
			
		||||
// met:
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//     * 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.
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
// 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.
 | 
			
		||||
 | 
			
		||||
// stackwalker_selftest.cc: Tests StackwalkerX86 or StackwalkerPPC using the
 | 
			
		||||
// running process' stack as test data, if running on an x86 or ppc and
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
 | 
			
		||||
#include "processor/stackwalker_x86.h"
 | 
			
		||||
#include "google_airbag/processor/call_stack.h"
 | 
			
		||||
#include "google_airbag/processor/minidump.h"
 | 
			
		||||
#include "google_airbag/processor/memory_region.h"
 | 
			
		||||
#include "google_airbag/processor/stack_frame_cpu.h"
 | 
			
		||||
#include "processor/linked_ptr.h"
 | 
			
		||||
#include "processor/stack_frame_info.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ namespace google_airbag {
 | 
			
		|||
 | 
			
		||||
StackwalkerX86::StackwalkerX86(const MDRawContextX86 *context,
 | 
			
		||||
                               MemoryRegion *memory,
 | 
			
		||||
                               MinidumpModuleList *modules,
 | 
			
		||||
                               const CodeModules *modules,
 | 
			
		||||
                               SymbolSupplier *supplier)
 | 
			
		||||
    : Stackwalker(memory, modules, supplier),
 | 
			
		||||
      context_(context) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,19 +45,18 @@
 | 
			
		|||
 | 
			
		||||
namespace google_airbag {
 | 
			
		||||
 | 
			
		||||
class MinidumpContext;
 | 
			
		||||
class MinidumpModuleList;
 | 
			
		||||
class CodeModules;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class StackwalkerX86 : public Stackwalker {
 | 
			
		||||
 public:
 | 
			
		||||
  // context is a MinidumpContext object that gives access to x86-specific
 | 
			
		||||
  // context is an x86 context object that gives access to x86-specific
 | 
			
		||||
  // register state corresponding to the innermost called frame to be
 | 
			
		||||
  // included in the stack.  The other arguments are passed directly through
 | 
			
		||||
  // to the base Stackwalker constructor.
 | 
			
		||||
  StackwalkerX86(const MDRawContextX86 *context,
 | 
			
		||||
                 MemoryRegion *memory,
 | 
			
		||||
                 MinidumpModuleList *modules,
 | 
			
		||||
                 const CodeModules *modules,
 | 
			
		||||
                 SymbolSupplier *supplier);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										91
									
								
								src/processor/testdata/minidump2.dump.out
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										91
									
								
								src/processor/testdata/minidump2.dump.out
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -200,13 +200,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x132c
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "c:\test_app.exe"
 | 
			
		||||
  (code_file)                     = "c:\test_app.exe"
 | 
			
		||||
  (code_identifier)               = "454fa44d2b000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 8ddb7e9a-3657-4893-8d6e-b08b1dca31aa
 | 
			
		||||
  (cv_record).age                 = 1
 | 
			
		||||
  (cv_record).pdb_file_name       = "c:\test_app.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "c:\test_app.pdb"
 | 
			
		||||
  (debug_file)                    = "c:\test_app.pdb"
 | 
			
		||||
  (debug_identifier)              = "8DDB7E9A365748938D6EB08B1DCA31AA1"
 | 
			
		||||
  (version)                       = ""
 | 
			
		||||
 | 
			
		||||
module[1]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -229,13 +232,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x1354
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\ntdll.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\ntdll.dll"
 | 
			
		||||
  (code_identifier)               = "411096b4b0000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 36515fb5-d043-45e4-91f6-72fa2e2878c0
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "ntdll.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "ntdll.pdb"
 | 
			
		||||
  (debug_file)                    = "ntdll.pdb"
 | 
			
		||||
  (debug_identifier)              = "36515FB5D04345E491F672FA2E2878C02"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[2]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -258,13 +264,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x1376
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\kernel32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\kernel32.dll"
 | 
			
		||||
  (code_identifier)               = "44ab9a84f4000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = bce8785c-57b4-4245-a669-896b6a19b954
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "kernel32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "kernel32.pdb"
 | 
			
		||||
  (debug_file)                    = "kernel32.pdb"
 | 
			
		||||
  (debug_identifier)              = "BCE8785C57B44245A669896B6A19B9542"
 | 
			
		||||
  (version)                       = "5.1.2600.2945"
 | 
			
		||||
 | 
			
		||||
module[3]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -287,13 +296,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x139b
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\ole32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\ole32.dll"
 | 
			
		||||
  (code_identifier)               = "42e5be9313d000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 683b65b2-46f4-4187-96d2-ee6d4c55eb11
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "ole32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "ole32.pdb"
 | 
			
		||||
  (debug_file)                    = "ole32.pdb"
 | 
			
		||||
  (debug_identifier)              = "683B65B246F4418796D2EE6D4C55EB112"
 | 
			
		||||
  (version)                       = "5.1.2600.2726"
 | 
			
		||||
 | 
			
		||||
module[4]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -316,13 +328,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x13bd
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\advapi32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\advapi32.dll"
 | 
			
		||||
  (code_identifier)               = "411096a79b000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 455d6c5f-184d-45bb-b5c5-f30f82975114
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "advapi32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "advapi32.pdb"
 | 
			
		||||
  (debug_file)                    = "advapi32.pdb"
 | 
			
		||||
  (debug_identifier)              = "455D6C5F184D45BBB5C5F30F829751142"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[5]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -345,13 +360,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x13e2
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\rpcrt4.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\rpcrt4.dll"
 | 
			
		||||
  (code_identifier)               = "411096ae91000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = bea45a72-1da1-41da-a3ba-86b3a2031153
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "rpcrt4.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "rpcrt4.pdb"
 | 
			
		||||
  (debug_file)                    = "rpcrt4.pdb"
 | 
			
		||||
  (debug_identifier)              = "BEA45A721DA141DAA3BA86B3A20311532"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[6]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -374,13 +392,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x1405
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\gdi32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\gdi32.dll"
 | 
			
		||||
  (code_identifier)               = "43b34feb47000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = c0ea66be-00a6-4bd7-aef7-9e443a91869c
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "gdi32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "gdi32.pdb"
 | 
			
		||||
  (debug_file)                    = "gdi32.pdb"
 | 
			
		||||
  (debug_identifier)              = "C0EA66BE00A64BD7AEF79E443A91869C2"
 | 
			
		||||
  (version)                       = "5.1.2600.2818"
 | 
			
		||||
 | 
			
		||||
module[7]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -403,13 +424,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x1427
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\user32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\user32.dll"
 | 
			
		||||
  (code_identifier)               = "4226015990000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = ee2b714d-83a3-4c9d-8802-7621272f8326
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "user32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "user32.pdb"
 | 
			
		||||
  (debug_file)                    = "user32.pdb"
 | 
			
		||||
  (debug_identifier)              = "EE2B714D83A34C9D88027621272F83262"
 | 
			
		||||
  (version)                       = "5.1.2600.2622"
 | 
			
		||||
 | 
			
		||||
module[8]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -432,13 +456,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x144a
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\msvcrt.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\msvcrt.dll"
 | 
			
		||||
  (code_identifier)               = "4110975258000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = a678f3c3-0ded-426b-8390-32b996987e38
 | 
			
		||||
  (cv_record).age                 = 1
 | 
			
		||||
  (cv_record).pdb_file_name       = "msvcrt.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "msvcrt.pdb"
 | 
			
		||||
  (debug_file)                    = "msvcrt.pdb"
 | 
			
		||||
  (debug_identifier)              = "A678F3C30DED426B839032B996987E381"
 | 
			
		||||
  (version)                       = "7.0.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[9]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -461,13 +488,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x146d
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\imm32.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\imm32.dll"
 | 
			
		||||
  (code_identifier)               = "411096ae1d000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 2c17a49c-251b-4c8e-b9e2-ad13d7d9ea16
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "imm32.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "imm32.pdb"
 | 
			
		||||
  (debug_file)                    = "imm32.pdb"
 | 
			
		||||
  (debug_identifier)              = "2C17A49C251B4C8EB9E2AD13D7D9EA162"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[10]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -490,13 +520,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x148f
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\dbghelp.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\dbghelp.dll"
 | 
			
		||||
  (code_identifier)               = "4110969aa1000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 39559573-e21b-46f2-8e28-6923be9e6a76
 | 
			
		||||
  (cv_record).age                 = 1
 | 
			
		||||
  (cv_record).pdb_file_name       = "dbghelp.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "dbghelp.pdb"
 | 
			
		||||
  (debug_file)                    = "dbghelp.pdb"
 | 
			
		||||
  (debug_identifier)              = "39559573E21B46F28E286923BE9E6A761"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[11]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -519,13 +552,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x14b3
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\version.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\version.dll"
 | 
			
		||||
  (code_identifier)               = "411096b78000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = 180a90c4-0384-463e-82dd-c45b2c8ab76e
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "version.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "version.pdb"
 | 
			
		||||
  (debug_file)                    = "version.pdb"
 | 
			
		||||
  (debug_identifier)              = "180A90C40384463E82DDC45B2C8AB76E2"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
module[12]
 | 
			
		||||
MDRawModule
 | 
			
		||||
| 
						 | 
				
			
			@ -548,13 +584,16 @@ MDRawModule
 | 
			
		|||
  cv_record.rva                   = 0x14d7
 | 
			
		||||
  misc_record.data_size           = 0
 | 
			
		||||
  misc_record.rva                 = 0x0
 | 
			
		||||
  (module_name)                   = "C:\WINDOWS\system32\psapi.dll"
 | 
			
		||||
  (code_file)                     = "C:\WINDOWS\system32\psapi.dll"
 | 
			
		||||
  (code_identifier)               = "411096cab000"
 | 
			
		||||
  (cv_record).cv_signature        = 0x53445352
 | 
			
		||||
  (cv_record).signature           = a5c3a1f9-689f-43d8-ad22-8a0929388970
 | 
			
		||||
  (cv_record).age                 = 2
 | 
			
		||||
  (cv_record).pdb_file_name       = "psapi.pdb"
 | 
			
		||||
  (misc_record)                   = (null)
 | 
			
		||||
  (debug_filename)                = "psapi.pdb"
 | 
			
		||||
  (debug_file)                    = "psapi.pdb"
 | 
			
		||||
  (debug_identifier)              = "A5C3A1F9689F43D8AD228A09293889702"
 | 
			
		||||
  (version)                       = "5.1.2600.2180"
 | 
			
		||||
 | 
			
		||||
MinidumpMemoryList
 | 
			
		||||
  region_count = 3
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								src/processor/testdata/minidump2.stackwalk.out
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								src/processor/testdata/minidump2.stackwalk.out
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -17,3 +17,18 @@ Thread 0 (crashed)
 | 
			
		|||
    eip = 0x0040395c   esp = 0x0012ff78   ebp = 0x0012ffc0
 | 
			
		||||
 3  kernel32.dll!BaseProcessStart + 0x22
 | 
			
		||||
    eip = 0x7c816fd7   esp = 0x0012ffc8   ebp = 0x0012fff0
 | 
			
		||||
 | 
			
		||||
Loaded modules:
 | 
			
		||||
0x00400000 - 0x0042afff  test_app.exe  ???  (main)
 | 
			
		||||
0x59a60000 - 0x59b00fff  dbghelp.dll  5.1.2600.2180
 | 
			
		||||
0x76390000 - 0x763acfff  imm32.dll  5.1.2600.2180
 | 
			
		||||
0x76bf0000 - 0x76bfafff  psapi.dll  5.1.2600.2180
 | 
			
		||||
0x774e0000 - 0x7761cfff  ole32.dll  5.1.2600.2726
 | 
			
		||||
0x77c00000 - 0x77c07fff  version.dll  5.1.2600.2180
 | 
			
		||||
0x77c10000 - 0x77c67fff  msvcrt.dll  7.0.2600.2180
 | 
			
		||||
0x77d40000 - 0x77dcffff  user32.dll  5.1.2600.2622
 | 
			
		||||
0x77dd0000 - 0x77e6afff  advapi32.dll  5.1.2600.2180
 | 
			
		||||
0x77e70000 - 0x77f00fff  rpcrt4.dll  5.1.2600.2180
 | 
			
		||||
0x77f10000 - 0x77f56fff  gdi32.dll  5.1.2600.2818
 | 
			
		||||
0x7c800000 - 0x7c8f3fff  kernel32.dll  5.1.2600.2945
 | 
			
		||||
0x7c900000 - 0x7c9affff  ntdll.dll  5.1.2600.2180
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue