From: Denis Khalikov Date: Sat, 29 Jul 2017 19:18:59 +0000 (+0300) Subject: PR sanitizer/77631 X-Git-Tag: accepted/tizen/base/20170908.223816~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F56%2F134256%2F16;p=platform%2Fupstream%2Flinaro-gcc.git PR sanitizer/77631 * Makefile.am: Updated. * configure.ac: Updated. * configure: Regenerated. * Makefile.in: Regenerated. * elf.c (enum type_of_file): New enum. (enum type_of_elf): New enum. (enum debug_path): New enum. (get_uint32): New function. (get_crc32): New function. (base_name_len): New function. (check_sum): New function. Verify sum. (process_elf_header): New function. Process elf header. (elf_get_section_by_name): New function. Get section by name. (backtrace_readlink): New function. Get type of file from filename. (resolve_realname): New function. Resolve real name if file is link. (backtrace_resolve_realname): New function. Resolve real name for any file type. (search_for_debugfile): New function. Search for debug file in known paths. (open_debugfile_by_gnulink): New function. Open debug file with gnulink. (hex): New function. Convert to hex. (get_build_id_name): New function. Generate build-id name. (open_debugfile_by_build_id): New function. Open debug file with build-id. (backtrace_open_debugfile): New function. Open debug file. (get_exec_filename): New function. Get pathname of the executable. (elf_add): Move code which reads elf header, headers section and names section to process_elf_header. Call backtrace_open_debugfile_file for executable. (phdr_callback): Call backtrace_open_debugfile function for shared library. * crc32.c: New file. (gnu_debuglink_crc32): New function. Generate crc32 sum. Change-Id: I30d9fbcfa24b3aadf3b7c54525dccedd60cd1a5d --- diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog index 4cb639b..c2546be 100644 --- a/libbacktrace/ChangeLog +++ b/libbacktrace/ChangeLog @@ -1,3 +1,42 @@ +2017-07-29 Denis Khalikov + + PR sanitizer/77631 + * Makefile.am: Updated. + * configure.ac: Updated. + * configure: Regenerated. + * Makefile.in: Regenerated. + * elf.c (enum type_of_file): New enum. + (enum type_of_elf): New enum. + (enum debug_path): New enum. + (get_uint32): New function. + (get_crc32): New function. + (base_name_len): New function. + (check_sum): New function. Verify sum. + (process_elf_header): New function. Process elf header. + (elf_get_section_by_name): New function. Get section by name. + (backtrace_readlink): New function. Get type of file from filename. + (resolve_realname): New function. Resolve real name if file is link. + (backtrace_resolve_realname): New function. Resolve real name for any + file type. + (search_for_debugfile): New function. Search for debug file in known + paths. + (open_debugfile_by_gnulink): New function. Open debug file with + gnulink. + (hex): New function. Convert to hex. + (get_build_id_name): New function. Generate build-id name. + (open_debugfile_by_build_id): New function. Open debug file with + build-id. + (backtrace_open_debugfile): New function. Open debug file. + (get_exec_filename): New function. Get pathname of the executable. + (elf_add): Move code which reads elf header, headers section and names + section to process_elf_header. + Call backtrace_open_debugfile_file for executable. + (phdr_callback): Call backtrace_open_debugfile function for shared + library. + * crc32.c: New file. + (gnu_debuglink_crc32): New function. Generate crc32 sum. + + 2016-12-21 Release Manager * GCC 6.3.0 released. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index a7df025..61f1804 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -100,8 +100,161 @@ stest_LDADD = libbacktrace.la check_PROGRAMS += stest -endif NATIVE +glinktest_SOURCES = btest.c +glinktest_CFLAGS = $(AM_CFLAGS) -g -O +glinktest_LDADD = libbacktrace.la + +check_PROGRAMS += glinktest + +bidtest_SOURCES = btest.c +bidtest_CFLAGS = $(AM_CFLAGS) -g -O -Wl,--build-id=0x0123456789abcdef0123456789abcdef01234567 +bidtest_LDADD = libbacktrace.la + +check_PROGRAMS += bidtest + +pictest_SOURCES = btest.c +pictest_CFLAGS = $(AM_CFLAGS) -g -O -fPIC -pie +pictest_LDADD = libbacktrace.la +check_PROGRAMS += pictest + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if ! test -e glinktest.debug; then \ + $(OBJCOPY) --only-keep-debug glinktest glinktest.debug; \ + $(STRIP) glinktest; \ + $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest; \ + fi; \ + if ! test -e pictest.debug; then \ + $(OBJCOPY) --only-keep-debug pictest pictest.debug; \ + $(STRIP) pictest; \ + $(OBJCOPY) --add-gnu-debuglink=pictest.debug pictest; \ + fi; \ + if ! test -e .build-id; then \ + mkdir .build-id; \ + mkdir .build-id/01/; \ + mkdir temp; \ + $(OBJCOPY) --only-keep-debug bidtest bidtest.debug; \ + $(STRIP) bidtest; \ + touch temp; \ + mv bidtest.debug temp;\ + ln -s ../../temp/bidtest.debug .build-id/01/23456789abcdef0123456789abcdef01234567.debug; \ + fi; \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + + +clean-checkPROGRAMS: + @if test -e glinktest.debug; then \ + echo "rm -f glinktest.debug pictest.debug"; \ + rm -f glinktest.debug pictest.debug; \ + fi; \ + if test -d temp; then \ + echo "rm -rf temp"; \ + rm -rf temp; \ + fi; \ + if test -d .build-id; then \ + echo "rm -rf .build-id"; \ + rm -rf .build-id; \ + fi; \ + list='$(check_PROGRAMS)'; \ + test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list; + +endif NATIVE # We can't use automake's automatic dependency tracking, because it # breaks when using bootstrap-lean. Automatic dependency tracking # with GCC bootstrap will cause some of the objects to depend on diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in index 586b6a6..1f51c4e 100644 --- a/libbacktrace/Makefile.in +++ b/libbacktrace/Makefile.in @@ -16,7 +16,7 @@ @SET_MAKE@ # Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012-2015 Free Software Foundation, Inc. +# Copyright (C) 2012-2016 Free Software Foundation, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -84,7 +84,7 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = $(am__EXEEXT_1) -@NATIVE_TRUE@am__append_1 = btest stest +@NATIVE_TRUE@am__append_1 = btest stest glinktest bidtest pictest subdir = . DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/configure \ @@ -113,13 +113,33 @@ am__DEPENDENCIES_1 = am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ print.lo sort.lo state.lo libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) -@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) +@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \ +@NATIVE_TRUE@ glinktest$(EXEEXT) bidtest$(EXEEXT) \ +@NATIVE_TRUE@ pictest$(EXEEXT) +@NATIVE_TRUE@am_bidtest_OBJECTS = bidtest-btest.$(OBJEXT) +bidtest_OBJECTS = $(am_bidtest_OBJECTS) +@NATIVE_TRUE@bidtest_DEPENDENCIES = libbacktrace.la +bidtest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(bidtest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) btest_OBJECTS = $(am_btest_OBJECTS) @NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ +@NATIVE_TRUE@am_glinktest_OBJECTS = glinktest-btest.$(OBJEXT) +glinktest_OBJECTS = $(am_glinktest_OBJECTS) +@NATIVE_TRUE@glinktest_DEPENDENCIES = libbacktrace.la +glinktest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(glinktest_CFLAGS) \ + $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +@NATIVE_TRUE@am_pictest_OBJECTS = pictest-btest.$(OBJEXT) +pictest_OBJECTS = $(am_pictest_OBJECTS) +@NATIVE_TRUE@pictest_DEPENDENCIES = libbacktrace.la +pictest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(pictest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) stest_OBJECTS = $(am_stest_OBJECTS) @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la @@ -136,7 +156,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ - $(btest_SOURCES) $(stest_SOURCES) + $(bidtest_SOURCES) $(btest_SOURCES) $(glinktest_SOURCES) \ + $(pictest_SOURCES) $(stest_SOURCES) MULTISRCTOP = MULTIBUILDTOP = MULTIDIRS = @@ -200,6 +221,7 @@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ +OBJCOPY = @OBJCOPY@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ @@ -330,6 +352,15 @@ TESTS = $(check_PROGRAMS) @NATIVE_TRUE@btest_LDADD = libbacktrace.la @NATIVE_TRUE@stest_SOURCES = stest.c @NATIVE_TRUE@stest_LDADD = libbacktrace.la +@NATIVE_TRUE@glinktest_SOURCES = btest.c +@NATIVE_TRUE@glinktest_CFLAGS = $(AM_CFLAGS) -g -O +@NATIVE_TRUE@glinktest_LDADD = libbacktrace.la +@NATIVE_TRUE@bidtest_SOURCES = btest.c +@NATIVE_TRUE@bidtest_CFLAGS = $(AM_CFLAGS) -g -O -Wl,--build-id=0x0123456789abcdef0123456789abcdef01234567 +@NATIVE_TRUE@bidtest_LDADD = libbacktrace.la +@NATIVE_TRUE@pictest_SOURCES = btest.c +@NATIVE_TRUE@pictest_CFLAGS = $(AM_CFLAGS) -g -O -fPIC -pie +@NATIVE_TRUE@pictest_LDADD = libbacktrace.la # We can't use automake's automatic dependency tracking, because it # breaks when using bootstrap-lean. Automatic dependency tracking @@ -411,17 +442,26 @@ clean-noinstLTLIBRARIES: libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) $(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS) -clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list +@NATIVE_FALSE@clean-checkPROGRAMS: +@NATIVE_FALSE@ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ +@NATIVE_FALSE@ echo " rm -f" $$list; \ +@NATIVE_FALSE@ rm -f $$list || exit $$?; \ +@NATIVE_FALSE@ test -n "$(EXEEXT)" || exit 0; \ +@NATIVE_FALSE@ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ +@NATIVE_FALSE@ echo " rm -f" $$list; \ +@NATIVE_FALSE@ rm -f $$list +bidtest$(EXEEXT): $(bidtest_OBJECTS) $(bidtest_DEPENDENCIES) $(EXTRA_bidtest_DEPENDENCIES) + @rm -f bidtest$(EXEEXT) + $(bidtest_LINK) $(bidtest_OBJECTS) $(bidtest_LDADD) $(LIBS) btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) @rm -f btest$(EXEEXT) $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) +glinktest$(EXEEXT): $(glinktest_OBJECTS) $(glinktest_DEPENDENCIES) $(EXTRA_glinktest_DEPENDENCIES) + @rm -f glinktest$(EXEEXT) + $(glinktest_LINK) $(glinktest_OBJECTS) $(glinktest_LDADD) $(LIBS) +pictest$(EXEEXT): $(pictest_OBJECTS) $(pictest_DEPENDENCIES) $(EXTRA_pictest_DEPENDENCIES) + @rm -f pictest$(EXEEXT) + $(pictest_LINK) $(pictest_OBJECTS) $(pictest_LDADD) $(LIBS) stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) @rm -f stest$(EXEEXT) $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) @@ -441,12 +481,30 @@ distclean-compile: .c.lo: $(LTCOMPILE) -c -o $@ $< +bidtest-btest.o: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bidtest_CFLAGS) $(CFLAGS) -c -o bidtest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c + +bidtest-btest.obj: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(bidtest_CFLAGS) $(CFLAGS) -c -o bidtest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` + btest-btest.o: btest.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c btest-btest.obj: btest.c $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` +glinktest-btest.o: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(glinktest_CFLAGS) $(CFLAGS) -c -o glinktest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c + +glinktest-btest.obj: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(glinktest_CFLAGS) $(CFLAGS) -c -o glinktest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` + +pictest-btest.o: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pictest_CFLAGS) $(CFLAGS) -c -o pictest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c + +pictest-btest.obj: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pictest_CFLAGS) $(CFLAGS) -c -o pictest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` + mostlyclean-libtool: -rm -f *.lo @@ -525,98 +583,98 @@ GTAGS: distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -check-TESTS: $(TESTS) - @failed=0; all=0; xfail=0; xpass=0; skip=0; \ - srcdir=$(srcdir); export srcdir; \ - list=' $(TESTS) '; \ - $(am__tty_colors); \ - if test -n "$$list"; then \ - for tst in $$list; do \ - if test -f ./$$tst; then dir=./; \ - elif test -f $$tst; then dir=; \ - else dir="$(srcdir)/"; fi; \ - if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xpass=`expr $$xpass + 1`; \ - failed=`expr $$failed + 1`; \ - col=$$red; res=XPASS; \ - ;; \ - *) \ - col=$$grn; res=PASS; \ - ;; \ - esac; \ - elif test $$? -ne 77; then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xfail=`expr $$xfail + 1`; \ - col=$$lgn; res=XFAIL; \ - ;; \ - *) \ - failed=`expr $$failed + 1`; \ - col=$$red; res=FAIL; \ - ;; \ - esac; \ - else \ - skip=`expr $$skip + 1`; \ - col=$$blu; res=SKIP; \ - fi; \ - echo "$${col}$$res$${std}: $$tst"; \ - done; \ - if test "$$all" -eq 1; then \ - tests="test"; \ - All=""; \ - else \ - tests="tests"; \ - All="All "; \ - fi; \ - if test "$$failed" -eq 0; then \ - if test "$$xfail" -eq 0; then \ - banner="$$All$$all $$tests passed"; \ - else \ - if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ - banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ - fi; \ - else \ - if test "$$xpass" -eq 0; then \ - banner="$$failed of $$all $$tests failed"; \ - else \ - if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ - banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ - fi; \ - fi; \ - dashes="$$banner"; \ - skipped=""; \ - if test "$$skip" -ne 0; then \ - if test "$$skip" -eq 1; then \ - skipped="($$skip test was not run)"; \ - else \ - skipped="($$skip tests were not run)"; \ - fi; \ - test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$skipped"; \ - fi; \ - report=""; \ - if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ - report="Please report to $(PACKAGE_BUGREPORT)"; \ - test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$report"; \ - fi; \ - dashes=`echo "$$dashes" | sed s/./=/g`; \ - if test "$$failed" -eq 0; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - fi; \ - echo "$${col}$$dashes$${std}"; \ - echo "$${col}$$banner$${std}"; \ - test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ - test -z "$$report" || echo "$${col}$$report$${std}"; \ - echo "$${col}$$dashes$${std}"; \ - test "$$failed" -eq 0; \ - else :; fi +@NATIVE_FALSE@check-TESTS: $(TESTS) +@NATIVE_FALSE@ @failed=0; all=0; xfail=0; xpass=0; skip=0; \ +@NATIVE_FALSE@ srcdir=$(srcdir); export srcdir; \ +@NATIVE_FALSE@ list=' $(TESTS) '; \ +@NATIVE_FALSE@ $(am__tty_colors); \ +@NATIVE_FALSE@ if test -n "$$list"; then \ +@NATIVE_FALSE@ for tst in $$list; do \ +@NATIVE_FALSE@ if test -f ./$$tst; then dir=./; \ +@NATIVE_FALSE@ elif test -f $$tst; then dir=; \ +@NATIVE_FALSE@ else dir="$(srcdir)/"; fi; \ +@NATIVE_FALSE@ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ +@NATIVE_FALSE@ all=`expr $$all + 1`; \ +@NATIVE_FALSE@ case " $(XFAIL_TESTS) " in \ +@NATIVE_FALSE@ *[\ \ ]$$tst[\ \ ]*) \ +@NATIVE_FALSE@ xpass=`expr $$xpass + 1`; \ +@NATIVE_FALSE@ failed=`expr $$failed + 1`; \ +@NATIVE_FALSE@ col=$$red; res=XPASS; \ +@NATIVE_FALSE@ ;; \ +@NATIVE_FALSE@ *) \ +@NATIVE_FALSE@ col=$$grn; res=PASS; \ +@NATIVE_FALSE@ ;; \ +@NATIVE_FALSE@ esac; \ +@NATIVE_FALSE@ elif test $$? -ne 77; then \ +@NATIVE_FALSE@ all=`expr $$all + 1`; \ +@NATIVE_FALSE@ case " $(XFAIL_TESTS) " in \ +@NATIVE_FALSE@ *[\ \ ]$$tst[\ \ ]*) \ +@NATIVE_FALSE@ xfail=`expr $$xfail + 1`; \ +@NATIVE_FALSE@ col=$$lgn; res=XFAIL; \ +@NATIVE_FALSE@ ;; \ +@NATIVE_FALSE@ *) \ +@NATIVE_FALSE@ failed=`expr $$failed + 1`; \ +@NATIVE_FALSE@ col=$$red; res=FAIL; \ +@NATIVE_FALSE@ ;; \ +@NATIVE_FALSE@ esac; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ skip=`expr $$skip + 1`; \ +@NATIVE_FALSE@ col=$$blu; res=SKIP; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ echo "$${col}$$res$${std}: $$tst"; \ +@NATIVE_FALSE@ done; \ +@NATIVE_FALSE@ if test "$$all" -eq 1; then \ +@NATIVE_FALSE@ tests="test"; \ +@NATIVE_FALSE@ All=""; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ tests="tests"; \ +@NATIVE_FALSE@ All="All "; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ if test "$$failed" -eq 0; then \ +@NATIVE_FALSE@ if test "$$xfail" -eq 0; then \ +@NATIVE_FALSE@ banner="$$All$$all $$tests passed"; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ +@NATIVE_FALSE@ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ if test "$$xpass" -eq 0; then \ +@NATIVE_FALSE@ banner="$$failed of $$all $$tests failed"; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ +@NATIVE_FALSE@ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ dashes="$$banner"; \ +@NATIVE_FALSE@ skipped=""; \ +@NATIVE_FALSE@ if test "$$skip" -ne 0; then \ +@NATIVE_FALSE@ if test "$$skip" -eq 1; then \ +@NATIVE_FALSE@ skipped="($$skip test was not run)"; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ skipped="($$skip tests were not run)"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ +@NATIVE_FALSE@ dashes="$$skipped"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ report=""; \ +@NATIVE_FALSE@ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ +@NATIVE_FALSE@ report="Please report to $(PACKAGE_BUGREPORT)"; \ +@NATIVE_FALSE@ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ +@NATIVE_FALSE@ dashes="$$report"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ dashes=`echo "$$dashes" | sed s/./=/g`; \ +@NATIVE_FALSE@ if test "$$failed" -eq 0; then \ +@NATIVE_FALSE@ col="$$grn"; \ +@NATIVE_FALSE@ else \ +@NATIVE_FALSE@ col="$$red"; \ +@NATIVE_FALSE@ fi; \ +@NATIVE_FALSE@ echo "$${col}$$dashes$${std}"; \ +@NATIVE_FALSE@ echo "$${col}$$banner$${std}"; \ +@NATIVE_FALSE@ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ +@NATIVE_FALSE@ test -z "$$report" || echo "$${col}$$report$${std}"; \ +@NATIVE_FALSE@ echo "$${col}$$dashes$${std}"; \ +@NATIVE_FALSE@ test "$$failed" -eq 0; \ +@NATIVE_FALSE@ else :; fi check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-TESTS @@ -745,6 +803,141 @@ uninstall-am: mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \ uninstall-am + +@NATIVE_TRUE@check-TESTS: $(TESTS) +@NATIVE_TRUE@ @failed=0; all=0; xfail=0; xpass=0; skip=0; \ +@NATIVE_TRUE@ srcdir=$(srcdir); export srcdir; \ +@NATIVE_TRUE@ list=' $(TESTS) '; \ +@NATIVE_TRUE@ $(am__tty_colors); \ +@NATIVE_TRUE@ if ! test -e glinktest.debug; then \ +@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug glinktest glinktest.debug; \ +@NATIVE_TRUE@ $(STRIP) glinktest; \ +@NATIVE_TRUE@ $(OBJCOPY) --add-gnu-debuglink=glinktest.debug glinktest; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if ! test -e pictest.debug; then \ +@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug pictest pictest.debug; \ +@NATIVE_TRUE@ $(STRIP) pictest; \ +@NATIVE_TRUE@ $(OBJCOPY) --add-gnu-debuglink=pictest.debug pictest; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if ! test -e .build-id; then \ +@NATIVE_TRUE@ mkdir .build-id; \ +@NATIVE_TRUE@ mkdir .build-id/01/; \ +@NATIVE_TRUE@ mkdir temp; \ +@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug bidtest bidtest.debug; \ +@NATIVE_TRUE@ $(STRIP) bidtest; \ +@NATIVE_TRUE@ touch temp; \ +@NATIVE_TRUE@ mv bidtest.debug temp;\ +@NATIVE_TRUE@ ln -s ../../temp/bidtest.debug .build-id/01/23456789abcdef0123456789abcdef01234567.debug; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if test -n "$$list"; then \ +@NATIVE_TRUE@ for tst in $$list; do \ +@NATIVE_TRUE@ if test -f ./$$tst; then dir=./; \ +@NATIVE_TRUE@ elif test -f $$tst; then dir=; \ +@NATIVE_TRUE@ else dir="$(srcdir)/"; fi; \ +@NATIVE_TRUE@ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ +@NATIVE_TRUE@ all=`expr $$all + 1`; \ +@NATIVE_TRUE@ case " $(XFAIL_TESTS) " in \ +@NATIVE_TRUE@ *[\ \ ]$$tst[\ \ ]*) \ +@NATIVE_TRUE@ xpass=`expr $$xpass + 1`; \ +@NATIVE_TRUE@ failed=`expr $$failed + 1`; \ +@NATIVE_TRUE@ col=$$red; res=XPASS; \ +@NATIVE_TRUE@ ;; \ +@NATIVE_TRUE@ *) \ +@NATIVE_TRUE@ col=$$grn; res=PASS; \ +@NATIVE_TRUE@ ;; \ +@NATIVE_TRUE@ esac; \ +@NATIVE_TRUE@ elif test $$? -ne 77; then \ +@NATIVE_TRUE@ all=`expr $$all + 1`; \ +@NATIVE_TRUE@ case " $(XFAIL_TESTS) " in \ +@NATIVE_TRUE@ *[\ \ ]$$tst[\ \ ]*) \ +@NATIVE_TRUE@ xfail=`expr $$xfail + 1`; \ +@NATIVE_TRUE@ col=$$lgn; res=XFAIL; \ +@NATIVE_TRUE@ ;; \ +@NATIVE_TRUE@ *) \ +@NATIVE_TRUE@ failed=`expr $$failed + 1`; \ +@NATIVE_TRUE@ col=$$red; res=FAIL; \ +@NATIVE_TRUE@ ;; \ +@NATIVE_TRUE@ esac; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ skip=`expr $$skip + 1`; \ +@NATIVE_TRUE@ col=$$blu; res=SKIP; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ echo "$${col}$$res$${std}: $$tst"; \ +@NATIVE_TRUE@ done; \ +@NATIVE_TRUE@ if test "$$all" -eq 1; then \ +@NATIVE_TRUE@ tests="test"; \ +@NATIVE_TRUE@ All=""; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ tests="tests"; \ +@NATIVE_TRUE@ All="All "; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if test "$$failed" -eq 0; then \ +@NATIVE_TRUE@ if test "$$xfail" -eq 0; then \ +@NATIVE_TRUE@ banner="$$All$$all $$tests passed"; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ +@NATIVE_TRUE@ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ if test "$$xpass" -eq 0; then \ +@NATIVE_TRUE@ banner="$$failed of $$all $$tests failed"; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ +@NATIVE_TRUE@ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ dashes="$$banner"; \ +@NATIVE_TRUE@ skipped=""; \ +@NATIVE_TRUE@ if test "$$skip" -ne 0; then \ +@NATIVE_TRUE@ if test "$$skip" -eq 1; then \ +@NATIVE_TRUE@ skipped="($$skip test was not run)"; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ skipped="($$skip tests were not run)"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ +@NATIVE_TRUE@ dashes="$$skipped"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ report=""; \ +@NATIVE_TRUE@ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ +@NATIVE_TRUE@ report="Please report to $(PACKAGE_BUGREPORT)"; \ +@NATIVE_TRUE@ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ +@NATIVE_TRUE@ dashes="$$report"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ dashes=`echo "$$dashes" | sed s/./=/g`; \ +@NATIVE_TRUE@ if test "$$failed" -eq 0; then \ +@NATIVE_TRUE@ col="$$grn"; \ +@NATIVE_TRUE@ else \ +@NATIVE_TRUE@ col="$$red"; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ echo "$${col}$$dashes$${std}"; \ +@NATIVE_TRUE@ echo "$${col}$$banner$${std}"; \ +@NATIVE_TRUE@ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ +@NATIVE_TRUE@ test -z "$$report" || echo "$${col}$$report$${std}"; \ +@NATIVE_TRUE@ echo "$${col}$$dashes$${std}"; \ +@NATIVE_TRUE@ test "$$failed" -eq 0; \ +@NATIVE_TRUE@ else :; fi + +@NATIVE_TRUE@clean-checkPROGRAMS: +@NATIVE_TRUE@ @if test -e glinktest.debug; then \ +@NATIVE_TRUE@ echo "rm -f glinktest.debug pictest.debug"; \ +@NATIVE_TRUE@ rm -f glinktest.debug pictest.debug; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if test -d temp; then \ +@NATIVE_TRUE@ echo "rm -rf temp"; \ +@NATIVE_TRUE@ rm -rf temp; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ if test -d .build-id; then \ +@NATIVE_TRUE@ echo "rm -rf .build-id"; \ +@NATIVE_TRUE@ rm -rf .build-id; \ +@NATIVE_TRUE@ fi; \ +@NATIVE_TRUE@ list='$(check_PROGRAMS)'; \ +@NATIVE_TRUE@ test -n "$$list" || exit 0; \ +@NATIVE_TRUE@ echo " rm -f" $$list; \ +@NATIVE_TRUE@ rm -f $$list || exit $$?; \ +@NATIVE_TRUE@ test -n "$(EXEEXT)" || exit 0; \ +@NATIVE_TRUE@ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ +@NATIVE_TRUE@ echo " rm -f" $$list; \ +@NATIVE_TRUE@ rm -f $$list; alloc.lo: config.h backtrace.h internal.h backtrace.lo: config.h backtrace.h internal.h btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h diff --git a/libbacktrace/configure b/libbacktrace/configure index 4e720e1..8910996 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -630,6 +630,7 @@ LD FGREP SED LIBTOOL +OBJCOPY RANLIB MAINT MAINTAINER_MODE_FALSE @@ -5011,6 +5012,44 @@ else fi +# Extract the first word of "objcopy", so it can be a program name with args. +set dummy objcopy; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJCOPY+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJCOPY"; then + ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJCOPY="objcopy" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJCOPY=$ac_cv_prog_OBJCOPY +if test -n "$OBJCOPY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5 +$as_echo "$OBJCOPY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. @@ -11131,7 +11170,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11134 "configure" +#line 11173 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11237,7 +11276,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11240 "configure" +#line 11279 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 71e8518..bc4e688 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -74,6 +74,8 @@ AC_SUBST(CFLAGS) AC_PROG_RANLIB +AC_CHECK_PROG(OBJCOPY, objcopy, objcopy) + AC_PROG_AWK case "$AWK" in "") AC_MSG_ERROR([can't build without awk]) ;; diff --git a/libbacktrace/crc32.c b/libbacktrace/crc32.c new file mode 100644 index 0000000..f38a422 --- /dev/null +++ b/libbacktrace/crc32.c @@ -0,0 +1,107 @@ +/* crc32.c -- compute the CRC-32 + + The CRC-32 defined in IEEE 802.3 using the polynomial: + + x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + + x2 + x + 1 + + Hexademical representation of the polynomial over GF(2): 0xedb88320 + + The table was generated by algorithm from zlib.(zlib/crc32.c) + The algorithm is described below. + + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + unsigned long crc_table[256]; + void make_crc_table() + { + unsigned long c; + int n, k; + unsigned long poly; + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (unsigned long)1 << (31 - p[n]); + + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + } +*/ + +static const uint32_t crc32_table[256] + = {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +static uint32_t +gnu_debuglink_crc32 (uint32_t crc, const unsigned char *buf, size_t len) +{ + const unsigned char *end; + end = buf + len; + crc = ~crc; + while (buf < end) + { + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + ++buf; + } + return ~crc; +} diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 81ba344..ec68737 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -35,6 +35,9 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #include #include +#include +#include +#include #ifdef HAVE_DL_ITERATE_PHDR #include @@ -42,6 +45,24 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#include "filenames.h" +/* In case some other libraries build libbacktrace from source + (for example: libsanitizer does that way), we should manually update + each Makefile for each library to avoid situation with undefined + references after adding new file into libbacktrace sources. + Another way is to include crc32.c file into preproccessing stage. */ +#include "crc32.c" + +#undef PATH_MAX +#define PATH_MAX 4096 + +#ifndef DIR_SEPARATOR +#define DIR_SEPARATOR '/' +#endif + +#ifndef HAVE_GETEXECNAME +#define getexecname() NULL +#endif #ifndef HAVE_DL_ITERATE_PHDR @@ -283,6 +304,853 @@ struct elf_syminfo_data size_t count; }; +/* Information to read ELF note section. */ + +typedef struct +{ + unsigned char namesz[4]; + unsigned char descsz[4]; + unsigned char type[4]; + unsigned char name[1]; +} Elf_External_Note; + +/* Information about type of the file. */ + +enum type_of_file +{ + FILE_TYPE_INVALID = -1, + FILE_TYPE_LINK = 1, + FILE_TYPE_REGULAR = 2 +}; + +/* Information about debug paths. */ + +enum debug_path +{ + DEBUG_PATH_CURRENT, + DEBUG_PATH_CURRENT_DEBUG, + DEBUG_PATH_USR_LIB_DEBUG, + DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE, + DEBUG_PATH_MAX +}; + +/* Type of the ELF file. */ + +enum type_of_elf +{ + ELF_TYPE_DYN = -1, + ELF_TYPE_INVALID = 0, + ELF_TYPE_EXEC = 1 +}; + +/* Paths to debug file. */ + +static const char *const debug_file_path[DEBUG_PATH_MAX] + = {"", ".debug/", "/usr/lib/debug/", "/usr/lib/debug"}; + +/* Get a uint32 from the buffer. */ + +static uint32_t +get_uint32 (const unsigned char *p, int is_bigendian) +{ + if (is_bigendian) + return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) + | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); + else + return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) + | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); +} + +/* Generate crc32 sum from the file. */ + +static uint32_t +get_crc32 (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data) +{ + uint32_t file_crc; + off_t offset; + size_t buffer_count; + size_t buffer_len; + size_t pass; + size_t out_of_buffer_len; + const unsigned char *buffer; + struct stat file_stat; + struct backtrace_view file_view; + + buffer_len = 8 * 1024; + offset = 0; + file_crc = 0; + out_of_buffer_len = 0; + + memset (&file_stat, 0, sizeof (struct stat)); + + if (fstat (descriptor, &file_stat) == -1) + { + if (errno != ENOENT) + error_callback (data, "fstat", errno); + return 0; + } + + if (!backtrace_get_view (state, descriptor, offset, file_stat.st_size, + error_callback, data, &file_view)) + return 0; + + buffer = (const unsigned char *) file_view.data; + buffer_count = file_stat.st_size / buffer_len; + out_of_buffer_len = file_stat.st_size % buffer_len; + + for (pass = 0; pass < buffer_count; ++pass) + { + file_crc = gnu_debuglink_crc32 (file_crc, buffer + offset, buffer_len); + offset += buffer_len; + } + + if (out_of_buffer_len) + file_crc + = gnu_debuglink_crc32 (file_crc, buffer + offset, out_of_buffer_len); + + backtrace_release_view (state, &file_view, error_callback, data); + return file_crc; +} + +/* Get length of the base name. */ + +static size_t +base_name_len (const char *buffer) +{ + size_t len; + + len = strlen (buffer); + while (len > 1 && !IS_DIR_SEPARATOR (buffer[len - 1])) + --len; + return len > 1 ? len : 0; +} + +/* Verify crc32 sum. */ + +static unsigned int +check_sum (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data, + const unsigned char *debug_link, size_t offset, size_t section_size, + int is_bigendian) +{ + uint32_t crc32_debug_link; + uint32_t crc32_debug_file; + offset += 1; + offset = (offset + 3) & ~3; + if (offset + 4 > section_size) + return 0; + crc32_debug_link = get_uint32 (debug_link + offset, is_bigendian); + crc32_debug_file = get_crc32 (state, descriptor, error_callback, data); + return crc32_debug_link == crc32_debug_file; +} + +/* Process elf header. Verify magic number, version, etc, of the ELF + header. Populate ehdr_out, names_view_out and shdrs_view_out. Caller + should release view of the names_view_out and shdrs_view_out. Return + ELF_TYPE_EXEC if the file type is EXE, ELF_TYPE_DYN if type of the + file is DYN and ELF_TYPE_INVALID on the fail. */ + +static enum type_of_elf +process_elf_header (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data, + int exe, b_elf_ehdr *ehdr_out, + struct backtrace_view *shdrs_view_out, + struct backtrace_view *names_view_out) +{ + struct backtrace_view ehdr_view; + const b_elf_shdr *shstrhdr; + const b_elf_shdr *shdrs; + unsigned int shstrndx; + unsigned int shnum; + off_t shoff; + int shdrs_view_valid; + + shdrs_view_valid = 0; + + if (!backtrace_get_view (state, descriptor, 0, sizeof *ehdr_out, + error_callback, data, &ehdr_view)) + goto fail; + + memcpy (ehdr_out, ehdr_view.data, sizeof *ehdr_out); + + backtrace_release_view (state, &ehdr_view, error_callback, data); + + if (ehdr_out->e_ident[EI_MAG0] != ELFMAG0 + || ehdr_out->e_ident[EI_MAG1] != ELFMAG1 + || ehdr_out->e_ident[EI_MAG2] != ELFMAG2 + || ehdr_out->e_ident[EI_MAG3] != ELFMAG3) + { + error_callback (data, "processed file is not ELF", 0); + goto fail; + } + if (ehdr_out->e_ident[EI_VERSION] != EV_CURRENT) + { + error_callback (data, "processed file is unrecognized ELF version", 0); + goto fail; + } + +#if BACKTRACE_ELF_SIZE == 32 +#define BACKTRACE_ELFCLASS ELFCLASS32 +#else +#define BACKTRACE_ELFCLASS ELFCLASS64 +#endif + + if (ehdr_out->e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) + { + error_callback (data, "processed file is unexpected ELF class", 0); + goto fail; + } + + if (ehdr_out->e_ident[EI_DATA] != ELFDATA2LSB + && ehdr_out->e_ident[EI_DATA] != ELFDATA2MSB) + { + error_callback (data, "processed file has unknown endianness", 0); + goto fail; + } + + /* If the executable is ET_DYN, it is either a PIE, or we are running + directly a shared library with .interp. We need to wait for + dl_iterate_phdr in that case to determine the actual base_address. */ + if (exe && ehdr_out->e_type == ET_DYN) + return ELF_TYPE_DYN; + + shoff = ehdr_out->e_shoff; + shnum = ehdr_out->e_shnum; + shstrndx = ehdr_out->e_shstrndx; + + if ((shnum == 0 || shstrndx == SHN_XINDEX) && shoff != 0) + { + struct backtrace_view shdr_view; + const b_elf_shdr *shdr; + + if (!backtrace_get_view (state, descriptor, shoff, sizeof (b_elf_shdr), + error_callback, data, &shdr_view)) + goto fail; + + shdr = (const b_elf_shdr *) shdr_view.data; + + if (shnum == 0) + shnum = shdr->sh_size; + + if (shstrndx == SHN_XINDEX) + { + shstrndx = shdr->sh_link; + + /* Versions of the GNU binutils between 2.12 and 2.18 did + not handle objects with more than SHN_LORESERVE sections + correctly. All large section indexes were offset by + 0x100. There is more information at + http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . + Fortunately these object files are easy to detect, as the + GNU binutils always put the section header string table + near the end of the list of sections. Thus if the + section header string table index is larger than the + number of sections, then we know we have to subtract + 0x100 to get the real section index. */ + if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) + shstrndx -= 0x100; + } + backtrace_release_view (state, &shdr_view, error_callback, data); + } + + /* Read the section headers, skipping the first one. */ + + if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), + (shnum - 1) * sizeof (b_elf_shdr), error_callback, + data, shdrs_view_out)) + goto fail; + + shdrs_view_valid = 1; + + shdrs = (const b_elf_shdr *) shdrs_view_out->data; + shstrhdr = &shdrs[shstrndx - 1]; + + /* Read the section names. */ + + if (!backtrace_get_view (state, descriptor, shstrhdr->sh_offset, + shstrhdr->sh_size, error_callback, data, + names_view_out)) + goto fail; + + ehdr_out->e_shoff = shoff; + ehdr_out->e_shnum = shnum; + ehdr_out->e_shstrndx = shstrndx; + + return ELF_TYPE_EXEC; + + fail: + /* In case fail happens with backtrace_get_view for names section. */ + if (shdrs_view_valid) + backtrace_release_view (state, shdrs_view_out, error_callback, data); + return ELF_TYPE_INVALID; +} + +/* Get content of the specifying section. */ + +static unsigned char * +elf_get_section_by_name (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data, + size_t *section_data_len_out, const char *section_name, + b_elf_ehdr *ehdr, struct backtrace_view *shdrs_view, + struct backtrace_view *names_view) +{ + const b_elf_shdr *shdrs; + const b_elf_shdr *shstrhdr; + size_t shstr_size; + struct backtrace_view section_view; + const char *names; + unsigned int i; + unsigned int shnum; + unsigned int shstrndx; + int section_view_valid; + unsigned char *section_data; + + section_view_valid = 0; + section_data = NULL; + + shnum = ehdr->e_shnum; + shstrndx = ehdr->e_shstrndx; + shdrs = (const b_elf_shdr *) shdrs_view->data; + shstrhdr = &shdrs[shstrndx - 1]; + shstr_size = shstrhdr->sh_size; + + names = (const char *) names_view->data; + + for (i = 1; i < shnum; ++i) + { + const b_elf_shdr *shdr; + unsigned int sh_name; + const char *name; + shdr = &shdrs[i - 1]; + sh_name = shdr->sh_name; + if (sh_name >= shstr_size) + { + error_callback (data, "ELF section name out of range", 0); + goto exit; + } + + name = names + sh_name; + + if (strcmp (name, section_name) == 0) + { + if (backtrace_get_view (state, descriptor, shdr->sh_offset, + shdr->sh_size, error_callback, data, + §ion_view)) + { + section_view_valid = 1; + section_data + = backtrace_alloc (state, shdr->sh_size, error_callback, data); + if (section_data == NULL) + goto exit; + memcpy (section_data, section_view.data, shdr->sh_size); + *section_data_len_out = shdr->sh_size; + } + break; + } + } + + exit: + if (section_view_valid) + backtrace_release_view (state, §ion_view, error_callback, data); + return section_data; +} + +/* Verify type of the file. */ + +static enum type_of_file +backtrace_readlink (const char *filename, + backtrace_error_callback error_callback, void *data) +{ + struct stat link_stat; + enum type_of_file file_type; + mode_t mode; + + memset (&link_stat, 0, sizeof (struct stat)); + + if (lstat (filename, &link_stat) == -1) + { + if (errno != ENOENT) + error_callback (data, filename, errno); + file_type = FILE_TYPE_INVALID; + } + + mode = link_stat.st_mode & S_IFMT; + + switch (mode) + { + case S_IFLNK: + file_type = FILE_TYPE_LINK; + break; + case S_IFREG: + file_type = FILE_TYPE_REGULAR; + break; + default: + file_type = FILE_TYPE_INVALID; + } + return file_type; +} + +/* Resolve full name of the link. In this case we can't use realpath function + because it could be undefined on some platfroms, also it allocates memory + by malloc, which we can't use. */ + +static ssize_t +resolve_realname (const char *filename, char *buffer, + struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + char *temp_buffer; + enum type_of_file file_type; + ssize_t filename_len; + size_t temp_filename_len; + size_t base_len; + int valid_temp_buffer; + + valid_temp_buffer = 0; + filename_len = -1; + file_type = FILE_TYPE_LINK; + + /* Allocate memory for sizeof(PATH_MAX) + 1 bytes because at this time + we don't know how long path could be. */ + temp_buffer = backtrace_alloc (state, PATH_MAX + 1, error_callback, data); + if (temp_buffer == NULL) + return -1; + + valid_temp_buffer = 1; + + memset (temp_buffer, 0, PATH_MAX + 1); + memcpy (temp_buffer, filename, strlen (filename)); + + while (file_type == FILE_TYPE_LINK) + { + filename_len = readlink (temp_buffer, buffer, PATH_MAX); + if (filename_len < 1) + goto exit; + + temp_filename_len = strlen (buffer); + + /* Full path. */ + if (IS_ABSOLUTE_PATH (buffer)) + { + memset (temp_buffer, 0, PATH_MAX); + memcpy (temp_buffer, buffer, temp_filename_len); + } + else + { + /* Relative path. */ + base_len = base_name_len (temp_buffer); + if (!base_len || (base_len + filename_len > PATH_MAX)) + { + filename_len = -1; + goto exit; + } + memcpy (temp_buffer + base_len, buffer, filename_len); + temp_buffer[base_len + filename_len] = '\0'; + } + + file_type = backtrace_readlink (temp_buffer, error_callback, data); + memset (buffer, 0, filename_len); + } + + if (file_type != FILE_TYPE_REGULAR) + { + filename_len = -1; + goto exit; + } + + filename_len = strlen (temp_buffer); + memcpy (buffer, temp_buffer, filename_len); + + exit: + if (valid_temp_buffer) + backtrace_free (state, temp_buffer, PATH_MAX + 1, error_callback, data); + return filename_len; +} + +/* Resolve realname of the filename. This function verifies filename. + If filename is name of the file it populates realname buffer. + If filename is link, it calls resolve_realname function. */ + +static unsigned int +backtrace_resolve_realname (const char *filename, char *realname, + struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + enum type_of_file file_type; + ssize_t filename_len; + + filename_len = -1; + + file_type = backtrace_readlink (filename, error_callback, data); + + if (file_type == FILE_TYPE_LINK) + { + /* Read the actual filename. */ + filename_len + = resolve_realname (filename, realname, state, error_callback, data); + if (filename_len < 1) + return 0; + } + else if (file_type == FILE_TYPE_REGULAR) + { + filename_len = strlen (filename); + if (filename_len > PATH_MAX) + return 0; + memcpy (realname, filename, filename_len); + } + /* FILE_TYPE_INVALID. */ + else + return 0; + + return 1; +} + +/* Search for debug file into specifying directorires. */ + +static int +search_for_debugfile (char *realname, char *debug_filename, + backtrace_error_callback error_callback, void *data, + struct backtrace_state *state) +{ + size_t debug_filename_len; + size_t pass; + size_t debug_path_len; + size_t buffer_len; + size_t base_len; + int debug_does_not_exist; + int debug_descriptor; + int valid_buffer; + char *buffer; + + debug_descriptor = -1; + valid_buffer = 0; + + base_len = base_name_len (realname); + + if (!base_len) + return debug_descriptor; + + debug_filename_len = strlen ((const char *) debug_filename); + + if (!debug_filename_len) + return debug_descriptor; + + buffer_len = base_len + strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG]) + + debug_filename_len + 1; + + buffer = backtrace_alloc (state, buffer_len, error_callback, data); + + if (buffer == NULL) + return debug_descriptor; + + valid_buffer = 1; + + memset (buffer, 0, buffer_len); + memcpy (buffer, realname, base_len); + + for (pass = 0; pass < DEBUG_PATH_MAX; ++pass) + { + switch (pass) + { + case DEBUG_PATH_CURRENT: + { + memcpy (buffer + base_len, debug_filename, debug_filename_len); + break; + } + case DEBUG_PATH_CURRENT_DEBUG: + { + debug_path_len = strlen (debug_file_path[DEBUG_PATH_CURRENT_DEBUG]); + memcpy (buffer + base_len, + debug_file_path[DEBUG_PATH_CURRENT_DEBUG], debug_path_len); + memcpy (buffer + base_len + debug_path_len, debug_filename, + debug_filename_len); + break; + } + case DEBUG_PATH_USR_LIB_DEBUG: + { + debug_path_len = strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG]); + memset (buffer, 0, buffer_len); + memcpy (buffer, debug_file_path[DEBUG_PATH_USR_LIB_DEBUG], + debug_path_len); + memcpy (buffer + debug_path_len, debug_filename, + debug_filename_len); + break; + } + case DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE: + { + debug_path_len + = strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE]); + memset (buffer, 0, buffer_len); + memcpy (buffer, + debug_file_path[DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE], + debug_path_len); + memcpy (buffer + debug_path_len, realname, base_len); + memcpy (buffer + debug_path_len + base_len, debug_filename, + debug_filename_len); + break; + } + default: + goto exit; + } + + debug_descriptor + = backtrace_open (buffer, error_callback, data, &debug_does_not_exist); + + if (debug_descriptor >= 0) + break; + } + + exit: + if (valid_buffer) + backtrace_free (state, buffer, buffer_len, error_callback, data); + return debug_descriptor; +} + +/* Open debug file by gnulink. */ + +static int +open_debugfile_by_gnulink (char *realname, unsigned char *section_data, + size_t section_data_len, int is_bigendian, + struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + int debug_descriptor; + + debug_descriptor = search_for_debugfile (realname, (char *) section_data, + error_callback, data, state); + if (debug_descriptor < 0) + return -1; + + /* Check the crc32 checksum if it is not the same return -1. */ + + if (!check_sum (state, debug_descriptor, error_callback, data, + (const unsigned char *) section_data, + strlen ((char *) section_data), section_data_len, + is_bigendian)) + { + /* If crc32 sums are different, just close the descriptor + associated with debuginfo file. */ + backtrace_close (debug_descriptor, error_callback, data); + debug_descriptor = -1; + } + + return debug_descriptor; +} + +/* Convert char to hex */ + +static char +hex (char ch) +{ + return ch > 9 ? ('a' + (ch - 10)) : ('0' + ch); +} + +/* Get build-id name. */ + +static char * +get_build_id_name (unsigned char *section_data, size_t *len, + int is_bigendian, struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + Elf_External_Note *build_id_section; + char *build_id_name; + char *temp; + const char *debug_postfix; + const char *debug_prefix; + size_t debug_postfix_len; + size_t debug_prefix_len; + size_t name_size; + size_t offset; + unsigned char *hash_start; + uint32_t hash_size; + uint32_t identifier; + + debug_postfix_len = 6; + debug_prefix_len = 10; + debug_postfix = ".debug"; + debug_prefix = ".build-id/"; + + build_id_section = (Elf_External_Note *) section_data; + hash_size = get_uint32 (build_id_section->descsz, is_bigendian); + identifier = get_uint32 (build_id_section->type, is_bigendian); + name_size = get_uint32 (build_id_section->namesz, is_bigendian); + + if (identifier != NT_GNU_BUILD_ID || hash_size == 0 || name_size != 4 + || strncmp ((char *) build_id_section->name, "GNU", 3) != 0) + return NULL; + + offset = 16; + hash_start = section_data + offset; + *len = hash_size * 2 + debug_postfix_len + debug_prefix_len + 1; + build_id_name = backtrace_alloc (state, *len, error_callback, data); + + if (build_id_name == NULL) + { + *len = 0; + return NULL; + } + + memset (build_id_name, 0, *len); + memcpy (build_id_name, debug_prefix, debug_prefix_len); + temp = build_id_name + debug_prefix_len; + + *temp++ = hex ((*hash_start & 0xF0) >> 4); + *temp++ = hex (*hash_start & 0x0F); + ++hash_start; + --hash_size; + *temp++ = DIR_SEPARATOR; + + while (hash_size--) + { + *temp++ = hex ((*hash_start & 0xF0) >> 4); + *temp++ = hex (*hash_start & 0x0F); + ++hash_start; + } + + memcpy (temp, debug_postfix, debug_postfix_len); + return build_id_name; +} + +/* Open file by build-id. */ + +static int +open_debugfile_by_build_id (char *realname, unsigned char *section_data, + int is_bigendian, struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) + +{ + char *build_id_name; + int debug_descriptor; + size_t build_id_name_len; + int valid_build_id_name; + + debug_descriptor = -1; + valid_build_id_name = 0; + build_id_name_len = 0; + + build_id_name = get_build_id_name (section_data, &build_id_name_len, + is_bigendian, state, error_callback, data); + + if (!build_id_name_len) + return -1; + + valid_build_id_name = 1; + + debug_descriptor = search_for_debugfile (realname, build_id_name, + error_callback, data, state); + + if (valid_build_id_name) + backtrace_free (state, build_id_name, build_id_name_len, error_callback, + data); + return debug_descriptor; +} + +/* Open debug file. */ + +static int +backtrace_open_debugfile (int descriptor, const char *filename, + backtrace_error_callback error_callback, void *data, + struct backtrace_state *state) +{ + int debug_descriptor; + unsigned char *gnulink_section_data; + unsigned char *build_id_section_data; + int valid_descriptor; + int valid_gnulink_section_data; + int valid_build_id_section_data; + int valid_realname; + int valid_elf_header; + size_t build_id_section_data_len; + size_t gnu_link_section_data_len; + char *realname; + b_elf_ehdr ehdr; + struct backtrace_view shdrs_view; + struct backtrace_view names_view; + + valid_elf_header = 0; + valid_realname = 0; + valid_descriptor = 0; + valid_gnulink_section_data = 0; + valid_build_id_section_data = 0; + build_id_section_data_len = 0; + gnu_link_section_data_len = 0; + debug_descriptor = -1; + + if (!process_elf_header (state, descriptor, error_callback, data, 0, &ehdr, + &shdrs_view, &names_view)) + return -1; + + valid_elf_header = 1; + + realname = backtrace_alloc (state, PATH_MAX + 1, error_callback, data); + + if (realname == NULL) + goto exit; + + /* Indicates that we successfully allocated memory. */ + valid_realname = 1; + + /* Populate the buffer with realname. */ + if (!backtrace_resolve_realname (filename, realname, state, error_callback, + data)) + goto exit; + + /* Check if build-id section does exist. */ + build_id_section_data + = elf_get_section_by_name (state, descriptor, error_callback, data, + &build_id_section_data_len, ".note.gnu.build-id", + &ehdr, &shdrs_view, &names_view); + + if (build_id_section_data_len) + { + valid_build_id_section_data = 1; + debug_descriptor + = open_debugfile_by_build_id (realname, build_id_section_data, + ehdr.e_ident[EI_DATA] == ELFDATA2MSB, + state, error_callback, data); + } + + if (debug_descriptor < 0) + { + gnulink_section_data + = elf_get_section_by_name (state, descriptor, error_callback, data, + &gnu_link_section_data_len, ".gnu_debuglink", + &ehdr, &shdrs_view, &names_view); + + if (gnu_link_section_data_len) + { + valid_gnulink_section_data = 1; + debug_descriptor + = open_debugfile_by_gnulink (realname, gnulink_section_data, + gnu_link_section_data_len, + ehdr.e_ident[EI_DATA] == ELFDATA2MSB, + state, error_callback, data); + } + } + + if (debug_descriptor >= 0) + valid_descriptor = 1; + + exit: + if (valid_descriptor) + backtrace_close (descriptor, error_callback, data); + if (valid_gnulink_section_data) + backtrace_free (state, gnulink_section_data, gnu_link_section_data_len, + error_callback, data); + if (valid_build_id_section_data) + backtrace_free (state, build_id_section_data, build_id_section_data_len, + error_callback, data); + if (valid_realname) + backtrace_free (state, realname, PATH_MAX + 1, error_callback, data); + if (valid_elf_header) + { + backtrace_release_view (state, &names_view, error_callback, data); + backtrace_release_view (state, &shdrs_view, error_callback, data); + } + return debug_descriptor; +} + /* A dummy callback function used when we can't find any debug info. */ static int @@ -521,9 +1389,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, backtrace_error_callback error_callback, void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe) { - struct backtrace_view ehdr_view; b_elf_ehdr ehdr; - off_t shoff; unsigned int shnum; unsigned int shstrndx; struct backtrace_view shdrs_view; @@ -531,7 +1397,6 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, const b_elf_shdr *shdrs; const b_elf_shdr *shstrhdr; size_t shstr_size; - off_t shstr_off; struct backtrace_view names_view; int names_view_valid; const char *names; @@ -547,6 +1412,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, off_t max_offset; struct backtrace_view debug_view; int debug_view_valid; + enum type_of_elf elf_type; *found_sym = 0; *found_dwarf = 0; @@ -557,116 +1423,32 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, strtab_view_valid = 0; debug_view_valid = 0; - if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, - data, &ehdr_view)) - goto fail; - - memcpy (&ehdr, ehdr_view.data, sizeof ehdr); - - backtrace_release_view (state, &ehdr_view, error_callback, data); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0 - || ehdr.e_ident[EI_MAG1] != ELFMAG1 - || ehdr.e_ident[EI_MAG2] != ELFMAG2 - || ehdr.e_ident[EI_MAG3] != ELFMAG3) - { - error_callback (data, "executable file is not ELF", 0); - goto fail; - } - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) - { - error_callback (data, "executable file is unrecognized ELF version", 0); - goto fail; - } - -#if BACKTRACE_ELF_SIZE == 32 -#define BACKTRACE_ELFCLASS ELFCLASS32 -#else -#define BACKTRACE_ELFCLASS ELFCLASS64 -#endif - - if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) + elf_type = process_elf_header (state, descriptor, error_callback, data, exe, + &ehdr, &shdrs_view, &names_view); + switch (elf_type) { - error_callback (data, "executable file is unexpected ELF class", 0); + /* Binary compiled with PIE option. */ + case ELF_TYPE_DYN: + return -1; + case ELF_TYPE_EXEC: + break; + /* Header is invalid. */ + case ELF_TYPE_INVALID: goto fail; } - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB - && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) - { - error_callback (data, "executable file has unknown endianness", 0); - goto fail; - } - - /* If the executable is ET_DYN, it is either a PIE, or we are running - directly a shared library with .interp. We need to wait for - dl_iterate_phdr in that case to determine the actual base_address. */ - if (exe && ehdr.e_type == ET_DYN) - return -1; - - shoff = ehdr.e_shoff; - shnum = ehdr.e_shnum; - shstrndx = ehdr.e_shstrndx; - - if ((shnum == 0 || shstrndx == SHN_XINDEX) - && shoff != 0) - { - struct backtrace_view shdr_view; - const b_elf_shdr *shdr; - - if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, - error_callback, data, &shdr_view)) - goto fail; - - shdr = (const b_elf_shdr *) shdr_view.data; - - if (shnum == 0) - shnum = shdr->sh_size; - - if (shstrndx == SHN_XINDEX) - { - shstrndx = shdr->sh_link; - - /* Versions of the GNU binutils between 2.12 and 2.18 did - not handle objects with more than SHN_LORESERVE sections - correctly. All large section indexes were offset by - 0x100. There is more information at - http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . - Fortunately these object files are easy to detect, as the - GNU binutils always put the section header string table - near the end of the list of sections. Thus if the - section header string table index is larger than the - number of sections, then we know we have to subtract - 0x100 to get the real section index. */ - if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) - shstrndx -= 0x100; - } - - backtrace_release_view (state, &shdr_view, error_callback, data); - } + shdrs_view_valid = 1; + names_view_valid = 1; /* To translate PC to file/line when using DWARF, we need to find the .debug_info and .debug_line sections. */ - /* Read the section headers, skipping the first one. */ - - if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), - (shnum - 1) * sizeof (b_elf_shdr), - error_callback, data, &shdrs_view)) - goto fail; - shdrs_view_valid = 1; shdrs = (const b_elf_shdr *) shdrs_view.data; - /* Read the section names. */ - + shnum = ehdr.e_shnum; + shstrndx = ehdr.e_shstrndx; shstrhdr = &shdrs[shstrndx - 1]; shstr_size = shstrhdr->sh_size; - shstr_off = shstrhdr->sh_offset; - - if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size, - error_callback, data, &names_view)) - goto fail; - names_view_valid = 1; names = (const char *) names_view.data; symtab_shndx = 0; @@ -877,6 +1659,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, int does_not_exist; fileline elf_fileline_fn; int found_dwarf; + int debug_descriptor; /* There is not much we can do if we don't have the module name, unless executable is ET_DYN, where we expect the very first @@ -895,11 +1678,19 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); pd->exe_descriptor = -1; } + debug_descriptor = -1; descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data, &does_not_exist); + if (descriptor < 0) return 0; + + debug_descriptor + = backtrace_open_debugfile (descriptor, info->dlpi_name, + pd->error_callback, pd->data, pd->state); + if (debug_descriptor >= 0) + descriptor = debug_descriptor; } if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback, @@ -915,6 +1706,53 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, return 0; } +/* On succcess returns pathname of the executable. On fail returns NULL. */ +static const char * +get_exec_filename (backtrace_error_callback error_callback, void *data) +{ + int descriptor; + const char *filename; + unsigned int pass; + + descriptor = -1; + filename = NULL; + + for (pass = 0; pass < 4; ++pass) + { + int does_not_exist; + + switch (pass) + { + case 0: + filename = getexecname (); + break; + case 1: + filename = "/proc/self/exe"; + break; + case 2: + filename = "/proc/curproc/file"; + break; + default: + filename = NULL; + break; + } + + if (filename == NULL) + continue; + + descriptor + = backtrace_open (filename, error_callback, data, &does_not_exist); + + if (descriptor >= 0) + break; + } + + if (descriptor >= 0) + backtrace_close (descriptor, error_callback, data); + + return filename; +} + /* Initialize the backtrace data we need from an ELF executable. At the ELF level, all we need to do is find the debug info sections. */ @@ -929,6 +1767,24 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, int found_dwarf; fileline elf_fileline_fn = elf_nodebug; struct phdr_data pd; + int debug_descriptor; + const char *filename; + + debug_descriptor = -1; + + /* In case state->filename is not initialized, we should resolve the + executable name, because that name is needed to find the path to + the file with debug info. So to avoid changing API for + backtrace_initalize we can do it with some overhead by iterating + through all possible names and trying to open the file. */ + filename = state->filename == NULL ? get_exec_filename (error_callback, data) + : state->filename; + + if (filename != NULL) + debug_descriptor = backtrace_open_debugfile (descriptor, filename, + error_callback, data, state); + if (debug_descriptor >= 0) + descriptor = debug_descriptor; ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn, &found_sym, &found_dwarf, 1);