Import the asan runtime library into GCC tree
This patch imports the runtime library in the GCC tree, ensures that -lasan is passed to the linker when -faddress-sanitizer is used and sets up the build system accordingly. ChangeLog: * configure.ac: Add libsanitizer to target_libraries. * Makefile.def: Ditto. * configure: Regenerate. * Makefile.in: Regenerate. * libsanitizer: New directory for asan runtime. Contains an empty tsan directory. gcc/ChangeLog: * gcc.c (LINK_COMMAND_SPEC): Add -laddress-sanitizer to link command if -faddress-sanitizer is on. libsanitizer: Initial checkin: migrate asan runtime from llvm. From-SVN: r193441
This commit is contained in:
parent
25ae50273a
commit
f35db108b9
@ -1,3 +1,12 @@
|
||||
2012-11-12 Wei Mi <wmi@google.com>
|
||||
|
||||
* configure.ac: Add libsanitizer to target_libraries.
|
||||
* Makefile.def: Ditto.
|
||||
* configure: Regenerate.
|
||||
* Makefile.in: Regenerate.
|
||||
* libsanitizer: New directory for asan runtime. Contains an empty
|
||||
tsan directory.
|
||||
|
||||
2012-11-03 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* configure.ac (FLAGS_FOR_TARGET,target=cygwin): Fix for building
|
||||
|
16
ChangeLog.asan
Normal file
16
ChangeLog.asan
Normal file
@ -0,0 +1,16 @@
|
||||
2012-11-1 Wei Mi <wmi@google.com>
|
||||
|
||||
* configure.ac: Change target-libasan to target-libsanitizer.
|
||||
* configure.in: Regenerate.
|
||||
* Makefile.def: Change libasan module to libsanitizer.
|
||||
* Makefile.in: Regenerate.
|
||||
* libsanitizer: Change libasan to libsanitizer and add
|
||||
an empty tsan directory under libsanitizer.
|
||||
|
||||
2012-10-29 Wei Mi <wmi@google.com>
|
||||
|
||||
* configure.ac: Add libasan to target_libraries
|
||||
* Makefile.def: Ditto
|
||||
* configure: Regenerate
|
||||
* Makefile.in: Regenerate
|
||||
* libasan: New directory for asan runtime
|
@ -119,6 +119,7 @@ target_modules = { module= libstdc++-v3;
|
||||
lib_path=src/.libs;
|
||||
raw_cxx=true; };
|
||||
target_modules = { module= libmudflap; lib_path=.libs; };
|
||||
target_modules = { module= libsanitizer; lib_path=.libs; };
|
||||
target_modules = { module= libssp; lib_path=.libs; };
|
||||
target_modules = { module= newlib; };
|
||||
target_modules = { module= libgcc; bootstrap=true; no_check=true; };
|
||||
@ -503,6 +504,7 @@ dependencies = { module=all-target-libjava; on=all-target-libffi; };
|
||||
dependencies = { module=configure-target-libobjc; on=configure-target-boehm-gc; };
|
||||
dependencies = { module=all-target-libobjc; on=all-target-boehm-gc; };
|
||||
dependencies = { module=configure-target-libstdc++-v3; on=configure-target-libgomp; };
|
||||
dependencies = { module=configure-target-libsanitizer; on=all-target-libstdc++-v3; };
|
||||
// parallel_list.o and parallel_settings.o depend on omp.h, which is
|
||||
// generated by the libgomp configure. Unfortunately, due to the use of
|
||||
// recursive make, we can't be that specific.
|
||||
|
487
Makefile.in
487
Makefile.in
@ -575,7 +575,7 @@ all:
|
||||
|
||||
# This is the list of directories that may be needed in RPATH_ENVVAR
|
||||
# so that programs built for the target machine work.
|
||||
TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libmudflap)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc)
|
||||
TARGET_LIB_PATH = $(TARGET_LIB_PATH_libstdc++-v3)$(TARGET_LIB_PATH_libmudflap)$(TARGET_LIB_PATH_libsanitizer)$(TARGET_LIB_PATH_libssp)$(TARGET_LIB_PATH_libgomp)$(TARGET_LIB_PATH_libitm)$(TARGET_LIB_PATH_libatomic)$(HOST_LIB_PATH_gcc)
|
||||
|
||||
@if target-libstdc++-v3
|
||||
TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs:
|
||||
@ -585,6 +585,10 @@ TARGET_LIB_PATH_libstdc++-v3 = $$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs:
|
||||
TARGET_LIB_PATH_libmudflap = $$r/$(TARGET_SUBDIR)/libmudflap/.libs:
|
||||
@endif target-libmudflap
|
||||
|
||||
@if target-libsanitizer
|
||||
TARGET_LIB_PATH_libsanitizer = $$r/$(TARGET_SUBDIR)/libsanitizer/.libs:
|
||||
@endif target-libsanitizer
|
||||
|
||||
@if target-libssp
|
||||
TARGET_LIB_PATH_libssp = $$r/$(TARGET_SUBDIR)/libssp/.libs:
|
||||
@endif target-libssp
|
||||
@ -920,6 +924,7 @@ configure-host: \
|
||||
configure-target: \
|
||||
maybe-configure-target-libstdc++-v3 \
|
||||
maybe-configure-target-libmudflap \
|
||||
maybe-configure-target-libsanitizer \
|
||||
maybe-configure-target-libssp \
|
||||
maybe-configure-target-newlib \
|
||||
maybe-configure-target-libgcc \
|
||||
@ -1068,6 +1073,7 @@ all-host: maybe-all-lto-plugin
|
||||
all-target: maybe-all-target-libstdc++-v3
|
||||
@endif target-libstdc++-v3-no-bootstrap
|
||||
all-target: maybe-all-target-libmudflap
|
||||
all-target: maybe-all-target-libsanitizer
|
||||
all-target: maybe-all-target-libssp
|
||||
all-target: maybe-all-target-newlib
|
||||
@if target-libgcc-no-bootstrap
|
||||
@ -1158,6 +1164,7 @@ info-host: maybe-info-lto-plugin
|
||||
|
||||
info-target: maybe-info-target-libstdc++-v3
|
||||
info-target: maybe-info-target-libmudflap
|
||||
info-target: maybe-info-target-libsanitizer
|
||||
info-target: maybe-info-target-libssp
|
||||
info-target: maybe-info-target-newlib
|
||||
info-target: maybe-info-target-libgcc
|
||||
@ -1239,6 +1246,7 @@ dvi-host: maybe-dvi-lto-plugin
|
||||
|
||||
dvi-target: maybe-dvi-target-libstdc++-v3
|
||||
dvi-target: maybe-dvi-target-libmudflap
|
||||
dvi-target: maybe-dvi-target-libsanitizer
|
||||
dvi-target: maybe-dvi-target-libssp
|
||||
dvi-target: maybe-dvi-target-newlib
|
||||
dvi-target: maybe-dvi-target-libgcc
|
||||
@ -1320,6 +1328,7 @@ pdf-host: maybe-pdf-lto-plugin
|
||||
|
||||
pdf-target: maybe-pdf-target-libstdc++-v3
|
||||
pdf-target: maybe-pdf-target-libmudflap
|
||||
pdf-target: maybe-pdf-target-libsanitizer
|
||||
pdf-target: maybe-pdf-target-libssp
|
||||
pdf-target: maybe-pdf-target-newlib
|
||||
pdf-target: maybe-pdf-target-libgcc
|
||||
@ -1401,6 +1410,7 @@ html-host: maybe-html-lto-plugin
|
||||
|
||||
html-target: maybe-html-target-libstdc++-v3
|
||||
html-target: maybe-html-target-libmudflap
|
||||
html-target: maybe-html-target-libsanitizer
|
||||
html-target: maybe-html-target-libssp
|
||||
html-target: maybe-html-target-newlib
|
||||
html-target: maybe-html-target-libgcc
|
||||
@ -1482,6 +1492,7 @@ TAGS-host: maybe-TAGS-lto-plugin
|
||||
|
||||
TAGS-target: maybe-TAGS-target-libstdc++-v3
|
||||
TAGS-target: maybe-TAGS-target-libmudflap
|
||||
TAGS-target: maybe-TAGS-target-libsanitizer
|
||||
TAGS-target: maybe-TAGS-target-libssp
|
||||
TAGS-target: maybe-TAGS-target-newlib
|
||||
TAGS-target: maybe-TAGS-target-libgcc
|
||||
@ -1563,6 +1574,7 @@ install-info-host: maybe-install-info-lto-plugin
|
||||
|
||||
install-info-target: maybe-install-info-target-libstdc++-v3
|
||||
install-info-target: maybe-install-info-target-libmudflap
|
||||
install-info-target: maybe-install-info-target-libsanitizer
|
||||
install-info-target: maybe-install-info-target-libssp
|
||||
install-info-target: maybe-install-info-target-newlib
|
||||
install-info-target: maybe-install-info-target-libgcc
|
||||
@ -1644,6 +1656,7 @@ install-pdf-host: maybe-install-pdf-lto-plugin
|
||||
|
||||
install-pdf-target: maybe-install-pdf-target-libstdc++-v3
|
||||
install-pdf-target: maybe-install-pdf-target-libmudflap
|
||||
install-pdf-target: maybe-install-pdf-target-libsanitizer
|
||||
install-pdf-target: maybe-install-pdf-target-libssp
|
||||
install-pdf-target: maybe-install-pdf-target-newlib
|
||||
install-pdf-target: maybe-install-pdf-target-libgcc
|
||||
@ -1725,6 +1738,7 @@ install-html-host: maybe-install-html-lto-plugin
|
||||
|
||||
install-html-target: maybe-install-html-target-libstdc++-v3
|
||||
install-html-target: maybe-install-html-target-libmudflap
|
||||
install-html-target: maybe-install-html-target-libsanitizer
|
||||
install-html-target: maybe-install-html-target-libssp
|
||||
install-html-target: maybe-install-html-target-newlib
|
||||
install-html-target: maybe-install-html-target-libgcc
|
||||
@ -1806,6 +1820,7 @@ installcheck-host: maybe-installcheck-lto-plugin
|
||||
|
||||
installcheck-target: maybe-installcheck-target-libstdc++-v3
|
||||
installcheck-target: maybe-installcheck-target-libmudflap
|
||||
installcheck-target: maybe-installcheck-target-libsanitizer
|
||||
installcheck-target: maybe-installcheck-target-libssp
|
||||
installcheck-target: maybe-installcheck-target-newlib
|
||||
installcheck-target: maybe-installcheck-target-libgcc
|
||||
@ -1887,6 +1902,7 @@ mostlyclean-host: maybe-mostlyclean-lto-plugin
|
||||
|
||||
mostlyclean-target: maybe-mostlyclean-target-libstdc++-v3
|
||||
mostlyclean-target: maybe-mostlyclean-target-libmudflap
|
||||
mostlyclean-target: maybe-mostlyclean-target-libsanitizer
|
||||
mostlyclean-target: maybe-mostlyclean-target-libssp
|
||||
mostlyclean-target: maybe-mostlyclean-target-newlib
|
||||
mostlyclean-target: maybe-mostlyclean-target-libgcc
|
||||
@ -1968,6 +1984,7 @@ clean-host: maybe-clean-lto-plugin
|
||||
|
||||
clean-target: maybe-clean-target-libstdc++-v3
|
||||
clean-target: maybe-clean-target-libmudflap
|
||||
clean-target: maybe-clean-target-libsanitizer
|
||||
clean-target: maybe-clean-target-libssp
|
||||
clean-target: maybe-clean-target-newlib
|
||||
clean-target: maybe-clean-target-libgcc
|
||||
@ -2049,6 +2066,7 @@ distclean-host: maybe-distclean-lto-plugin
|
||||
|
||||
distclean-target: maybe-distclean-target-libstdc++-v3
|
||||
distclean-target: maybe-distclean-target-libmudflap
|
||||
distclean-target: maybe-distclean-target-libsanitizer
|
||||
distclean-target: maybe-distclean-target-libssp
|
||||
distclean-target: maybe-distclean-target-newlib
|
||||
distclean-target: maybe-distclean-target-libgcc
|
||||
@ -2130,6 +2148,7 @@ maintainer-clean-host: maybe-maintainer-clean-lto-plugin
|
||||
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-libstdc++-v3
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-libmudflap
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-libsanitizer
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-libssp
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-newlib
|
||||
maintainer-clean-target: maybe-maintainer-clean-target-libgcc
|
||||
@ -2266,6 +2285,7 @@ check-host: \
|
||||
check-target: \
|
||||
maybe-check-target-libstdc++-v3 \
|
||||
maybe-check-target-libmudflap \
|
||||
maybe-check-target-libsanitizer \
|
||||
maybe-check-target-libssp \
|
||||
maybe-check-target-newlib \
|
||||
maybe-check-target-libgcc \
|
||||
@ -2420,6 +2440,7 @@ install-host: \
|
||||
install-target: \
|
||||
maybe-install-target-libstdc++-v3 \
|
||||
maybe-install-target-libmudflap \
|
||||
maybe-install-target-libsanitizer \
|
||||
maybe-install-target-libssp \
|
||||
maybe-install-target-newlib \
|
||||
maybe-install-target-libgcc \
|
||||
@ -2521,6 +2542,7 @@ install-strip-host: \
|
||||
install-strip-target: \
|
||||
maybe-install-strip-target-libstdc++-v3 \
|
||||
maybe-install-strip-target-libmudflap \
|
||||
maybe-install-strip-target-libsanitizer \
|
||||
maybe-install-strip-target-libssp \
|
||||
maybe-install-strip-target-newlib \
|
||||
maybe-install-strip-target-libgcc \
|
||||
@ -32154,6 +32176,463 @@ maintainer-clean-target-libmudflap:
|
||||
|
||||
|
||||
|
||||
.PHONY: configure-target-libsanitizer maybe-configure-target-libsanitizer
|
||||
maybe-configure-target-libsanitizer:
|
||||
@if gcc-bootstrap
|
||||
configure-target-libsanitizer: stage_current
|
||||
@endif gcc-bootstrap
|
||||
@if target-libsanitizer
|
||||
maybe-configure-target-libsanitizer: configure-target-libsanitizer
|
||||
configure-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
echo "Checking multilib configuration for libsanitizer..."; \
|
||||
$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libsanitizer ; \
|
||||
$(CC_FOR_TARGET) --print-multi-lib > $(TARGET_SUBDIR)/libsanitizer/multilib.tmp 2> /dev/null ; \
|
||||
if test -r $(TARGET_SUBDIR)/libsanitizer/multilib.out; then \
|
||||
if cmp -s $(TARGET_SUBDIR)/libsanitizer/multilib.tmp $(TARGET_SUBDIR)/libsanitizer/multilib.out; then \
|
||||
rm -f $(TARGET_SUBDIR)/libsanitizer/multilib.tmp; \
|
||||
else \
|
||||
rm -f $(TARGET_SUBDIR)/libsanitizer/Makefile; \
|
||||
mv $(TARGET_SUBDIR)/libsanitizer/multilib.tmp $(TARGET_SUBDIR)/libsanitizer/multilib.out; \
|
||||
fi; \
|
||||
else \
|
||||
mv $(TARGET_SUBDIR)/libsanitizer/multilib.tmp $(TARGET_SUBDIR)/libsanitizer/multilib.out; \
|
||||
fi; \
|
||||
test ! -f $(TARGET_SUBDIR)/libsanitizer/Makefile || exit 0; \
|
||||
$(SHELL) $(srcdir)/mkinstalldirs $(TARGET_SUBDIR)/libsanitizer ; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo Configuring in $(TARGET_SUBDIR)/libsanitizer; \
|
||||
cd "$(TARGET_SUBDIR)/libsanitizer" || exit 1; \
|
||||
case $(srcdir) in \
|
||||
/* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
|
||||
*) topdir=`echo $(TARGET_SUBDIR)/libsanitizer/ | \
|
||||
sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
|
||||
esac; \
|
||||
srcdiroption="--srcdir=$${topdir}/libsanitizer"; \
|
||||
libsrcdir="$$s/libsanitizer"; \
|
||||
rm -f no-such-file || : ; \
|
||||
CONFIG_SITE=no-such-file $(SHELL) $${libsrcdir}/configure \
|
||||
$(TARGET_CONFIGARGS) --build=${build_alias} --host=${target_alias} \
|
||||
--target=${target_alias} $${srcdiroption} \
|
||||
|| exit 1
|
||||
@endif target-libsanitizer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.PHONY: all-target-libsanitizer maybe-all-target-libsanitizer
|
||||
maybe-all-target-libsanitizer:
|
||||
@if gcc-bootstrap
|
||||
all-target-libsanitizer: stage_current
|
||||
@endif gcc-bootstrap
|
||||
@if target-libsanitizer
|
||||
TARGET-target-libsanitizer=all
|
||||
maybe-all-target-libsanitizer: all-target-libsanitizer
|
||||
all-target-libsanitizer: configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_TARGET_FLAGS) \
|
||||
$(TARGET-target-libsanitizer))
|
||||
@endif target-libsanitizer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.PHONY: check-target-libsanitizer maybe-check-target-libsanitizer
|
||||
maybe-check-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-check-target-libsanitizer: check-target-libsanitizer
|
||||
|
||||
check-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(TARGET_FLAGS_TO_PASS) check)
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: install-target-libsanitizer maybe-install-target-libsanitizer
|
||||
maybe-install-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-install-target-libsanitizer: install-target-libsanitizer
|
||||
|
||||
install-target-libsanitizer: installdirs
|
||||
@: $(MAKE); $(unstage)
|
||||
@r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(TARGET_FLAGS_TO_PASS) install)
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: install-strip-target-libsanitizer maybe-install-strip-target-libsanitizer
|
||||
maybe-install-strip-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-install-strip-target-libsanitizer: install-strip-target-libsanitizer
|
||||
|
||||
install-strip-target-libsanitizer: installdirs
|
||||
@: $(MAKE); $(unstage)
|
||||
@r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(TARGET_FLAGS_TO_PASS) install-strip)
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
# Other targets (info, dvi, pdf, etc.)
|
||||
|
||||
.PHONY: maybe-info-target-libsanitizer info-target-libsanitizer
|
||||
maybe-info-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-info-target-libsanitizer: info-target-libsanitizer
|
||||
|
||||
info-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing info in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
info) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-dvi-target-libsanitizer dvi-target-libsanitizer
|
||||
maybe-dvi-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-dvi-target-libsanitizer: dvi-target-libsanitizer
|
||||
|
||||
dvi-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing dvi in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
dvi) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-pdf-target-libsanitizer pdf-target-libsanitizer
|
||||
maybe-pdf-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-pdf-target-libsanitizer: pdf-target-libsanitizer
|
||||
|
||||
pdf-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing pdf in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
pdf) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-html-target-libsanitizer html-target-libsanitizer
|
||||
maybe-html-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-html-target-libsanitizer: html-target-libsanitizer
|
||||
|
||||
html-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing html in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
html) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-TAGS-target-libsanitizer TAGS-target-libsanitizer
|
||||
maybe-TAGS-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-TAGS-target-libsanitizer: TAGS-target-libsanitizer
|
||||
|
||||
TAGS-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing TAGS in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
TAGS) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-install-info-target-libsanitizer install-info-target-libsanitizer
|
||||
maybe-install-info-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-install-info-target-libsanitizer: install-info-target-libsanitizer
|
||||
|
||||
install-info-target-libsanitizer: \
|
||||
configure-target-libsanitizer \
|
||||
info-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing install-info in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
install-info) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-install-pdf-target-libsanitizer install-pdf-target-libsanitizer
|
||||
maybe-install-pdf-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-install-pdf-target-libsanitizer: install-pdf-target-libsanitizer
|
||||
|
||||
install-pdf-target-libsanitizer: \
|
||||
configure-target-libsanitizer \
|
||||
pdf-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing install-pdf in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
install-pdf) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-install-html-target-libsanitizer install-html-target-libsanitizer
|
||||
maybe-install-html-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-install-html-target-libsanitizer: install-html-target-libsanitizer
|
||||
|
||||
install-html-target-libsanitizer: \
|
||||
configure-target-libsanitizer \
|
||||
html-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing install-html in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
install-html) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-installcheck-target-libsanitizer installcheck-target-libsanitizer
|
||||
maybe-installcheck-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-installcheck-target-libsanitizer: installcheck-target-libsanitizer
|
||||
|
||||
installcheck-target-libsanitizer: \
|
||||
configure-target-libsanitizer
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing installcheck in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
installcheck) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-mostlyclean-target-libsanitizer mostlyclean-target-libsanitizer
|
||||
maybe-mostlyclean-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-mostlyclean-target-libsanitizer: mostlyclean-target-libsanitizer
|
||||
|
||||
mostlyclean-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing mostlyclean in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
mostlyclean) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-clean-target-libsanitizer clean-target-libsanitizer
|
||||
maybe-clean-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-clean-target-libsanitizer: clean-target-libsanitizer
|
||||
|
||||
clean-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing clean in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
clean) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-distclean-target-libsanitizer distclean-target-libsanitizer
|
||||
maybe-distclean-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-distclean-target-libsanitizer: distclean-target-libsanitizer
|
||||
|
||||
distclean-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing distclean in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
distclean) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
.PHONY: maybe-maintainer-clean-target-libsanitizer maintainer-clean-target-libsanitizer
|
||||
maybe-maintainer-clean-target-libsanitizer:
|
||||
@if target-libsanitizer
|
||||
maybe-maintainer-clean-target-libsanitizer: maintainer-clean-target-libsanitizer
|
||||
|
||||
maintainer-clean-target-libsanitizer:
|
||||
@: $(MAKE); $(unstage)
|
||||
@[ -f $(TARGET_SUBDIR)/libsanitizer/Makefile ] || exit 0 ; \
|
||||
r=`${PWD_COMMAND}`; export r; \
|
||||
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
|
||||
$(NORMAL_TARGET_EXPORTS) \
|
||||
echo "Doing maintainer-clean in $(TARGET_SUBDIR)/libsanitizer" ; \
|
||||
for flag in $(EXTRA_TARGET_FLAGS); do \
|
||||
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
|
||||
done; \
|
||||
(cd $(TARGET_SUBDIR)/libsanitizer && \
|
||||
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
|
||||
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
|
||||
"RANLIB=$${RANLIB}" \
|
||||
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
|
||||
maintainer-clean) \
|
||||
|| exit 1
|
||||
|
||||
@endif target-libsanitizer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.PHONY: configure-target-libssp maybe-configure-target-libssp
|
||||
maybe-configure-target-libssp:
|
||||
@if gcc-bootstrap
|
||||
@ -44390,6 +44869,7 @@ configure-stage4-target-libstdc++-v3: maybe-all-stage4-gcc
|
||||
configure-stageprofile-target-libstdc++-v3: maybe-all-stageprofile-gcc
|
||||
configure-stagefeedback-target-libstdc++-v3: maybe-all-stagefeedback-gcc
|
||||
configure-target-libmudflap: stage_last
|
||||
configure-target-libsanitizer: stage_last
|
||||
configure-target-libssp: stage_last
|
||||
configure-target-newlib: stage_last
|
||||
configure-stage1-target-libgcc: maybe-all-stage1-gcc
|
||||
@ -44425,6 +44905,7 @@ configure-target-libatomic: stage_last
|
||||
@if gcc-no-bootstrap
|
||||
configure-target-libstdc++-v3: maybe-all-gcc
|
||||
configure-target-libmudflap: maybe-all-gcc
|
||||
configure-target-libsanitizer: maybe-all-gcc
|
||||
configure-target-libssp: maybe-all-gcc
|
||||
configure-target-newlib: maybe-all-gcc
|
||||
configure-target-libgcc: maybe-all-gcc
|
||||
@ -45166,6 +45647,7 @@ configure-stage3-target-libstdc++-v3: maybe-configure-stage3-target-libgomp
|
||||
configure-stage4-target-libstdc++-v3: maybe-configure-stage4-target-libgomp
|
||||
configure-stageprofile-target-libstdc++-v3: maybe-configure-stageprofile-target-libgomp
|
||||
configure-stagefeedback-target-libstdc++-v3: maybe-configure-stagefeedback-target-libgomp
|
||||
configure-target-libsanitizer: maybe-all-target-libstdc++-v3
|
||||
all-target-libstdc++-v3: maybe-configure-target-libgomp
|
||||
|
||||
all-stage1-target-libstdc++-v3: maybe-configure-stage1-target-libgomp
|
||||
@ -45204,6 +45686,7 @@ configure-stagefeedback-target-libgomp: maybe-all-stagefeedback-target-libgcc
|
||||
@if gcc-no-bootstrap
|
||||
configure-target-libstdc++-v3: maybe-all-target-libgcc
|
||||
configure-target-libmudflap: maybe-all-target-libgcc
|
||||
configure-target-libsanitizer: maybe-all-target-libgcc
|
||||
configure-target-libssp: maybe-all-target-libgcc
|
||||
configure-target-newlib: maybe-all-target-libgcc
|
||||
configure-target-libbacktrace: maybe-all-target-libgcc
|
||||
@ -45230,6 +45713,8 @@ configure-target-libstdc++-v3: maybe-all-target-newlib maybe-all-target-libgloss
|
||||
|
||||
configure-target-libmudflap: maybe-all-target-newlib maybe-all-target-libgloss
|
||||
|
||||
configure-target-libsanitizer: maybe-all-target-newlib maybe-all-target-libgloss
|
||||
|
||||
configure-target-libssp: maybe-all-target-newlib maybe-all-target-libgloss
|
||||
|
||||
|
||||
|
1
configure
vendored
1
configure
vendored
@ -2773,6 +2773,7 @@ target_libraries="target-libgcc \
|
||||
target-libitm \
|
||||
target-libstdc++-v3 \
|
||||
target-libmudflap \
|
||||
target-libsanitizer \
|
||||
target-libssp \
|
||||
target-libquadmath \
|
||||
target-libgfortran \
|
||||
|
@ -160,6 +160,7 @@ target_libraries="target-libgcc \
|
||||
target-libitm \
|
||||
target-libstdc++-v3 \
|
||||
target-libmudflap \
|
||||
target-libsanitizer \
|
||||
target-libssp \
|
||||
target-libquadmath \
|
||||
target-libgfortran \
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-11-12 Wei Mi <wmi@google.com>
|
||||
|
||||
* gcc.c (LINK_COMMAND_SPEC): Add -lasan to link command if
|
||||
-faddress-sanitizer is on.
|
||||
|
||||
2012-11-12 Dodji Seketeli <dodji@redhat.com>
|
||||
|
||||
* gimple.h (is_gimple_builtin_call): Declare ...
|
||||
|
@ -687,6 +687,7 @@ proper position among the other output files. */
|
||||
%{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
|
||||
%(mflib) " STACK_SPLIT_SPEC "\
|
||||
%{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
|
||||
%{faddress-sanitizer:-lasan}\
|
||||
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
|
||||
%{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}"
|
||||
#endif
|
||||
|
3
libsanitizer/ChangeLog.asan
Normal file
3
libsanitizer/ChangeLog.asan
Normal file
@ -0,0 +1,3 @@
|
||||
2012-10-29 Wei Mi <wmi@google.com>
|
||||
|
||||
Initial checkin: migrate asan runtime from llvm.
|
97
libsanitizer/LICENSE.TXT
Normal file
97
libsanitizer/LICENSE.TXT
Normal file
@ -0,0 +1,97 @@
|
||||
==============================================================================
|
||||
compiler_rt License
|
||||
==============================================================================
|
||||
|
||||
The compiler_rt library is dual licensed under both the University of Illinois
|
||||
"BSD-Like" license and the MIT license. As a user of this code you may choose
|
||||
to use it under either license. As a contributor, you agree to allow your code
|
||||
to be used under both.
|
||||
|
||||
Full text of the relevant licenses is included below.
|
||||
|
||||
==============================================================================
|
||||
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 2009-2012 by the contributors listed in CREDITS.TXT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
Copyrights and Licenses for Third Party Software Distributed with LLVM:
|
||||
==============================================================================
|
||||
The LLVM software contains code written by third parties. Such software will
|
||||
have its own individual LICENSE.TXT file in the directory in which it appears.
|
||||
This file will describe the copyrights, license, and restrictions which apply
|
||||
to that code.
|
||||
|
||||
The disclaimer of warranty in the University of Illinois Open Source License
|
||||
applies to all code in the LLVM Distribution, and nothing in any of the
|
||||
other licenses gives permission to use the names of the LLVM Team or the
|
||||
University of Illinois to endorse or promote products derived from this
|
||||
Software.
|
||||
|
||||
The following pieces of software have additional or alternate copyrights,
|
||||
licenses, and/or restrictions:
|
||||
|
||||
Program Directory
|
||||
------- ---------
|
||||
mach_override lib/interception/mach_override
|
46
libsanitizer/Makefile.am
Normal file
46
libsanitizer/Makefile.am
Normal file
@ -0,0 +1,46 @@
|
||||
SUBDIRS = interception sanitizer_common asan
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES=
|
||||
|
||||
## ################################################################
|
||||
|
773
libsanitizer/Makefile.in
Normal file
773
libsanitizer/Makefile.in
Normal file
@ -0,0 +1,773 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in 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.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = .
|
||||
DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in $(top_srcdir)/configure config.guess \
|
||||
config.sub depcomp install-sh ltmain.sh missing
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
html-recursive info-recursive install-data-recursive \
|
||||
install-dvi-recursive install-exec-recursive \
|
||||
install-html-recursive install-info-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
|
||||
$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
|
||||
distdir dist dist-all distcheck
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
|
||||
&& rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = --best
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = find . -type f -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
enable_shared = @enable_shared@
|
||||
enable_static = @enable_static@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
SUBDIRS = interception sanitizer_common asan
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES =
|
||||
all: all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
distclean-libtool:
|
||||
-rm -f libtool config.lt
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
# To change the values of `make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in `config.status', edit `config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run `make');
|
||||
# (2) otherwise, pass the desired values on the `make' command line.
|
||||
$(RECURSIVE_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
$(RECURSIVE_CLEAN_TARGETS):
|
||||
@fail= failcom='exit 1'; \
|
||||
for f in x $$MAKEFLAGS; do \
|
||||
case $$f in \
|
||||
*=* | --[!k]*);; \
|
||||
*k*) failcom='fail=yes';; \
|
||||
esac; \
|
||||
done; \
|
||||
dot_seen=no; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
rev=''; for subdir in $$list; do \
|
||||
if test "$$subdir" = "."; then :; else \
|
||||
rev="$$subdir $$rev"; \
|
||||
fi; \
|
||||
done; \
|
||||
rev="$$rev ."; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
for subdir in $$rev; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done && test -z "$$fail"
|
||||
tags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
|
||||
done
|
||||
ctags-recursive:
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
$(am__remove_distdir)
|
||||
test -d "$(distdir)" || mkdir "$(distdir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-test -n "$(am__skip_mode_fix)" \
|
||||
|| find "$(distdir)" -type d ! -perm -755 \
|
||||
-exec chmod u+rwx,go+rx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist dist-all: distdir
|
||||
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
|
||||
$(am__remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir); chmod a+w $(distdir)
|
||||
mkdir $(distdir)/_build
|
||||
mkdir $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
test -d $(distdir)/_build || exit 0; \
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
|
||||
&& cd "$$am__cwd" \
|
||||
|| exit 1
|
||||
$(am__remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-libtool \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
|
||||
install-am install-strip tags-recursive
|
||||
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
|
||||
dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ dist-xz \
|
||||
dist-zip distcheck distclean distclean-generic \
|
||||
distclean-libtool distclean-tags distcleancheck distdir \
|
||||
distuninstallcheck dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
installdirs-am maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
|
||||
ps ps-am tags tags-recursive uninstall uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
4
libsanitizer/README.gcc
Normal file
4
libsanitizer/README.gcc
Normal file
@ -0,0 +1,4 @@
|
||||
The AddressSanitizer (http://code.google.com/p/address-sanitizer) is
|
||||
a project developed by Google Inc. The source files of the project
|
||||
are hosted at http://llvm.org/svn/llvm-project/compiler-rt. These files
|
||||
are the ones in the asan subdirectory of that project.
|
9599
libsanitizer/aclocal.m4
vendored
Normal file
9599
libsanitizer/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load Diff
76
libsanitizer/asan/Makefile.am
Normal file
76
libsanitizer/asan/Makefile.am
Normal file
@ -0,0 +1,76 @@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
|
||||
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DASAN_HAS_EXCEPTIONS=1 -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=0 -DASAN_NEEDS_SEGV=1
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
toolexeclib_LTLIBRARIES = libasan.la
|
||||
|
||||
asan_files = \
|
||||
asan_allocator.cc \
|
||||
asan_interceptors.cc \
|
||||
asan_mac.cc \
|
||||
asan_malloc_mac.cc \
|
||||
asan_new_delete.cc \
|
||||
asan_posix.cc \
|
||||
asan_rtl.cc \
|
||||
asan_stats.cc \
|
||||
asan_thread_registry.cc \
|
||||
asan_globals.cc \
|
||||
asan_linux.cc \
|
||||
asan_malloc_linux.cc \
|
||||
asan_malloc_win.cc \
|
||||
asan_poisoning.cc \
|
||||
asan_report.cc \
|
||||
asan_stack.cc \
|
||||
asan_thread.cc \
|
||||
asan_win.cc
|
||||
|
||||
libasan_la_SOURCES = $(asan_files)
|
||||
libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(top_builddir)/../libstdc++-v3/src/libstdc++.la
|
||||
libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` -lpthread -ldl
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES=
|
||||
|
||||
## ################################################################
|
||||
|
631
libsanitizer/asan/Makefile.in
Normal file
631
libsanitizer/asan/Makefile.in
Normal file
@ -0,0 +1,631 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in 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.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = asan
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
|
||||
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
|
||||
libasan_la_DEPENDENCIES = \
|
||||
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
|
||||
$(top_builddir)/interception/libinterception.la \
|
||||
$(top_builddir)/../libstdc++-v3/src/libstdc++.la
|
||||
am__objects_1 = asan_allocator.lo asan_interceptors.lo asan_mac.lo \
|
||||
asan_malloc_mac.lo asan_new_delete.lo asan_posix.lo \
|
||||
asan_rtl.lo asan_stats.lo asan_thread_registry.lo \
|
||||
asan_globals.lo asan_linux.lo asan_malloc_linux.lo \
|
||||
asan_malloc_win.lo asan_poisoning.lo asan_report.lo \
|
||||
asan_stack.lo asan_thread.lo asan_win.lo
|
||||
am_libasan_la_OBJECTS = $(am__objects_1)
|
||||
libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
|
||||
libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
|
||||
$(CXXFLAGS) $(libasan_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libasan_la_SOURCES)
|
||||
DIST_SOURCES = $(libasan_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DASAN_HAS_EXCEPTIONS=1 -DASAN_FLEXIBLE_MAPPING_AND_OFFSET=0 -DASAN_NEEDS_SEGV=1
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
enable_shared = @enable_shared@
|
||||
enable_static = @enable_static@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
toolexeclib_LTLIBRARIES = libasan.la
|
||||
asan_files = \
|
||||
asan_allocator.cc \
|
||||
asan_interceptors.cc \
|
||||
asan_mac.cc \
|
||||
asan_malloc_mac.cc \
|
||||
asan_new_delete.cc \
|
||||
asan_posix.cc \
|
||||
asan_rtl.cc \
|
||||
asan_stats.cc \
|
||||
asan_thread_registry.cc \
|
||||
asan_globals.cc \
|
||||
asan_linux.cc \
|
||||
asan_malloc_linux.cc \
|
||||
asan_malloc_win.cc \
|
||||
asan_poisoning.cc \
|
||||
asan_report.cc \
|
||||
asan_stack.cc \
|
||||
asan_thread.cc \
|
||||
asan_win.cc
|
||||
|
||||
libasan_la_SOURCES = $(asan_files)
|
||||
libasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(top_builddir)/../libstdc++-v3/src/libstdc++.la
|
||||
libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` -lpthread -ldl
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES =
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cc .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign asan/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign asan/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(toolexeclibdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)"
|
||||
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
|
||||
list2=; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
list2="$$list2 $$p"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
|
||||
}
|
||||
|
||||
uninstall-toolexeclibLTLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
|
||||
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
|
||||
done
|
||||
|
||||
clean-toolexeclibLTLIBRARIES:
|
||||
-test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
|
||||
@list='$(toolexeclib_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libasan.la: $(libasan_la_OBJECTS) $(libasan_la_DEPENDENCIES) $(EXTRA_libasan_la_DEPENDENCIES)
|
||||
$(libasan_la_LINK) -rpath $(toolexeclibdir) $(libasan_la_OBJECTS) $(libasan_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_win.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_new_delete.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_poisoning.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_posix.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_report.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_rtl.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stack.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stats.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread_registry.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||
|
||||
.cc.obj:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.cc.lo:
|
||||
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-toolexeclibLTLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-toolexeclibLTLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-toolexeclibLTLIBRARIES ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip install-toolexeclibLTLIBRARIES installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags uninstall uninstall-am uninstall-toolexeclibLTLIBRARIES
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
1045
libsanitizer/asan/asan_allocator.cc
Normal file
1045
libsanitizer/asan/asan_allocator.cc
Normal file
File diff suppressed because it is too large
Load Diff
177
libsanitizer/asan/asan_allocator.h
Normal file
177
libsanitizer/asan/asan_allocator.h
Normal file
@ -0,0 +1,177 @@
|
||||
//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_allocator.cc.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_ALLOCATOR_H
|
||||
#define ASAN_ALLOCATOR_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static const uptr kNumberOfSizeClasses = 255;
|
||||
struct AsanChunk;
|
||||
|
||||
class AsanChunkView {
|
||||
public:
|
||||
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
|
||||
bool IsValid() { return chunk_ != 0; }
|
||||
uptr Beg(); // first byte of user memory.
|
||||
uptr End(); // last byte of user memory.
|
||||
uptr UsedSize(); // size requested by the user.
|
||||
uptr AllocTid();
|
||||
uptr FreeTid();
|
||||
void GetAllocStack(StackTrace *stack);
|
||||
void GetFreeStack(StackTrace *stack);
|
||||
bool AddrIsInside(uptr addr, uptr access_size, uptr *offset);
|
||||
bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset);
|
||||
bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset);
|
||||
private:
|
||||
AsanChunk *const chunk_;
|
||||
};
|
||||
|
||||
AsanChunkView FindHeapChunkByAddress(uptr address);
|
||||
|
||||
class AsanChunkFifoList {
|
||||
public:
|
||||
explicit AsanChunkFifoList(LinkerInitialized) { }
|
||||
AsanChunkFifoList() { clear(); }
|
||||
void Push(AsanChunk *n);
|
||||
void PushList(AsanChunkFifoList *q);
|
||||
AsanChunk *Pop();
|
||||
uptr size() { return size_; }
|
||||
void clear() {
|
||||
first_ = last_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
private:
|
||||
AsanChunk *first_;
|
||||
AsanChunk *last_;
|
||||
uptr size_;
|
||||
};
|
||||
|
||||
struct AsanThreadLocalMallocStorage {
|
||||
explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
|
||||
: quarantine_(x) { }
|
||||
AsanThreadLocalMallocStorage() {
|
||||
CHECK(REAL(memset));
|
||||
REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
|
||||
}
|
||||
|
||||
AsanChunkFifoList quarantine_;
|
||||
AsanChunk *free_lists_[kNumberOfSizeClasses];
|
||||
void CommitBack();
|
||||
};
|
||||
|
||||
// Fake stack frame contains local variables of one function.
|
||||
// This struct should fit into a stack redzone (32 bytes).
|
||||
struct FakeFrame {
|
||||
uptr magic; // Modified by the instrumented code.
|
||||
uptr descr; // Modified by the instrumented code.
|
||||
FakeFrame *next;
|
||||
u64 real_stack : 48;
|
||||
u64 size_minus_one : 16;
|
||||
};
|
||||
|
||||
struct FakeFrameFifo {
|
||||
public:
|
||||
void FifoPush(FakeFrame *node);
|
||||
FakeFrame *FifoPop();
|
||||
private:
|
||||
FakeFrame *first_, *last_;
|
||||
};
|
||||
|
||||
class FakeFrameLifo {
|
||||
public:
|
||||
void LifoPush(FakeFrame *node) {
|
||||
node->next = top_;
|
||||
top_ = node;
|
||||
}
|
||||
void LifoPop() {
|
||||
CHECK(top_);
|
||||
top_ = top_->next;
|
||||
}
|
||||
FakeFrame *top() { return top_; }
|
||||
private:
|
||||
FakeFrame *top_;
|
||||
};
|
||||
|
||||
// For each thread we create a fake stack and place stack objects on this fake
|
||||
// stack instead of the real stack. The fake stack is not really a stack but
|
||||
// a fast malloc-like allocator so that when a function exits the fake stack
|
||||
// is not poped but remains there for quite some time until gets used again.
|
||||
// So, we poison the objects on the fake stack when function returns.
|
||||
// It helps us find use-after-return bugs.
|
||||
// We can not rely on __asan_stack_free being called on every function exit,
|
||||
// so we maintain a lifo list of all current fake frames and update it on every
|
||||
// call to __asan_stack_malloc.
|
||||
class FakeStack {
|
||||
public:
|
||||
FakeStack();
|
||||
explicit FakeStack(LinkerInitialized) {}
|
||||
void Init(uptr stack_size);
|
||||
void StopUsingFakeStack() { alive_ = false; }
|
||||
void Cleanup();
|
||||
uptr AllocateStack(uptr size, uptr real_stack);
|
||||
static void OnFree(uptr ptr, uptr size, uptr real_stack);
|
||||
// Return the bottom of the maped region.
|
||||
uptr AddrIsInFakeStack(uptr addr);
|
||||
bool StackSize() { return stack_size_; }
|
||||
|
||||
private:
|
||||
static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B.
|
||||
static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K.
|
||||
static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
|
||||
static const uptr kNumberOfSizeClasses =
|
||||
kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
|
||||
|
||||
bool AddrIsInSizeClass(uptr addr, uptr size_class);
|
||||
|
||||
// Each size class should be large enough to hold all frames.
|
||||
uptr ClassMmapSize(uptr size_class);
|
||||
|
||||
uptr ClassSize(uptr size_class) {
|
||||
return 1UL << (size_class + kMinStackFrameSizeLog);
|
||||
}
|
||||
|
||||
void DeallocateFrame(FakeFrame *fake_frame);
|
||||
|
||||
uptr ComputeSizeClass(uptr alloc_size);
|
||||
void AllocateOneSizeClass(uptr size_class);
|
||||
|
||||
uptr stack_size_;
|
||||
bool alive_;
|
||||
|
||||
uptr allocated_size_classes_[kNumberOfSizeClasses];
|
||||
FakeFrameFifo size_classes_[kNumberOfSizeClasses];
|
||||
FakeFrameLifo call_stack_;
|
||||
};
|
||||
|
||||
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack);
|
||||
void asan_free(void *ptr, StackTrace *stack);
|
||||
|
||||
void *asan_malloc(uptr size, StackTrace *stack);
|
||||
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
|
||||
void *asan_realloc(void *p, uptr size, StackTrace *stack);
|
||||
void *asan_valloc(uptr size, StackTrace *stack);
|
||||
void *asan_pvalloc(uptr size, StackTrace *stack);
|
||||
|
||||
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
||||
StackTrace *stack);
|
||||
uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
|
||||
|
||||
uptr asan_mz_size(const void *ptr);
|
||||
void asan_mz_force_lock();
|
||||
void asan_mz_force_unlock();
|
||||
|
||||
} // namespace __asan
|
||||
#endif // ASAN_ALLOCATOR_H
|
103
libsanitizer/asan/asan_flags.h
Normal file
103
libsanitizer/asan/asan_flags.h
Normal file
@ -0,0 +1,103 @@
|
||||
//===-- asan_flags.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan runtime flags.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_FLAGS_H
|
||||
#define ASAN_FLAGS_H
|
||||
|
||||
#include "sanitizer/common_interface_defs.h"
|
||||
|
||||
// ASan flag values can be defined in three ways:
|
||||
// 1) initialized with default values at startup.
|
||||
// 2) overriden from string returned by user-specified function
|
||||
// __asan_default_options().
|
||||
// 3) overriden from env variable ASAN_OPTIONS.
|
||||
|
||||
namespace __asan {
|
||||
|
||||
struct Flags {
|
||||
// Size (in bytes) of quarantine used to detect use-after-free errors.
|
||||
// Lower value may reduce memory usage but increase the chance of
|
||||
// false negatives.
|
||||
int quarantine_size;
|
||||
// If set, uses in-process symbolizer from common sanitizer runtime.
|
||||
bool symbolize;
|
||||
// Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
|
||||
int verbosity;
|
||||
// Size (in bytes) of redzones around heap objects.
|
||||
// Requirement: redzone >= 32, is a power of two.
|
||||
int redzone;
|
||||
// If set, prints some debugging information and does additional checks.
|
||||
bool debug;
|
||||
// Controls the way to handle globals (0 - don't detect buffer overflow
|
||||
// on globals, 1 - detect buffer overflow, 2 - print data about registered
|
||||
// globals).
|
||||
int report_globals;
|
||||
// If set, attempts to catch initialization order issues.
|
||||
bool check_initialization_order;
|
||||
// Max number of stack frames kept for each allocation.
|
||||
int malloc_context_size;
|
||||
// If set, uses custom wrappers and replacements for libc string functions
|
||||
// to find more errors.
|
||||
bool replace_str;
|
||||
// If set, uses custom wrappers for memset/memcpy/memmove intinsics.
|
||||
bool replace_intrin;
|
||||
// Used on Mac only. See comments in asan_mac.cc and asan_malloc_mac.cc.
|
||||
bool replace_cfallocator;
|
||||
// Used on Mac only.
|
||||
bool mac_ignore_invalid_free;
|
||||
// ASan allocator flag. See asan_allocator.cc.
|
||||
bool use_fake_stack;
|
||||
// ASan allocator flag. Sets the maximal size of allocation request
|
||||
// that would return memory filled with zero bytes.
|
||||
int max_malloc_fill_size;
|
||||
// Override exit status if something was reported.
|
||||
int exitcode;
|
||||
// If set, user may manually mark memory regions as poisoned or unpoisoned.
|
||||
bool allow_user_poisoning;
|
||||
// Number of seconds to sleep between printing an error report and
|
||||
// terminating application. Useful for debug purposes (when one needs
|
||||
// to attach gdb, for example).
|
||||
int sleep_before_dying;
|
||||
// If set, registers ASan custom segv handler.
|
||||
bool handle_segv;
|
||||
// If set, uses alternate stack for signal handling.
|
||||
bool use_sigaltstack;
|
||||
// Allow the users to work around the bug in Nvidia drivers prior to 295.*.
|
||||
bool check_malloc_usable_size;
|
||||
// If set, explicitly unmaps (huge) shadow at exit.
|
||||
bool unmap_shadow_on_exit;
|
||||
// If set, calls abort() instead of _exit() after printing an error report.
|
||||
bool abort_on_error;
|
||||
// If set, prints ASan exit stats even after program terminates successfully.
|
||||
bool atexit;
|
||||
// By default, disable core dumper on 64-bit - it makes little sense
|
||||
// to dump 16T+ core.
|
||||
bool disable_core;
|
||||
// Allow the tool to re-exec the program. This may interfere badly with the
|
||||
// debugger.
|
||||
bool allow_reexec;
|
||||
// Strips this prefix from file paths in error reports.
|
||||
const char *strip_path_prefix;
|
||||
// If set, prints not only thread creation stacks for threads in error report,
|
||||
// but also thread creation stacks for threads that created those threads,
|
||||
// etc. up to main thread.
|
||||
bool print_full_thread_history;
|
||||
// ASan will write logs to "log_path.pid" instead of stderr.
|
||||
const char *log_path;
|
||||
};
|
||||
|
||||
Flags *flags();
|
||||
void InitializeFlags(Flags *f, const char *env);
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_FLAGS_H
|
206
libsanitizer/asan/asan_globals.cc
Normal file
206
libsanitizer/asan/asan_globals.cc
Normal file
@ -0,0 +1,206 @@
|
||||
//===-- asan_globals.cc ---------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Handle globals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
typedef __asan_global Global;
|
||||
|
||||
struct ListOfGlobals {
|
||||
const Global *g;
|
||||
ListOfGlobals *next;
|
||||
};
|
||||
|
||||
static AsanLock mu_for_globals(LINKER_INITIALIZED);
|
||||
static LowLevelAllocator allocator_for_globals;
|
||||
static ListOfGlobals *list_of_all_globals;
|
||||
static ListOfGlobals *list_of_dynamic_init_globals;
|
||||
|
||||
void PoisonRedZones(const Global &g) {
|
||||
uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
|
||||
CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
|
||||
// full right redzone
|
||||
uptr g_aligned_size = kGlobalAndStackRedzone *
|
||||
((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
|
||||
PoisonShadow(g.beg + g_aligned_size,
|
||||
kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
|
||||
if ((g.size % kGlobalAndStackRedzone) != 0) {
|
||||
// partial right redzone
|
||||
u64 g_aligned_down_size = kGlobalAndStackRedzone *
|
||||
(g.size / kGlobalAndStackRedzone);
|
||||
CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
|
||||
PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
|
||||
g.size % kGlobalAndStackRedzone,
|
||||
kGlobalAndStackRedzone,
|
||||
kAsanGlobalRedzoneMagic);
|
||||
}
|
||||
}
|
||||
|
||||
static uptr GetAlignedSize(uptr size) {
|
||||
return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
|
||||
* kGlobalAndStackRedzone;
|
||||
}
|
||||
|
||||
bool DescribeAddressIfGlobal(uptr addr) {
|
||||
if (!flags()->report_globals) return false;
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
bool res = false;
|
||||
for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
|
||||
const Global &g = *l->g;
|
||||
if (flags()->report_globals >= 2)
|
||||
Report("Search Global: beg=%p size=%zu name=%s\n",
|
||||
(void*)g.beg, g.size, (char*)g.name);
|
||||
res |= DescribeAddressRelativeToGlobal(addr, g);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Register a global variable.
|
||||
// This function may be called more than once for every global
|
||||
// so we store the globals in a map.
|
||||
static void RegisterGlobal(const Global *g) {
|
||||
CHECK(asan_inited);
|
||||
if (flags()->report_globals >= 2)
|
||||
Report("Added Global: beg=%p size=%zu/%zu name=%s dyn.init=%zu\n",
|
||||
(void*)g->beg, g->size, g->size_with_redzone, g->name,
|
||||
g->has_dynamic_init);
|
||||
CHECK(flags()->report_globals);
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
|
||||
PoisonRedZones(*g);
|
||||
ListOfGlobals *l =
|
||||
(ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
|
||||
l->g = g;
|
||||
l->next = list_of_all_globals;
|
||||
list_of_all_globals = l;
|
||||
if (g->has_dynamic_init) {
|
||||
l = (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
|
||||
l->g = g;
|
||||
l->next = list_of_dynamic_init_globals;
|
||||
list_of_dynamic_init_globals = l;
|
||||
}
|
||||
}
|
||||
|
||||
static void UnregisterGlobal(const Global *g) {
|
||||
CHECK(asan_inited);
|
||||
CHECK(flags()->report_globals);
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
|
||||
PoisonShadow(g->beg, g->size_with_redzone, 0);
|
||||
// We unpoison the shadow memory for the global but we do not remove it from
|
||||
// the list because that would require O(n^2) time with the current list
|
||||
// implementation. It might not be worth doing anyway.
|
||||
}
|
||||
|
||||
// Poison all shadow memory for a single global.
|
||||
static void PoisonGlobalAndRedzones(const Global *g) {
|
||||
CHECK(asan_inited);
|
||||
CHECK(flags()->check_initialization_order);
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
|
||||
if (flags()->report_globals >= 3)
|
||||
Printf("DynInitPoison : %s\n", g->name);
|
||||
PoisonShadow(g->beg, g->size_with_redzone, kAsanInitializationOrderMagic);
|
||||
}
|
||||
|
||||
static void UnpoisonGlobal(const Global *g) {
|
||||
CHECK(asan_inited);
|
||||
CHECK(flags()->check_initialization_order);
|
||||
CHECK(AddrIsInMem(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->beg));
|
||||
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
|
||||
if (flags()->report_globals >= 3)
|
||||
Printf("DynInitUnpoison: %s\n", g->name);
|
||||
PoisonShadow(g->beg, g->size_with_redzone, 0);
|
||||
PoisonRedZones(*g);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// Register one global with a default redzone.
|
||||
void __asan_register_global(uptr addr, uptr size,
|
||||
const char *name) {
|
||||
if (!flags()->report_globals) return;
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
Global *g = (Global *)allocator_for_globals.Allocate(sizeof(Global));
|
||||
g->beg = addr;
|
||||
g->size = size;
|
||||
g->size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
|
||||
g->name = name;
|
||||
RegisterGlobal(g);
|
||||
}
|
||||
|
||||
// Register an array of globals.
|
||||
void __asan_register_globals(__asan_global *globals, uptr n) {
|
||||
if (!flags()->report_globals) return;
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
for (uptr i = 0; i < n; i++) {
|
||||
RegisterGlobal(&globals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister an array of globals.
|
||||
// We must do this when a shared objects gets dlclosed.
|
||||
void __asan_unregister_globals(__asan_global *globals, uptr n) {
|
||||
if (!flags()->report_globals) return;
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
for (uptr i = 0; i < n; i++) {
|
||||
UnregisterGlobal(&globals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// This method runs immediately prior to dynamic initialization in each TU,
|
||||
// when all dynamically initialized globals are unpoisoned. This method
|
||||
// poisons all global variables not defined in this TU, so that a dynamic
|
||||
// initializer can only touch global variables in the same TU.
|
||||
void __asan_before_dynamic_init(uptr first_addr, uptr last_addr) {
|
||||
if (!flags()->check_initialization_order) return;
|
||||
CHECK(list_of_dynamic_init_globals);
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
bool from_current_tu = false;
|
||||
// The list looks like:
|
||||
// a => ... => b => last_addr => ... => first_addr => c => ...
|
||||
// The globals of the current TU reside between last_addr and first_addr.
|
||||
for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next) {
|
||||
if (l->g->beg == last_addr)
|
||||
from_current_tu = true;
|
||||
if (!from_current_tu)
|
||||
PoisonGlobalAndRedzones(l->g);
|
||||
if (l->g->beg == first_addr)
|
||||
from_current_tu = false;
|
||||
}
|
||||
CHECK(!from_current_tu);
|
||||
}
|
||||
|
||||
// This method runs immediately after dynamic initialization in each TU, when
|
||||
// all dynamically initialized globals except for those defined in the current
|
||||
// TU are poisoned. It simply unpoisons all dynamically initialized globals.
|
||||
void __asan_after_dynamic_init() {
|
||||
if (!flags()->check_initialization_order) return;
|
||||
ScopedLock lock(&mu_for_globals);
|
||||
for (ListOfGlobals *l = list_of_dynamic_init_globals; l; l = l->next)
|
||||
UnpoisonGlobal(l->g);
|
||||
}
|
217
libsanitizer/asan/asan_intercepted_functions.h
Normal file
217
libsanitizer/asan/asan_intercepted_functions.h
Normal file
@ -0,0 +1,217 @@
|
||||
//===-- asan_intercepted_functions.h ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header containing prototypes for wrapper functions and wrappers
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_INTERCEPTED_FUNCTIONS_H
|
||||
#define ASAN_INTERCEPTED_FUNCTIONS_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "interception/interception.h"
|
||||
|
||||
using __sanitizer::uptr;
|
||||
|
||||
// Use macro to describe if specific function should be
|
||||
// intercepted on a given platform.
|
||||
#if !defined(_WIN32)
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
|
||||
# define ASAN_INTERCEPT__LONGJMP 1
|
||||
# define ASAN_INTERCEPT_STRDUP 1
|
||||
# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 1
|
||||
# define ASAN_INTERCEPT_INDEX 1
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
|
||||
# define ASAN_INTERCEPT_MLOCKX 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
|
||||
# define ASAN_INTERCEPT__LONGJMP 0
|
||||
# define ASAN_INTERCEPT_STRDUP 0
|
||||
# define ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP 0
|
||||
# define ASAN_INTERCEPT_INDEX 0
|
||||
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
|
||||
# define ASAN_INTERCEPT_MLOCKX 0
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
|
||||
#else
|
||||
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
|
||||
#endif
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
# define ASAN_INTERCEPT_STRNLEN 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_STRNLEN 0
|
||||
#endif
|
||||
|
||||
#if !defined(ANDROID) && !defined(_WIN32)
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
|
||||
#endif
|
||||
|
||||
// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
|
||||
// there.
|
||||
#if !defined(_WIN32) && (!defined(__APPLE__) || MAC_INTERPOSE_FUNCTIONS)
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SIGLONGJMP 0
|
||||
#endif
|
||||
|
||||
#if ASAN_HAS_EXCEPTIONS && !defined(_WIN32)
|
||||
# define ASAN_INTERCEPT___CXA_THROW 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT___CXA_THROW 0
|
||||
#endif
|
||||
|
||||
#define DECLARE_FUNCTION_AND_WRAPPER(ret_type, func, ...) \
|
||||
ret_type func(__VA_ARGS__); \
|
||||
ret_type WRAP(func)(__VA_ARGS__)
|
||||
|
||||
// Use extern declarations of intercepted functions on Mac and Windows
|
||||
// to avoid including system headers.
|
||||
#if defined(__APPLE__) || (defined(_WIN32) && !defined(_DLL))
|
||||
extern "C" {
|
||||
// signal.h
|
||||
# if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
struct sigaction;
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, sigaction, int sig,
|
||||
const struct sigaction *act,
|
||||
struct sigaction *oldact);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void*, signal, int signum, void *handler);
|
||||
# endif
|
||||
|
||||
// setjmp.h
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, longjmp, void *env, int value);
|
||||
# if ASAN_INTERCEPT__LONGJMP
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, _longjmp, void *env, int value);
|
||||
# endif
|
||||
# if ASAN_INTERCEPT_SIGLONGJMP
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, siglongjmp, void *env, int value);
|
||||
# endif
|
||||
# if ASAN_INTERCEPT___CXA_THROW
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, __cxa_throw, void *a, void *b, void *c);
|
||||
#endif
|
||||
|
||||
// string.h / strings.h
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, memcmp,
|
||||
const void *a1, const void *a2, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void*, memmove,
|
||||
void *to, const void *from, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void*, memcpy,
|
||||
void *to, const void *from, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void*, memset, void *block, int c, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strchr, const char *str, int c);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strcat, /* NOLINT */
|
||||
char *to, const char* from);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strncat,
|
||||
char *to, const char* from, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strcpy, /* NOLINT */
|
||||
char *to, const char* from);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strncpy,
|
||||
char *to, const char* from, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, strcmp, const char *s1, const char* s2);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, strncmp,
|
||||
const char *s1, const char* s2, uptr size);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(uptr, strlen, const char *s);
|
||||
# if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, strcasecmp, const char *s1, const char *s2);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, strncasecmp,
|
||||
const char *s1, const char *s2, uptr n);
|
||||
# endif
|
||||
# if ASAN_INTERCEPT_STRDUP
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, strdup, const char *s);
|
||||
# endif
|
||||
# if ASAN_INTERCEPT_STRNLEN
|
||||
DECLARE_FUNCTION_AND_WRAPPER(uptr, strnlen, const char *s, uptr maxlen);
|
||||
# endif
|
||||
#if ASAN_INTERCEPT_INDEX
|
||||
DECLARE_FUNCTION_AND_WRAPPER(char*, index, const char *string, int c);
|
||||
#endif
|
||||
|
||||
// stdlib.h
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, atoi, const char *nptr);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(long, atol, const char *nptr); // NOLINT
|
||||
DECLARE_FUNCTION_AND_WRAPPER(long, strtol, const char *nptr, char **endptr, int base); // NOLINT
|
||||
# if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
DECLARE_FUNCTION_AND_WRAPPER(long long, atoll, const char *nptr); // NOLINT
|
||||
DECLARE_FUNCTION_AND_WRAPPER(long long, strtoll, const char *nptr, char **endptr, int base); // NOLINT
|
||||
# endif
|
||||
|
||||
# if ASAN_INTERCEPT_MLOCKX
|
||||
// mlock/munlock
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, mlock, const void *addr, size_t len);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, munlock, const void *addr, size_t len);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, mlockall, int flags);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, munlockall, void);
|
||||
# endif
|
||||
|
||||
// Windows threads.
|
||||
# if defined(_WIN32)
|
||||
__declspec(dllimport)
|
||||
void* __stdcall CreateThread(void *sec, uptr st, void* start,
|
||||
void *arg, DWORD fl, DWORD *id);
|
||||
# endif
|
||||
// Posix threads.
|
||||
# if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
DECLARE_FUNCTION_AND_WRAPPER(int, pthread_create,
|
||||
void *thread, void *attr,
|
||||
void *(*start_routine)(void*), void *arg);
|
||||
# endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
typedef void* pthread_workqueue_t;
|
||||
typedef void* pthread_workitem_handle_t;
|
||||
|
||||
typedef void* dispatch_group_t;
|
||||
typedef void* dispatch_queue_t;
|
||||
typedef void* dispatch_source_t;
|
||||
typedef u64 dispatch_time_t;
|
||||
typedef void (*dispatch_function_t)(void *block);
|
||||
typedef void* (*worker_t)(void *block);
|
||||
typedef void* CFStringRef;
|
||||
typedef void* CFAllocatorRef;
|
||||
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async_f,
|
||||
dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_sync_f,
|
||||
dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after_f,
|
||||
dispatch_time_t when, dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_barrier_async_f,
|
||||
dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async_f,
|
||||
dispatch_group_t group, dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, __CFInitialize, void);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(CFStringRef, CFStringCreateCopy,
|
||||
CFAllocatorRef alloc, CFStringRef str);
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, free, void* ptr);
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
|
||||
dispatch_group_t dg,
|
||||
dispatch_queue_t dq, void (^work)(void));
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_async,
|
||||
dispatch_queue_t dq, void (^work)(void));
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_after,
|
||||
dispatch_queue_t dq, void (^work)(void));
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_event_handler,
|
||||
dispatch_source_t ds, void (^work)(void));
|
||||
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
|
||||
dispatch_source_t ds, void (^work)(void));
|
||||
#endif // MAC_INTERPOSE_FUNCTIONS
|
||||
#endif // __APPLE__
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ASAN_INTERCEPTED_FUNCTIONS_H
|
704
libsanitizer/asan/asan_interceptors.cc
Normal file
704
libsanitizer/asan/asan_interceptors.cc
Normal file
@ -0,0 +1,704 @@
|
||||
//===-- asan_interceptors.cc ----------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Intercept various libc functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_interceptors.h"
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_intercepted_functions.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// Instruments read/write access to a single byte in memory.
|
||||
// On error calls __asan_report_error, which aborts the program.
|
||||
#define ACCESS_ADDRESS(address, isWrite) do { \
|
||||
if (!AddrIsInMem(address) || AddressIsPoisoned(address)) { \
|
||||
GET_CURRENT_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, address, isWrite, /* access_size */ 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
|
||||
// and ASAN_WRITE_RANGE as macro instead of function so
|
||||
// that no extra frames are created, and stack trace contains
|
||||
// relevant information only.
|
||||
|
||||
// Instruments read/write access to a memory range.
|
||||
// More complex implementation is possible, for now just
|
||||
// checking the first and the last byte of a range.
|
||||
#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
|
||||
if (size > 0) { \
|
||||
uptr ptr = (uptr)(offset); \
|
||||
ACCESS_ADDRESS(ptr, isWrite); \
|
||||
ACCESS_ADDRESS(ptr + (size) - 1, isWrite); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_READ_RANGE(offset, size) do { \
|
||||
ACCESS_MEMORY_RANGE(offset, size, false); \
|
||||
} while (0)
|
||||
|
||||
#define ASAN_WRITE_RANGE(offset, size) do { \
|
||||
ACCESS_MEMORY_RANGE(offset, size, true); \
|
||||
} while (0)
|
||||
|
||||
// Behavior of functions like "memcpy" or "strcpy" is undefined
|
||||
// if memory intervals overlap. We report error in this case.
|
||||
// Macro is used to avoid creation of new frames.
|
||||
static inline bool RangesOverlap(const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2) {
|
||||
return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
|
||||
}
|
||||
#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
|
||||
const char *offset1 = (const char*)_offset1; \
|
||||
const char *offset2 = (const char*)_offset2; \
|
||||
if (RangesOverlap(offset1, length1, offset2, length2)) { \
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax); \
|
||||
ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
|
||||
offset2, length2, &stack); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE_ASAN_INITED() do { \
|
||||
CHECK(!asan_init_is_running); \
|
||||
if (!asan_inited) { \
|
||||
__asan_init(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
if (REAL(strnlen) != 0) {
|
||||
return REAL(strnlen)(s, maxlen);
|
||||
}
|
||||
#endif
|
||||
return internal_strnlen(s, maxlen);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Wrappers ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
|
||||
AsanThread *t = (AsanThread*)arg;
|
||||
asanThreadRegistry().SetCurrent(t);
|
||||
return t->ThreadStart();
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
INTERCEPTOR(int, pthread_create, void *thread,
|
||||
void *attr, void *(*start_routine)(void*), void *arg) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
|
||||
asanThreadRegistry().RegisterThread(t);
|
||||
return REAL(pthread_create)(thread, attr, asan_thread_start, t);
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
INTERCEPTOR(void*, signal, int signum, void *handler) {
|
||||
if (!AsanInterceptsSignal(signum)) {
|
||||
return REAL(signal)(signum, handler);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact) {
|
||||
if (!AsanInterceptsSignal(signum)) {
|
||||
return REAL(sigaction)(signum, act, oldact);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#elif ASAN_POSIX
|
||||
// We need to have defined REAL(sigaction) on posix systems.
|
||||
DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact);
|
||||
#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
|
||||
INTERCEPTOR(void, longjmp, void *env, int val) {
|
||||
__asan_handle_no_return();
|
||||
REAL(longjmp)(env, val);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT__LONGJMP
|
||||
INTERCEPTOR(void, _longjmp, void *env, int val) {
|
||||
__asan_handle_no_return();
|
||||
REAL(_longjmp)(env, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT_SIGLONGJMP
|
||||
INTERCEPTOR(void, siglongjmp, void *env, int val) {
|
||||
__asan_handle_no_return();
|
||||
REAL(siglongjmp)(env, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT___CXA_THROW
|
||||
INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
|
||||
CHECK(REAL(__cxa_throw));
|
||||
__asan_handle_no_return();
|
||||
REAL(__cxa_throw)(a, b, c);
|
||||
}
|
||||
#endif
|
||||
|
||||
// intercept mlock and friends.
|
||||
// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
|
||||
// All functions return 0 (success).
|
||||
static void MlockIsUnsupported() {
|
||||
static bool printed = 0;
|
||||
if (printed) return;
|
||||
printed = true;
|
||||
Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
INTERCEPTOR(int, mlock, const void *addr, uptr len) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, munlock, const void *addr, uptr len) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, mlockall, int flags) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, munlockall, void) {
|
||||
MlockIsUnsupported();
|
||||
return 0;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
static inline int CharCmp(unsigned char c1, unsigned char c2) {
|
||||
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
|
||||
}
|
||||
|
||||
static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
|
||||
int c1_low = ToLower(c1);
|
||||
int c2_low = ToLower(c2);
|
||||
return c1_low - c2_low;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
|
||||
if (!asan_inited) return internal_memcmp(a1, a2, size);
|
||||
ENSURE_ASAN_INITED();
|
||||
unsigned char c1 = 0, c2 = 0;
|
||||
const unsigned char *s1 = (const unsigned char*)a1;
|
||||
const unsigned char *s2 = (const unsigned char*)a2;
|
||||
uptr i;
|
||||
for (i = 0; i < size; i++) {
|
||||
c1 = s1[i];
|
||||
c2 = s2[i];
|
||||
if (c1 != c2) break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, Min(i + 1, size));
|
||||
ASAN_READ_RANGE(s2, Min(i + 1, size));
|
||||
return CharCmp(c1, c2);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
|
||||
if (!asan_inited) return internal_memcpy(to, from, size);
|
||||
// memcpy is called during __asan_init() from the internals
|
||||
// of printf(...).
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memcpy)(to, from, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
if (to != from) {
|
||||
// We do not treat memcpy with to==from as a bug.
|
||||
// See http://llvm.org/bugs/show_bug.cgi?id=11763.
|
||||
CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
|
||||
}
|
||||
ASAN_WRITE_RANGE(from, size);
|
||||
ASAN_READ_RANGE(to, size);
|
||||
}
|
||||
return REAL(memcpy)(to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
if (!asan_inited) return REAL(memmove)(to, from, size);
|
||||
#endif
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memmove)(to, from, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
ASAN_WRITE_RANGE(from, size);
|
||||
ASAN_READ_RANGE(to, size);
|
||||
}
|
||||
return REAL(memmove)(to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
|
||||
if (!asan_inited) return internal_memset(block, c, size);
|
||||
// memset is called inside Printf.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memset)(block, c, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_intrin) {
|
||||
ASAN_WRITE_RANGE(block, size);
|
||||
}
|
||||
return REAL(memset)(block, c, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strchr, const char *str, int c) {
|
||||
if (!asan_inited) return internal_strchr(str, c);
|
||||
// strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
|
||||
// used.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strchr)(str, c);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
char *result = REAL(strchr)(str, c);
|
||||
if (flags()->replace_str) {
|
||||
uptr bytes_read = (result ? result - str : REAL(strlen)(str)) + 1;
|
||||
ASAN_READ_RANGE(str, bytes_read);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_INDEX
|
||||
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
|
||||
INTERCEPTOR(char*, index, const char *string, int c)
|
||||
ALIAS(WRAPPER_NAME(strchr));
|
||||
# else
|
||||
DEFINE_REAL(char*, index, const char *string, int c)
|
||||
# endif
|
||||
#endif // ASAN_INTERCEPT_INDEX
|
||||
|
||||
// For both strcat() and strncat() we need to check the validity of |to|
|
||||
// argument irrespective of the |from| length.
|
||||
INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_length = REAL(strlen)(from);
|
||||
ASAN_READ_RANGE(from, from_length + 1);
|
||||
uptr to_length = REAL(strlen)(to);
|
||||
ASAN_READ_RANGE(to, to_length);
|
||||
ASAN_WRITE_RANGE(to + to_length, from_length + 1);
|
||||
// If the copying actually happens, the |from| string should not overlap
|
||||
// with the resulting string starting at |to|, which has a length of
|
||||
// to_length + from_length + 1.
|
||||
if (from_length > 0) {
|
||||
CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1,
|
||||
from, from_length + 1);
|
||||
}
|
||||
}
|
||||
return REAL(strcat)(to, from); // NOLINT
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_length = MaybeRealStrnlen(from, size);
|
||||
uptr copy_length = Min(size, from_length + 1);
|
||||
ASAN_READ_RANGE(from, copy_length);
|
||||
uptr to_length = REAL(strlen)(to);
|
||||
ASAN_READ_RANGE(to, to_length);
|
||||
ASAN_WRITE_RANGE(to + to_length, from_length + 1);
|
||||
if (from_length > 0) {
|
||||
CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
|
||||
from, copy_length);
|
||||
}
|
||||
}
|
||||
return REAL(strncat)(to, from, size);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
|
||||
if (!asan_inited) return internal_strcmp(s1, s2);
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strcmp)(s1, s2);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
unsigned char c1, c2;
|
||||
uptr i;
|
||||
for (i = 0; ; i++) {
|
||||
c1 = (unsigned char)s1[i];
|
||||
c2 = (unsigned char)s2[i];
|
||||
if (c1 != c2 || c1 == '\0') break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, i + 1);
|
||||
ASAN_READ_RANGE(s2, i + 1);
|
||||
return CharCmp(c1, c2);
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
|
||||
#endif
|
||||
// strcpy is called from malloc_default_purgeable_zone()
|
||||
// in __asan::ReplaceSystemAlloc() on Mac.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strcpy)(to, from); // NOLINT
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_size = REAL(strlen)(from) + 1;
|
||||
CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
|
||||
ASAN_READ_RANGE(from, from_size);
|
||||
ASAN_WRITE_RANGE(to, from_size);
|
||||
}
|
||||
return REAL(strcpy)(to, from); // NOLINT
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
INTERCEPTOR(char*, strdup, const char *s) {
|
||||
if (!asan_inited) return internal_strdup(s);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr length = REAL(strlen)(s);
|
||||
ASAN_READ_RANGE(s, length + 1);
|
||||
}
|
||||
return REAL(strdup)(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(uptr, strlen, const char *s) {
|
||||
if (!asan_inited) return internal_strlen(s);
|
||||
// strlen is called from malloc_default_purgeable_zone()
|
||||
// in __asan::ReplaceSystemAlloc() on Mac.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strlen)(s);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
uptr length = REAL(strlen)(s);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(s, length + 1);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
|
||||
INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
|
||||
ENSURE_ASAN_INITED();
|
||||
unsigned char c1, c2;
|
||||
uptr i;
|
||||
for (i = 0; ; i++) {
|
||||
c1 = (unsigned char)s1[i];
|
||||
c2 = (unsigned char)s2[i];
|
||||
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, i + 1);
|
||||
ASAN_READ_RANGE(s2, i + 1);
|
||||
return CharCaseCmp(c1, c2);
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, uptr n) {
|
||||
ENSURE_ASAN_INITED();
|
||||
unsigned char c1 = 0, c2 = 0;
|
||||
uptr i;
|
||||
for (i = 0; i < n; i++) {
|
||||
c1 = (unsigned char)s1[i];
|
||||
c2 = (unsigned char)s2[i];
|
||||
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, Min(i + 1, n));
|
||||
ASAN_READ_RANGE(s2, Min(i + 1, n));
|
||||
return CharCaseCmp(c1, c2);
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
|
||||
|
||||
INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
|
||||
if (!asan_inited) return internal_strncmp(s1, s2, size);
|
||||
// strncmp is called from malloc_default_purgeable_zone()
|
||||
// in __asan::ReplaceSystemAlloc() on Mac.
|
||||
if (asan_init_is_running) {
|
||||
return REAL(strncmp)(s1, s2, size);
|
||||
}
|
||||
ENSURE_ASAN_INITED();
|
||||
unsigned char c1 = 0, c2 = 0;
|
||||
uptr i;
|
||||
for (i = 0; i < size; i++) {
|
||||
c1 = (unsigned char)s1[i];
|
||||
c2 = (unsigned char)s2[i];
|
||||
if (c1 != c2 || c1 == '\0') break;
|
||||
}
|
||||
ASAN_READ_RANGE(s1, Min(i + 1, size));
|
||||
ASAN_READ_RANGE(s2, Min(i + 1, size));
|
||||
return CharCmp(c1, c2);
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
|
||||
CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
|
||||
ASAN_READ_RANGE(from, from_size);
|
||||
ASAN_WRITE_RANGE(to, size);
|
||||
}
|
||||
return REAL(strncpy)(to, from, size);
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
|
||||
ENSURE_ASAN_INITED();
|
||||
uptr length = REAL(strnlen)(s, maxlen);
|
||||
if (flags()->replace_str) {
|
||||
ASAN_READ_RANGE(s, Min(length + 1, maxlen));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_STRNLEN
|
||||
|
||||
static inline bool IsValidStrtolBase(int base) {
|
||||
return (base == 0) || (2 <= base && base <= 36);
|
||||
}
|
||||
|
||||
static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) {
|
||||
CHECK(endptr != 0);
|
||||
if (nptr == *endptr) {
|
||||
// No digits were found at strtol call, we need to find out the last
|
||||
// symbol accessed by strtoll on our own.
|
||||
// We get this symbol by skipping leading blanks and optional +/- sign.
|
||||
while (IsSpace(*nptr)) nptr++;
|
||||
if (*nptr == '+' || *nptr == '-') nptr++;
|
||||
*endptr = (char*)nptr;
|
||||
}
|
||||
CHECK(*endptr >= nptr);
|
||||
}
|
||||
|
||||
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(strtol)(nptr, endptr, base);
|
||||
}
|
||||
char *real_endptr;
|
||||
long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
|
||||
if (endptr != 0) {
|
||||
*endptr = real_endptr;
|
||||
}
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, atoi, const char *nptr) {
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
if (!asan_inited) return REAL(atoi)(nptr);
|
||||
#endif
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(atoi)(nptr);
|
||||
}
|
||||
char *real_endptr;
|
||||
// "man atoi" tells that behavior of atoi(nptr) is the same as
|
||||
// strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
|
||||
// parsed integer can't be stored in *long* type (even if it's
|
||||
// different from int). So, we just imitate this behavior.
|
||||
int result = REAL(strtol)(nptr, &real_endptr, 10);
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
if (!asan_inited) return REAL(atol)(nptr);
|
||||
#endif
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(atol)(nptr);
|
||||
}
|
||||
char *real_endptr;
|
||||
long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
|
||||
char **endptr, int base) {
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(strtoll)(nptr, endptr, base);
|
||||
}
|
||||
char *real_endptr;
|
||||
long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
|
||||
if (endptr != 0) {
|
||||
*endptr = real_endptr;
|
||||
}
|
||||
// If base has unsupported value, strtoll can exit with EINVAL
|
||||
// without reading any characters. So do additional checks only
|
||||
// if base is valid.
|
||||
if (IsValidStrtolBase(base)) {
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
|
||||
ENSURE_ASAN_INITED();
|
||||
if (!flags()->replace_str) {
|
||||
return REAL(atoll)(nptr);
|
||||
}
|
||||
char *real_endptr;
|
||||
long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
|
||||
FixRealStrtolEndptr(nptr, &real_endptr);
|
||||
ASAN_READ_RANGE(nptr, (real_endptr - nptr) + 1);
|
||||
return result;
|
||||
}
|
||||
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
|
||||
#define ASAN_INTERCEPT_FUNC(name) do { \
|
||||
if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
|
||||
Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
|
||||
} while (0)
|
||||
|
||||
#if defined(_WIN32)
|
||||
INTERCEPTOR_WINAPI(DWORD, CreateThread,
|
||||
void* security, uptr stack_size,
|
||||
DWORD (__stdcall *start_routine)(void*), void* arg,
|
||||
DWORD flags, void* tid) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
|
||||
asanThreadRegistry().RegisterThread(t);
|
||||
return REAL(CreateThread)(security, stack_size,
|
||||
asan_thread_start, t, flags, tid);
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
void InitializeWindowsInterceptors() {
|
||||
ASAN_INTERCEPT_FUNC(CreateThread);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
#endif
|
||||
|
||||
// ---------------------- InitializeAsanInterceptors ---------------- {{{1
|
||||
namespace __asan {
|
||||
void InitializeAsanInterceptors() {
|
||||
static bool was_called_once;
|
||||
CHECK(was_called_once == false);
|
||||
was_called_once = true;
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
return;
|
||||
#endif
|
||||
// Intercept mem* functions.
|
||||
ASAN_INTERCEPT_FUNC(memcmp);
|
||||
ASAN_INTERCEPT_FUNC(memmove);
|
||||
ASAN_INTERCEPT_FUNC(memset);
|
||||
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
|
||||
ASAN_INTERCEPT_FUNC(memcpy);
|
||||
} else {
|
||||
#if !MAC_INTERPOSE_FUNCTIONS
|
||||
// If we're using dynamic interceptors on Mac, these two are just plain
|
||||
// functions.
|
||||
internal_memcpy(&REAL(memcpy), &REAL(memmove), sizeof(REAL(memmove)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Intercept str* functions.
|
||||
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(strchr);
|
||||
ASAN_INTERCEPT_FUNC(strcmp);
|
||||
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(strlen);
|
||||
ASAN_INTERCEPT_FUNC(strncat);
|
||||
ASAN_INTERCEPT_FUNC(strncmp);
|
||||
ASAN_INTERCEPT_FUNC(strncpy);
|
||||
#if ASAN_INTERCEPT_STRCASECMP_AND_STRNCASECMP
|
||||
ASAN_INTERCEPT_FUNC(strcasecmp);
|
||||
ASAN_INTERCEPT_FUNC(strncasecmp);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
ASAN_INTERCEPT_FUNC(strdup);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_STRNLEN
|
||||
ASAN_INTERCEPT_FUNC(strnlen);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_INDEX
|
||||
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
|
||||
ASAN_INTERCEPT_FUNC(index);
|
||||
# else
|
||||
CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ASAN_INTERCEPT_FUNC(atoi);
|
||||
ASAN_INTERCEPT_FUNC(atol);
|
||||
ASAN_INTERCEPT_FUNC(strtol);
|
||||
#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
|
||||
ASAN_INTERCEPT_FUNC(atoll);
|
||||
ASAN_INTERCEPT_FUNC(strtoll);
|
||||
#endif
|
||||
|
||||
#if ASAN_INTERCEPT_MLOCKX
|
||||
// Intercept mlock/munlock.
|
||||
ASAN_INTERCEPT_FUNC(mlock);
|
||||
ASAN_INTERCEPT_FUNC(munlock);
|
||||
ASAN_INTERCEPT_FUNC(mlockall);
|
||||
ASAN_INTERCEPT_FUNC(munlockall);
|
||||
#endif
|
||||
|
||||
// Intecept signal- and jump-related functions.
|
||||
ASAN_INTERCEPT_FUNC(longjmp);
|
||||
#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
ASAN_INTERCEPT_FUNC(sigaction);
|
||||
ASAN_INTERCEPT_FUNC(signal);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT__LONGJMP
|
||||
ASAN_INTERCEPT_FUNC(_longjmp);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_SIGLONGJMP
|
||||
ASAN_INTERCEPT_FUNC(siglongjmp);
|
||||
#endif
|
||||
|
||||
// Intercept exception handling functions.
|
||||
#if ASAN_INTERCEPT___CXA_THROW
|
||||
INTERCEPT_FUNCTION(__cxa_throw);
|
||||
#endif
|
||||
|
||||
// Intercept threading-related functions
|
||||
#if ASAN_INTERCEPT_PTHREAD_CREATE
|
||||
ASAN_INTERCEPT_FUNC(pthread_create);
|
||||
#endif
|
||||
|
||||
// Some Windows-specific interceptors.
|
||||
#if defined(_WIN32)
|
||||
InitializeWindowsInterceptors();
|
||||
#endif
|
||||
|
||||
// Some Mac-specific interceptors.
|
||||
#if defined(__APPLE__)
|
||||
InitializeMacInterceptors();
|
||||
#endif
|
||||
|
||||
if (flags()->verbosity > 0) {
|
||||
Report("AddressSanitizer: libc interceptors initialized\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
39
libsanitizer/asan/asan_interceptors.h
Normal file
39
libsanitizer/asan/asan_interceptors.h
Normal file
@ -0,0 +1,39 @@
|
||||
//===-- asan_interceptors.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_interceptors.cc
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_INTERCEPTORS_H
|
||||
#define ASAN_INTERCEPTORS_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "interception/interception.h"
|
||||
|
||||
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
|
||||
DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
|
||||
DECLARE_REAL(void*, memset, void *block, int c, uptr size)
|
||||
DECLARE_REAL(char*, strchr, const char *str, int c)
|
||||
DECLARE_REAL(uptr, strlen, const char *s)
|
||||
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
|
||||
DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
|
||||
DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
|
||||
struct sigaction;
|
||||
DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializeAsanInterceptors();
|
||||
#if defined(__APPLE__)
|
||||
void InitializeMacInterceptors();
|
||||
#endif // __APPLE__
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_INTERCEPTORS_H
|
169
libsanitizer/asan/asan_internal.h
Normal file
169
libsanitizer/asan/asan_internal.h
Normal file
@ -0,0 +1,169 @@
|
||||
//===-- asan_internal.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header which defines various general utilities.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_INTERNAL_H
|
||||
#define ASAN_INTERNAL_H
|
||||
|
||||
#include "asan_flags.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
|
||||
# error "This operating system is not supported by AddressSanitizer"
|
||||
#endif
|
||||
|
||||
#define ASAN_DEFAULT_FAILURE_EXITCODE 1
|
||||
|
||||
#if defined(__linux__)
|
||||
# define ASAN_LINUX 1
|
||||
#else
|
||||
# define ASAN_LINUX 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ASAN_MAC 1
|
||||
#else
|
||||
# define ASAN_MAC 0
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define ASAN_WINDOWS 1
|
||||
#else
|
||||
# define ASAN_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
# define ASAN_ANDROID 1
|
||||
#else
|
||||
# define ASAN_ANDROID 0
|
||||
#endif
|
||||
|
||||
|
||||
#define ASAN_POSIX (ASAN_LINUX || ASAN_MAC)
|
||||
|
||||
#if __has_feature(address_sanitizer)
|
||||
# error "The AddressSanitizer run-time should not be"
|
||||
" instrumented by AddressSanitizer"
|
||||
#endif
|
||||
|
||||
// Build-time configuration options.
|
||||
|
||||
// If set, asan will install its own SEGV signal handler.
|
||||
#ifndef ASAN_NEEDS_SEGV
|
||||
# if ASAN_ANDROID == 1
|
||||
# define ASAN_NEEDS_SEGV 0
|
||||
# else
|
||||
# define ASAN_NEEDS_SEGV 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// If set, asan will intercept C++ exception api call(s).
|
||||
#ifndef ASAN_HAS_EXCEPTIONS
|
||||
# define ASAN_HAS_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
// If set, asan uses the values of SHADOW_SCALE and SHADOW_OFFSET
|
||||
// provided by the instrumented objects. Otherwise constants are used.
|
||||
#ifndef ASAN_FLEXIBLE_MAPPING_AND_OFFSET
|
||||
# define ASAN_FLEXIBLE_MAPPING_AND_OFFSET 0
|
||||
#endif
|
||||
|
||||
// If set, values like allocator chunk size, as well as defaults for some flags
|
||||
// will be changed towards less memory overhead.
|
||||
#ifndef ASAN_LOW_MEMORY
|
||||
# ifdef ASAN_ANDROID
|
||||
# define ASAN_LOW_MEMORY 1
|
||||
# else
|
||||
# define ASAN_LOW_MEMORY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// All internal functions in asan reside inside the __asan namespace
|
||||
// to avoid namespace collisions with the user programs.
|
||||
// Seperate namespace also makes it simpler to distinguish the asan run-time
|
||||
// functions from the instrumented user code in a profile.
|
||||
namespace __asan {
|
||||
|
||||
class AsanThread;
|
||||
using __sanitizer::StackTrace;
|
||||
|
||||
// asan_rtl.cc
|
||||
void NORETURN ShowStatsAndAbort();
|
||||
|
||||
void ReplaceOperatorsNewAndDelete();
|
||||
// asan_malloc_linux.cc / asan_malloc_mac.cc
|
||||
void ReplaceSystemMalloc();
|
||||
|
||||
// asan_linux.cc / asan_mac.cc / asan_win.cc
|
||||
void *AsanDoesNotSupportStaticLinkage();
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
|
||||
|
||||
void MaybeReexec();
|
||||
bool AsanInterceptsSignal(int signum);
|
||||
void SetAlternateSignalStack();
|
||||
void UnsetAlternateSignalStack();
|
||||
void InstallSignalHandlers();
|
||||
void AsanPlatformThreadInit();
|
||||
|
||||
// Wrapper for TLS/TSD.
|
||||
void AsanTSDInit(void (*destructor)(void *tsd));
|
||||
void *AsanTSDGet();
|
||||
void AsanTSDSet(void *tsd);
|
||||
|
||||
void AppendToErrorMessageBuffer(const char *buffer);
|
||||
|
||||
// asan_poisoning.cc
|
||||
// Poisons the shadow memory for "size" bytes starting from "addr".
|
||||
void PoisonShadow(uptr addr, uptr size, u8 value);
|
||||
// Poisons the shadow memory for "redzone_size" bytes starting from
|
||||
// "addr + size".
|
||||
void PoisonShadowPartialRightRedzone(uptr addr,
|
||||
uptr size,
|
||||
uptr redzone_size,
|
||||
u8 value);
|
||||
|
||||
// Platfrom-specific options.
|
||||
#ifdef __APPLE__
|
||||
bool PlatformHasDifferentMemcpyAndMemmove();
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
|
||||
(PlatformHasDifferentMemcpyAndMemmove())
|
||||
#else
|
||||
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
|
||||
#endif // __APPLE__
|
||||
|
||||
extern int asan_inited;
|
||||
// Used to avoid infinite recursion in __asan_init().
|
||||
extern bool asan_init_is_running;
|
||||
extern void (*death_callback)(void);
|
||||
|
||||
// These magic values are written to shadow for better error reporting.
|
||||
const int kAsanHeapLeftRedzoneMagic = 0xfa;
|
||||
const int kAsanHeapRightRedzoneMagic = 0xfb;
|
||||
const int kAsanHeapFreeMagic = 0xfd;
|
||||
const int kAsanStackLeftRedzoneMagic = 0xf1;
|
||||
const int kAsanStackMidRedzoneMagic = 0xf2;
|
||||
const int kAsanStackRightRedzoneMagic = 0xf3;
|
||||
const int kAsanStackPartialRedzoneMagic = 0xf4;
|
||||
const int kAsanStackAfterReturnMagic = 0xf5;
|
||||
const int kAsanInitializationOrderMagic = 0xf6;
|
||||
const int kAsanUserPoisonedMemoryMagic = 0xf7;
|
||||
const int kAsanGlobalRedzoneMagic = 0xf9;
|
||||
const int kAsanInternalHeapMagic = 0xfe;
|
||||
|
||||
static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
|
||||
static const uptr kRetiredStackFrameMagic = 0x45E0360E;
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_INTERNAL_H
|
150
libsanitizer/asan/asan_linux.cc
Normal file
150
libsanitizer/asan/asan_linux.cc
Normal file
@ -0,0 +1,150 @@
|
||||
//===-- asan_linux.cc -----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Linux-specific details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef __linux__
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#if !ASAN_ANDROID
|
||||
// FIXME: where to get ucontext on Android?
|
||||
#include <sys/ucontext.h>
|
||||
#endif
|
||||
|
||||
extern "C" void* _DYNAMIC;
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void MaybeReexec() {
|
||||
// No need to re-exec on Linux.
|
||||
}
|
||||
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
// This will fail to link with -static.
|
||||
return &_DYNAMIC; // defined in link.h
|
||||
}
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
#if ASAN_ANDROID
|
||||
*pc = *sp = *bp = 0;
|
||||
#elif defined(__arm__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.arm_pc;
|
||||
*bp = ucontext->uc_mcontext.arm_fp;
|
||||
*sp = ucontext->uc_mcontext.arm_sp;
|
||||
# elif defined(__x86_64__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
*bp = ucontext->uc_mcontext.gregs[REG_RBP];
|
||||
*sp = ucontext->uc_mcontext.gregs[REG_RSP];
|
||||
# elif defined(__i386__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
|
||||
#else
|
||||
# error "Unsupported arch"
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AsanInterceptsSignal(int signum) {
|
||||
return signum == SIGSEGV && flags()->handle_segv;
|
||||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
// Nothing here for now.
|
||||
}
|
||||
|
||||
AsanLock::AsanLock(LinkerInitialized) {
|
||||
// We assume that pthread_mutex_t initialized to all zeroes is a valid
|
||||
// unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
|
||||
// a gcc warning:
|
||||
// extended initializer lists only available with -std=c++0x or -std=gnu++0x
|
||||
}
|
||||
|
||||
void AsanLock::Lock() {
|
||||
CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
|
||||
pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
|
||||
CHECK(!owner_);
|
||||
owner_ = (uptr)pthread_self();
|
||||
}
|
||||
|
||||
void AsanLock::Unlock() {
|
||||
CHECK(owner_ == (uptr)pthread_self());
|
||||
owner_ = 0;
|
||||
pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
|
||||
}
|
||||
|
||||
#ifdef __arm__
|
||||
#define UNWIND_STOP _URC_END_OF_STACK
|
||||
#define UNWIND_CONTINUE _URC_NO_REASON
|
||||
#else
|
||||
#define UNWIND_STOP _URC_NORMAL_STOP
|
||||
#define UNWIND_CONTINUE _URC_NO_REASON
|
||||
#endif
|
||||
|
||||
uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
|
||||
#ifdef __arm__
|
||||
uptr val;
|
||||
_Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
|
||||
15 /* r15 = PC */, _UVRSD_UINT32, &val);
|
||||
CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
|
||||
// Clear the Thumb bit.
|
||||
return val & ~(uptr)1;
|
||||
#else
|
||||
return _Unwind_GetIP(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
|
||||
void *param) {
|
||||
StackTrace *b = (StackTrace*)param;
|
||||
CHECK(b->size < b->max_size);
|
||||
uptr pc = Unwind_GetIP(ctx);
|
||||
b->trace[b->size++] = pc;
|
||||
if (b->size == b->max_size) return UNWIND_STOP;
|
||||
return UNWIND_CONTINUE;
|
||||
}
|
||||
|
||||
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
||||
stack->size = 0;
|
||||
stack->trace[0] = pc;
|
||||
if ((max_s) > 1) {
|
||||
stack->max_size = max_s;
|
||||
#ifdef __arm__
|
||||
_Unwind_Backtrace(Unwind_Trace, stack);
|
||||
#else
|
||||
if (!asan_inited) return;
|
||||
if (AsanThread *t = asanThreadRegistry().GetCurrent())
|
||||
stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // __linux__
|
40
libsanitizer/asan/asan_lock.h
Normal file
40
libsanitizer/asan/asan_lock.h
Normal file
@ -0,0 +1,40 @@
|
||||
//===-- asan_lock.h ---------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// A wrapper for a simple lock.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_LOCK_H
|
||||
#define ASAN_LOCK_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_mutex.h"
|
||||
#include "asan_internal.h"
|
||||
|
||||
// The locks in ASan are global objects and they are never destroyed to avoid
|
||||
// at-exit races (that is, a lock is being used by other threads while the main
|
||||
// thread is doing atexit destructors).
|
||||
// We define the class using opaque storage to avoid including system headers.
|
||||
|
||||
namespace __asan {
|
||||
|
||||
class AsanLock {
|
||||
public:
|
||||
explicit AsanLock(LinkerInitialized);
|
||||
void Lock();
|
||||
void Unlock();
|
||||
bool IsLocked() { return owner_ != 0; }
|
||||
private:
|
||||
uptr opaque_storage_[10];
|
||||
uptr owner_; // for debugging and for malloc_introspection_t interface
|
||||
};
|
||||
|
||||
typedef GenericScopedLock<AsanLock> ScopedLock;
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_LOCK_H
|
526
libsanitizer/asan/asan_mac.cc
Normal file
526
libsanitizer/asan/asan_mac.cc
Normal file
@ -0,0 +1,526 @@
|
||||
//===-- asan_mac.cc -------------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mac.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
#include <crt_externs.h> // for _NSGetArgv
|
||||
#include <dlfcn.h> // for dladdr()
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h> // for free()
|
||||
#include <unistd.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
# if __WORDSIZE == 64
|
||||
*pc = ucontext->uc_mcontext->__ss.__rip;
|
||||
*bp = ucontext->uc_mcontext->__ss.__rbp;
|
||||
*sp = ucontext->uc_mcontext->__ss.__rsp;
|
||||
# else
|
||||
*pc = ucontext->uc_mcontext->__ss.__eip;
|
||||
*bp = ucontext->uc_mcontext->__ss.__ebp;
|
||||
*sp = ucontext->uc_mcontext->__ss.__esp;
|
||||
# endif // __WORDSIZE
|
||||
}
|
||||
|
||||
int GetMacosVersion() {
|
||||
int mib[2] = { CTL_KERN, KERN_OSRELEASE };
|
||||
char version[100];
|
||||
uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
|
||||
for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
|
||||
// Get the version length.
|
||||
CHECK(sysctl(mib, 2, 0, &len, 0, 0) != -1);
|
||||
CHECK(len < maxlen);
|
||||
CHECK(sysctl(mib, 2, version, &len, 0, 0) != -1);
|
||||
switch (version[0]) {
|
||||
case '9': return MACOS_VERSION_LEOPARD;
|
||||
case '1': {
|
||||
switch (version[1]) {
|
||||
case '0': return MACOS_VERSION_SNOW_LEOPARD;
|
||||
case '1': return MACOS_VERSION_LION;
|
||||
default: return MACOS_VERSION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
default: return MACOS_VERSION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlatformHasDifferentMemcpyAndMemmove() {
|
||||
// On OS X 10.7 memcpy() and memmove() are both resolved
|
||||
// into memmove$VARIANT$sse42.
|
||||
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=34.
|
||||
// TODO(glider): need to check dynamically that memcpy() and memmove() are
|
||||
// actually the same function.
|
||||
return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void __asan_init();
|
||||
|
||||
static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
|
||||
|
||||
void MaybeReexec() {
|
||||
if (!flags()->allow_reexec) return;
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
// If the program is linked with the dynamic ASan runtime library, make sure
|
||||
// the library is preloaded so that the wrappers work. If it is not, set
|
||||
// DYLD_INSERT_LIBRARIES and re-exec ourselves.
|
||||
Dl_info info;
|
||||
CHECK(dladdr((void*)((uptr)__asan_init), &info));
|
||||
const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
|
||||
if (!dyld_insert_libraries ||
|
||||
!REAL(strstr)(dyld_insert_libraries, info.dli_fname)) {
|
||||
// DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
|
||||
// library.
|
||||
char program_name[1024];
|
||||
uint32_t buf_size = sizeof(program_name);
|
||||
_NSGetExecutablePath(program_name, &buf_size);
|
||||
// Ok to use setenv() since the wrappers don't depend on the value of
|
||||
// asan_inited.
|
||||
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
|
||||
if (flags()->verbosity >= 1) {
|
||||
Report("exec()-ing the program with\n");
|
||||
Report("%s=%s\n", kDyldInsertLibraries, info.dli_fname);
|
||||
Report("to enable ASan wrappers.\n");
|
||||
Report("Set ASAN_OPTIONS=allow_reexec=0 to disable this.\n");
|
||||
}
|
||||
execv(program_name, *_NSGetArgv());
|
||||
}
|
||||
#endif // MAC_INTERPOSE_FUNCTIONS
|
||||
// If we're not using the dynamic runtime, do nothing.
|
||||
}
|
||||
|
||||
// No-op. Mac does not support static linkage anyway.
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AsanInterceptsSignal(int signum) {
|
||||
return (signum == SIGSEGV || signum == SIGBUS) && flags()->handle_segv;
|
||||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
ReplaceCFAllocator();
|
||||
}
|
||||
|
||||
AsanLock::AsanLock(LinkerInitialized) {
|
||||
// We assume that OS_SPINLOCK_INIT is zero
|
||||
}
|
||||
|
||||
void AsanLock::Lock() {
|
||||
CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
|
||||
CHECK(OS_SPINLOCK_INIT == 0);
|
||||
CHECK(owner_ != (uptr)pthread_self());
|
||||
OSSpinLockLock((OSSpinLock*)&opaque_storage_);
|
||||
CHECK(!owner_);
|
||||
owner_ = (uptr)pthread_self();
|
||||
}
|
||||
|
||||
void AsanLock::Unlock() {
|
||||
CHECK(owner_ == (uptr)pthread_self());
|
||||
owner_ = 0;
|
||||
OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
|
||||
}
|
||||
|
||||
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
||||
stack->size = 0;
|
||||
stack->trace[0] = pc;
|
||||
if ((max_s) > 1) {
|
||||
stack->max_size = max_s;
|
||||
if (!asan_inited) return;
|
||||
if (AsanThread *t = asanThreadRegistry().GetCurrent())
|
||||
stack->FastUnwindStack(pc, bp, t->stack_top(), t->stack_bottom());
|
||||
}
|
||||
}
|
||||
|
||||
// The range of pages to be used for escape islands.
|
||||
// TODO(glider): instead of mapping a fixed range we must find a range of
|
||||
// unmapped pages in vmmap and take them.
|
||||
// These constants were chosen empirically and may not work if the shadow
|
||||
// memory layout changes. Unfortunately they do necessarily depend on
|
||||
// kHighMemBeg or kHighMemEnd.
|
||||
static void *island_allocator_pos = 0;
|
||||
|
||||
#if __WORDSIZE == 32
|
||||
# define kIslandEnd (0xffdf0000 - kPageSize)
|
||||
# define kIslandBeg (kIslandEnd - 256 * kPageSize)
|
||||
#else
|
||||
# define kIslandEnd (0x7fffffdf0000 - kPageSize)
|
||||
# define kIslandBeg (kIslandEnd - 256 * kPageSize)
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
mach_error_t __interception_allocate_island(void **ptr,
|
||||
uptr unused_size,
|
||||
void *unused_hint) {
|
||||
if (!island_allocator_pos) {
|
||||
island_allocator_pos =
|
||||
internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
|
||||
-1, 0);
|
||||
if (island_allocator_pos != (void*)kIslandBeg) {
|
||||
return KERN_NO_SPACE;
|
||||
}
|
||||
if (flags()->verbosity) {
|
||||
Report("Mapped pages %p--%p for branch islands.\n",
|
||||
(void*)kIslandBeg, (void*)kIslandEnd);
|
||||
}
|
||||
// Should not be very performance-critical.
|
||||
internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg);
|
||||
};
|
||||
*ptr = island_allocator_pos;
|
||||
island_allocator_pos = (char*)island_allocator_pos + kPageSize;
|
||||
if (flags()->verbosity) {
|
||||
Report("Branch island allocated at %p\n", *ptr);
|
||||
}
|
||||
return err_none;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
mach_error_t __interception_deallocate_island(void *ptr) {
|
||||
// Do nothing.
|
||||
// TODO(glider): allow to free and reuse the island memory.
|
||||
return err_none;
|
||||
}
|
||||
|
||||
// Support for the following functions from libdispatch on Mac OS:
|
||||
// dispatch_async_f()
|
||||
// dispatch_async()
|
||||
// dispatch_sync_f()
|
||||
// dispatch_sync()
|
||||
// dispatch_after_f()
|
||||
// dispatch_after()
|
||||
// dispatch_group_async_f()
|
||||
// dispatch_group_async()
|
||||
// TODO(glider): libdispatch API contains other functions that we don't support
|
||||
// yet.
|
||||
//
|
||||
// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
|
||||
// they can cause jobs to run on a thread different from the current one.
|
||||
// TODO(glider): if so, we need a test for this (otherwise we should remove
|
||||
// them).
|
||||
//
|
||||
// The following functions use dispatch_barrier_async_f() (which isn't a library
|
||||
// function but is exported) and are thus supported:
|
||||
// dispatch_source_set_cancel_handler_f()
|
||||
// dispatch_source_set_cancel_handler()
|
||||
// dispatch_source_set_event_handler_f()
|
||||
// dispatch_source_set_event_handler()
|
||||
//
|
||||
// The reference manual for Grand Central Dispatch is available at
|
||||
// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
|
||||
// The implementation details are at
|
||||
// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
|
||||
|
||||
typedef void* pthread_workqueue_t;
|
||||
typedef void* pthread_workitem_handle_t;
|
||||
|
||||
typedef void* dispatch_group_t;
|
||||
typedef void* dispatch_queue_t;
|
||||
typedef void* dispatch_source_t;
|
||||
typedef u64 dispatch_time_t;
|
||||
typedef void (*dispatch_function_t)(void *block);
|
||||
typedef void* (*worker_t)(void *block);
|
||||
|
||||
// A wrapper for the ObjC blocks used to support libdispatch.
|
||||
typedef struct {
|
||||
void *block;
|
||||
dispatch_function_t func;
|
||||
u32 parent_tid;
|
||||
} asan_block_context_t;
|
||||
|
||||
// We use extern declarations of libdispatch functions here instead
|
||||
// of including <dispatch/dispatch.h>. This header is not present on
|
||||
// Mac OS X Leopard and eariler, and although we don't expect ASan to
|
||||
// work on legacy systems, it's bad to break the build of
|
||||
// LLVM compiler-rt there.
|
||||
extern "C" {
|
||||
void dispatch_async_f(dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func);
|
||||
void dispatch_sync_f(dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func);
|
||||
void dispatch_after_f(dispatch_time_t when, dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func);
|
||||
void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func);
|
||||
void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t dq,
|
||||
void *ctxt, dispatch_function_t func);
|
||||
int pthread_workqueue_additem_np(pthread_workqueue_t workq,
|
||||
void *(*workitem_func)(void *), void * workitem_arg,
|
||||
pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp);
|
||||
} // extern "C"
|
||||
|
||||
static ALWAYS_INLINE
|
||||
void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
|
||||
AsanThread *t = asanThreadRegistry().GetCurrent();
|
||||
if (!t) {
|
||||
t = AsanThread::Create(parent_tid, 0, 0, stack);
|
||||
asanThreadRegistry().RegisterThread(t);
|
||||
t->Init();
|
||||
asanThreadRegistry().SetCurrent(t);
|
||||
}
|
||||
}
|
||||
|
||||
// For use by only those functions that allocated the context via
|
||||
// alloc_asan_context().
|
||||
extern "C"
|
||||
void asan_dispatch_call_block_and_release(void *block) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
asan_block_context_t *context = (asan_block_context_t*)block;
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("asan_dispatch_call_block_and_release(): "
|
||||
"context: %p, pthread_self: %p\n",
|
||||
block, pthread_self());
|
||||
}
|
||||
asan_register_worker_thread(context->parent_tid, &stack);
|
||||
// Call the original dispatcher for the block.
|
||||
context->func(context->block);
|
||||
asan_free(context, &stack);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// Wrap |ctxt| and |func| into an asan_block_context_t.
|
||||
// The caller retains control of the allocated context.
|
||||
extern "C"
|
||||
asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
|
||||
StackTrace *stack) {
|
||||
asan_block_context_t *asan_ctxt =
|
||||
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
|
||||
asan_ctxt->block = ctxt;
|
||||
asan_ctxt->func = func;
|
||||
asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
return asan_ctxt;
|
||||
}
|
||||
|
||||
// Define interceptor for dispatch_*_f function with the three most common
|
||||
// parameters: dispatch_queue_t, context, dispatch_function_t.
|
||||
#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
|
||||
INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
|
||||
dispatch_function_t func) { \
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax); \
|
||||
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
|
||||
if (flags()->verbosity >= 2) { \
|
||||
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
|
||||
asan_ctxt, pthread_self()); \
|
||||
PRINT_CURRENT_STACK(); \
|
||||
} \
|
||||
return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \
|
||||
asan_dispatch_call_block_and_release); \
|
||||
}
|
||||
|
||||
INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
|
||||
INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
|
||||
INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
|
||||
|
||||
INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
|
||||
dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("dispatch_after_f: %p\n", asan_ctxt);
|
||||
PRINT_CURRENT_STACK();
|
||||
}
|
||||
return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt,
|
||||
asan_dispatch_call_block_and_release);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
|
||||
dispatch_queue_t dq, void *ctxt,
|
||||
dispatch_function_t func) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
|
||||
asan_ctxt, pthread_self());
|
||||
PRINT_CURRENT_STACK();
|
||||
}
|
||||
REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt,
|
||||
asan_dispatch_call_block_and_release);
|
||||
}
|
||||
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
// dispatch_async, dispatch_group_async and others tailcall the corresponding
|
||||
// dispatch_*_f functions. When wrapping functions with mach_override, those
|
||||
// dispatch_*_f are intercepted automatically. But with dylib interposition
|
||||
// this does not work, because the calls within the same library are not
|
||||
// interposed.
|
||||
// Therefore we need to re-implement dispatch_async and friends.
|
||||
|
||||
extern "C" {
|
||||
// FIXME: consolidate these declarations with asan_intercepted_functions.h.
|
||||
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
|
||||
void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
|
||||
void(^work)(void));
|
||||
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
|
||||
void(^work)(void));
|
||||
void dispatch_source_set_cancel_handler(dispatch_source_t ds,
|
||||
void(^work)(void));
|
||||
void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void));
|
||||
}
|
||||
|
||||
#define GET_ASAN_BLOCK(work) \
|
||||
void (^asan_block)(void); \
|
||||
int parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); \
|
||||
asan_block = ^(void) { \
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax); \
|
||||
asan_register_worker_thread(parent_tid, &stack); \
|
||||
work(); \
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_async,
|
||||
dispatch_queue_t dq, void(^work)(void)) {
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_async)(dq, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_group_async,
|
||||
dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) {
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_group_async)(dg, dq, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_after,
|
||||
dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) {
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_after)(when, queue, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_source_set_cancel_handler,
|
||||
dispatch_source_t ds, void(^work)(void)) {
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_source_set_cancel_handler)(ds, asan_block);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, dispatch_source_set_event_handler,
|
||||
dispatch_source_t ds, void(^work)(void)) {
|
||||
GET_ASAN_BLOCK(work);
|
||||
REAL(dispatch_source_set_event_handler)(ds, asan_block);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The following stuff has been extremely helpful while looking for the
|
||||
// unhandled functions that spawned jobs on Chromium shutdown. If the verbosity
|
||||
// level is 2 or greater, we wrap pthread_workqueue_additem_np() in order to
|
||||
// find the points of worker thread creation (each of such threads may be used
|
||||
// to run several tasks, that's why this is not enough to support the whole
|
||||
// libdispatch API.
|
||||
extern "C"
|
||||
void *wrap_workitem_func(void *arg) {
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("wrap_workitem_func: %p, pthread_self: %p\n", arg, pthread_self());
|
||||
}
|
||||
asan_block_context_t *ctxt = (asan_block_context_t*)arg;
|
||||
worker_t fn = (worker_t)(ctxt->func);
|
||||
void *result = fn(ctxt->block);
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
asan_free(arg, &stack);
|
||||
return result;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, pthread_workqueue_additem_np, pthread_workqueue_t workq,
|
||||
void *(*workitem_func)(void *), void * workitem_arg,
|
||||
pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) {
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax);
|
||||
asan_block_context_t *asan_ctxt =
|
||||
(asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack);
|
||||
asan_ctxt->block = workitem_arg;
|
||||
asan_ctxt->func = (dispatch_function_t)workitem_func;
|
||||
asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("pthread_workqueue_additem_np: %p\n", asan_ctxt);
|
||||
PRINT_CURRENT_STACK();
|
||||
}
|
||||
return REAL(pthread_workqueue_additem_np)(workq, wrap_workitem_func,
|
||||
asan_ctxt, itemhandlep,
|
||||
gencountp);
|
||||
}
|
||||
|
||||
// See http://opensource.apple.com/source/CF/CF-635.15/CFString.c
|
||||
int __CFStrIsConstant(CFStringRef str) {
|
||||
CFRuntimeBase *base = (CFRuntimeBase*)str;
|
||||
#if __LP64__
|
||||
return base->_rc == 0;
|
||||
#else
|
||||
return (base->_cfinfo[CF_RC_BITS]) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
INTERCEPTOR(CFStringRef, CFStringCreateCopy, CFAllocatorRef alloc,
|
||||
CFStringRef str) {
|
||||
if (__CFStrIsConstant(str)) {
|
||||
return str;
|
||||
} else {
|
||||
return REAL(CFStringCreateCopy)(alloc, str);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
|
||||
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void, __CFInitialize, void)
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void InitializeMacInterceptors() {
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
|
||||
CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
|
||||
// We don't need to intercept pthread_workqueue_additem_np() to support the
|
||||
// libdispatch API, but it helps us to debug the unsupported functions. Let's
|
||||
// intercept it only during verbose runs.
|
||||
if (flags()->verbosity >= 2) {
|
||||
CHECK(INTERCEPT_FUNCTION(pthread_workqueue_additem_np));
|
||||
}
|
||||
// Normally CFStringCreateCopy should not copy constant CF strings.
|
||||
// Replacing the default CFAllocator causes constant strings to be copied
|
||||
// rather than just returned, which leads to bugs in big applications like
|
||||
// Chromium and WebKit, see
|
||||
// http://code.google.com/p/address-sanitizer/issues/detail?id=10
|
||||
// Until this problem is fixed we need to check that the string is
|
||||
// non-constant before calling CFStringCreateCopy.
|
||||
CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy));
|
||||
// Some of the library functions call free() directly, so we have to
|
||||
// intercept it.
|
||||
CHECK(INTERCEPT_FUNCTION(free));
|
||||
if (flags()->replace_cfallocator) {
|
||||
CHECK(INTERCEPT_FUNCTION(__CFInitialize));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // __APPLE__
|
54
libsanitizer/asan/asan_mac.h
Normal file
54
libsanitizer/asan/asan_mac.h
Normal file
@ -0,0 +1,54 @@
|
||||
//===-- asan_mac.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific ASan definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_MAC_H
|
||||
#define ASAN_MAC_H
|
||||
|
||||
// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal
|
||||
// and subject to change in further CoreFoundation versions. Apple does not
|
||||
// guarantee any binary compatibility from release to release.
|
||||
|
||||
// See http://opensource.apple.com/source/CF/CF-635.15/CFInternal.h
|
||||
#if defined(__BIG_ENDIAN__)
|
||||
#define CF_RC_BITS 0
|
||||
#endif
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
#define CF_RC_BITS 3
|
||||
#endif
|
||||
|
||||
// See http://opensource.apple.com/source/CF/CF-635.15/CFRuntime.h
|
||||
typedef struct __CFRuntimeBase {
|
||||
uptr _cfisa;
|
||||
u8 _cfinfo[4];
|
||||
#if __LP64__
|
||||
u32 _rc;
|
||||
#endif
|
||||
} CFRuntimeBase;
|
||||
|
||||
enum {
|
||||
MACOS_VERSION_UNKNOWN = 0,
|
||||
MACOS_VERSION_LEOPARD,
|
||||
MACOS_VERSION_SNOW_LEOPARD,
|
||||
MACOS_VERSION_LION
|
||||
};
|
||||
|
||||
// Used by asan_malloc_mac.cc and asan_mac.cc
|
||||
extern "C" void __CFInitialize();
|
||||
|
||||
namespace __asan {
|
||||
|
||||
int GetMacosVersion();
|
||||
void ReplaceCFAllocator();
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_MAC_H
|
142
libsanitizer/asan/asan_malloc_linux.cc
Normal file
142
libsanitizer/asan/asan_malloc_linux.cc
Normal file
@ -0,0 +1,142 @@
|
||||
//===-- asan_malloc_linux.cc ----------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Linux-specific malloc interception.
|
||||
// We simply define functions like malloc, free, realloc, etc.
|
||||
// They will replace the corresponding libc functions automagically.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef __linux__
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
|
||||
#if ASAN_ANDROID
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, calloc, uptr nmemb, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, realloc, void *ptr, uptr size)
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void*, memalign, uptr boundary, uptr size)
|
||||
|
||||
struct MallocDebug {
|
||||
void* (*malloc)(uptr bytes);
|
||||
void (*free)(void* mem);
|
||||
void* (*calloc)(uptr n_elements, uptr elem_size);
|
||||
void* (*realloc)(void* oldMem, uptr bytes);
|
||||
void* (*memalign)(uptr alignment, uptr bytes);
|
||||
};
|
||||
|
||||
const MallocDebug asan_malloc_dispatch ALIGNED(32) = {
|
||||
WRAP(malloc), WRAP(free), WRAP(calloc), WRAP(realloc), WRAP(memalign)
|
||||
};
|
||||
|
||||
extern "C" const MallocDebug* __libc_malloc_dispatch;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
__libc_malloc_dispatch = &asan_malloc_dispatch;
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#else // ANDROID
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
}
|
||||
} // namespace __asan
|
||||
#endif // ANDROID
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
asan_free(ptr, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void, cfree, void *ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
asan_free(ptr, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, malloc, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
if (!asan_inited) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const uptr kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static uptr allocated;
|
||||
uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
allocated += size_in_words;
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_memalign(boundary, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
|
||||
ALIAS("memalign");
|
||||
|
||||
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc_usable_size(ptr, &stack);
|
||||
}
|
||||
|
||||
// We avoid including malloc.h for portability reasons.
|
||||
// man mallinfo says the fields are "long", but the implementation uses int.
|
||||
// It doesn't matter much -- we just need to make sure that the libc's mallinfo
|
||||
// is not called.
|
||||
struct fake_mallinfo {
|
||||
int x[10];
|
||||
};
|
||||
|
||||
INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
|
||||
struct fake_mallinfo res;
|
||||
REAL(memset)(&res, 0, sizeof(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, mallopt, int cmd, int value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
// Printf("posix_memalign: %zx %zu\n", alignment, size);
|
||||
return asan_posix_memalign(memptr, alignment, size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, valloc, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_valloc(size, &stack);
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, pvalloc, uptr size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_pvalloc(size, &stack);
|
||||
}
|
||||
|
||||
#endif // __linux__
|
427
libsanitizer/asan/asan_malloc_mac.cc
Normal file
427
libsanitizer/asan/asan_malloc_mac.cc
Normal file
@ -0,0 +1,427 @@
|
||||
//===-- asan_malloc_mac.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific malloc interception.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <CoreFoundation/CFBase.h>
|
||||
#include <dlfcn.h>
|
||||
#include <malloc/malloc.h>
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mac.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread_registry.h"
|
||||
|
||||
// Similar code is used in Google Perftools,
|
||||
// http://code.google.com/p/google-perftools.
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// TODO(glider): do we need both zones?
|
||||
static malloc_zone_t *system_malloc_zone = 0;
|
||||
static malloc_zone_t *system_purgeable_zone = 0;
|
||||
static malloc_zone_t asan_zone;
|
||||
CFAllocatorRef cf_asan = 0;
|
||||
|
||||
// _CFRuntimeCreateInstance() checks whether the supplied allocator is
|
||||
// kCFAllocatorSystemDefault and, if it is not, stores the allocator reference
|
||||
// at the beginning of the allocated memory and returns the pointer to the
|
||||
// allocated memory plus sizeof(CFAllocatorRef). See
|
||||
// http://www.opensource.apple.com/source/CF/CF-635.21/CFRuntime.c
|
||||
// Pointers returned by _CFRuntimeCreateInstance() can then be passed directly
|
||||
// to free() or CFAllocatorDeallocate(), which leads to false invalid free
|
||||
// reports.
|
||||
// The corresponding rdar bug is http://openradar.appspot.com/radar?id=1796404.
|
||||
void* ALWAYS_INLINE get_saved_cfallocator_ref(void *ptr) {
|
||||
if (flags()->replace_cfallocator) {
|
||||
// Make sure we're not hitting the previous page. This may be incorrect
|
||||
// if ASan's malloc returns an address ending with 0xFF8, which will be
|
||||
// then padded to a page boundary with a CFAllocatorRef.
|
||||
uptr arith_ptr = (uptr)ptr;
|
||||
if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) {
|
||||
CFAllocatorRef *saved =
|
||||
(CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef));
|
||||
if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// The free() implementation provided by OS X calls malloc_zone_from_ptr()
|
||||
// to find the owner of |ptr|. If the result is 0, an invalid free() is
|
||||
// reported. Our implementation falls back to asan_free() in this case
|
||||
// in order to print an ASan-style report.
|
||||
//
|
||||
// For the objects created by _CFRuntimeCreateInstance a CFAllocatorRef is
|
||||
// placed at the beginning of the allocated chunk and the pointer returned by
|
||||
// our allocator is off by sizeof(CFAllocatorRef). This pointer can be then
|
||||
// passed directly to free(), which will lead to errors.
|
||||
// To overcome this we're checking whether |ptr-sizeof(CFAllocatorRef)|
|
||||
// contains a pointer to our CFAllocator (assuming no other allocator is used).
|
||||
// See http://code.google.com/p/address-sanitizer/issues/detail?id=70 for more
|
||||
// info.
|
||||
INTERCEPTOR(void, free, void *ptr) {
|
||||
malloc_zone_t *zone = malloc_zone_from_ptr(ptr);
|
||||
if (zone) {
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
if ((zone->version >= 6) && (zone->free_definite_size)) {
|
||||
zone->free_definite_size(zone, ptr, malloc_size(ptr));
|
||||
} else {
|
||||
malloc_zone_free(zone, ptr);
|
||||
}
|
||||
#else
|
||||
malloc_zone_free(zone, ptr);
|
||||
#endif
|
||||
} else {
|
||||
if (!asan_mz_size(ptr)) ptr = get_saved_cfallocator_ref(ptr);
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
asan_free(ptr, &stack);
|
||||
}
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceCFAllocator();
|
||||
}
|
||||
|
||||
// We can't always replace the default CFAllocator with cf_asan right in
|
||||
// ReplaceSystemMalloc(), because it is sometimes called before
|
||||
// __CFInitialize(), when the default allocator is invalid and replacing it may
|
||||
// crash the program. Instead we wait for the allocator to initialize and jump
|
||||
// in just after __CFInitialize(). Nobody is going to allocate memory using
|
||||
// CFAllocators before that, so we won't miss anything.
|
||||
//
|
||||
// See http://code.google.com/p/address-sanitizer/issues/detail?id=87
|
||||
// and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c
|
||||
INTERCEPTOR(void, __CFInitialize, void) {
|
||||
// If the runtime is built as dynamic library, __CFInitialize wrapper may be
|
||||
// called before __asan_init.
|
||||
#if !MAC_INTERPOSE_FUNCTIONS
|
||||
CHECK(flags()->replace_cfallocator);
|
||||
CHECK(asan_inited);
|
||||
#endif
|
||||
REAL(__CFInitialize)();
|
||||
if (!cf_asan && asan_inited) ReplaceCFAllocator();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO(glider): the mz_* functions should be united with the Linux wrappers,
|
||||
// as they are basically copied from there.
|
||||
size_t mz_size(malloc_zone_t* zone, const void* ptr) {
|
||||
return asan_mz_size(ptr);
|
||||
}
|
||||
|
||||
void *mz_malloc(malloc_zone_t *zone, size_t size) {
|
||||
if (!asan_inited) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_malloc(system_malloc_zone, size);
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
|
||||
if (!asan_inited) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_malloc(system_malloc_zone, size);
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
|
||||
if (!asan_inited) {
|
||||
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
|
||||
const size_t kCallocPoolSize = 1024;
|
||||
static uptr calloc_memory_for_dlsym[kCallocPoolSize];
|
||||
static size_t allocated;
|
||||
size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
|
||||
void *mem = (void*)&calloc_memory_for_dlsym[allocated];
|
||||
allocated += size_in_words;
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
void *mz_valloc(malloc_zone_t *zone, size_t size) {
|
||||
if (!asan_inited) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_valloc(system_malloc_zone, size);
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_memalign(kPageSize, size, &stack);
|
||||
}
|
||||
|
||||
#define GET_ZONE_FOR_PTR(ptr) \
|
||||
malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
|
||||
const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
|
||||
|
||||
void ALWAYS_INLINE free_common(void *context, void *ptr) {
|
||||
if (!ptr) return;
|
||||
if (asan_mz_size(ptr)) {
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
asan_free(ptr, &stack);
|
||||
} else {
|
||||
// If the pointer does not belong to any of the zones, use one of the
|
||||
// fallback methods to free memory.
|
||||
malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr);
|
||||
if (zone_ptr == system_purgeable_zone) {
|
||||
// allocations from malloc_default_purgeable_zone() done before
|
||||
// __asan_init() may be occasionally freed via free_common().
|
||||
// see http://code.google.com/p/address-sanitizer/issues/detail?id=99.
|
||||
malloc_zone_free(zone_ptr, ptr);
|
||||
} else {
|
||||
// If the memory chunk pointer was moved to store additional
|
||||
// CFAllocatorRef, fix it back.
|
||||
ptr = get_saved_cfallocator_ref(ptr);
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
if (!flags()->mac_ignore_invalid_free) {
|
||||
asan_free(ptr, &stack);
|
||||
} else {
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(glider): the allocation callbacks need to be refactored.
|
||||
void mz_free(malloc_zone_t *zone, void *ptr) {
|
||||
free_common(zone, ptr);
|
||||
}
|
||||
|
||||
void cf_free(void *ptr, void *info) {
|
||||
free_common(info, ptr);
|
||||
}
|
||||
|
||||
void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
|
||||
if (!ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
} else {
|
||||
if (asan_mz_size(ptr)) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
} else {
|
||||
// We can't recover from reallocating an unknown address, because
|
||||
// this would require reading at most |size| bytes from
|
||||
// potentially unaccessible memory.
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
|
||||
if (!ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
} else {
|
||||
if (asan_mz_size(ptr)) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
} else {
|
||||
// We can't recover from reallocating an unknown address, because
|
||||
// this would require reading at most |size| bytes from
|
||||
// potentially unaccessible memory.
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
GET_ZONE_FOR_PTR(ptr);
|
||||
ReportMacCfReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mz_destroy(malloc_zone_t* zone) {
|
||||
// A no-op -- we will not be destroyed!
|
||||
Printf("mz_destroy() called -- ignoring\n");
|
||||
}
|
||||
// from AvailabilityMacros.h
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
|
||||
if (!asan_inited) {
|
||||
CHECK(system_malloc_zone);
|
||||
return malloc_zone_memalign(system_malloc_zone, align, size);
|
||||
}
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_memalign(align, size, &stack);
|
||||
}
|
||||
|
||||
// This function is currently unused, and we build with -Werror.
|
||||
#if 0
|
||||
void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
|
||||
// TODO(glider): check that |size| is valid.
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
kern_return_t mi_enumerator(task_t task, void *,
|
||||
unsigned type_mask, vm_address_t zone_address,
|
||||
memory_reader_t reader,
|
||||
vm_range_recorder_t recorder) {
|
||||
// Should enumerate all the pointers we have. Seems like a lot of work.
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
size_t mi_good_size(malloc_zone_t *zone, size_t size) {
|
||||
// I think it's always safe to return size, but we maybe could do better.
|
||||
return size;
|
||||
}
|
||||
|
||||
boolean_t mi_check(malloc_zone_t *zone) {
|
||||
UNIMPLEMENTED();
|
||||
return true;
|
||||
}
|
||||
|
||||
void mi_print(malloc_zone_t *zone, boolean_t verbose) {
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
void mi_log(malloc_zone_t *zone, void *address) {
|
||||
// I don't think we support anything like this
|
||||
}
|
||||
|
||||
void mi_force_lock(malloc_zone_t *zone) {
|
||||
asan_mz_force_lock();
|
||||
}
|
||||
|
||||
void mi_force_unlock(malloc_zone_t *zone) {
|
||||
asan_mz_force_unlock();
|
||||
}
|
||||
|
||||
void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
|
||||
AsanMallocStats malloc_stats;
|
||||
asanThreadRegistry().FillMallocStatistics(&malloc_stats);
|
||||
CHECK(sizeof(malloc_statistics_t) == sizeof(AsanMallocStats));
|
||||
internal_memcpy(stats, &malloc_stats, sizeof(malloc_statistics_t));
|
||||
}
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
boolean_t mi_zone_locked(malloc_zone_t *zone) {
|
||||
// UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
extern int __CFRuntimeClassTableSize;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceCFAllocator() {
|
||||
static CFAllocatorContext asan_context = {
|
||||
/*version*/ 0, /*info*/ &asan_zone,
|
||||
/*retain*/ 0, /*release*/ 0,
|
||||
/*copyDescription*/0,
|
||||
/*allocate*/ &cf_malloc,
|
||||
/*reallocate*/ &cf_realloc,
|
||||
/*deallocate*/ &cf_free,
|
||||
/*preferredSize*/ 0 };
|
||||
if (!cf_asan)
|
||||
cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
|
||||
if (CFAllocatorGetDefault() != cf_asan)
|
||||
CFAllocatorSetDefault(cf_asan);
|
||||
}
|
||||
|
||||
void ReplaceSystemMalloc() {
|
||||
static malloc_introspection_t asan_introspection;
|
||||
// Ok to use internal_memset, these places are not performance-critical.
|
||||
internal_memset(&asan_introspection, 0, sizeof(asan_introspection));
|
||||
|
||||
asan_introspection.enumerator = &mi_enumerator;
|
||||
asan_introspection.good_size = &mi_good_size;
|
||||
asan_introspection.check = &mi_check;
|
||||
asan_introspection.print = &mi_print;
|
||||
asan_introspection.log = &mi_log;
|
||||
asan_introspection.force_lock = &mi_force_lock;
|
||||
asan_introspection.force_unlock = &mi_force_unlock;
|
||||
asan_introspection.statistics = &mi_statistics;
|
||||
|
||||
internal_memset(&asan_zone, 0, sizeof(malloc_zone_t));
|
||||
|
||||
// Start with a version 4 zone which is used for OS X 10.4 and 10.5.
|
||||
asan_zone.version = 4;
|
||||
asan_zone.zone_name = "asan";
|
||||
asan_zone.size = &mz_size;
|
||||
asan_zone.malloc = &mz_malloc;
|
||||
asan_zone.calloc = &mz_calloc;
|
||||
asan_zone.valloc = &mz_valloc;
|
||||
asan_zone.free = &mz_free;
|
||||
asan_zone.realloc = &mz_realloc;
|
||||
asan_zone.destroy = &mz_destroy;
|
||||
asan_zone.batch_malloc = 0;
|
||||
asan_zone.batch_free = 0;
|
||||
asan_zone.introspect = &asan_introspection;
|
||||
|
||||
// from AvailabilityMacros.h
|
||||
#if defined(MAC_OS_X_VERSION_10_6) && \
|
||||
MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||
// Switch to version 6 on OSX 10.6 to support memalign.
|
||||
asan_zone.version = 6;
|
||||
asan_zone.free_definite_size = 0;
|
||||
asan_zone.memalign = &mz_memalign;
|
||||
asan_introspection.zone_locked = &mi_zone_locked;
|
||||
|
||||
// Request the default purgable zone to force its creation. The
|
||||
// current default zone is registered with the purgable zone for
|
||||
// doing tiny and small allocs. Sadly, it assumes that the default
|
||||
// zone is the szone implementation from OS X and will crash if it
|
||||
// isn't. By creating the zone now, this will be true and changing
|
||||
// the default zone won't cause a problem. (OS X 10.6 and higher.)
|
||||
system_purgeable_zone = malloc_default_purgeable_zone();
|
||||
#endif
|
||||
|
||||
// Register the ASan zone. At this point, it will not be the
|
||||
// default zone.
|
||||
malloc_zone_register(&asan_zone);
|
||||
|
||||
// Unregister and reregister the default zone. Unregistering swaps
|
||||
// the specified zone with the last one registered which for the
|
||||
// default zone makes the more recently registered zone the default
|
||||
// zone. The default zone is then re-registered to ensure that
|
||||
// allocations made from it earlier will be handled correctly.
|
||||
// Things are not guaranteed to work that way, but it's how they work now.
|
||||
system_malloc_zone = malloc_default_zone();
|
||||
malloc_zone_unregister(system_malloc_zone);
|
||||
malloc_zone_register(system_malloc_zone);
|
||||
// Make sure the default allocator was replaced.
|
||||
CHECK(malloc_default_zone() == &asan_zone);
|
||||
|
||||
if (flags()->replace_cfallocator) {
|
||||
// If __CFInitialize() hasn't been called yet, cf_asan will be created and
|
||||
// installed as the default allocator after __CFInitialize() finishes (see
|
||||
// the interceptor for __CFInitialize() above). Otherwise install cf_asan
|
||||
// right now. On both Snow Leopard and Lion __CFInitialize() calls
|
||||
// __CFAllocatorInitialize(), which initializes the _base._cfisa field of
|
||||
// the default allocators we check here.
|
||||
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
|
||||
ReplaceCFAllocator();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#endif // __APPLE__
|
140
libsanitizer/asan/asan_malloc_win.cc
Normal file
140
libsanitizer/asan/asan_malloc_win.cc
Normal file
@ -0,0 +1,140 @@
|
||||
//===-- asan_malloc_win.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Windows-specific malloc interception.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
#include "interception/interception.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// ---------------------- Replacement functions ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// FIXME: Simply defining functions with the same signature in *.obj
|
||||
// files overrides the standard functions in *.lib
|
||||
// This works well for simple helloworld-like tests but might need to be
|
||||
// revisited in the future.
|
||||
|
||||
extern "C" {
|
||||
void free(void *ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);
|
||||
return asan_free(ptr, &stack);
|
||||
}
|
||||
|
||||
void _free_dbg(void* ptr, int) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void cfree(void *ptr) {
|
||||
CHECK(!"cfree() should not be used on Windows?");
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc(size, &stack);
|
||||
}
|
||||
|
||||
void* _malloc_dbg(size_t size, int , const char*, int) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_calloc(nmemb, size, &stack);
|
||||
}
|
||||
|
||||
void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
|
||||
return calloc(n, size);
|
||||
}
|
||||
|
||||
void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_realloc(ptr, size, &stack);
|
||||
}
|
||||
|
||||
void *_realloc_dbg(void *ptr, size_t size, int) {
|
||||
CHECK(!"_realloc_dbg should not exist!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* _recalloc(void* p, size_t n, size_t elem_size) {
|
||||
if (!p)
|
||||
return calloc(n, elem_size);
|
||||
const size_t size = n * elem_size;
|
||||
if (elem_size != 0 && size / elem_size != n)
|
||||
return 0;
|
||||
return realloc(p, size);
|
||||
}
|
||||
|
||||
size_t _msize(void *ptr) {
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;
|
||||
return asan_malloc_usable_size(ptr, &stack);
|
||||
}
|
||||
|
||||
int _CrtDbgReport(int, const char*, int,
|
||||
const char*, const char*, ...) {
|
||||
ShowStatsAndAbort();
|
||||
}
|
||||
|
||||
int _CrtDbgReportW(int reportType, const wchar_t*, int,
|
||||
const wchar_t*, const wchar_t*, ...) {
|
||||
ShowStatsAndAbort();
|
||||
}
|
||||
|
||||
int _CrtSetReportMode(int, int) {
|
||||
return 0;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
using __interception::GetRealFunctionAddress;
|
||||
|
||||
// We don't want to include "windows.h" in this file to avoid extra attributes
|
||||
// set on malloc/free etc (e.g. dllimport), so declare a few things manually:
|
||||
extern "C" int __stdcall VirtualProtect(void* addr, size_t size,
|
||||
DWORD prot, DWORD *old_prot);
|
||||
const int PAGE_EXECUTE_READWRITE = 0x40;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceSystemMalloc() {
|
||||
#if defined(_DLL)
|
||||
# ifdef _WIN64
|
||||
# error ReplaceSystemMalloc was not tested on x64
|
||||
# endif
|
||||
char *crt_malloc;
|
||||
if (GetRealFunctionAddress("malloc", (void**)&crt_malloc)) {
|
||||
// Replace malloc in the CRT dll with a jump to our malloc.
|
||||
DWORD old_prot, unused;
|
||||
CHECK(VirtualProtect(crt_malloc, 16, PAGE_EXECUTE_READWRITE, &old_prot));
|
||||
REAL(memset)(crt_malloc, 0xCC /* int 3 */, 16); // just in case.
|
||||
|
||||
ptrdiff_t jmp_offset = (char*)malloc - (char*)crt_malloc - 5;
|
||||
crt_malloc[0] = 0xE9; // jmp, should be followed by an offset.
|
||||
REAL(memcpy)(crt_malloc + 1, &jmp_offset, sizeof(jmp_offset));
|
||||
|
||||
CHECK(VirtualProtect(crt_malloc, 16, old_prot, &unused));
|
||||
|
||||
// FYI: FlushInstructionCache is needed on Itanium etc but not on x86/x64.
|
||||
}
|
||||
|
||||
// FIXME: investigate whether anything else is needed.
|
||||
#endif
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
#endif // _WIN32
|
120
libsanitizer/asan/asan_mapping.h
Normal file
120
libsanitizer/asan/asan_mapping.h
Normal file
@ -0,0 +1,120 @@
|
||||
//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Defines ASan memory mapping.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_MAPPING_H
|
||||
#define ASAN_MAPPING_H
|
||||
|
||||
#include "asan_internal.h"
|
||||
|
||||
// The full explanation of the memory mapping could be found here:
|
||||
// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
|
||||
|
||||
#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
|
||||
extern __attribute__((visibility("default"))) uptr __asan_mapping_scale;
|
||||
extern __attribute__((visibility("default"))) uptr __asan_mapping_offset;
|
||||
# define SHADOW_SCALE (__asan_mapping_scale)
|
||||
# define SHADOW_OFFSET (__asan_mapping_offset)
|
||||
#else
|
||||
# if ASAN_ANDROID
|
||||
# define SHADOW_SCALE (3)
|
||||
# define SHADOW_OFFSET (0)
|
||||
# else
|
||||
# define SHADOW_SCALE (3)
|
||||
# if __WORDSIZE == 32
|
||||
# define SHADOW_OFFSET (1 << 29)
|
||||
# else
|
||||
# define SHADOW_OFFSET (1ULL << 44)
|
||||
# endif
|
||||
# endif
|
||||
#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
|
||||
|
||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
|
||||
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
static const uptr kHighMemEnd = 0x00007fffffffffffUL;
|
||||
#else // __WORDSIZE == 32
|
||||
static const uptr kHighMemEnd = 0xffffffff;
|
||||
#endif // __WORDSIZE
|
||||
|
||||
|
||||
#define kLowMemBeg 0
|
||||
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
|
||||
|
||||
#define kLowShadowBeg SHADOW_OFFSET
|
||||
#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd)
|
||||
|
||||
#define kHighMemBeg (MEM_TO_SHADOW(kHighMemEnd) + 1)
|
||||
|
||||
#define kHighShadowBeg MEM_TO_SHADOW(kHighMemBeg)
|
||||
#define kHighShadowEnd MEM_TO_SHADOW(kHighMemEnd)
|
||||
|
||||
#define kShadowGapBeg (kLowShadowEnd ? kLowShadowEnd + 1 : 16 * kPageSize)
|
||||
#define kShadowGapEnd (kHighShadowBeg - 1)
|
||||
|
||||
#define kGlobalAndStackRedzone \
|
||||
(SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static inline bool AddrIsInLowMem(uptr a) {
|
||||
return a < kLowMemEnd;
|
||||
}
|
||||
|
||||
static inline bool AddrIsInLowShadow(uptr a) {
|
||||
return a >= kLowShadowBeg && a <= kLowShadowEnd;
|
||||
}
|
||||
|
||||
static inline bool AddrIsInHighMem(uptr a) {
|
||||
return a >= kHighMemBeg && a <= kHighMemEnd;
|
||||
}
|
||||
|
||||
static inline bool AddrIsInMem(uptr a) {
|
||||
return AddrIsInLowMem(a) || AddrIsInHighMem(a);
|
||||
}
|
||||
|
||||
static inline uptr MemToShadow(uptr p) {
|
||||
CHECK(AddrIsInMem(p));
|
||||
return MEM_TO_SHADOW(p);
|
||||
}
|
||||
|
||||
static inline bool AddrIsInHighShadow(uptr a) {
|
||||
return a >= kHighShadowBeg && a <= kHighMemEnd;
|
||||
}
|
||||
|
||||
static inline bool AddrIsInShadow(uptr a) {
|
||||
return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
|
||||
}
|
||||
|
||||
static inline bool AddrIsInShadowGap(uptr a) {
|
||||
return a >= kShadowGapBeg && a <= kShadowGapEnd;
|
||||
}
|
||||
|
||||
static inline bool AddrIsAlignedByGranularity(uptr a) {
|
||||
return (a & (SHADOW_GRANULARITY - 1)) == 0;
|
||||
}
|
||||
|
||||
static inline bool AddressIsPoisoned(uptr a) {
|
||||
const uptr kAccessSize = 1;
|
||||
u8 *shadow_address = (u8*)MemToShadow(a);
|
||||
s8 shadow_value = *shadow_address;
|
||||
if (shadow_value) {
|
||||
u8 last_accessed_byte = (a & (SHADOW_GRANULARITY - 1))
|
||||
+ kAccessSize - 1;
|
||||
return (last_accessed_byte >= shadow_value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_MAPPING_H
|
54
libsanitizer/asan/asan_new_delete.cc
Normal file
54
libsanitizer/asan/asan_new_delete.cc
Normal file
@ -0,0 +1,54 @@
|
||||
//===-- asan_interceptors.cc ----------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Interceptors for operators new and delete.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <new>
|
||||
|
||||
namespace __asan {
|
||||
// This function is a no-op. We need it to make sure that object file
|
||||
// with our replacements will actually be loaded from static ASan
|
||||
// run-time library at link-time.
|
||||
void ReplaceOperatorsNewAndDelete() { }
|
||||
}
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;\
|
||||
return asan_memalign(0, size, &stack);
|
||||
|
||||
#if ASAN_ANDROID
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
#else
|
||||
void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_NEW_BODY; }
|
||||
#endif
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);\
|
||||
asan_free(ptr, &stack);
|
||||
|
||||
void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
|
||||
void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
|
||||
void operator delete(void *ptr, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
void operator delete[](void *ptr, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_DELETE_BODY; }
|
151
libsanitizer/asan/asan_poisoning.cc
Normal file
151
libsanitizer/asan/asan_poisoning.cc
Normal file
@ -0,0 +1,151 @@
|
||||
//===-- asan_poisoning.cc -------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Shadow memory poisoning by ASan RTL and by user application.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void PoisonShadow(uptr addr, uptr size, u8 value) {
|
||||
CHECK(AddrIsAlignedByGranularity(addr));
|
||||
CHECK(AddrIsAlignedByGranularity(addr + size));
|
||||
uptr shadow_beg = MemToShadow(addr);
|
||||
uptr shadow_end = MemToShadow(addr + size);
|
||||
CHECK(REAL(memset) != 0);
|
||||
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
|
||||
}
|
||||
|
||||
void PoisonShadowPartialRightRedzone(uptr addr,
|
||||
uptr size,
|
||||
uptr redzone_size,
|
||||
u8 value) {
|
||||
CHECK(AddrIsAlignedByGranularity(addr));
|
||||
u8 *shadow = (u8*)MemToShadow(addr);
|
||||
for (uptr i = 0; i < redzone_size;
|
||||
i += SHADOW_GRANULARITY, shadow++) {
|
||||
if (i + SHADOW_GRANULARITY <= size) {
|
||||
*shadow = 0; // fully addressable
|
||||
} else if (i >= size) {
|
||||
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
|
||||
} else {
|
||||
*shadow = size - i; // first size-i bytes are addressable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ShadowSegmentEndpoint {
|
||||
u8 *chunk;
|
||||
s8 offset; // in [0, SHADOW_GRANULARITY)
|
||||
s8 value; // = *chunk;
|
||||
|
||||
explicit ShadowSegmentEndpoint(uptr address) {
|
||||
chunk = (u8*)MemToShadow(address);
|
||||
offset = address & (SHADOW_GRANULARITY - 1);
|
||||
value = *chunk;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// Current implementation of __asan_(un)poison_memory_region doesn't check
|
||||
// that user program (un)poisons the memory it owns. It poisons memory
|
||||
// conservatively, and unpoisons progressively to make sure asan shadow
|
||||
// mapping invariant is preserved (see detailed mapping description here:
|
||||
// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm).
|
||||
//
|
||||
// * if user asks to poison region [left, right), the program poisons
|
||||
// at least [left, AlignDown(right)).
|
||||
// * if user asks to unpoison region [left, right), the program unpoisons
|
||||
// at most [AlignDown(left), right).
|
||||
void __asan_poison_memory_region(void const volatile *addr, uptr size) {
|
||||
if (!flags()->allow_user_poisoning || size == 0) return;
|
||||
uptr beg_addr = (uptr)addr;
|
||||
uptr end_addr = beg_addr + size;
|
||||
if (flags()->verbosity >= 1) {
|
||||
Printf("Trying to poison memory region [%p, %p)\n",
|
||||
(void*)beg_addr, (void*)end_addr);
|
||||
}
|
||||
ShadowSegmentEndpoint beg(beg_addr);
|
||||
ShadowSegmentEndpoint end(end_addr);
|
||||
if (beg.chunk == end.chunk) {
|
||||
CHECK(beg.offset < end.offset);
|
||||
s8 value = beg.value;
|
||||
CHECK(value == end.value);
|
||||
// We can only poison memory if the byte in end.offset is unaddressable.
|
||||
// No need to re-poison memory if it is poisoned already.
|
||||
if (value > 0 && value <= end.offset) {
|
||||
if (beg.offset > 0) {
|
||||
*beg.chunk = Min(value, beg.offset);
|
||||
} else {
|
||||
*beg.chunk = kAsanUserPoisonedMemoryMagic;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
CHECK(beg.chunk < end.chunk);
|
||||
if (beg.offset > 0) {
|
||||
// Mark bytes from beg.offset as unaddressable.
|
||||
if (beg.value == 0) {
|
||||
*beg.chunk = beg.offset;
|
||||
} else {
|
||||
*beg.chunk = Min(beg.value, beg.offset);
|
||||
}
|
||||
beg.chunk++;
|
||||
}
|
||||
REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk);
|
||||
// Poison if byte in end.offset is unaddressable.
|
||||
if (end.value > 0 && end.value <= end.offset) {
|
||||
*end.chunk = kAsanUserPoisonedMemoryMagic;
|
||||
}
|
||||
}
|
||||
|
||||
void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
|
||||
if (!flags()->allow_user_poisoning || size == 0) return;
|
||||
uptr beg_addr = (uptr)addr;
|
||||
uptr end_addr = beg_addr + size;
|
||||
if (flags()->verbosity >= 1) {
|
||||
Printf("Trying to unpoison memory region [%p, %p)\n",
|
||||
(void*)beg_addr, (void*)end_addr);
|
||||
}
|
||||
ShadowSegmentEndpoint beg(beg_addr);
|
||||
ShadowSegmentEndpoint end(end_addr);
|
||||
if (beg.chunk == end.chunk) {
|
||||
CHECK(beg.offset < end.offset);
|
||||
s8 value = beg.value;
|
||||
CHECK(value == end.value);
|
||||
// We unpoison memory bytes up to enbytes up to end.offset if it is not
|
||||
// unpoisoned already.
|
||||
if (value != 0) {
|
||||
*beg.chunk = Max(value, end.offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
CHECK(beg.chunk < end.chunk);
|
||||
if (beg.offset > 0) {
|
||||
*beg.chunk = 0;
|
||||
beg.chunk++;
|
||||
}
|
||||
REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk);
|
||||
if (end.offset > 0 && end.value != 0) {
|
||||
*end.chunk = Max(end.value, end.offset);
|
||||
}
|
||||
}
|
||||
|
||||
bool __asan_address_is_poisoned(void const volatile *addr) {
|
||||
return __asan::AddressIsPoisoned((uptr)addr);
|
||||
}
|
118
libsanitizer/asan/asan_posix.cc
Normal file
118
libsanitizer/asan/asan_posix.cc
Normal file
@ -0,0 +1,118 @@
|
||||
//===-- asan_linux.cc -----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Posix-specific details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static void MaybeInstallSigaction(int signum,
|
||||
void (*handler)(int, siginfo_t *, void *)) {
|
||||
if (!AsanInterceptsSignal(signum))
|
||||
return;
|
||||
struct sigaction sigact;
|
||||
REAL(memset)(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = handler;
|
||||
sigact.sa_flags = SA_SIGINFO;
|
||||
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
|
||||
CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
|
||||
if (flags()->verbosity >= 1) {
|
||||
Report("Installed the sigaction for signal %d\n", signum);
|
||||
}
|
||||
}
|
||||
|
||||
static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
|
||||
uptr addr = (uptr)siginfo->si_addr;
|
||||
// Write the first message using the bullet-proof write.
|
||||
if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
|
||||
uptr pc, sp, bp;
|
||||
GetPcSpBp(context, &pc, &sp, &bp);
|
||||
ReportSIGSEGV(pc, sp, bp, addr);
|
||||
}
|
||||
|
||||
void SetAlternateSignalStack() {
|
||||
stack_t altstack, oldstack;
|
||||
CHECK(0 == sigaltstack(0, &oldstack));
|
||||
// If the alternate stack is already in place, do nothing.
|
||||
if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
|
||||
// TODO(glider): the mapped stack should have the MAP_STACK flag in the
|
||||
// future. It is not required by man 2 sigaltstack now (they're using
|
||||
// malloc()).
|
||||
void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
|
||||
altstack.ss_sp = base;
|
||||
altstack.ss_flags = 0;
|
||||
altstack.ss_size = kAltStackSize;
|
||||
CHECK(0 == sigaltstack(&altstack, 0));
|
||||
if (flags()->verbosity > 0) {
|
||||
Report("Alternative stack for T%d set: [%p,%p)\n",
|
||||
asanThreadRegistry().GetCurrentTidOrInvalid(),
|
||||
altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
|
||||
}
|
||||
}
|
||||
|
||||
void UnsetAlternateSignalStack() {
|
||||
stack_t altstack, oldstack;
|
||||
altstack.ss_sp = 0;
|
||||
altstack.ss_flags = SS_DISABLE;
|
||||
altstack.ss_size = 0;
|
||||
CHECK(0 == sigaltstack(&altstack, &oldstack));
|
||||
UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
|
||||
}
|
||||
|
||||
void InstallSignalHandlers() {
|
||||
// Set the alternate signal stack for the main thread.
|
||||
// This will cause SetAlternateSignalStack to be called twice, but the stack
|
||||
// will be actually set only once.
|
||||
if (flags()->use_sigaltstack) SetAlternateSignalStack();
|
||||
MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
|
||||
MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
|
||||
static pthread_key_t tsd_key;
|
||||
static bool tsd_key_inited = false;
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
CHECK(!tsd_key_inited);
|
||||
tsd_key_inited = true;
|
||||
CHECK(0 == pthread_key_create(&tsd_key, destructor));
|
||||
}
|
||||
|
||||
void *AsanTSDGet() {
|
||||
CHECK(tsd_key_inited);
|
||||
return pthread_getspecific(tsd_key);
|
||||
}
|
||||
|
||||
void AsanTSDSet(void *tsd) {
|
||||
CHECK(tsd_key_inited);
|
||||
pthread_setspecific(tsd_key, tsd);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // __linux__ || __APPLE_
|
492
libsanitizer/asan/asan_report.cc
Normal file
492
libsanitizer/asan/asan_report.cc
Normal file
@ -0,0 +1,492 @@
|
||||
//===-- asan_report.cc ----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file contains error reporting code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// -------------------- User-specified callbacks ----------------- {{{1
|
||||
static void (*error_report_callback)(const char*);
|
||||
static char *error_message_buffer = 0;
|
||||
static uptr error_message_buffer_pos = 0;
|
||||
static uptr error_message_buffer_size = 0;
|
||||
|
||||
void AppendToErrorMessageBuffer(const char *buffer) {
|
||||
if (error_message_buffer) {
|
||||
uptr length = internal_strlen(buffer);
|
||||
CHECK_GE(error_message_buffer_size, error_message_buffer_pos);
|
||||
uptr remaining = error_message_buffer_size - error_message_buffer_pos;
|
||||
internal_strncpy(error_message_buffer + error_message_buffer_pos,
|
||||
buffer, remaining);
|
||||
error_message_buffer[error_message_buffer_size - 1] = '\0';
|
||||
// FIXME: reallocate the buffer instead of truncating the message.
|
||||
error_message_buffer_pos += remaining > length ? length : remaining;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------- Helper functions ----------------------- {{{1
|
||||
|
||||
static void PrintBytes(const char *before, uptr *a) {
|
||||
u8 *bytes = (u8*)a;
|
||||
uptr byte_num = (__WORDSIZE) / 8;
|
||||
Printf("%s%p:", before, (void*)a);
|
||||
for (uptr i = 0; i < byte_num; i++) {
|
||||
Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
|
||||
}
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
static void PrintShadowMemoryForAddress(uptr addr) {
|
||||
if (!AddrIsInMem(addr))
|
||||
return;
|
||||
uptr shadow_addr = MemToShadow(addr);
|
||||
Printf("Shadow byte and word:\n");
|
||||
Printf(" %p: %x\n", (void*)shadow_addr, *(unsigned char*)shadow_addr);
|
||||
uptr aligned_shadow = shadow_addr & ~(kWordSize - 1);
|
||||
PrintBytes(" ", (uptr*)(aligned_shadow));
|
||||
Printf("More shadow bytes:\n");
|
||||
for (int i = -4; i <= 4; i++) {
|
||||
const char *prefix = (i == 0) ? "=>" : " ";
|
||||
PrintBytes(prefix, (uptr*)(aligned_shadow + i * kWordSize));
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
|
||||
const char *zone_name) {
|
||||
if (zone_ptr) {
|
||||
if (zone_name) {
|
||||
Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
|
||||
ptr, zone_ptr, zone_name);
|
||||
} else {
|
||||
Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
|
||||
ptr, zone_ptr);
|
||||
}
|
||||
} else {
|
||||
Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------- Address Descriptions ------------------- {{{1
|
||||
|
||||
static bool IsASCII(unsigned char c) {
|
||||
return /*0x00 <= c &&*/ c <= 0x7F;
|
||||
}
|
||||
|
||||
// Check if the global is a zero-terminated ASCII string. If so, print it.
|
||||
static void PrintGlobalNameIfASCII(const __asan_global &g) {
|
||||
for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
|
||||
if (!IsASCII(*(unsigned char*)p)) return;
|
||||
}
|
||||
if (*(char*)(g.beg + g.size - 1) != 0) return;
|
||||
Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
|
||||
}
|
||||
|
||||
bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
|
||||
if (addr < g.beg - kGlobalAndStackRedzone) return false;
|
||||
if (addr >= g.beg + g.size_with_redzone) return false;
|
||||
Printf("%p is located ", (void*)addr);
|
||||
if (addr < g.beg) {
|
||||
Printf("%zd bytes to the left", g.beg - addr);
|
||||
} else if (addr >= g.beg + g.size) {
|
||||
Printf("%zd bytes to the right", addr - (g.beg + g.size));
|
||||
} else {
|
||||
Printf("%zd bytes inside", addr - g.beg); // Can it happen?
|
||||
}
|
||||
Printf(" of global variable '%s' (0x%zx) of size %zu\n",
|
||||
g.name, g.beg, g.size);
|
||||
PrintGlobalNameIfASCII(g);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescribeAddressIfShadow(uptr addr) {
|
||||
if (AddrIsInMem(addr))
|
||||
return false;
|
||||
static const char kAddrInShadowReport[] =
|
||||
"Address %p is located in the %s.\n";
|
||||
if (AddrIsInShadowGap(addr)) {
|
||||
Printf(kAddrInShadowReport, addr, "shadow gap area");
|
||||
return true;
|
||||
}
|
||||
if (AddrIsInHighShadow(addr)) {
|
||||
Printf(kAddrInShadowReport, addr, "high shadow area");
|
||||
return true;
|
||||
}
|
||||
if (AddrIsInLowShadow(addr)) {
|
||||
Printf(kAddrInShadowReport, addr, "low shadow area");
|
||||
return true;
|
||||
}
|
||||
CHECK(0 && "Address is not in memory and not in shadow?");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
||||
AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
|
||||
if (!t) return false;
|
||||
const sptr kBufSize = 4095;
|
||||
char buf[kBufSize];
|
||||
uptr offset = 0;
|
||||
const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
|
||||
// This string is created by the compiler and has the following form:
|
||||
// "FunctioName n alloc_1 alloc_2 ... alloc_n"
|
||||
// where alloc_i looks like "offset size len ObjectName ".
|
||||
CHECK(frame_descr);
|
||||
// Report the function name and the offset.
|
||||
const char *name_end = internal_strchr(frame_descr, ' ');
|
||||
CHECK(name_end);
|
||||
buf[0] = 0;
|
||||
internal_strncat(buf, frame_descr,
|
||||
Min(kBufSize,
|
||||
static_cast<sptr>(name_end - frame_descr)));
|
||||
Printf("Address %p is located at offset %zu "
|
||||
"in frame <%s> of T%d's stack:\n",
|
||||
(void*)addr, offset, buf, t->tid());
|
||||
// Report the number of stack objects.
|
||||
char *p;
|
||||
uptr n_objects = internal_simple_strtoll(name_end, &p, 10);
|
||||
CHECK(n_objects > 0);
|
||||
Printf(" This frame has %zu object(s):\n", n_objects);
|
||||
// Report all objects in this frame.
|
||||
for (uptr i = 0; i < n_objects; i++) {
|
||||
uptr beg, size;
|
||||
sptr len;
|
||||
beg = internal_simple_strtoll(p, &p, 10);
|
||||
size = internal_simple_strtoll(p, &p, 10);
|
||||
len = internal_simple_strtoll(p, &p, 10);
|
||||
if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
|
||||
Printf("AddressSanitizer can't parse the stack frame "
|
||||
"descriptor: |%s|\n", frame_descr);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
buf[0] = 0;
|
||||
internal_strncat(buf, p, Min(kBufSize, len));
|
||||
p += len;
|
||||
Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
|
||||
}
|
||||
Printf("HINT: this may be a false positive if your program uses "
|
||||
"some custom stack unwind mechanism\n"
|
||||
" (longjmp and C++ exceptions *are* supported)\n");
|
||||
DescribeThread(t->summary());
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
|
||||
uptr access_size) {
|
||||
uptr offset;
|
||||
Printf("%p is located ", (void*)addr);
|
||||
if (chunk.AddrIsInside(addr, access_size, &offset)) {
|
||||
Printf("%zu bytes inside of", offset);
|
||||
} else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
|
||||
Printf("%zu bytes to the left of", offset);
|
||||
} else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
|
||||
Printf("%zu bytes to the right of", offset);
|
||||
} else {
|
||||
Printf(" somewhere around (this is AddressSanitizer bug!)");
|
||||
}
|
||||
Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
|
||||
(void*)(chunk.Beg()), (void*)(chunk.End()));
|
||||
}
|
||||
|
||||
void DescribeHeapAddress(uptr addr, uptr access_size) {
|
||||
AsanChunkView chunk = FindHeapChunkByAddress(addr);
|
||||
if (!chunk.IsValid()) return;
|
||||
DescribeAccessToHeapChunk(chunk, addr, access_size);
|
||||
CHECK(chunk.AllocTid() != kInvalidTid);
|
||||
AsanThreadSummary *alloc_thread =
|
||||
asanThreadRegistry().FindByTid(chunk.AllocTid());
|
||||
StackTrace alloc_stack;
|
||||
chunk.GetAllocStack(&alloc_stack);
|
||||
AsanThread *t = asanThreadRegistry().GetCurrent();
|
||||
CHECK(t);
|
||||
if (chunk.FreeTid() != kInvalidTid) {
|
||||
AsanThreadSummary *free_thread =
|
||||
asanThreadRegistry().FindByTid(chunk.FreeTid());
|
||||
Printf("freed by thread T%d here:\n", free_thread->tid());
|
||||
StackTrace free_stack;
|
||||
chunk.GetFreeStack(&free_stack);
|
||||
PrintStack(&free_stack);
|
||||
Printf("previously allocated by thread T%d here:\n", alloc_thread->tid());
|
||||
PrintStack(&alloc_stack);
|
||||
DescribeThread(t->summary());
|
||||
DescribeThread(free_thread);
|
||||
DescribeThread(alloc_thread);
|
||||
} else {
|
||||
Printf("allocated by thread T%d here:\n", alloc_thread->tid());
|
||||
PrintStack(&alloc_stack);
|
||||
DescribeThread(t->summary());
|
||||
DescribeThread(alloc_thread);
|
||||
}
|
||||
}
|
||||
|
||||
void DescribeAddress(uptr addr, uptr access_size) {
|
||||
// Check if this is shadow or shadow gap.
|
||||
if (DescribeAddressIfShadow(addr))
|
||||
return;
|
||||
CHECK(AddrIsInMem(addr));
|
||||
if (DescribeAddressIfGlobal(addr))
|
||||
return;
|
||||
if (DescribeAddressIfStack(addr, access_size))
|
||||
return;
|
||||
// Assume it is a heap address.
|
||||
DescribeHeapAddress(addr, access_size);
|
||||
}
|
||||
|
||||
// ------------------- Thread description -------------------- {{{1
|
||||
|
||||
void DescribeThread(AsanThreadSummary *summary) {
|
||||
CHECK(summary);
|
||||
// No need to announce the main thread.
|
||||
if (summary->tid() == 0 || summary->announced()) {
|
||||
return;
|
||||
}
|
||||
summary->set_announced(true);
|
||||
Printf("Thread T%d created by T%d here:\n",
|
||||
summary->tid(), summary->parent_tid());
|
||||
PrintStack(summary->stack());
|
||||
// Recursively described parent thread if needed.
|
||||
if (flags()->print_full_thread_history) {
|
||||
AsanThreadSummary *parent_summary =
|
||||
asanThreadRegistry().FindByTid(summary->parent_tid());
|
||||
DescribeThread(parent_summary);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Different kinds of reports ----------------- {{{1
|
||||
|
||||
// Use ScopedInErrorReport to run common actions just before and
|
||||
// immediately after printing error report.
|
||||
class ScopedInErrorReport {
|
||||
public:
|
||||
ScopedInErrorReport() {
|
||||
static atomic_uint32_t num_calls;
|
||||
static u32 reporting_thread_tid;
|
||||
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
|
||||
// Do not print more than one report, otherwise they will mix up.
|
||||
// Error reporting functions shouldn't return at this situation, as
|
||||
// they are defined as no-return.
|
||||
Report("AddressSanitizer: while reporting a bug found another one."
|
||||
"Ignoring.\n");
|
||||
u32 current_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
if (current_tid != reporting_thread_tid) {
|
||||
// ASan found two bugs in different threads simultaneously. Sleep
|
||||
// long enough to make sure that the thread which started to print
|
||||
// an error report will finish doing it.
|
||||
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
||||
}
|
||||
Die();
|
||||
}
|
||||
__asan_on_error();
|
||||
reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
Printf("===================================================="
|
||||
"=============\n");
|
||||
if (reporting_thread_tid != kInvalidTid) {
|
||||
// We started reporting an error message. Stop using the fake stack
|
||||
// in case we call an instrumented function from a symbolizer.
|
||||
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
|
||||
CHECK(curr_thread);
|
||||
curr_thread->fake_stack().StopUsingFakeStack();
|
||||
}
|
||||
}
|
||||
// Destructor is NORETURN, as functions that report errors are.
|
||||
NORETURN ~ScopedInErrorReport() {
|
||||
// Make sure the current thread is announced.
|
||||
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
|
||||
if (curr_thread) {
|
||||
DescribeThread(curr_thread->summary());
|
||||
}
|
||||
// Print memory stats.
|
||||
__asan_print_accumulated_stats();
|
||||
if (error_report_callback) {
|
||||
error_report_callback(error_message_buffer);
|
||||
}
|
||||
Report("ABORTING\n");
|
||||
Die();
|
||||
}
|
||||
};
|
||||
|
||||
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer crashed on unknown address %p"
|
||||
" (pc %p sp %p bp %p T%d)\n",
|
||||
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
|
||||
asanThreadRegistry().GetCurrentTidOrInvalid());
|
||||
Printf("AddressSanitizer can not provide additional info.\n");
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
|
||||
PrintStack(&stack);
|
||||
}
|
||||
|
||||
void ReportDoubleFree(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting double-free on %p:\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting free on address "
|
||||
"which was not malloc()-ed: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting to call "
|
||||
"malloc_usable_size() for pointer which is "
|
||||
"not owned: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting to call "
|
||||
"__asan_get_allocated_size() for pointer which is "
|
||||
"not owned: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportStringFunctionMemoryRangesOverlap(
|
||||
const char *function, const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer %s-param-overlap: "
|
||||
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
||||
function, offset1, offset1 + length1, offset2, offset2 + length2);
|
||||
PrintStack(stack);
|
||||
DescribeAddress((uptr)offset1, length1);
|
||||
DescribeAddress((uptr)offset2, length2);
|
||||
}
|
||||
|
||||
// ----------------------- Mac-specific reports ----------------- {{{1
|
||||
|
||||
void WarnMacFreeUnallocated(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
|
||||
// Just print a warning here.
|
||||
Printf("free_common(%p) -- attempting to free unallocated memory.\n"
|
||||
"AddressSanitizer is ignoring this error on Mac OS now.\n",
|
||||
addr);
|
||||
PrintZoneForPointer(addr, zone_ptr, zone_name);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportMacMzReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
||||
"This is an unrecoverable problem, exiting now.\n",
|
||||
addr);
|
||||
PrintZoneForPointer(addr, zone_ptr, zone_name);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportMacCfReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
|
||||
"This is an unrecoverable problem, exiting now.\n",
|
||||
addr);
|
||||
PrintZoneForPointer(addr, zone_ptr, zone_name);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// --------------------------- Interface --------------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||
uptr addr, bool is_write, uptr access_size) {
|
||||
ScopedInErrorReport in_report;
|
||||
|
||||
// Determine the error type.
|
||||
const char *bug_descr = "unknown-crash";
|
||||
if (AddrIsInMem(addr)) {
|
||||
u8 *shadow_addr = (u8*)MemToShadow(addr);
|
||||
// If we are accessing 16 bytes, look at the second shadow byte.
|
||||
if (*shadow_addr == 0 && access_size > SHADOW_GRANULARITY)
|
||||
shadow_addr++;
|
||||
// If we are in the partial right redzone, look at the next shadow byte.
|
||||
if (*shadow_addr > 0 && *shadow_addr < 128)
|
||||
shadow_addr++;
|
||||
switch (*shadow_addr) {
|
||||
case kAsanHeapLeftRedzoneMagic:
|
||||
case kAsanHeapRightRedzoneMagic:
|
||||
bug_descr = "heap-buffer-overflow";
|
||||
break;
|
||||
case kAsanHeapFreeMagic:
|
||||
bug_descr = "heap-use-after-free";
|
||||
break;
|
||||
case kAsanStackLeftRedzoneMagic:
|
||||
bug_descr = "stack-buffer-underflow";
|
||||
break;
|
||||
case kAsanInitializationOrderMagic:
|
||||
bug_descr = "initialization-order-fiasco";
|
||||
break;
|
||||
case kAsanStackMidRedzoneMagic:
|
||||
case kAsanStackRightRedzoneMagic:
|
||||
case kAsanStackPartialRedzoneMagic:
|
||||
bug_descr = "stack-buffer-overflow";
|
||||
break;
|
||||
case kAsanStackAfterReturnMagic:
|
||||
bug_descr = "stack-use-after-return";
|
||||
break;
|
||||
case kAsanUserPoisonedMemoryMagic:
|
||||
bug_descr = "use-after-poison";
|
||||
break;
|
||||
case kAsanGlobalRedzoneMagic:
|
||||
bug_descr = "global-buffer-overflow";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Report("ERROR: AddressSanitizer %s on address "
|
||||
"%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
|
||||
bug_descr, (void*)addr, pc, bp, sp);
|
||||
|
||||
u32 curr_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
Printf("%s of size %zu at %p thread T%d\n",
|
||||
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
|
||||
access_size, (void*)addr, curr_tid);
|
||||
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp);
|
||||
PrintStack(&stack);
|
||||
|
||||
DescribeAddress(addr, access_size);
|
||||
|
||||
PrintShadowMemoryForAddress(addr);
|
||||
}
|
||||
|
||||
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
|
||||
error_report_callback = callback;
|
||||
if (callback) {
|
||||
error_message_buffer_size = 1 << 16;
|
||||
error_message_buffer =
|
||||
(char*)MmapOrDie(error_message_buffer_size, __FUNCTION__);
|
||||
error_message_buffer_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Provide default implementation of __asan_on_error that does nothing
|
||||
// and may be overriden by user.
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
|
||||
void __asan_on_error() {}
|
51
libsanitizer/asan/asan_report.h
Normal file
51
libsanitizer/asan/asan_report.h
Normal file
@ -0,0 +1,51 @@
|
||||
//===-- asan_report.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for error reporting functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_internal.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// The following functions prints address description depending
|
||||
// on the memory type (shadow/heap/stack/global).
|
||||
void DescribeHeapAddress(uptr addr, uptr access_size);
|
||||
bool DescribeAddressIfGlobal(uptr addr);
|
||||
bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g);
|
||||
bool DescribeAddressIfShadow(uptr addr);
|
||||
bool DescribeAddressIfStack(uptr addr, uptr access_size);
|
||||
// Determines memory type on its own.
|
||||
void DescribeAddress(uptr addr, uptr access_size);
|
||||
|
||||
void DescribeThread(AsanThreadSummary *summary);
|
||||
|
||||
// Different kinds of error reports.
|
||||
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
|
||||
void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack);
|
||||
void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack);
|
||||
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
|
||||
StackTrace *stack);
|
||||
void NORETURN ReportAsanGetAllocatedSizeNotOwned(uptr addr,
|
||||
StackTrace *stack);
|
||||
void NORETURN ReportStringFunctionMemoryRangesOverlap(
|
||||
const char *function, const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2, StackTrace *stack);
|
||||
|
||||
// Mac-specific errors and warnings.
|
||||
void WarnMacFreeUnallocated(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
void NORETURN ReportMacMzReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
void NORETURN ReportMacCfReallocUnknown(
|
||||
uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
404
libsanitizer/asan/asan_rtl.cc
Normal file
404
libsanitizer/asan/asan_rtl.cc
Normal file
@ -0,0 +1,404 @@
|
||||
//===-- asan_rtl.cc -------------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Main file of the ASan run-time library.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_report.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static void AsanDie() {
|
||||
static atomic_uint32_t num_calls;
|
||||
if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
|
||||
// Don't die twice - run a busy loop.
|
||||
while (1) { }
|
||||
}
|
||||
if (flags()->sleep_before_dying) {
|
||||
Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
|
||||
SleepForSeconds(flags()->sleep_before_dying);
|
||||
}
|
||||
if (flags()->unmap_shadow_on_exit)
|
||||
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
|
||||
if (death_callback)
|
||||
death_callback();
|
||||
if (flags()->abort_on_error)
|
||||
Abort();
|
||||
Exit(flags()->exitcode);
|
||||
}
|
||||
|
||||
static void AsanCheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2) {
|
||||
Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||
file, line, cond, (uptr)v1, (uptr)v2);
|
||||
// FIXME: check for infinite recursion without a thread-local counter here.
|
||||
PRINT_CURRENT_STACK();
|
||||
ShowStatsAndAbort();
|
||||
}
|
||||
|
||||
// -------------------------- Flags ------------------------- {{{1
|
||||
static const int kDeafultMallocContextSize = 30;
|
||||
|
||||
static Flags asan_flags;
|
||||
|
||||
Flags *flags() {
|
||||
return &asan_flags;
|
||||
}
|
||||
|
||||
static void ParseFlagsFromString(Flags *f, const char *str) {
|
||||
ParseFlag(str, &f->quarantine_size, "quarantine_size");
|
||||
ParseFlag(str, &f->symbolize, "symbolize");
|
||||
ParseFlag(str, &f->verbosity, "verbosity");
|
||||
ParseFlag(str, &f->redzone, "redzone");
|
||||
CHECK(f->redzone >= 16);
|
||||
CHECK(IsPowerOfTwo(f->redzone));
|
||||
|
||||
ParseFlag(str, &f->debug, "debug");
|
||||
ParseFlag(str, &f->report_globals, "report_globals");
|
||||
ParseFlag(str, &f->check_initialization_order, "initialization_order");
|
||||
ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
|
||||
CHECK((uptr)f->malloc_context_size <= kStackTraceMax);
|
||||
|
||||
ParseFlag(str, &f->replace_str, "replace_str");
|
||||
ParseFlag(str, &f->replace_intrin, "replace_intrin");
|
||||
ParseFlag(str, &f->replace_cfallocator, "replace_cfallocator");
|
||||
ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
|
||||
ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
|
||||
ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
|
||||
ParseFlag(str, &f->exitcode, "exitcode");
|
||||
ParseFlag(str, &f->allow_user_poisoning, "allow_user_poisoning");
|
||||
ParseFlag(str, &f->sleep_before_dying, "sleep_before_dying");
|
||||
ParseFlag(str, &f->handle_segv, "handle_segv");
|
||||
ParseFlag(str, &f->use_sigaltstack, "use_sigaltstack");
|
||||
ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
|
||||
ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
|
||||
ParseFlag(str, &f->abort_on_error, "abort_on_error");
|
||||
ParseFlag(str, &f->atexit, "atexit");
|
||||
ParseFlag(str, &f->disable_core, "disable_core");
|
||||
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
|
||||
ParseFlag(str, &f->allow_reexec, "allow_reexec");
|
||||
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
|
||||
ParseFlag(str, &f->log_path, "log_path");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_WEAK_ATTRIBUTE
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const char* __asan_default_options() { return ""; }
|
||||
} // extern "C"
|
||||
|
||||
void InitializeFlags(Flags *f, const char *env) {
|
||||
internal_memset(f, 0, sizeof(*f));
|
||||
|
||||
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
|
||||
f->symbolize = false;
|
||||
f->verbosity = 0;
|
||||
f->redzone = (ASAN_LOW_MEMORY) ? 64 : 128;
|
||||
f->debug = false;
|
||||
f->report_globals = 1;
|
||||
f->check_initialization_order = true;
|
||||
f->malloc_context_size = kDeafultMallocContextSize;
|
||||
f->replace_str = true;
|
||||
f->replace_intrin = true;
|
||||
f->replace_cfallocator = true;
|
||||
f->mac_ignore_invalid_free = false;
|
||||
f->use_fake_stack = true;
|
||||
f->max_malloc_fill_size = 0;
|
||||
f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE;
|
||||
f->allow_user_poisoning = true;
|
||||
f->sleep_before_dying = 0;
|
||||
f->handle_segv = ASAN_NEEDS_SEGV;
|
||||
f->use_sigaltstack = false;
|
||||
f->check_malloc_usable_size = true;
|
||||
f->unmap_shadow_on_exit = false;
|
||||
f->abort_on_error = false;
|
||||
f->atexit = false;
|
||||
f->disable_core = (__WORDSIZE == 64);
|
||||
f->strip_path_prefix = "";
|
||||
f->allow_reexec = true;
|
||||
f->print_full_thread_history = true;
|
||||
f->log_path = 0;
|
||||
|
||||
// Override from user-specified string.
|
||||
ParseFlagsFromString(f, __asan_default_options());
|
||||
if (flags()->verbosity) {
|
||||
Report("Using the defaults from __asan_default_options: %s\n",
|
||||
__asan_default_options());
|
||||
}
|
||||
|
||||
// Override from command line.
|
||||
ParseFlagsFromString(f, env);
|
||||
}
|
||||
|
||||
// -------------------------- Globals --------------------- {{{1
|
||||
int asan_inited;
|
||||
bool asan_init_is_running;
|
||||
void (*death_callback)(void);
|
||||
|
||||
// -------------------------- Misc ---------------- {{{1
|
||||
void ShowStatsAndAbort() {
|
||||
__asan_print_accumulated_stats();
|
||||
Die();
|
||||
}
|
||||
|
||||
// ---------------------- mmap -------------------- {{{1
|
||||
// Reserve memory range [beg, end].
|
||||
static void ReserveShadowMemoryRange(uptr beg, uptr end) {
|
||||
CHECK((beg % kPageSize) == 0);
|
||||
CHECK(((end + 1) % kPageSize) == 0);
|
||||
uptr size = end - beg + 1;
|
||||
void *res = MmapFixedNoReserve(beg, size);
|
||||
if (res != (void*)beg) {
|
||||
Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
|
||||
"Perhaps you're using ulimit -v\n", size);
|
||||
Abort();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------- LowLevelAllocateCallbac ---------- {{{1
|
||||
static void OnLowLevelAllocate(uptr ptr, uptr size) {
|
||||
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
|
||||
}
|
||||
|
||||
// -------------------------- Run-time entry ------------------- {{{1
|
||||
// exported functions
|
||||
#define ASAN_REPORT_ERROR(type, is_write, size) \
|
||||
extern "C" NOINLINE INTERFACE_ATTRIBUTE \
|
||||
void __asan_report_ ## type ## size(uptr addr); \
|
||||
void __asan_report_ ## type ## size(uptr addr) { \
|
||||
GET_CALLER_PC_BP_SP; \
|
||||
__asan_report_error(pc, bp, sp, addr, is_write, size); \
|
||||
}
|
||||
|
||||
ASAN_REPORT_ERROR(load, false, 1)
|
||||
ASAN_REPORT_ERROR(load, false, 2)
|
||||
ASAN_REPORT_ERROR(load, false, 4)
|
||||
ASAN_REPORT_ERROR(load, false, 8)
|
||||
ASAN_REPORT_ERROR(load, false, 16)
|
||||
ASAN_REPORT_ERROR(store, true, 1)
|
||||
ASAN_REPORT_ERROR(store, true, 2)
|
||||
ASAN_REPORT_ERROR(store, true, 4)
|
||||
ASAN_REPORT_ERROR(store, true, 8)
|
||||
ASAN_REPORT_ERROR(store, true, 16)
|
||||
|
||||
// Force the linker to keep the symbols for various ASan interface functions.
|
||||
// We want to keep those in the executable in order to let the instrumented
|
||||
// dynamic libraries access the symbol even if it is not used by the executable
|
||||
// itself. This should help if the build system is removing dead code at link
|
||||
// time.
|
||||
static NOINLINE void force_interface_symbols() {
|
||||
volatile int fake_condition = 0; // prevent dead condition elimination.
|
||||
// __asan_report_* functions are noreturn, so we need a switch to prevent
|
||||
// the compiler from removing any of them.
|
||||
switch (fake_condition) {
|
||||
case 1: __asan_report_load1(0); break;
|
||||
case 2: __asan_report_load2(0); break;
|
||||
case 3: __asan_report_load4(0); break;
|
||||
case 4: __asan_report_load8(0); break;
|
||||
case 5: __asan_report_load16(0); break;
|
||||
case 6: __asan_report_store1(0); break;
|
||||
case 7: __asan_report_store2(0); break;
|
||||
case 8: __asan_report_store4(0); break;
|
||||
case 9: __asan_report_store8(0); break;
|
||||
case 10: __asan_report_store16(0); break;
|
||||
case 11: __asan_register_global(0, 0, 0); break;
|
||||
case 12: __asan_register_globals(0, 0); break;
|
||||
case 13: __asan_unregister_globals(0, 0); break;
|
||||
case 14: __asan_set_death_callback(0); break;
|
||||
case 15: __asan_set_error_report_callback(0); break;
|
||||
case 16: __asan_handle_no_return(); break;
|
||||
case 17: __asan_address_is_poisoned(0); break;
|
||||
case 18: __asan_get_allocated_size(0); break;
|
||||
case 19: __asan_get_current_allocated_bytes(); break;
|
||||
case 20: __asan_get_estimated_allocated_size(0); break;
|
||||
case 21: __asan_get_free_bytes(); break;
|
||||
case 22: __asan_get_heap_size(); break;
|
||||
case 23: __asan_get_ownership(0); break;
|
||||
case 24: __asan_get_unmapped_bytes(); break;
|
||||
case 25: __asan_poison_memory_region(0, 0); break;
|
||||
case 26: __asan_unpoison_memory_region(0, 0); break;
|
||||
case 27: __asan_set_error_exit_code(0); break;
|
||||
case 28: __asan_stack_free(0, 0, 0); break;
|
||||
case 29: __asan_stack_malloc(0, 0); break;
|
||||
case 30: __asan_on_error(); break;
|
||||
case 31: __asan_default_options(); break;
|
||||
case 32: __asan_before_dynamic_init(0, 0); break;
|
||||
case 33: __asan_after_dynamic_init(); break;
|
||||
case 34: __asan_malloc_hook(0, 0); break;
|
||||
case 35: __asan_free_hook(0); break;
|
||||
case 36: __asan_symbolize(0, 0, 0); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void asan_atexit() {
|
||||
Printf("AddressSanitizer exit stats:\n");
|
||||
__asan_print_accumulated_stats();
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
int NOINLINE __asan_set_error_exit_code(int exit_code) {
|
||||
int old = flags()->exitcode;
|
||||
flags()->exitcode = exit_code;
|
||||
return old;
|
||||
}
|
||||
|
||||
void NOINLINE __asan_handle_no_return() {
|
||||
int local_stack;
|
||||
AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
|
||||
CHECK(curr_thread);
|
||||
uptr top = curr_thread->stack_top();
|
||||
uptr bottom = ((uptr)&local_stack - kPageSize) & ~(kPageSize-1);
|
||||
PoisonShadow(bottom, top - bottom, 0);
|
||||
}
|
||||
|
||||
void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
|
||||
death_callback = callback;
|
||||
}
|
||||
|
||||
void __asan_init() {
|
||||
if (asan_inited) return;
|
||||
CHECK(!asan_init_is_running && "ASan init calls itself!");
|
||||
asan_init_is_running = true;
|
||||
|
||||
// Make sure we are not statically linked.
|
||||
AsanDoesNotSupportStaticLinkage();
|
||||
|
||||
// Install tool-specific callbacks in sanitizer_common.
|
||||
SetDieCallback(AsanDie);
|
||||
SetCheckFailedCallback(AsanCheckFailed);
|
||||
SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
|
||||
|
||||
// Initialize flags. This must be done early, because most of the
|
||||
// initialization steps look at flags().
|
||||
const char *options = GetEnv("ASAN_OPTIONS");
|
||||
InitializeFlags(flags(), options);
|
||||
__sanitizer_set_report_path(flags()->log_path);
|
||||
|
||||
if (flags()->verbosity && options) {
|
||||
Report("Parsed ASAN_OPTIONS: %s\n", options);
|
||||
}
|
||||
|
||||
// Re-exec ourselves if we need to set additional env or command line args.
|
||||
MaybeReexec();
|
||||
|
||||
// Setup internal allocator callback.
|
||||
SetLowLevelAllocateCallback(OnLowLevelAllocate);
|
||||
|
||||
if (flags()->atexit) {
|
||||
Atexit(asan_atexit);
|
||||
}
|
||||
|
||||
// interceptors
|
||||
InitializeAsanInterceptors();
|
||||
|
||||
ReplaceSystemMalloc();
|
||||
ReplaceOperatorsNewAndDelete();
|
||||
|
||||
if (flags()->verbosity) {
|
||||
Printf("|| `[%p, %p]` || HighMem ||\n",
|
||||
(void*)kHighMemBeg, (void*)kHighMemEnd);
|
||||
Printf("|| `[%p, %p]` || HighShadow ||\n",
|
||||
(void*)kHighShadowBeg, (void*)kHighShadowEnd);
|
||||
Printf("|| `[%p, %p]` || ShadowGap ||\n",
|
||||
(void*)kShadowGapBeg, (void*)kShadowGapEnd);
|
||||
Printf("|| `[%p, %p]` || LowShadow ||\n",
|
||||
(void*)kLowShadowBeg, (void*)kLowShadowEnd);
|
||||
Printf("|| `[%p, %p]` || LowMem ||\n",
|
||||
(void*)kLowMemBeg, (void*)kLowMemEnd);
|
||||
Printf("MemToShadow(shadow): %p %p %p %p\n",
|
||||
(void*)MEM_TO_SHADOW(kLowShadowBeg),
|
||||
(void*)MEM_TO_SHADOW(kLowShadowEnd),
|
||||
(void*)MEM_TO_SHADOW(kHighShadowBeg),
|
||||
(void*)MEM_TO_SHADOW(kHighShadowEnd));
|
||||
Printf("red_zone=%zu\n", (uptr)flags()->redzone);
|
||||
Printf("malloc_context_size=%zu\n", (uptr)flags()->malloc_context_size);
|
||||
|
||||
Printf("SHADOW_SCALE: %zx\n", (uptr)SHADOW_SCALE);
|
||||
Printf("SHADOW_GRANULARITY: %zx\n", (uptr)SHADOW_GRANULARITY);
|
||||
Printf("SHADOW_OFFSET: %zx\n", (uptr)SHADOW_OFFSET);
|
||||
CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
|
||||
}
|
||||
|
||||
if (flags()->disable_core) {
|
||||
DisableCoreDumper();
|
||||
}
|
||||
|
||||
uptr shadow_start = kLowShadowBeg;
|
||||
if (kLowShadowBeg > 0) shadow_start -= kMmapGranularity;
|
||||
uptr shadow_end = kHighShadowEnd;
|
||||
if (MemoryRangeIsAvailable(shadow_start, shadow_end)) {
|
||||
if (kLowShadowBeg != kLowShadowEnd) {
|
||||
// mmap the low shadow plus at least one page.
|
||||
ReserveShadowMemoryRange(kLowShadowBeg - kMmapGranularity, kLowShadowEnd);
|
||||
}
|
||||
// mmap the high shadow.
|
||||
ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd);
|
||||
// protect the gap
|
||||
void *prot = Mprotect(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
|
||||
CHECK(prot == (void*)kShadowGapBeg);
|
||||
} else {
|
||||
Report("Shadow memory range interleaves with an existing memory mapping. "
|
||||
"ASan cannot proceed correctly. ABORTING.\n");
|
||||
DumpProcessMap();
|
||||
Die();
|
||||
}
|
||||
|
||||
InstallSignalHandlers();
|
||||
// Start symbolizer process if necessary.
|
||||
if (flags()->symbolize) {
|
||||
const char *external_symbolizer = GetEnv("ASAN_SYMBOLIZER_PATH");
|
||||
if (external_symbolizer) {
|
||||
InitializeExternalSymbolizer(external_symbolizer);
|
||||
}
|
||||
}
|
||||
|
||||
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
|
||||
// should be set to 1 prior to initializing the threads.
|
||||
asan_inited = 1;
|
||||
asan_init_is_running = false;
|
||||
|
||||
asanThreadRegistry().Init();
|
||||
asanThreadRegistry().GetMain()->ThreadStart();
|
||||
force_interface_symbols(); // no-op.
|
||||
|
||||
if (flags()->verbosity) {
|
||||
Report("AddressSanitizer Init done\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ASAN_USE_PREINIT_ARRAY)
|
||||
// On Linux, we force __asan_init to be called before anyone else
|
||||
// by placing it into .preinit_array section.
|
||||
// FIXME: do we have anything like this on Mac?
|
||||
__attribute__((section(".preinit_array")))
|
||||
typeof(__asan_init) *__asan_preinit =__asan_init;
|
||||
#elif defined(_WIN32) && defined(_DLL)
|
||||
// On Windows, when using dynamic CRT (/MD), we can put a pointer
|
||||
// to __asan_init into the global list of C initializers.
|
||||
// See crt0dat.c in the CRT sources for the details.
|
||||
#pragma section(".CRT$XIB", long, read) // NOLINT
|
||||
__declspec(allocate(".CRT$XIB")) void (*__asan_preinit)() = __asan_init;
|
||||
#endif
|
35
libsanitizer/asan/asan_stack.cc
Normal file
35
libsanitizer/asan/asan_stack.cc
Normal file
@ -0,0 +1,35 @@
|
||||
//===-- asan_stack.cc -----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Code for ASan stack trace.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_flags.h"
|
||||
#include "asan_stack.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void PrintStack(StackTrace *stack) {
|
||||
stack->PrintStack(stack->trace, stack->size, flags()->symbolize,
|
||||
flags()->strip_path_prefix, __asan_symbolize);
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ------------------ Interface -------------- {{{1
|
||||
|
||||
// Provide default implementation of __asan_symbolize that does nothing
|
||||
// and may be overriden by user if he wants to use his own symbolization.
|
||||
// ASan on Windows has its own implementation of this.
|
||||
#ifndef _WIN32
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
|
||||
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
52
libsanitizer/asan/asan_stack.h
Normal file
52
libsanitizer/asan/asan_stack.h
Normal file
@ -0,0 +1,52 @@
|
||||
//===-- asan_stack.h --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_stack.cc.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_STACK_H
|
||||
#define ASAN_STACK_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp);
|
||||
void PrintStack(StackTrace *stack);
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// Get the stack trace with the given pc and bp.
|
||||
// The pc will be in the position 0 of the resulting stack trace.
|
||||
// The bp may refer to the current frame or to the caller's frame.
|
||||
// fast_unwind is currently unused.
|
||||
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp) \
|
||||
StackTrace stack; \
|
||||
GetStackTrace(&stack, max_s, pc, bp)
|
||||
|
||||
// NOTE: A Rule of thumb is to retrieve stack trace in the interceptors
|
||||
// as early as possible (in functions exposed to the user), as we generally
|
||||
// don't want stack trace to contain functions from ASan internals.
|
||||
|
||||
#define GET_STACK_TRACE_HERE(max_size) \
|
||||
GET_STACK_TRACE_WITH_PC_AND_BP(max_size, \
|
||||
StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
|
||||
|
||||
#define GET_STACK_TRACE_HERE_FOR_MALLOC \
|
||||
GET_STACK_TRACE_HERE(flags()->malloc_context_size)
|
||||
|
||||
#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \
|
||||
GET_STACK_TRACE_HERE(flags()->malloc_context_size)
|
||||
|
||||
#define PRINT_CURRENT_STACK() \
|
||||
{ \
|
||||
GET_STACK_TRACE_HERE(kStackTraceMax); \
|
||||
PrintStack(&stack); \
|
||||
}
|
||||
|
||||
#endif // ASAN_STACK_H
|
86
libsanitizer/asan/asan_stats.cc
Normal file
86
libsanitizer/asan/asan_stats.cc
Normal file
@ -0,0 +1,86 @@
|
||||
//===-- asan_stats.cc -----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Code related to statistics collected by AddressSanitizer.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer/asan_interface.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
AsanStats::AsanStats() {
|
||||
CHECK(REAL(memset) != 0);
|
||||
REAL(memset)(this, 0, sizeof(AsanStats));
|
||||
}
|
||||
|
||||
static void PrintMallocStatsArray(const char *prefix,
|
||||
uptr (&array)[kNumberOfSizeClasses]) {
|
||||
Printf("%s", prefix);
|
||||
for (uptr i = 0; i < kNumberOfSizeClasses; i++) {
|
||||
if (!array[i]) continue;
|
||||
Printf("%zu:%zu; ", i, array[i]);
|
||||
}
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
void AsanStats::Print() {
|
||||
Printf("Stats: %zuM malloced (%zuM for red zones) by %zu calls\n",
|
||||
malloced>>20, malloced_redzones>>20, mallocs);
|
||||
Printf("Stats: %zuM realloced by %zu calls\n", realloced>>20, reallocs);
|
||||
Printf("Stats: %zuM freed by %zu calls\n", freed>>20, frees);
|
||||
Printf("Stats: %zuM really freed by %zu calls\n",
|
||||
really_freed>>20, real_frees);
|
||||
Printf("Stats: %zuM (%zu full pages) mmaped in %zu calls\n",
|
||||
mmaped>>20, mmaped / kPageSize, mmaps);
|
||||
|
||||
PrintMallocStatsArray(" mmaps by size class: ", mmaped_by_size);
|
||||
PrintMallocStatsArray(" mallocs by size class: ", malloced_by_size);
|
||||
PrintMallocStatsArray(" frees by size class: ", freed_by_size);
|
||||
PrintMallocStatsArray(" rfrees by size class: ", really_freed_by_size);
|
||||
Printf("Stats: malloc large: %zu small slow: %zu\n",
|
||||
malloc_large, malloc_small_slow);
|
||||
}
|
||||
|
||||
static AsanLock print_lock(LINKER_INITIALIZED);
|
||||
|
||||
static void PrintAccumulatedStats() {
|
||||
AsanStats stats = asanThreadRegistry().GetAccumulatedStats();
|
||||
// Use lock to keep reports from mixing up.
|
||||
ScopedLock lock(&print_lock);
|
||||
stats.Print();
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
uptr __asan_get_current_allocated_bytes() {
|
||||
return asanThreadRegistry().GetCurrentAllocatedBytes();
|
||||
}
|
||||
|
||||
uptr __asan_get_heap_size() {
|
||||
return asanThreadRegistry().GetHeapSize();
|
||||
}
|
||||
|
||||
uptr __asan_get_free_bytes() {
|
||||
return asanThreadRegistry().GetFreeBytes();
|
||||
}
|
||||
|
||||
uptr __asan_get_unmapped_bytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __asan_print_accumulated_stats() {
|
||||
PrintAccumulatedStats();
|
||||
}
|
65
libsanitizer/asan/asan_stats.h
Normal file
65
libsanitizer/asan/asan_stats.h
Normal file
@ -0,0 +1,65 @@
|
||||
//===-- asan_stats.h --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for statistics.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_STATS_H
|
||||
#define ASAN_STATS_H
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// AsanStats struct is NOT thread-safe.
|
||||
// Each AsanThread has its own AsanStats, which are sometimes flushed
|
||||
// to the accumulated AsanStats.
|
||||
struct AsanStats {
|
||||
// AsanStats must be a struct consisting of uptr fields only.
|
||||
// When merging two AsanStats structs, we treat them as arrays of uptr.
|
||||
uptr mallocs;
|
||||
uptr malloced;
|
||||
uptr malloced_redzones;
|
||||
uptr frees;
|
||||
uptr freed;
|
||||
uptr real_frees;
|
||||
uptr really_freed;
|
||||
uptr really_freed_redzones;
|
||||
uptr reallocs;
|
||||
uptr realloced;
|
||||
uptr mmaps;
|
||||
uptr mmaped;
|
||||
uptr mmaped_by_size[kNumberOfSizeClasses];
|
||||
uptr malloced_by_size[kNumberOfSizeClasses];
|
||||
uptr freed_by_size[kNumberOfSizeClasses];
|
||||
uptr really_freed_by_size[kNumberOfSizeClasses];
|
||||
|
||||
uptr malloc_large;
|
||||
uptr malloc_small_slow;
|
||||
|
||||
// Ctor for global AsanStats (accumulated stats and main thread stats).
|
||||
explicit AsanStats(LinkerInitialized) { }
|
||||
// Default ctor for thread-local stats.
|
||||
AsanStats();
|
||||
|
||||
// Prints formatted stats to stderr.
|
||||
void Print();
|
||||
};
|
||||
|
||||
// A cross-platform equivalent of malloc_statistics_t on Mac OS.
|
||||
struct AsanMallocStats {
|
||||
uptr blocks_in_use;
|
||||
uptr size_in_use;
|
||||
uptr max_size_in_use;
|
||||
uptr size_allocated;
|
||||
};
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_STATS_H
|
153
libsanitizer/asan/asan_thread.cc
Normal file
153
libsanitizer/asan/asan_thread.cc
Normal file
@ -0,0 +1,153 @@
|
||||
//===-- asan_thread.cc ----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Thread-related code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
AsanThread::AsanThread(LinkerInitialized x)
|
||||
: fake_stack_(x),
|
||||
malloc_storage_(x),
|
||||
stats_(x) { }
|
||||
|
||||
AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
|
||||
void *arg, StackTrace *stack) {
|
||||
uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
|
||||
AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
|
||||
thread->start_routine_ = start_routine;
|
||||
thread->arg_ = arg;
|
||||
|
||||
const uptr kSummaryAllocSize = kPageSize;
|
||||
CHECK_LE(sizeof(AsanThreadSummary), kSummaryAllocSize);
|
||||
AsanThreadSummary *summary =
|
||||
(AsanThreadSummary*)MmapOrDie(kPageSize, "AsanThreadSummary");
|
||||
summary->Init(parent_tid, stack);
|
||||
summary->set_thread(thread);
|
||||
thread->set_summary(summary);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
void AsanThreadSummary::TSDDtor(void *tsd) {
|
||||
AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
|
||||
if (flags()->verbosity >= 1) {
|
||||
Report("T%d TSDDtor\n", summary->tid());
|
||||
}
|
||||
if (summary->thread()) {
|
||||
summary->thread()->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void AsanThread::Destroy() {
|
||||
if (flags()->verbosity >= 1) {
|
||||
Report("T%d exited\n", tid());
|
||||
}
|
||||
|
||||
asanThreadRegistry().UnregisterThread(this);
|
||||
CHECK(summary()->thread() == 0);
|
||||
// We also clear the shadow on thread destruction because
|
||||
// some code may still be executing in later TSD destructors
|
||||
// and we don't want it to have any poisoned stack.
|
||||
ClearShadowForThreadStack();
|
||||
fake_stack().Cleanup();
|
||||
uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
|
||||
UnmapOrDie(this, size);
|
||||
}
|
||||
|
||||
void AsanThread::Init() {
|
||||
SetThreadStackTopAndBottom();
|
||||
CHECK(AddrIsInMem(stack_bottom_));
|
||||
CHECK(AddrIsInMem(stack_top_));
|
||||
ClearShadowForThreadStack();
|
||||
if (flags()->verbosity >= 1) {
|
||||
int local = 0;
|
||||
Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
|
||||
tid(), (void*)stack_bottom_, (void*)stack_top_,
|
||||
stack_top_ - stack_bottom_, &local);
|
||||
}
|
||||
fake_stack_.Init(stack_size());
|
||||
AsanPlatformThreadInit();
|
||||
}
|
||||
|
||||
thread_return_t AsanThread::ThreadStart() {
|
||||
Init();
|
||||
if (flags()->use_sigaltstack) SetAlternateSignalStack();
|
||||
|
||||
if (!start_routine_) {
|
||||
// start_routine_ == 0 if we're on the main thread or on one of the
|
||||
// OS X libdispatch worker threads. But nobody is supposed to call
|
||||
// ThreadStart() for the worker threads.
|
||||
CHECK(tid() == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread_return_t res = start_routine_(arg_);
|
||||
malloc_storage().CommitBack();
|
||||
if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
|
||||
|
||||
this->Destroy();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void AsanThread::SetThreadStackTopAndBottom() {
|
||||
GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
|
||||
int local;
|
||||
CHECK(AddrIsInStack((uptr)&local));
|
||||
}
|
||||
|
||||
void AsanThread::ClearShadowForThreadStack() {
|
||||
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
|
||||
}
|
||||
|
||||
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
|
||||
uptr bottom = 0;
|
||||
bool is_fake_stack = false;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
} else {
|
||||
bottom = fake_stack().AddrIsInFakeStack(addr);
|
||||
CHECK(bottom);
|
||||
is_fake_stack = true;
|
||||
}
|
||||
uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr != kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
}
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr == kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
}
|
||||
|
||||
if (shadow_ptr < shadow_bottom) {
|
||||
*offset = 0;
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
|
||||
CHECK((ptr[0] == kCurrentStackFrameMagic) ||
|
||||
(is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
|
||||
*offset = addr - (uptr)ptr;
|
||||
return (const char*)ptr[1];
|
||||
}
|
||||
|
||||
} // namespace __asan
|
103
libsanitizer/asan/asan_thread.h
Normal file
103
libsanitizer/asan/asan_thread.h
Normal file
@ -0,0 +1,103 @@
|
||||
//===-- asan_thread.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_thread.cc.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef ASAN_THREAD_H
|
||||
#define ASAN_THREAD_H
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
|
||||
|
||||
class AsanThread;
|
||||
|
||||
// These objects are created for every thread and are never deleted,
|
||||
// so we can find them by tid even if the thread is long dead.
|
||||
class AsanThreadSummary {
|
||||
public:
|
||||
explicit AsanThreadSummary(LinkerInitialized) { } // for T0.
|
||||
void Init(u32 parent_tid, StackTrace *stack) {
|
||||
parent_tid_ = parent_tid;
|
||||
announced_ = false;
|
||||
tid_ = kInvalidTid;
|
||||
if (stack) {
|
||||
internal_memcpy(&stack_, stack, sizeof(*stack));
|
||||
}
|
||||
thread_ = 0;
|
||||
}
|
||||
u32 tid() { return tid_; }
|
||||
void set_tid(u32 tid) { tid_ = tid; }
|
||||
u32 parent_tid() { return parent_tid_; }
|
||||
bool announced() { return announced_; }
|
||||
void set_announced(bool announced) { announced_ = announced; }
|
||||
StackTrace *stack() { return &stack_; }
|
||||
AsanThread *thread() { return thread_; }
|
||||
void set_thread(AsanThread *thread) { thread_ = thread; }
|
||||
static void TSDDtor(void *tsd);
|
||||
|
||||
private:
|
||||
u32 tid_;
|
||||
u32 parent_tid_;
|
||||
bool announced_;
|
||||
StackTrace stack_;
|
||||
AsanThread *thread_;
|
||||
};
|
||||
|
||||
// AsanThread are stored in TSD and destroyed when the thread dies.
|
||||
class AsanThread {
|
||||
public:
|
||||
explicit AsanThread(LinkerInitialized); // for T0.
|
||||
static AsanThread *Create(u32 parent_tid, thread_callback_t start_routine,
|
||||
void *arg, StackTrace *stack);
|
||||
void Destroy();
|
||||
|
||||
void Init(); // Should be called from the thread itself.
|
||||
thread_return_t ThreadStart();
|
||||
|
||||
uptr stack_top() { return stack_top_; }
|
||||
uptr stack_bottom() { return stack_bottom_; }
|
||||
uptr stack_size() { return stack_top_ - stack_bottom_; }
|
||||
u32 tid() { return summary_->tid(); }
|
||||
AsanThreadSummary *summary() { return summary_; }
|
||||
void set_summary(AsanThreadSummary *summary) { summary_ = summary; }
|
||||
|
||||
const char *GetFrameNameByAddr(uptr addr, uptr *offset);
|
||||
|
||||
bool AddrIsInStack(uptr addr) {
|
||||
return addr >= stack_bottom_ && addr < stack_top_;
|
||||
}
|
||||
|
||||
FakeStack &fake_stack() { return fake_stack_; }
|
||||
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
|
||||
AsanStats &stats() { return stats_; }
|
||||
|
||||
private:
|
||||
void SetThreadStackTopAndBottom();
|
||||
void ClearShadowForThreadStack();
|
||||
AsanThreadSummary *summary_;
|
||||
thread_callback_t start_routine_;
|
||||
void *arg_;
|
||||
uptr stack_top_;
|
||||
uptr stack_bottom_;
|
||||
|
||||
FakeStack fake_stack_;
|
||||
AsanThreadLocalMallocStorage malloc_storage_;
|
||||
AsanStats stats_;
|
||||
};
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_THREAD_H
|
188
libsanitizer/asan/asan_thread_registry.cc
Normal file
188
libsanitizer/asan/asan_thread_registry.cc
Normal file
@ -0,0 +1,188 @@
|
||||
//===-- asan_thread_registry.cc -------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// AsanThreadRegistry-related code. AsanThreadRegistry is a container
|
||||
// for summaries of all created threads.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_stack.h"
|
||||
#include "asan_thread.h"
|
||||
#include "asan_thread_registry.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
static AsanThreadRegistry asan_thread_registry(LINKER_INITIALIZED);
|
||||
|
||||
AsanThreadRegistry &asanThreadRegistry() {
|
||||
return asan_thread_registry;
|
||||
}
|
||||
|
||||
AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
|
||||
: main_thread_(x),
|
||||
main_thread_summary_(x),
|
||||
accumulated_stats_(x),
|
||||
max_malloced_memory_(x),
|
||||
mu_(x) { }
|
||||
|
||||
void AsanThreadRegistry::Init() {
|
||||
AsanTSDInit(AsanThreadSummary::TSDDtor);
|
||||
main_thread_.set_summary(&main_thread_summary_);
|
||||
main_thread_summary_.set_thread(&main_thread_);
|
||||
RegisterThread(&main_thread_);
|
||||
SetCurrent(&main_thread_);
|
||||
// At this point only one thread exists.
|
||||
inited_ = true;
|
||||
}
|
||||
|
||||
void AsanThreadRegistry::RegisterThread(AsanThread *thread) {
|
||||
ScopedLock lock(&mu_);
|
||||
u32 tid = n_threads_;
|
||||
n_threads_++;
|
||||
CHECK(n_threads_ < kMaxNumberOfThreads);
|
||||
|
||||
AsanThreadSummary *summary = thread->summary();
|
||||
CHECK(summary != 0);
|
||||
summary->set_tid(tid);
|
||||
thread_summaries_[tid] = summary;
|
||||
}
|
||||
|
||||
void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
|
||||
ScopedLock lock(&mu_);
|
||||
FlushToAccumulatedStatsUnlocked(&thread->stats());
|
||||
AsanThreadSummary *summary = thread->summary();
|
||||
CHECK(summary);
|
||||
summary->set_thread(0);
|
||||
}
|
||||
|
||||
AsanThread *AsanThreadRegistry::GetMain() {
|
||||
return &main_thread_;
|
||||
}
|
||||
|
||||
AsanThread *AsanThreadRegistry::GetCurrent() {
|
||||
AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
|
||||
if (!summary) {
|
||||
#if ASAN_ANDROID
|
||||
// On Android, libc constructor is called _after_ asan_init, and cleans up
|
||||
// TSD. Try to figure out if this is still the main thread by the stack
|
||||
// address. We are not entirely sure that we have correct main thread
|
||||
// limits, so only do this magic on Android, and only if the found thread is
|
||||
// the main thread.
|
||||
AsanThread* thread = FindThreadByStackAddress((uptr)&summary);
|
||||
if (thread && thread->tid() == 0) {
|
||||
SetCurrent(thread);
|
||||
return thread;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return summary->thread();
|
||||
}
|
||||
|
||||
void AsanThreadRegistry::SetCurrent(AsanThread *t) {
|
||||
CHECK(t->summary());
|
||||
if (flags()->verbosity >= 2) {
|
||||
Report("SetCurrent: %p for thread %p\n",
|
||||
t->summary(), (void*)GetThreadSelf());
|
||||
}
|
||||
// Make sure we do not reset the current AsanThread.
|
||||
CHECK(AsanTSDGet() == 0);
|
||||
AsanTSDSet(t->summary());
|
||||
CHECK(AsanTSDGet() == t->summary());
|
||||
}
|
||||
|
||||
AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
|
||||
AsanThread *t = GetCurrent();
|
||||
return (t) ? t->stats() : main_thread_.stats();
|
||||
}
|
||||
|
||||
AsanStats AsanThreadRegistry::GetAccumulatedStats() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_;
|
||||
}
|
||||
|
||||
uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_.malloced - accumulated_stats_.freed;
|
||||
}
|
||||
|
||||
uptr AsanThreadRegistry::GetHeapSize() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_.mmaped;
|
||||
}
|
||||
|
||||
uptr AsanThreadRegistry::GetFreeBytes() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_.mmaped
|
||||
- accumulated_stats_.malloced
|
||||
- accumulated_stats_.malloced_redzones
|
||||
+ accumulated_stats_.really_freed
|
||||
+ accumulated_stats_.really_freed_redzones;
|
||||
}
|
||||
|
||||
// Return several stats counters with a single call to
|
||||
// UpdateAccumulatedStatsUnlocked().
|
||||
void AsanThreadRegistry::FillMallocStatistics(AsanMallocStats *malloc_stats) {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
malloc_stats->blocks_in_use = accumulated_stats_.mallocs;
|
||||
malloc_stats->size_in_use = accumulated_stats_.malloced;
|
||||
malloc_stats->max_size_in_use = max_malloced_memory_;
|
||||
malloc_stats->size_allocated = accumulated_stats_.mmaped;
|
||||
}
|
||||
|
||||
AsanThreadSummary *AsanThreadRegistry::FindByTid(u32 tid) {
|
||||
CHECK(tid < n_threads_);
|
||||
CHECK(thread_summaries_[tid]);
|
||||
return thread_summaries_[tid];
|
||||
}
|
||||
|
||||
AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uptr addr) {
|
||||
ScopedLock lock(&mu_);
|
||||
for (u32 tid = 0; tid < n_threads_; tid++) {
|
||||
AsanThread *t = thread_summaries_[tid]->thread();
|
||||
if (!t || !(t->fake_stack().StackSize())) continue;
|
||||
if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
|
||||
for (u32 tid = 0; tid < n_threads_; tid++) {
|
||||
AsanThread *t = thread_summaries_[tid]->thread();
|
||||
if (t != 0) {
|
||||
FlushToAccumulatedStatsUnlocked(&t->stats());
|
||||
}
|
||||
}
|
||||
// This is not very accurate: we may miss allocation peaks that happen
|
||||
// between two updates of accumulated_stats_. For more accurate bookkeeping
|
||||
// the maximum should be updated on every malloc(), which is unacceptable.
|
||||
if (max_malloced_memory_ < accumulated_stats_.malloced) {
|
||||
max_malloced_memory_ = accumulated_stats_.malloced;
|
||||
}
|
||||
}
|
||||
|
||||
void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
|
||||
// AsanStats consists of variables of type uptr only.
|
||||
uptr *dst = (uptr*)&accumulated_stats_;
|
||||
uptr *src = (uptr*)stats;
|
||||
uptr num_fields = sizeof(AsanStats) / sizeof(uptr);
|
||||
for (uptr i = 0; i < num_fields; i++) {
|
||||
dst[i] += src[i];
|
||||
src[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __asan
|
83
libsanitizer/asan/asan_thread_registry.h
Normal file
83
libsanitizer/asan/asan_thread_registry.h
Normal file
@ -0,0 +1,83 @@
|
||||
//===-- asan_thread_registry.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// ASan-private header for asan_thread_registry.cc
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ASAN_THREAD_REGISTRY_H
|
||||
#define ASAN_THREAD_REGISTRY_H
|
||||
|
||||
#include "asan_lock.h"
|
||||
#include "asan_stack.h"
|
||||
#include "asan_stats.h"
|
||||
#include "asan_thread.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// Stores summaries of all created threads, returns current thread,
|
||||
// thread by tid, thread by stack address. There is a single instance
|
||||
// of AsanThreadRegistry for the whole program.
|
||||
// AsanThreadRegistry is thread-safe.
|
||||
class AsanThreadRegistry {
|
||||
public:
|
||||
explicit AsanThreadRegistry(LinkerInitialized);
|
||||
void Init();
|
||||
void RegisterThread(AsanThread *thread);
|
||||
void UnregisterThread(AsanThread *thread);
|
||||
|
||||
AsanThread *GetMain();
|
||||
// Get the current thread. May return 0.
|
||||
AsanThread *GetCurrent();
|
||||
void SetCurrent(AsanThread *t);
|
||||
|
||||
u32 GetCurrentTidOrInvalid() {
|
||||
if (!inited_) return 0;
|
||||
AsanThread *t = GetCurrent();
|
||||
return t ? t->tid() : kInvalidTid;
|
||||
}
|
||||
|
||||
// Returns stats for GetCurrent(), or stats for
|
||||
// T0 if GetCurrent() returns 0.
|
||||
AsanStats &GetCurrentThreadStats();
|
||||
// Flushes all thread-local stats to accumulated stats, and returns
|
||||
// a copy of accumulated stats.
|
||||
AsanStats GetAccumulatedStats();
|
||||
uptr GetCurrentAllocatedBytes();
|
||||
uptr GetHeapSize();
|
||||
uptr GetFreeBytes();
|
||||
void FillMallocStatistics(AsanMallocStats *malloc_stats);
|
||||
|
||||
AsanThreadSummary *FindByTid(u32 tid);
|
||||
AsanThread *FindThreadByStackAddress(uptr addr);
|
||||
|
||||
private:
|
||||
void UpdateAccumulatedStatsUnlocked();
|
||||
// Adds values of all counters in "stats" to accumulated stats,
|
||||
// and fills "stats" with zeroes.
|
||||
void FlushToAccumulatedStatsUnlocked(AsanStats *stats);
|
||||
|
||||
static const u32 kMaxNumberOfThreads = (1 << 22); // 4M
|
||||
AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads];
|
||||
AsanThread main_thread_;
|
||||
AsanThreadSummary main_thread_summary_;
|
||||
AsanStats accumulated_stats_;
|
||||
// Required for malloc_zone_statistics() on OS X. This can't be stored in
|
||||
// per-thread AsanStats.
|
||||
uptr max_malloced_memory_;
|
||||
u32 n_threads_;
|
||||
AsanLock mu_;
|
||||
bool inited_;
|
||||
};
|
||||
|
||||
// Returns a single instance of registry.
|
||||
AsanThreadRegistry &asanThreadRegistry();
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // ASAN_THREAD_REGISTRY_H
|
190
libsanitizer/asan/asan_win.cc
Normal file
190
libsanitizer/asan/asan_win.cc
Normal file
@ -0,0 +1,190 @@
|
||||
//===-- asan_win.cc -------------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Windows-specific details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <new> // FIXME: temporarily needed for placement new in AsanLock.
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_lock.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
|
||||
static AsanLock dbghelp_lock(LINKER_INITIALIZED);
|
||||
static bool dbghelp_initialized = false;
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
||||
stack->max_size = max_s;
|
||||
void *tmp[kStackTraceMax];
|
||||
|
||||
// FIXME: CaptureStackBackTrace might be too slow for us.
|
||||
// FIXME: Compare with StackWalk64.
|
||||
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
|
||||
uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
|
||||
uptr offset = 0;
|
||||
// Skip the RTL frames by searching for the PC in the stacktrace.
|
||||
// FIXME: this doesn't work well for the malloc/free stacks yet.
|
||||
for (uptr i = 0; i < cs_ret; i++) {
|
||||
if (pc != (uptr)tmp[i])
|
||||
continue;
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
|
||||
stack->size = cs_ret - offset;
|
||||
for (uptr i = 0; i < stack->size; i++)
|
||||
stack->trace[i] = (uptr)tmp[i + offset];
|
||||
}
|
||||
|
||||
// ---------------------- AsanLock ---------------- {{{1
|
||||
enum LockState {
|
||||
LOCK_UNINITIALIZED = 0,
|
||||
LOCK_READY = -1,
|
||||
};
|
||||
|
||||
AsanLock::AsanLock(LinkerInitialized li) {
|
||||
// FIXME: see comments in AsanLock::Lock() for the details.
|
||||
CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
|
||||
|
||||
CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
|
||||
InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
owner_ = LOCK_READY;
|
||||
}
|
||||
|
||||
void AsanLock::Lock() {
|
||||
if (owner_ == LOCK_UNINITIALIZED) {
|
||||
// FIXME: hm, global AsanLock objects are not initialized?!?
|
||||
// This might be a side effect of the clang+cl+link Frankenbuild...
|
||||
new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1));
|
||||
|
||||
// FIXME: If it turns out the linker doesn't invoke our
|
||||
// constructors, we should probably manually Lock/Unlock all the global
|
||||
// locks while we're starting in one thread to avoid double-init races.
|
||||
}
|
||||
EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
CHECK(owner_ == LOCK_READY);
|
||||
owner_ = GetThreadSelf();
|
||||
}
|
||||
|
||||
void AsanLock::Unlock() {
|
||||
CHECK(owner_ == GetThreadSelf());
|
||||
owner_ = LOCK_READY;
|
||||
LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
|
||||
}
|
||||
|
||||
// ---------------------- TSD ---------------- {{{1
|
||||
static bool tsd_key_inited = false;
|
||||
|
||||
static __declspec(thread) void *fake_tsd = 0;
|
||||
|
||||
void AsanTSDInit(void (*destructor)(void *tsd)) {
|
||||
// FIXME: we're ignoring the destructor for now.
|
||||
tsd_key_inited = true;
|
||||
}
|
||||
|
||||
void *AsanTSDGet() {
|
||||
CHECK(tsd_key_inited);
|
||||
return fake_tsd;
|
||||
}
|
||||
|
||||
void AsanTSDSet(void *tsd) {
|
||||
CHECK(tsd_key_inited);
|
||||
fake_tsd = tsd;
|
||||
}
|
||||
|
||||
// ---------------------- Various stuff ---------------- {{{1
|
||||
void MaybeReexec() {
|
||||
// No need to re-exec on Windows.
|
||||
}
|
||||
|
||||
void *AsanDoesNotSupportStaticLinkage() {
|
||||
#if defined(_DEBUG)
|
||||
#error Please build the runtime with a non-debug CRT: /MD or /MT
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetAlternateSignalStack() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
void UnsetAlternateSignalStack() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
void InstallSignalHandlers() {
|
||||
// FIXME: Decide what to do on Windows.
|
||||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
// Nothing here for now.
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
|
||||
bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
|
||||
ScopedLock lock(&dbghelp_lock);
|
||||
if (!dbghelp_initialized) {
|
||||
SymSetOptions(SYMOPT_DEFERRED_LOADS |
|
||||
SYMOPT_UNDNAME |
|
||||
SYMOPT_LOAD_LINES);
|
||||
CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
|
||||
// FIXME: We don't call SymCleanup() on exit yet - should we?
|
||||
dbghelp_initialized = true;
|
||||
}
|
||||
|
||||
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
DWORD64 offset = 0;
|
||||
BOOL got_objname = SymFromAddr(GetCurrentProcess(),
|
||||
(DWORD64)addr, &offset, symbol);
|
||||
if (!got_objname)
|
||||
return false;
|
||||
|
||||
DWORD unused;
|
||||
IMAGEHLP_LINE64 info;
|
||||
info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
|
||||
(DWORD64)addr, &unused, &info);
|
||||
int written = 0;
|
||||
out_buffer[0] = '\0';
|
||||
// FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
|
||||
if (got_fileline) {
|
||||
written += internal_snprintf(out_buffer + written, buffer_size - written,
|
||||
" %s %s:%d", symbol->Name,
|
||||
info.FileName, info.LineNumber);
|
||||
} else {
|
||||
written += internal_snprintf(out_buffer + written, buffer_size - written,
|
||||
" %s+0x%p", symbol->Name, offset);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
|
||||
#endif // _WIN32
|
6
libsanitizer/asan/libtool-version
Normal file
6
libsanitizer/asan/libtool-version
Normal file
@ -0,0 +1,6 @@
|
||||
# This file is used to maintain libtool version info for libmudflap. See
|
||||
# the libtool manual to understand the meaning of the fields. This is
|
||||
# a separate file so that version updates don't involve re-running
|
||||
# automake.
|
||||
# CURRENT:REVISION:AGE
|
||||
0:0:0
|
1530
libsanitizer/config.guess
vendored
Normal file
1530
libsanitizer/config.guess
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1773
libsanitizer/config.sub
vendored
Normal file
1773
libsanitizer/config.sub
vendored
Normal file
File diff suppressed because it is too large
Load Diff
17589
libsanitizer/configure
vendored
Executable file
17589
libsanitizer/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
42
libsanitizer/configure.ac
Normal file
42
libsanitizer/configure.ac
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT(package-unused, version-unused, libsanitizer)
|
||||
AC_CONFIG_SRCDIR([include/sanitizer/common_interface_defs.h])
|
||||
AC_CONFIG_AUX_DIR(.)
|
||||
AM_INIT_AUTOMAKE(foreign)
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AM_PROG_AS
|
||||
|
||||
AC_LIBTOOL_DLOPEN
|
||||
AM_PROG_LIBTOOL
|
||||
|
||||
AC_SUBST(enable_shared)
|
||||
AC_SUBST(enable_static)
|
||||
|
||||
#AM_ENABLE_MULTILIB(, ..)
|
||||
target_alias=${target_alias-$host_alias}
|
||||
AC_SUBST(target_alias)
|
||||
|
||||
toolexecdir='$(libdir)/gcc-lib/$(target_alias)'
|
||||
toolexeclibdir='$(libdir)'
|
||||
AC_SUBST(toolexecdir)
|
||||
AC_SUBST(toolexeclibdir)
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
||||
AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common asan], [DIR/Makefile ]),
|
||||
[cat > vpsed$$ << \_EOF
|
||||
s!`test -f '$<' || echo '$(srcdir)/'`!!
|
||||
_EOF
|
||||
sed -f vpsed$$ $ac_file > tmp$$
|
||||
mv tmp$$ $ac_file
|
||||
rm vpsed$$
|
||||
echo 'MULTISUBDIR =' >> $ac_file
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
630
libsanitizer/depcomp
Normal file
630
libsanitizer/depcomp
Normal file
@ -0,0 +1,630 @@
|
||||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
|
||||
# Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by `PROGRAMS ARGS'.
|
||||
object Object file output by `PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputing dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u="sed s,\\\\\\\\,/,g"
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say).
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts `$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
icc)
|
||||
# Intel's C compiler understands `-MD -MF file'. However on
|
||||
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||
# ICC 7.0 will fill foo.d with something like
|
||||
# foo.o: sub/foo.c
|
||||
# foo.o: sub/foo.h
|
||||
# which is wrong. We want:
|
||||
# sub/foo.o: sub/foo.c
|
||||
# sub/foo.o: sub/foo.h
|
||||
# sub/foo.c:
|
||||
# sub/foo.h:
|
||||
# ICC 7.1 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using \ :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
|
||||
sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add `dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||
test "x$dir" = "x$object" && dir=
|
||||
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# With Tru64 cc, shared objects can also be used to make a
|
||||
# static library. This mechanism is used in libtool 1.4 series to
|
||||
# handle both shared and static libraries in a single compilation.
|
||||
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
|
||||
#
|
||||
# With libtool 1.5 this exception was removed, and libtool now
|
||||
# generates 2 separate objects for the 2 libraries. These two
|
||||
# compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
|
||||
tmpdepfile2=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
|
||||
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.o.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
tmpdepfile4=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a tab and a space in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for `:'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove `-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E |
|
||||
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||
sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
197
libsanitizer/include/sanitizer/asan_interface.h
Normal file
197
libsanitizer/include/sanitizer/asan_interface.h
Normal file
@ -0,0 +1,197 @@
|
||||
//===-- sanitizer/asan_interface.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This header can be included by the instrumented program to fetch
|
||||
// data (mostly allocator statistics) from ASan runtime library.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_ASAN_INTERFACE_H
|
||||
#define SANITIZER_ASAN_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
// ----------- ATTENTION -------------
|
||||
// This header should NOT include any other headers from ASan runtime.
|
||||
// All functions in this header are extern "C" and start with __asan_.
|
||||
|
||||
using __sanitizer::uptr;
|
||||
|
||||
extern "C" {
|
||||
// This function should be called at the very beginning of the process,
|
||||
// before any instrumented code is executed and before any call to malloc.
|
||||
void __asan_init() SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// This function should be called by the instrumented code.
|
||||
// 'addr' is the address of a global variable called 'name' of 'size' bytes.
|
||||
void __asan_register_global(uptr addr, uptr size, const char *name)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// This structure describes an instrumented global variable.
|
||||
struct __asan_global {
|
||||
uptr beg; // The address of the global.
|
||||
uptr size; // The original size of the global.
|
||||
uptr size_with_redzone; // The size with the redzone.
|
||||
const char *name; // Name as a C string.
|
||||
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
|
||||
};
|
||||
|
||||
// These two functions should be called by the instrumented code.
|
||||
// 'globals' is an array of structures describing 'n' globals.
|
||||
void __asan_register_globals(__asan_global *globals, uptr n)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __asan_unregister_globals(__asan_global *globals, uptr n)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// These two functions should be called before and after dynamic initializers
|
||||
// run, respectively. They should be called with parameters describing all
|
||||
// dynamically initialized globals defined in the calling TU.
|
||||
void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __asan_after_dynamic_init()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// These two functions are used by the instrumented code in the
|
||||
// use-after-return mode. __asan_stack_malloc allocates size bytes of
|
||||
// fake stack and __asan_stack_free poisons it. real_stack is a pointer to
|
||||
// the real stack region.
|
||||
uptr __asan_stack_malloc(uptr size, uptr real_stack)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Marks memory region [addr, addr+size) as unaddressable.
|
||||
// This memory must be previously allocated by the user program. Accessing
|
||||
// addresses in this region from instrumented code is forbidden until
|
||||
// this region is unpoisoned. This function is not guaranteed to poison
|
||||
// the whole region - it may poison only subregion of [addr, addr+size) due
|
||||
// to ASan alignment restrictions.
|
||||
// Method is NOT thread-safe in the sense that no two threads can
|
||||
// (un)poison memory in the same memory region simultaneously.
|
||||
void __asan_poison_memory_region(void const volatile *addr, uptr size)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Marks memory region [addr, addr+size) as addressable.
|
||||
// This memory must be previously allocated by the user program. Accessing
|
||||
// addresses in this region is allowed until this region is poisoned again.
|
||||
// This function may unpoison a superregion of [addr, addr+size) due to
|
||||
// ASan alignment restrictions.
|
||||
// Method is NOT thread-safe in the sense that no two threads can
|
||||
// (un)poison memory in the same memory region simultaneously.
|
||||
void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Performs cleanup before a NoReturn function. Must be called before things
|
||||
// like _exit and execl to avoid false positives on stack.
|
||||
void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// User code should use macro instead of functions.
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
__asan_poison_memory_region((addr), (size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
__asan_unpoison_memory_region((addr), (size))
|
||||
#else
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
#endif
|
||||
|
||||
// Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
|
||||
// address will result in error report from AddressSanitizer).
|
||||
bool __asan_address_is_poisoned(void const volatile *addr)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// This is an internal function that is called to report an error.
|
||||
// However it is still a part of the interface because users may want to
|
||||
// set a breakpoint on this function in a debugger.
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||
uptr addr, bool is_write, uptr access_size)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Sets the exit code to use when reporting an error.
|
||||
// Returns the old value.
|
||||
int __asan_set_error_exit_code(int exit_code)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Sets the callback to be called right before death on error.
|
||||
// Passing 0 will unset the callback.
|
||||
void __asan_set_death_callback(void (*callback)(void))
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
void __asan_set_error_report_callback(void (*callback)(const char*))
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// User may provide function that would be called right when ASan detects
|
||||
// an error. This can be used to notice cases when ASan detects an error, but
|
||||
// the program crashes before ASan report is printed.
|
||||
void __asan_on_error()
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// User may provide its own implementation for symbolization function.
|
||||
// It should print the description of instruction at address "pc" to
|
||||
// "out_buffer". Description should be at most "out_size" bytes long.
|
||||
// User-specified function should return true if symbolization was
|
||||
// successful.
|
||||
bool __asan_symbolize(const void *pc, char *out_buffer, int out_size)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Returns the estimated number of bytes that will be reserved by allocator
|
||||
// for request of "size" bytes. If ASan allocator can't allocate that much
|
||||
// memory, returns the maximal possible allocation size, otherwise returns
|
||||
// "size".
|
||||
uptr __asan_get_estimated_allocated_size(uptr size)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Returns true if p was returned by the ASan allocator and
|
||||
// is not yet freed.
|
||||
bool __asan_get_ownership(const void *p)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Returns the number of bytes reserved for the pointer p.
|
||||
// Requires (get_ownership(p) == true) or (p == 0).
|
||||
uptr __asan_get_allocated_size(const void *p)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Number of bytes, allocated and not yet freed by the application.
|
||||
uptr __asan_get_current_allocated_bytes()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Number of bytes, mmaped by asan allocator to fulfill allocation requests.
|
||||
// Generally, for request of X bytes, allocator can reserve and add to free
|
||||
// lists a large number of chunks of size X to use them for future requests.
|
||||
// All these chunks count toward the heap size. Currently, allocator never
|
||||
// releases memory to OS (instead, it just puts freed chunks to free lists).
|
||||
uptr __asan_get_heap_size()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Number of bytes, mmaped by asan allocator, which can be used to fulfill
|
||||
// allocation requests. When a user program frees memory chunk, it can first
|
||||
// fall into quarantine and will count toward __asan_get_free_bytes() later.
|
||||
uptr __asan_get_free_bytes()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Number of bytes in unmapped pages, that are released to OS. Currently,
|
||||
// always returns 0.
|
||||
uptr __asan_get_unmapped_bytes()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
// Prints accumulated stats to stderr. Used for debugging.
|
||||
void __asan_print_accumulated_stats()
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// This function may be overriden by user to provide a string containing
|
||||
// ASan runtime options. See asan_flags.h for details.
|
||||
const char* __asan_default_options()
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Malloc hooks that may be overriden by user.
|
||||
// __asan_malloc_hook(ptr, size) is called immediately after
|
||||
// allocation of "size" bytes, which returned "ptr".
|
||||
// __asan_free_hook(ptr) is called immediately before
|
||||
// deallocation of "ptr".
|
||||
// If user doesn't provide implementations of these hooks, they are no-op.
|
||||
void __asan_malloc_hook(void *ptr, uptr size)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __asan_free_hook(void *ptr)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
} // extern "C"
|
||||
|
||||
#endif // SANITIZER_ASAN_INTERFACE_H
|
66
libsanitizer/include/sanitizer/common_interface_defs.h
Normal file
66
libsanitizer/include/sanitizer/common_interface_defs.h
Normal file
@ -0,0 +1,66 @@
|
||||
//===-- sanitizer/common_interface_defs.h -----------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer.
|
||||
// It contains basic macro and types.
|
||||
// NOTE: This file may be included into user code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
|
||||
#define SANITIZER_COMMON_INTERFACE_DEFS_H
|
||||
|
||||
// ----------- ATTENTION -------------
|
||||
// This header should NOT include any other headers to avoid portability issues.
|
||||
|
||||
#if defined(_WIN32)
|
||||
// FIXME find out what we need on Windows. __declspec(dllexport) ?
|
||||
# define SANITIZER_INTERFACE_ATTRIBUTE
|
||||
# define SANITIZER_WEAK_ATTRIBUTE
|
||||
#elif defined(SANITIZER_GO)
|
||||
# define SANITIZER_INTERFACE_ATTRIBUTE
|
||||
# define SANITIZER_WEAK_ATTRIBUTE
|
||||
#else
|
||||
# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
|
||||
# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
|
||||
#endif
|
||||
|
||||
// __has_feature
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
// For portability reasons we do not include stddef.h, stdint.h or any other
|
||||
// system header, but we do need some basic types that are not defined
|
||||
// in a portable way by the language itself.
|
||||
namespace __sanitizer {
|
||||
|
||||
#if defined(_WIN64)
|
||||
// 64-bit Windows uses LLP64 data model.
|
||||
typedef unsigned long long uptr; // NOLINT
|
||||
typedef signed long long sptr; // NOLINT
|
||||
#else
|
||||
typedef unsigned long uptr; // NOLINT
|
||||
typedef signed long sptr; // NOLINT
|
||||
#endif // defined(_WIN64)
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16; // NOLINT
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64; // NOLINT
|
||||
typedef signed char s8;
|
||||
typedef signed short s16; // NOLINT
|
||||
typedef signed int s32;
|
||||
typedef signed long long s64; // NOLINT
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
extern "C" {
|
||||
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
|
||||
void __sanitizer_set_report_path(const char *path)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
} // extern "C"
|
||||
|
||||
#endif // SANITIZER_COMMON_INTERFACE_DEFS_H
|
527
libsanitizer/install-sh
Normal file
527
libsanitizer/install-sh
Normal file
@ -0,0 +1,527 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2011-01-19.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
nl='
|
||||
'
|
||||
IFS=" "" $nl"
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit=${DOITPROG-}
|
||||
if test -z "$doit"; then
|
||||
doit_exec=exec
|
||||
else
|
||||
doit_exec=$doit
|
||||
fi
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_glob='?'
|
||||
initialize_posix_glob='
|
||||
test "$posix_glob" != "?" || {
|
||||
if (set -f) 2>/dev/null; then
|
||||
posix_glob=
|
||||
else
|
||||
posix_glob=:
|
||||
fi
|
||||
}
|
||||
'
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
no_target_directory=
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *' '* | *'
|
||||
'* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t) dst_arg=$2
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) no_target_directory=true;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call `install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for `test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
if test -n "$no_target_directory"; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dst=$dstdir/`basename "$src"`
|
||||
dstdir_status=0
|
||||
else
|
||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
||||
dstdir=`
|
||||
(dirname "$dst") 2>/dev/null ||
|
||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$dst" : 'X\(//\)[^/]' \| \
|
||||
X"$dst" : 'X\(//\)$' \| \
|
||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
||||
echo X"$dst" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)[^/].*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\/\)$/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
/^X\(\/\).*/{
|
||||
s//\1/
|
||||
q
|
||||
}
|
||||
s/.*/./; q'
|
||||
`
|
||||
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
if (umask $mkdir_umask &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writeable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/d" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
eval "$initialize_posix_glob"
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
$posix_glob set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
$posix_glob set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
|
||||
eval "$initialize_posix_glob" &&
|
||||
$posix_glob set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
$posix_glob set +f &&
|
||||
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
59
libsanitizer/interception/Makefile.am
Normal file
59
libsanitizer/interception/Makefile.am
Normal file
@ -0,0 +1,59 @@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include
|
||||
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
noinst_LTLIBRARIES = libinterception.la
|
||||
|
||||
interception_files = \
|
||||
interception_linux.cc \
|
||||
interception_mac.cc \
|
||||
interception_win.cc
|
||||
|
||||
libinterception_la_SOURCES = $(interception_files)
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES=
|
||||
|
||||
## ################################################################
|
||||
|
535
libsanitizer/interception/Makefile.in
Normal file
535
libsanitizer/interception/Makefile.in
Normal file
@ -0,0 +1,535 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in 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.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = interception
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libinterception_la_LIBADD =
|
||||
am__objects_1 = interception_linux.lo interception_mac.lo \
|
||||
interception_win.lo
|
||||
am_libinterception_la_OBJECTS = $(am__objects_1)
|
||||
libinterception_la_OBJECTS = $(am_libinterception_la_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libinterception_la_SOURCES)
|
||||
DIST_SOURCES = $(libinterception_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
enable_shared = @enable_shared@
|
||||
enable_static = @enable_static@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
noinst_LTLIBRARIES = libinterception.la
|
||||
interception_files = \
|
||||
interception_linux.cc \
|
||||
interception_mac.cc \
|
||||
interception_win.cc
|
||||
|
||||
libinterception_la_SOURCES = $(interception_files)
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES =
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cc .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign interception/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign interception/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libinterception.la: $(libinterception_la_OBJECTS) $(libinterception_la_DEPENDENCIES) $(EXTRA_libinterception_la_DEPENDENCIES)
|
||||
$(CXXLINK) $(libinterception_la_OBJECTS) $(libinterception_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_win.Plo@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||
|
||||
.cc.obj:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.cc.lo:
|
||||
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstLTLIBRARIES ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
pdf pdf-am ps ps-am tags uninstall uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
195
libsanitizer/interception/interception.h
Normal file
195
libsanitizer/interception/interception.h
Normal file
@ -0,0 +1,195 @@
|
||||
//===-- interception.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Machinery for providing replacements/wrappers for system functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef INTERCEPTION_H
|
||||
#define INTERCEPTION_H
|
||||
|
||||
#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
|
||||
# error "Interception doesn't work on this operating system."
|
||||
#endif
|
||||
|
||||
// How to use this library:
|
||||
// 1) Include this header to define your own interceptors
|
||||
// (see details below).
|
||||
// 2) Build all *.cc files and link against them.
|
||||
// On Mac you will also need to:
|
||||
// 3) Provide your own implementation for the following functions:
|
||||
// mach_error_t __interception::allocate_island(void **ptr,
|
||||
// size_t size,
|
||||
// void *hint);
|
||||
// mach_error_t __interception::deallocate_island(void *ptr);
|
||||
// See "interception_mac.h" for more details.
|
||||
|
||||
// How to add an interceptor:
|
||||
// Suppose you need to wrap/replace system function (generally, from libc):
|
||||
// int foo(const char *bar, double baz);
|
||||
// You'll need to:
|
||||
// 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in
|
||||
// your source file.
|
||||
// 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo".
|
||||
// INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was
|
||||
// intercepted successfully.
|
||||
// You can access original function by calling REAL(foo)(bar, baz).
|
||||
// By default, REAL(foo) will be visible only inside your interceptor, and if
|
||||
// you want to use it in other parts of RTL, you'll need to:
|
||||
// 3a) add DECLARE_REAL(int, foo, const char*, double) to a
|
||||
// header file.
|
||||
// However, if the call "INTERCEPT_FUNCTION(foo)" and definition for
|
||||
// INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to:
|
||||
// 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double)
|
||||
// to a header file.
|
||||
|
||||
// Notes: 1. Things may not work properly if macro INTERCEPT(...) {...} or
|
||||
// DECLARE_REAL(...) are located inside namespaces.
|
||||
// 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo);" to
|
||||
// effectively redirect calls from "foo" to "zoo". In this case
|
||||
// you aren't required to implement
|
||||
// INTERCEPTOR(int, foo, const char *bar, double baz) {...}
|
||||
// but instead you'll have to add
|
||||
// DEFINE_REAL(int, foo, const char *bar, double baz) in your
|
||||
// source file (to define a pointer to overriden function).
|
||||
|
||||
// How it works:
|
||||
// To replace system functions on Linux we just need to declare functions
|
||||
// with same names in our library and then obtain the real function pointers
|
||||
// using dlsym().
|
||||
// There is one complication. A user may also intercept some of the functions
|
||||
// we intercept. To resolve this we declare our interceptors with __interceptor_
|
||||
// prefix, and then make actual interceptors weak aliases to __interceptor_
|
||||
// functions.
|
||||
// This is not so on Mac OS, where the two-level namespace makes
|
||||
// our replacement functions invisible to other libraries. This may be overcomed
|
||||
// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
|
||||
// libraries in Chromium were noticed when doing so. Instead we use
|
||||
// mach_override, a handy framework for patching functions at runtime.
|
||||
// To avoid possible name clashes, our replacement functions have
|
||||
// the "wrap_" prefix on Mac.
|
||||
// An alternative to function patching is to create a dylib containing a
|
||||
// __DATA,__interpose section that associates library functions with their
|
||||
// wrappers. When this dylib is preloaded before an executable using
|
||||
// DYLD_INSERT_LIBRARIES, it routes all the calls to interposed functions done
|
||||
// through stubs to the wrapper functions. Such a library is built with
|
||||
// -DMAC_INTERPOSE_FUNCTIONS=1.
|
||||
|
||||
#if !defined(MAC_INTERPOSE_FUNCTIONS) || !defined(__APPLE__)
|
||||
# define MAC_INTERPOSE_FUNCTIONS 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define WRAP(x) wrap_##x
|
||||
# define WRAPPER_NAME(x) "wrap_"#x
|
||||
# define INTERCEPTOR_ATTRIBUTE
|
||||
# define DECLARE_WRAPPER(ret_type, func, ...)
|
||||
#elif defined(_WIN32)
|
||||
# if defined(_DLL) // DLL CRT
|
||||
# define WRAP(x) x
|
||||
# define WRAPPER_NAME(x) #x
|
||||
# define INTERCEPTOR_ATTRIBUTE
|
||||
# else // Static CRT
|
||||
# define WRAP(x) wrap_##x
|
||||
# define WRAPPER_NAME(x) "wrap_"#x
|
||||
# define INTERCEPTOR_ATTRIBUTE
|
||||
# endif
|
||||
# define DECLARE_WRAPPER(ret_type, func, ...)
|
||||
#else
|
||||
# define WRAP(x) __interceptor_ ## x
|
||||
# define WRAPPER_NAME(x) "__interceptor_" #x
|
||||
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
|
||||
# define DECLARE_WRAPPER(ret_type, func, ...) \
|
||||
extern "C" ret_type func(__VA_ARGS__) \
|
||||
__attribute__((weak, alias("__interceptor_" #func), visibility("default")));
|
||||
#endif
|
||||
|
||||
#if !MAC_INTERPOSE_FUNCTIONS
|
||||
# define PTR_TO_REAL(x) real_##x
|
||||
# define REAL(x) __interception::PTR_TO_REAL(x)
|
||||
# define FUNC_TYPE(x) x##_f
|
||||
|
||||
# define DECLARE_REAL(ret_type, func, ...) \
|
||||
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
|
||||
namespace __interception { \
|
||||
extern FUNC_TYPE(func) PTR_TO_REAL(func); \
|
||||
}
|
||||
#else // MAC_INTERPOSE_FUNCTIONS
|
||||
# define REAL(x) x
|
||||
# define DECLARE_REAL(ret_type, func, ...) \
|
||||
extern "C" ret_type func(__VA_ARGS__);
|
||||
#endif // MAC_INTERPOSE_FUNCTIONS
|
||||
|
||||
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
|
||||
DECLARE_REAL(ret_type, func, __VA_ARGS__) \
|
||||
extern "C" ret_type WRAP(func)(__VA_ARGS__);
|
||||
|
||||
// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
|
||||
// macros does its job. In exceptional cases you may need to call REAL(foo)
|
||||
// without defining INTERCEPTOR(..., foo, ...). For example, if you override
|
||||
// foo with an interceptor for other function.
|
||||
#if !MAC_INTERPOSE_FUNCTIONS
|
||||
# define DEFINE_REAL(ret_type, func, ...) \
|
||||
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
|
||||
namespace __interception { \
|
||||
FUNC_TYPE(func) PTR_TO_REAL(func); \
|
||||
}
|
||||
#else
|
||||
# define DEFINE_REAL(ret_type, func, ...)
|
||||
#endif
|
||||
|
||||
#define INTERCEPTOR(ret_type, func, ...) \
|
||||
DEFINE_REAL(ret_type, func, __VA_ARGS__) \
|
||||
DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
|
||||
extern "C" \
|
||||
INTERCEPTOR_ATTRIBUTE \
|
||||
ret_type WRAP(func)(__VA_ARGS__)
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
|
||||
typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
|
||||
namespace __interception { \
|
||||
FUNC_TYPE(func) PTR_TO_REAL(func); \
|
||||
} \
|
||||
DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
|
||||
extern "C" \
|
||||
INTERCEPTOR_ATTRIBUTE \
|
||||
ret_type __stdcall WRAP(func)(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
|
||||
// so we use casting via an integral type __interception::uptr,
|
||||
// assuming that system is POSIX-compliant. Using other hacks seem
|
||||
// challenging, as we don't even pass function type to
|
||||
// INTERCEPT_FUNCTION macro, only its name.
|
||||
namespace __interception {
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned long long uptr; // NOLINT
|
||||
#else
|
||||
typedef unsigned long uptr; // NOLINT
|
||||
#endif // _WIN64
|
||||
} // namespace __interception
|
||||
|
||||
#define INCLUDED_FROM_INTERCEPTION_LIB
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "interception_linux.h"
|
||||
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
|
||||
#elif defined(__APPLE__)
|
||||
# include "interception_mac.h"
|
||||
# define OVERRIDE_FUNCTION(old_func, new_func) \
|
||||
OVERRIDE_FUNCTION_MAC(old_func, new_func)
|
||||
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
|
||||
#else // defined(_WIN32)
|
||||
# include "interception_win.h"
|
||||
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
|
||||
#endif
|
||||
|
||||
#undef INCLUDED_FROM_INTERCEPTION_LIB
|
||||
|
||||
#endif // INTERCEPTION_H
|
28
libsanitizer/interception/interception_linux.cc
Normal file
28
libsanitizer/interception/interception_linux.cc
Normal file
@ -0,0 +1,28 @@
|
||||
//===-- interception_linux.cc -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Linux-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __linux__
|
||||
#include "interception.h"
|
||||
|
||||
#include <stddef.h> // for NULL
|
||||
#include <dlfcn.h> // for dlsym
|
||||
|
||||
namespace __interception {
|
||||
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
|
||||
uptr real, uptr wrapper) {
|
||||
*func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
|
||||
return real == wrapper;
|
||||
}
|
||||
} // namespace __interception
|
||||
|
||||
|
||||
#endif // __linux__
|
35
libsanitizer/interception/interception_linux.h
Normal file
35
libsanitizer/interception/interception_linux.h
Normal file
@ -0,0 +1,35 @@
|
||||
//===-- interception_linux.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Linux-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
|
||||
# error "interception_linux.h should be included from interception library only"
|
||||
#endif
|
||||
|
||||
#ifndef INTERCEPTION_LINUX_H
|
||||
#define INTERCEPTION_LINUX_H
|
||||
|
||||
namespace __interception {
|
||||
// returns true if a function with the given name was found.
|
||||
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
|
||||
uptr real, uptr wrapper);
|
||||
} // namespace __interception
|
||||
|
||||
#define INTERCEPT_FUNCTION_LINUX(func) \
|
||||
::__interception::GetRealFunctionAddress( \
|
||||
#func, (::__interception::uptr*)&REAL(func), \
|
||||
(::__interception::uptr)&(func), \
|
||||
(::__interception::uptr)&WRAP(func))
|
||||
|
||||
#endif // INTERCEPTION_LINUX_H
|
||||
#endif // __linux__
|
29
libsanitizer/interception/interception_mac.cc
Normal file
29
libsanitizer/interception/interception_mac.cc
Normal file
@ -0,0 +1,29 @@
|
||||
//===-- interception_mac.cc -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include "interception.h"
|
||||
#include "mach_override/mach_override.h"
|
||||
|
||||
namespace __interception {
|
||||
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
|
||||
*orig_old_func = 0;
|
||||
int res = __asan_mach_override_ptr_custom((void*)old_func, (void*)new_func,
|
||||
(void**)orig_old_func,
|
||||
__interception_allocate_island,
|
||||
__interception_deallocate_island);
|
||||
return (res == 0) && (*orig_old_func != 0);
|
||||
}
|
||||
} // namespace __interception
|
||||
|
||||
#endif // __APPLE__
|
47
libsanitizer/interception/interception_mac.h
Normal file
47
libsanitizer/interception/interception_mac.h
Normal file
@ -0,0 +1,47 @@
|
||||
//===-- interception_mac.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Mac-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
|
||||
# error "interception_mac.h should be included from interception.h only"
|
||||
#endif
|
||||
|
||||
#ifndef INTERCEPTION_MAC_H
|
||||
#define INTERCEPTION_MAC_H
|
||||
|
||||
#include <mach/mach_error.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// Allocate memory for the escape island. This cannot be moved to
|
||||
// mach_override, because each user of interceptors may specify its
|
||||
// own memory range for escape islands.
|
||||
extern "C" {
|
||||
mach_error_t __interception_allocate_island(void **ptr, size_t unused_size,
|
||||
void *unused_hint);
|
||||
mach_error_t __interception_deallocate_island(void *ptr);
|
||||
} // extern "C"
|
||||
|
||||
namespace __interception {
|
||||
// returns true if the old function existed.
|
||||
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
|
||||
} // namespace __interception
|
||||
|
||||
# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \
|
||||
::__interception::OverrideFunction( \
|
||||
(::__interception::uptr)old_func, \
|
||||
(::__interception::uptr)new_func, \
|
||||
(::__interception::uptr*)((::__interception::uptr)&REAL(old_func)))
|
||||
# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func))
|
||||
|
||||
#endif // INTERCEPTION_MAC_H
|
||||
#endif // __APPLE__
|
149
libsanitizer/interception/interception_win.cc
Normal file
149
libsanitizer/interception/interception_win.cc
Normal file
@ -0,0 +1,149 @@
|
||||
//===-- interception_linux.cc -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Windows-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "interception.h"
|
||||
#include <windows.h>
|
||||
|
||||
namespace __interception {
|
||||
|
||||
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr) {
|
||||
const char *DLLS[] = {
|
||||
"msvcr80.dll",
|
||||
"msvcr90.dll",
|
||||
"kernel32.dll",
|
||||
NULL
|
||||
};
|
||||
*func_addr = 0;
|
||||
for (size_t i = 0; *func_addr == 0 && DLLS[i]; ++i) {
|
||||
*func_addr = (uptr)GetProcAddress(GetModuleHandleA(DLLS[i]), func_name);
|
||||
}
|
||||
return (*func_addr != 0);
|
||||
}
|
||||
|
||||
// FIXME: internal_str* and internal_mem* functions should be moved from the
|
||||
// ASan sources into interception/.
|
||||
|
||||
static void _memset(void *p, int value, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
((char*)p)[i] = (char)value;
|
||||
}
|
||||
|
||||
static void _memcpy(void *dst, void *src, size_t sz) {
|
||||
char *dst_c = (char*)dst,
|
||||
*src_c = (char*)src;
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
dst_c[i] = src_c[i];
|
||||
}
|
||||
|
||||
static void WriteJumpInstruction(char *jmp_from, char *to) {
|
||||
// jmp XXYYZZWW = E9 WW ZZ YY XX, where XXYYZZWW is an offset fromt jmp_from
|
||||
// to the next instruction to the destination.
|
||||
ptrdiff_t offset = to - jmp_from - 5;
|
||||
*jmp_from = '\xE9';
|
||||
*(ptrdiff_t*)(jmp_from + 1) = offset;
|
||||
}
|
||||
|
||||
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
|
||||
#ifdef _WIN64
|
||||
# error OverrideFunction was not tested on x64
|
||||
#endif
|
||||
// Basic idea:
|
||||
// We write 5 bytes (jmp-to-new_func) at the beginning of the 'old_func'
|
||||
// to override it. We want to be able to execute the original 'old_func' from
|
||||
// the wrapper, so we need to keep the leading 5+ bytes ('head') of the
|
||||
// original instructions somewhere with a "jmp old_func+head".
|
||||
// We call these 'head'+5 bytes of instructions a "trampoline".
|
||||
|
||||
// Trampolines are allocated from a common pool.
|
||||
const int POOL_SIZE = 1024;
|
||||
static char *pool = NULL;
|
||||
static size_t pool_used = 0;
|
||||
if (pool == NULL) {
|
||||
pool = (char*)VirtualAlloc(NULL, POOL_SIZE,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
// FIXME: set PAGE_EXECUTE_READ access after setting all interceptors?
|
||||
if (pool == NULL)
|
||||
return false;
|
||||
_memset(pool, 0xCC /* int 3 */, POOL_SIZE);
|
||||
}
|
||||
|
||||
char* old_bytes = (char*)old_func;
|
||||
char* trampoline = pool + pool_used;
|
||||
|
||||
// Find out the number of bytes of the instructions we need to copy to the
|
||||
// island and store it in 'head'.
|
||||
size_t head = 0;
|
||||
while (head < 5) {
|
||||
switch (old_bytes[head]) {
|
||||
case '\x55': // push ebp
|
||||
case '\x56': // push esi
|
||||
case '\x57': // push edi
|
||||
head++;
|
||||
continue;
|
||||
}
|
||||
switch (*(unsigned short*)(old_bytes + head)) { // NOLINT
|
||||
case 0xFF8B: // 8B FF = mov edi, edi
|
||||
case 0xEC8B: // 8B EC = mov ebp, esp
|
||||
case 0xC033: // 33 C0 = xor eax, eax
|
||||
head += 2;
|
||||
continue;
|
||||
case 0xEC83: // 83 EC XX = sub esp, XX
|
||||
head += 3;
|
||||
continue;
|
||||
case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
|
||||
head += 6;
|
||||
continue;
|
||||
}
|
||||
switch (0x00FFFFFF & *(unsigned int*)(old_bytes + head)) {
|
||||
case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
|
||||
case 0x244C8B: // 8B 4C 24 XX = mov ecx, dword ptr [esp+XXh]
|
||||
case 0x24548B: // 8B 54 24 XX = mov edx, dword ptr [esp+XXh]
|
||||
case 0x247C8B: // 8B 7C 24 XX = mov edi, dword ptr [esp+XXh]
|
||||
head += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unknown instruction!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pool_used + head + 5 > POOL_SIZE)
|
||||
return false;
|
||||
|
||||
// Now put the "jump to trampoline" instruction into the original code.
|
||||
DWORD old_prot, unused_prot;
|
||||
if (!VirtualProtect((void*)old_func, head, PAGE_EXECUTE_READWRITE,
|
||||
&old_prot))
|
||||
return false;
|
||||
|
||||
// Put the needed instructions into the trampoline bytes.
|
||||
_memcpy(trampoline, old_bytes, head);
|
||||
WriteJumpInstruction(trampoline + head, old_bytes + head);
|
||||
*orig_old_func = (uptr)trampoline;
|
||||
pool_used += head + 5;
|
||||
|
||||
// Intercept the 'old_func'.
|
||||
WriteJumpInstruction(old_bytes, (char*)new_func);
|
||||
_memset(old_bytes + 5, 0xCC /* int 3 */, head - 5);
|
||||
|
||||
if (!VirtualProtect((void*)old_func, head, old_prot, &unused_prot))
|
||||
return false; // not clear if this failure bothers us.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace __interception
|
||||
|
||||
#endif // _WIN32
|
43
libsanitizer/interception/interception_win.h
Normal file
43
libsanitizer/interception/interception_win.h
Normal file
@ -0,0 +1,43 @@
|
||||
//===-- interception_linux.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Windows-specific interception methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
|
||||
# error "interception_win.h should be included from interception library only"
|
||||
#endif
|
||||
|
||||
#ifndef INTERCEPTION_WIN_H
|
||||
#define INTERCEPTION_WIN_H
|
||||
|
||||
namespace __interception {
|
||||
// returns true if a function with the given name was found.
|
||||
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr);
|
||||
|
||||
// returns true if the old function existed, false on failure.
|
||||
bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
|
||||
} // namespace __interception
|
||||
|
||||
#if defined(_DLL)
|
||||
# define INTERCEPT_FUNCTION_WIN(func) \
|
||||
::__interception::GetRealFunctionAddress( \
|
||||
#func, (::__interception::uptr*)&REAL(func))
|
||||
#else
|
||||
# define INTERCEPT_FUNCTION_WIN(func) \
|
||||
::__interception::OverrideFunction( \
|
||||
(::__interception::uptr)func, \
|
||||
(::__interception::uptr)WRAP(func), \
|
||||
(::__interception::uptr*)&REAL(func))
|
||||
#endif
|
||||
|
||||
#endif // INTERCEPTION_WIN_H
|
||||
#endif // _WIN32
|
6
libsanitizer/libtool-version
Normal file
6
libsanitizer/libtool-version
Normal file
@ -0,0 +1,6 @@
|
||||
# This file is used to maintain libtool version info for libmudflap. See
|
||||
# the libtool manual to understand the meaning of the fields. This is
|
||||
# a separate file so that version updates don't involve re-running
|
||||
# automake.
|
||||
# CURRENT:REVISION:AGE
|
||||
0:0:0
|
9661
libsanitizer/ltmain.sh
Normal file
9661
libsanitizer/ltmain.sh
Normal file
File diff suppressed because it is too large
Load Diff
376
libsanitizer/missing
Normal file
376
libsanitizer/missing
Normal file
@ -0,0 +1,376 @@
|
||||
#! /bin/sh
|
||||
# Common stub for a few missing GNU programs while installing.
|
||||
|
||||
scriptversion=2009-04-28.21; # UTC
|
||||
|
||||
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
|
||||
# 2008, 2009 Free Software Foundation, Inc.
|
||||
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run=:
|
||||
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
|
||||
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
|
||||
|
||||
# In the cases where this matters, `missing' is being run in the
|
||||
# srcdir already.
|
||||
if test -f configure.ac; then
|
||||
configure_ac=configure.ac
|
||||
else
|
||||
configure_ac=configure.in
|
||||
fi
|
||||
|
||||
msg="missing on your system"
|
||||
|
||||
case $1 in
|
||||
--run)
|
||||
# Try to run requested program, and just exit if it succeeds.
|
||||
run=
|
||||
shift
|
||||
"$@" && exit 0
|
||||
# Exit code 63 means version mismatch. This often happens
|
||||
# when the user try to use an ancient version of a tool on
|
||||
# a file that requires a minimum version. In this case we
|
||||
# we should proceed has if the program had been absent, or
|
||||
# if --run hadn't been passed.
|
||||
if test $? = 63; then
|
||||
run=:
|
||||
msg="probably too old"
|
||||
fi
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||
error status if there is no known handling for PROGRAM.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
--run try to run the given command, and emulate it if it fails
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal touch file \`aclocal.m4'
|
||||
autoconf touch file \`configure'
|
||||
autoheader touch file \`config.h.in'
|
||||
autom4te touch the output file, or create a stub one
|
||||
automake touch all \`Makefile.in' files
|
||||
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
flex create \`lex.yy.c', if possible, from existing .c
|
||||
help2man touch the output file
|
||||
lex create \`lex.yy.c', if possible, from existing .c
|
||||
makeinfo touch the output file
|
||||
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
|
||||
\`g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: Unknown \`$1' option"
|
||||
echo 1>&2 "Try \`$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# normalize program name to check for.
|
||||
program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
# Now exit if we have it, but it failed. Also exit now if we
|
||||
# don't have it and --version was passed (most likely to detect
|
||||
# the program). This is about non-GNU programs, so use $1 not
|
||||
# $program.
|
||||
case $1 in
|
||||
lex*|yacc*)
|
||||
# Not GNU programs, they don't have --version.
|
||||
;;
|
||||
|
||||
tar*)
|
||||
if test -n "$run"; then
|
||||
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||
# We have it, but it failed.
|
||||
exit 1
|
||||
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||
# Could not run --version or --help. This is probably someone
|
||||
# running `$TOOL --version' or `$TOOL --help' to check whether
|
||||
# $TOOL exists and not knowing $TOOL uses missing.
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# If it does not exist, or fails to run (possibly an outdated version),
|
||||
# try to emulate it.
|
||||
case $program in
|
||||
aclocal*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||
any GNU archive site."
|
||||
touch aclocal.m4
|
||||
;;
|
||||
|
||||
autoconf*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`${configure_ac}'. You might want to install the
|
||||
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||
archive site."
|
||||
touch configure
|
||||
;;
|
||||
|
||||
autoheader*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||
from any GNU archive site."
|
||||
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||
test -z "$files" && files="config.h"
|
||||
touch_files=
|
||||
for f in $files; do
|
||||
case $f in
|
||||
*:*) touch_files="$touch_files "`echo "$f" |
|
||||
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||
*) touch_files="$touch_files $f.in";;
|
||||
esac
|
||||
done
|
||||
touch $touch_files
|
||||
;;
|
||||
|
||||
automake*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||
You might want to install the \`Automake' and \`Perl' packages.
|
||||
Grab them from any GNU archive site."
|
||||
find . -type f -name Makefile.am -print |
|
||||
sed 's/\.am$/.in/' |
|
||||
while read f; do touch "$f"; done
|
||||
;;
|
||||
|
||||
autom4te*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, but is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them.
|
||||
You can get \`$1' as part of \`Autoconf' from any GNU
|
||||
archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo "#! /bin/sh"
|
||||
echo "# Created by GNU Automake missing as a replacement of"
|
||||
echo "# $ $@"
|
||||
echo "exit 0"
|
||||
chmod +x $file
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
bison*|yacc*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' $msg. You should only need it if
|
||||
you modified a \`.y' file. You may need the \`Bison' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Bison' from any GNU archive site."
|
||||
rm -f y.tab.c y.tab.h
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
case $LASTARG in
|
||||
*.y)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.c
|
||||
fi
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" y.tab.h
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f y.tab.h; then
|
||||
echo >y.tab.h
|
||||
fi
|
||||
if test ! -f y.tab.c; then
|
||||
echo 'main() { return 0; }' >y.tab.c
|
||||
fi
|
||||
;;
|
||||
|
||||
lex*|flex*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.l' file. You may need the \`Flex' package
|
||||
in order for those modifications to take effect. You can get
|
||||
\`Flex' from any GNU archive site."
|
||||
rm -f lex.yy.c
|
||||
if test $# -ne 1; then
|
||||
eval LASTARG="\${$#}"
|
||||
case $LASTARG in
|
||||
*.l)
|
||||
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||
if test -f "$SRCFILE"; then
|
||||
cp "$SRCFILE" lex.yy.c
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if test ! -f lex.yy.c; then
|
||||
echo 'main() { return 0; }' >lex.yy.c
|
||||
fi
|
||||
;;
|
||||
|
||||
help2man*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a dependency of a manual page. You may need the
|
||||
\`Help2man' package in order for those modifications to take
|
||||
effect. You can get \`Help2man' from any GNU archive site."
|
||||
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -f "$file"; then
|
||||
touch $file
|
||||
else
|
||||
test -z "$file" || exec >$file
|
||||
echo ".ab help2man is required to generate this page"
|
||||
exit $?
|
||||
fi
|
||||
;;
|
||||
|
||||
makeinfo*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is $msg. You should only need it if
|
||||
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||
indirectly affecting the aspect of the manual. The spurious
|
||||
call might also be the consequence of using a buggy \`make' (AIX,
|
||||
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||
the \`GNU make' package. Grab either from any GNU archive site."
|
||||
# The file to touch is that specified with -o ...
|
||||
file=`echo "$*" | sed -n "$sed_output"`
|
||||
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
|
||||
if test -z "$file"; then
|
||||
# ... or it is the one specified with @setfilename ...
|
||||
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||
file=`sed -n '
|
||||
/^@setfilename/{
|
||||
s/.* \([^ ]*\) *$/\1/
|
||||
p
|
||||
q
|
||||
}' $infile`
|
||||
# ... or it is derived from the source name (dir/f.texi becomes f.info)
|
||||
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
|
||||
fi
|
||||
# If the file does not exist, the user really needs makeinfo;
|
||||
# let's fail without touching anything.
|
||||
test -f $file || exit 1
|
||||
touch $file
|
||||
;;
|
||||
|
||||
tar*)
|
||||
shift
|
||||
|
||||
# We have already tried tar in the generic part.
|
||||
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||
# messages.
|
||||
if (gnutar --version > /dev/null 2>&1); then
|
||||
gnutar "$@" && exit 0
|
||||
fi
|
||||
if (gtar --version > /dev/null 2>&1); then
|
||||
gtar "$@" && exit 0
|
||||
fi
|
||||
firstarg="$1"
|
||||
if shift; then
|
||||
case $firstarg in
|
||||
*o*)
|
||||
firstarg=`echo "$firstarg" | sed s/o//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
case $firstarg in
|
||||
*h*)
|
||||
firstarg=`echo "$firstarg" | sed s/h//`
|
||||
tar "$firstarg" "$@" && exit 0
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo 1>&2 "\
|
||||
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||
You may want to install GNU tar or Free paxutils, or check the
|
||||
command line arguments."
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
echo 1>&2 "\
|
||||
WARNING: \`$1' is needed, and is $msg.
|
||||
You might have modified some files without having the
|
||||
proper tools for further handling them. Check the \`README' file,
|
||||
it often tells you about the needed prerequisites for installing
|
||||
this package. You may also peek at any GNU archive site, in case
|
||||
some other package would contain this missing \`$1' program."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
71
libsanitizer/sanitizer_common/Makefile.am
Normal file
71
libsanitizer/sanitizer_common/Makefile.am
Normal file
@ -0,0 +1,71 @@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include
|
||||
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
noinst_LTLIBRARIES = libsanitizer_common.la
|
||||
|
||||
sanitizer_common_files = \
|
||||
sanitizer_allocator.cc \
|
||||
sanitizer_common.cc \
|
||||
sanitizer_flags.cc \
|
||||
sanitizer_libc.cc \
|
||||
sanitizer_linux.cc \
|
||||
sanitizer_mac.cc \
|
||||
sanitizer_posix.cc \
|
||||
sanitizer_printf.cc \
|
||||
sanitizer_stackdepot.cc \
|
||||
sanitizer_stacktrace.cc \
|
||||
sanitizer_symbolizer.cc \
|
||||
sanitizer_symbolizer_linux.cc \
|
||||
sanitizer_symbolizer_mac.cc \
|
||||
sanitizer_symbolizer_win.cc \
|
||||
sanitizer_win.cc
|
||||
|
||||
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES=
|
||||
|
||||
## ################################################################
|
||||
|
564
libsanitizer/sanitizer_common/Makefile.in
Normal file
564
libsanitizer/sanitizer_common/Makefile.in
Normal file
@ -0,0 +1,564 @@
|
||||
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# Foundation, Inc.
|
||||
# This Makefile.in 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.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = sanitizer_common
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libsanitizer_common_la_LIBADD =
|
||||
am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
|
||||
sanitizer_flags.lo sanitizer_libc.lo sanitizer_linux.lo \
|
||||
sanitizer_mac.lo sanitizer_posix.lo sanitizer_printf.lo \
|
||||
sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
|
||||
sanitizer_symbolizer.lo sanitizer_symbolizer_linux.lo \
|
||||
sanitizer_symbolizer_mac.lo sanitizer_symbolizer_win.lo \
|
||||
sanitizer_win.lo
|
||||
am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
|
||||
libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
CXXLD = $(CXX)
|
||||
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
||||
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libsanitizer_common_la_SOURCES)
|
||||
DIST_SOURCES = $(libsanitizer_common_la_SOURCES)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCAS = @CCAS@
|
||||
CCASDEPMODE = @CCASDEPMODE@
|
||||
CCASFLAGS = @CCASFLAGS@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CXX = @CXX@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
enable_shared = @enable_shared@
|
||||
enable_static = @enable_static@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
toolexecdir = @toolexecdir@
|
||||
toolexeclibdir = @toolexeclibdir@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CPPFLAGS = -I $(top_srcdir)/include
|
||||
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -Wno-c99-extensions
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
noinst_LTLIBRARIES = libsanitizer_common.la
|
||||
sanitizer_common_files = \
|
||||
sanitizer_allocator.cc \
|
||||
sanitizer_common.cc \
|
||||
sanitizer_flags.cc \
|
||||
sanitizer_libc.cc \
|
||||
sanitizer_linux.cc \
|
||||
sanitizer_mac.cc \
|
||||
sanitizer_posix.cc \
|
||||
sanitizer_printf.cc \
|
||||
sanitizer_stackdepot.cc \
|
||||
sanitizer_stacktrace.cc \
|
||||
sanitizer_symbolizer.cc \
|
||||
sanitizer_symbolizer_linux.cc \
|
||||
sanitizer_symbolizer_mac.cc \
|
||||
sanitizer_symbolizer_win.cc \
|
||||
sanitizer_win.cc
|
||||
|
||||
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
|
||||
|
||||
# Work around what appears to be a GNU make bug handling MAKEFLAGS
|
||||
# values defined in terms of make variables, as is the case for CC and
|
||||
# friends when we are called from the top level Makefile.
|
||||
AM_MAKEFLAGS = \
|
||||
"AR_FLAGS=$(AR_FLAGS)" \
|
||||
"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
|
||||
"CFLAGS=$(CFLAGS)" \
|
||||
"CXXFLAGS=$(CXXFLAGS)" \
|
||||
"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
|
||||
"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
|
||||
"INSTALL=$(INSTALL)" \
|
||||
"INSTALL_DATA=$(INSTALL_DATA)" \
|
||||
"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
|
||||
"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
|
||||
"JC1FLAGS=$(JC1FLAGS)" \
|
||||
"LDFLAGS=$(LDFLAGS)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
|
||||
"MAKE=$(MAKE)" \
|
||||
"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
|
||||
"SHELL=$(SHELL)" \
|
||||
"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
|
||||
"exec_prefix=$(exec_prefix)" \
|
||||
"infodir=$(infodir)" \
|
||||
"libdir=$(libdir)" \
|
||||
"prefix=$(prefix)" \
|
||||
"includedir=$(includedir)" \
|
||||
"AR=$(AR)" \
|
||||
"AS=$(AS)" \
|
||||
"CC=$(CC)" \
|
||||
"CXX=$(CXX)" \
|
||||
"LD=$(LD)" \
|
||||
"LIBCFLAGS=$(LIBCFLAGS)" \
|
||||
"NM=$(NM)" \
|
||||
"PICFLAG=$(PICFLAG)" \
|
||||
"RANLIB=$(RANLIB)" \
|
||||
"DESTDIR=$(DESTDIR)"
|
||||
|
||||
MAKEOVERRIDES =
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cc .lo .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign sanitizer_common/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign sanitizer_common/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
|
||||
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
|
||||
test "$$dir" != "$$p" || dir=.; \
|
||||
echo "rm -f \"$${dir}/so_locations\""; \
|
||||
rm -f "$${dir}/so_locations"; \
|
||||
done
|
||||
libsanitizer_common.la: $(libsanitizer_common_la_OBJECTS) $(libsanitizer_common_la_DEPENDENCIES) $(EXTRA_libsanitizer_common_la_DEPENDENCIES)
|
||||
$(CXXLINK) $(libsanitizer_common_la_OBJECTS) $(libsanitizer_common_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@
|
||||
|
||||
.cc.o:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
|
||||
|
||||
.cc.obj:
|
||||
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.cc.lo:
|
||||
@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstLTLIBRARIES ctags distclean \
|
||||
distclean-compile distclean-generic distclean-libtool \
|
||||
distclean-tags distdir dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
|
||||
pdf pdf-am ps ps-am tags uninstall uninstall-am
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
83
libsanitizer/sanitizer_common/sanitizer_allocator.cc
Normal file
83
libsanitizer/sanitizer_common/sanitizer_allocator.cc
Normal file
@ -0,0 +1,83 @@
|
||||
//===-- sanitizer_allocator.cc --------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// This allocator that is used inside run-times.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "sanitizer_common.h"
|
||||
|
||||
// FIXME: We should probably use more low-level allocator that would
|
||||
// mmap some pages and split them into chunks to fulfill requests.
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
extern "C" void *__libc_malloc(__sanitizer::uptr size);
|
||||
extern "C" void __libc_free(void *ptr);
|
||||
# define LIBC_MALLOC __libc_malloc
|
||||
# define LIBC_FREE __libc_free
|
||||
#else // __linux__ && !ANDROID
|
||||
# include <stdlib.h>
|
||||
# define LIBC_MALLOC malloc
|
||||
# define LIBC_FREE free
|
||||
#endif // __linux__ && !ANDROID
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
|
||||
|
||||
void *InternalAlloc(uptr size) {
|
||||
if (size + sizeof(u64) < size)
|
||||
return 0;
|
||||
void *p = LIBC_MALLOC(size + sizeof(u64));
|
||||
if (p == 0)
|
||||
return 0;
|
||||
((u64*)p)[0] = kBlockMagic;
|
||||
return (char*)p + sizeof(u64);
|
||||
}
|
||||
|
||||
void InternalFree(void *addr) {
|
||||
if (addr == 0)
|
||||
return;
|
||||
addr = (char*)addr - sizeof(u64);
|
||||
CHECK_EQ(((u64*)addr)[0], kBlockMagic);
|
||||
((u64*)addr)[0] = 0;
|
||||
LIBC_FREE(addr);
|
||||
}
|
||||
|
||||
void *InternalAllocBlock(void *p) {
|
||||
CHECK_NE(p, (void*)0);
|
||||
u64 *pp = (u64*)((uptr)p & ~0x7);
|
||||
for (; pp[0] != kBlockMagic; pp--) {}
|
||||
return pp + 1;
|
||||
}
|
||||
|
||||
// LowLevelAllocator
|
||||
static LowLevelAllocateCallback low_level_alloc_callback;
|
||||
|
||||
void *LowLevelAllocator::Allocate(uptr size) {
|
||||
// Align allocation size.
|
||||
size = RoundUpTo(size, 8);
|
||||
if (allocated_end_ - allocated_current_ < (sptr)size) {
|
||||
uptr size_to_allocate = Max(size, kPageSize);
|
||||
allocated_current_ =
|
||||
(char*)MmapOrDie(size_to_allocate, __FUNCTION__);
|
||||
allocated_end_ = allocated_current_ + size_to_allocate;
|
||||
if (low_level_alloc_callback) {
|
||||
low_level_alloc_callback((uptr)allocated_current_,
|
||||
size_to_allocate);
|
||||
}
|
||||
}
|
||||
CHECK(allocated_end_ - allocated_current_ >= (sptr)size);
|
||||
void *res = allocated_current_;
|
||||
allocated_current_ += size;
|
||||
return res;
|
||||
}
|
||||
|
||||
void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
|
||||
low_level_alloc_callback = callback;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
573
libsanitizer/sanitizer_common/sanitizer_allocator64.h
Normal file
573
libsanitizer/sanitizer_common/sanitizer_allocator64.h
Normal file
@ -0,0 +1,573 @@
|
||||
//===-- sanitizer_allocator64.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Specialized allocator which works only in 64-bit address space.
|
||||
// To be used by ThreadSanitizer, MemorySanitizer and possibly other tools.
|
||||
// The main feature of this allocator is that the header is located far away
|
||||
// from the user memory region, so that the tool does not use extra shadow
|
||||
// for the header.
|
||||
//
|
||||
// Status: not yet ready.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_ALLOCATOR_H
|
||||
#define SANITIZER_ALLOCATOR_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#if __WORDSIZE != 64
|
||||
# error "sanitizer_allocator64.h can only be used on 64-bit platforms"
|
||||
#endif
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_list.h"
|
||||
#include "sanitizer_mutex.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// Maps size class id to size and back.
|
||||
class DefaultSizeClassMap {
|
||||
private:
|
||||
// Here we use a spline composed of 5 polynomials of oder 1.
|
||||
// The first size class is l0, then the classes go with step s0
|
||||
// untill they reach l1, after which they go with step s1 and so on.
|
||||
// Steps should be powers of two for cheap division.
|
||||
// The size of the last size class should be a power of two.
|
||||
// There should be at most 256 size classes.
|
||||
static const uptr l0 = 1 << 4;
|
||||
static const uptr l1 = 1 << 9;
|
||||
static const uptr l2 = 1 << 12;
|
||||
static const uptr l3 = 1 << 15;
|
||||
static const uptr l4 = 1 << 18;
|
||||
static const uptr l5 = 1 << 21;
|
||||
|
||||
static const uptr s0 = 1 << 4;
|
||||
static const uptr s1 = 1 << 6;
|
||||
static const uptr s2 = 1 << 9;
|
||||
static const uptr s3 = 1 << 12;
|
||||
static const uptr s4 = 1 << 15;
|
||||
|
||||
static const uptr u0 = 0 + (l1 - l0) / s0;
|
||||
static const uptr u1 = u0 + (l2 - l1) / s1;
|
||||
static const uptr u2 = u1 + (l3 - l2) / s2;
|
||||
static const uptr u3 = u2 + (l4 - l3) / s3;
|
||||
static const uptr u4 = u3 + (l5 - l4) / s4;
|
||||
|
||||
// Max cached in local cache blocks.
|
||||
static const uptr c0 = 256;
|
||||
static const uptr c1 = 64;
|
||||
static const uptr c2 = 16;
|
||||
static const uptr c3 = 4;
|
||||
static const uptr c4 = 1;
|
||||
|
||||
public:
|
||||
static const uptr kNumClasses = u4 + 1;
|
||||
static const uptr kMaxSize = l5;
|
||||
static const uptr kMinSize = l0;
|
||||
|
||||
COMPILER_CHECK(kNumClasses <= 256);
|
||||
COMPILER_CHECK((kMaxSize & (kMaxSize - 1)) == 0);
|
||||
|
||||
static uptr Size(uptr class_id) {
|
||||
if (class_id <= u0) return l0 + s0 * (class_id - 0);
|
||||
if (class_id <= u1) return l1 + s1 * (class_id - u0);
|
||||
if (class_id <= u2) return l2 + s2 * (class_id - u1);
|
||||
if (class_id <= u3) return l3 + s3 * (class_id - u2);
|
||||
if (class_id <= u4) return l4 + s4 * (class_id - u3);
|
||||
return 0;
|
||||
}
|
||||
static uptr ClassID(uptr size) {
|
||||
if (size <= l1) return 0 + (size - l0 + s0 - 1) / s0;
|
||||
if (size <= l2) return u0 + (size - l1 + s1 - 1) / s1;
|
||||
if (size <= l3) return u1 + (size - l2 + s2 - 1) / s2;
|
||||
if (size <= l4) return u2 + (size - l3 + s3 - 1) / s3;
|
||||
if (size <= l5) return u3 + (size - l4 + s4 - 1) / s4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uptr MaxCached(uptr class_id) {
|
||||
if (class_id <= u0) return c0;
|
||||
if (class_id <= u1) return c1;
|
||||
if (class_id <= u2) return c2;
|
||||
if (class_id <= u3) return c3;
|
||||
if (class_id <= u4) return c4;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct AllocatorListNode {
|
||||
AllocatorListNode *next;
|
||||
};
|
||||
|
||||
typedef IntrusiveList<AllocatorListNode> AllocatorFreeList;
|
||||
|
||||
|
||||
// Space: a portion of address space of kSpaceSize bytes starting at
|
||||
// a fixed address (kSpaceBeg). Both constants are powers of two and
|
||||
// kSpaceBeg is kSpaceSize-aligned.
|
||||
//
|
||||
// Region: a part of Space dedicated to a single size class.
|
||||
// There are kNumClasses Regions of equal size.
|
||||
//
|
||||
// UserChunk: a piece of memory returned to user.
|
||||
// MetaChunk: kMetadataSize bytes of metadata associated with a UserChunk.
|
||||
//
|
||||
// A Region looks like this:
|
||||
// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1
|
||||
template <const uptr kSpaceBeg, const uptr kSpaceSize,
|
||||
const uptr kMetadataSize, class SizeClassMap>
|
||||
class SizeClassAllocator64 {
|
||||
public:
|
||||
void Init() {
|
||||
CHECK_EQ(AllocBeg(), reinterpret_cast<uptr>(MmapFixedNoReserve(
|
||||
AllocBeg(), AllocSize())));
|
||||
}
|
||||
|
||||
bool CanAllocate(uptr size, uptr alignment) {
|
||||
return size <= SizeClassMap::kMaxSize &&
|
||||
alignment <= SizeClassMap::kMaxSize;
|
||||
}
|
||||
|
||||
void *Allocate(uptr size, uptr alignment) {
|
||||
CHECK(CanAllocate(size, alignment));
|
||||
return AllocateBySizeClass(SizeClassMap::ClassID(size));
|
||||
}
|
||||
|
||||
void Deallocate(void *p) {
|
||||
CHECK(PointerIsMine(p));
|
||||
DeallocateBySizeClass(p, GetSizeClass(p));
|
||||
}
|
||||
|
||||
// Allocate several chunks of the given class_id.
|
||||
void BulkAllocate(uptr class_id, AllocatorFreeList *free_list) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
SpinMutexLock l(®ion->mutex);
|
||||
if (region->free_list.empty()) {
|
||||
PopulateFreeList(class_id, region);
|
||||
}
|
||||
CHECK(!region->free_list.empty());
|
||||
uptr count = SizeClassMap::MaxCached(class_id);
|
||||
if (region->free_list.size() <= count) {
|
||||
free_list->append_front(®ion->free_list);
|
||||
} else {
|
||||
for (uptr i = 0; i < count; i++) {
|
||||
AllocatorListNode *node = region->free_list.front();
|
||||
region->free_list.pop_front();
|
||||
free_list->push_front(node);
|
||||
}
|
||||
}
|
||||
CHECK(!free_list->empty());
|
||||
}
|
||||
|
||||
// Swallow the entire free_list for the given class_id.
|
||||
void BulkDeallocate(uptr class_id, AllocatorFreeList *free_list) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
SpinMutexLock l(®ion->mutex);
|
||||
region->free_list.append_front(free_list);
|
||||
}
|
||||
|
||||
static bool PointerIsMine(void *p) {
|
||||
return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
|
||||
}
|
||||
|
||||
static uptr GetSizeClass(void *p) {
|
||||
return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
|
||||
}
|
||||
|
||||
static void *GetBlockBegin(void *p) {
|
||||
uptr class_id = GetSizeClass(p);
|
||||
uptr size = SizeClassMap::Size(class_id);
|
||||
uptr chunk_idx = GetChunkIdx((uptr)p, size);
|
||||
uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
|
||||
uptr begin = reg_beg + chunk_idx * size;
|
||||
return (void*)begin;
|
||||
}
|
||||
|
||||
static uptr GetActuallyAllocatedSize(void *p) {
|
||||
CHECK(PointerIsMine(p));
|
||||
return SizeClassMap::Size(GetSizeClass(p));
|
||||
}
|
||||
|
||||
uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
|
||||
|
||||
void *GetMetaData(void *p) {
|
||||
uptr class_id = GetSizeClass(p);
|
||||
uptr size = SizeClassMap::Size(class_id);
|
||||
uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
|
||||
return reinterpret_cast<void*>(kSpaceBeg + (kRegionSize * (class_id + 1)) -
|
||||
(1 + chunk_idx) * kMetadataSize);
|
||||
}
|
||||
|
||||
uptr TotalMemoryUsed() {
|
||||
uptr res = 0;
|
||||
for (uptr i = 0; i < kNumClasses; i++)
|
||||
res += GetRegionInfo(i)->allocated_user;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Test-only.
|
||||
void TestOnlyUnmap() {
|
||||
UnmapOrDie(reinterpret_cast<void*>(AllocBeg()), AllocSize());
|
||||
}
|
||||
|
||||
static uptr AllocBeg() { return kSpaceBeg; }
|
||||
static uptr AllocEnd() { return kSpaceBeg + kSpaceSize + AdditionalSize(); }
|
||||
static uptr AllocSize() { return kSpaceSize + AdditionalSize(); }
|
||||
|
||||
static const uptr kNumClasses = 256; // Power of two <= 256
|
||||
typedef SizeClassMap SizeClassMapT;
|
||||
|
||||
private:
|
||||
COMPILER_CHECK(kSpaceBeg % kSpaceSize == 0);
|
||||
COMPILER_CHECK(kNumClasses <= SizeClassMap::kNumClasses);
|
||||
static const uptr kRegionSize = kSpaceSize / kNumClasses;
|
||||
COMPILER_CHECK((kRegionSize >> 32) > 0); // kRegionSize must be >= 2^32.
|
||||
// Populate the free list with at most this number of bytes at once
|
||||
// or with one element if its size is greater.
|
||||
static const uptr kPopulateSize = 1 << 18;
|
||||
|
||||
struct RegionInfo {
|
||||
SpinMutex mutex;
|
||||
AllocatorFreeList free_list;
|
||||
uptr allocated_user; // Bytes allocated for user memory.
|
||||
uptr allocated_meta; // Bytes allocated for metadata.
|
||||
char padding[kCacheLineSize - 3 * sizeof(uptr) - sizeof(AllocatorFreeList)];
|
||||
};
|
||||
COMPILER_CHECK(sizeof(RegionInfo) == kCacheLineSize);
|
||||
|
||||
static uptr AdditionalSize() {
|
||||
uptr res = sizeof(RegionInfo) * kNumClasses;
|
||||
CHECK_EQ(res % kPageSize, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
RegionInfo *GetRegionInfo(uptr class_id) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
|
||||
return ®ions[class_id];
|
||||
}
|
||||
|
||||
static uptr GetChunkIdx(uptr chunk, uptr size) {
|
||||
u32 offset = chunk % kRegionSize;
|
||||
// Here we divide by a non-constant. This is costly.
|
||||
// We require that kRegionSize is at least 2^32 so that offset is 32-bit.
|
||||
// We save 2x by using 32-bit div, but may need to use a 256-way switch.
|
||||
return offset / (u32)size;
|
||||
}
|
||||
|
||||
void PopulateFreeList(uptr class_id, RegionInfo *region) {
|
||||
uptr size = SizeClassMap::Size(class_id);
|
||||
uptr beg_idx = region->allocated_user;
|
||||
uptr end_idx = beg_idx + kPopulateSize;
|
||||
region->free_list.clear();
|
||||
uptr region_beg = kSpaceBeg + kRegionSize * class_id;
|
||||
uptr idx = beg_idx;
|
||||
uptr i = 0;
|
||||
do { // do-while loop because we need to put at least one item.
|
||||
uptr p = region_beg + idx;
|
||||
region->free_list.push_front(reinterpret_cast<AllocatorListNode*>(p));
|
||||
idx += size;
|
||||
i++;
|
||||
} while (idx < end_idx);
|
||||
region->allocated_user += idx - beg_idx;
|
||||
region->allocated_meta += i * kMetadataSize;
|
||||
CHECK_LT(region->allocated_user + region->allocated_meta, kRegionSize);
|
||||
}
|
||||
|
||||
void *AllocateBySizeClass(uptr class_id) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
SpinMutexLock l(®ion->mutex);
|
||||
if (region->free_list.empty()) {
|
||||
PopulateFreeList(class_id, region);
|
||||
}
|
||||
CHECK(!region->free_list.empty());
|
||||
AllocatorListNode *node = region->free_list.front();
|
||||
region->free_list.pop_front();
|
||||
return reinterpret_cast<void*>(node);
|
||||
}
|
||||
|
||||
void DeallocateBySizeClass(void *p, uptr class_id) {
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
SpinMutexLock l(®ion->mutex);
|
||||
region->free_list.push_front(reinterpret_cast<AllocatorListNode*>(p));
|
||||
}
|
||||
};
|
||||
|
||||
// Objects of this type should be used as local caches for SizeClassAllocator64.
|
||||
// Since the typical use of this class is to have one object per thread in TLS,
|
||||
// is has to be POD.
|
||||
template<const uptr kNumClasses, class SizeClassAllocator>
|
||||
struct SizeClassAllocatorLocalCache {
|
||||
// Don't need to call Init if the object is a global (i.e. zero-initialized).
|
||||
void Init() {
|
||||
internal_memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
AllocatorFreeList *free_list = &free_lists_[class_id];
|
||||
if (free_list->empty())
|
||||
allocator->BulkAllocate(class_id, free_list);
|
||||
CHECK(!free_list->empty());
|
||||
void *res = free_list->front();
|
||||
free_list->pop_front();
|
||||
return res;
|
||||
}
|
||||
|
||||
void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
AllocatorFreeList *free_list = &free_lists_[class_id];
|
||||
free_list->push_front(reinterpret_cast<AllocatorListNode*>(p));
|
||||
if (free_list->size() >= 2 * SizeClassMap::MaxCached(class_id))
|
||||
DrainHalf(allocator, class_id);
|
||||
}
|
||||
|
||||
void Drain(SizeClassAllocator *allocator) {
|
||||
for (uptr i = 0; i < kNumClasses; i++) {
|
||||
allocator->BulkDeallocate(i, &free_lists_[i]);
|
||||
CHECK(free_lists_[i].empty());
|
||||
}
|
||||
}
|
||||
|
||||
// private:
|
||||
typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
|
||||
AllocatorFreeList free_lists_[kNumClasses];
|
||||
|
||||
void DrainHalf(SizeClassAllocator *allocator, uptr class_id) {
|
||||
AllocatorFreeList *free_list = &free_lists_[class_id];
|
||||
AllocatorFreeList half;
|
||||
half.clear();
|
||||
const uptr count = free_list->size() / 2;
|
||||
for (uptr i = 0; i < count; i++) {
|
||||
AllocatorListNode *node = free_list->front();
|
||||
free_list->pop_front();
|
||||
half.push_front(node);
|
||||
}
|
||||
allocator->BulkDeallocate(class_id, &half);
|
||||
}
|
||||
};
|
||||
|
||||
// This class can (de)allocate only large chunks of memory using mmap/unmap.
|
||||
// The main purpose of this allocator is to cover large and rare allocation
|
||||
// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
|
||||
class LargeMmapAllocator {
|
||||
public:
|
||||
void Init() {
|
||||
internal_memset(this, 0, sizeof(*this));
|
||||
}
|
||||
void *Allocate(uptr size, uptr alignment) {
|
||||
CHECK(IsPowerOfTwo(alignment));
|
||||
uptr map_size = RoundUpMapSize(size);
|
||||
if (alignment > kPageSize)
|
||||
map_size += alignment;
|
||||
if (map_size < size) return 0; // Overflow.
|
||||
uptr map_beg = reinterpret_cast<uptr>(
|
||||
MmapOrDie(map_size, "LargeMmapAllocator"));
|
||||
uptr map_end = map_beg + map_size;
|
||||
uptr res = map_beg + kPageSize;
|
||||
if (res & (alignment - 1)) // Align.
|
||||
res += alignment - (res & (alignment - 1));
|
||||
CHECK_EQ(0, res & (alignment - 1));
|
||||
CHECK_LE(res + size, map_end);
|
||||
Header *h = GetHeader(res);
|
||||
h->size = size;
|
||||
h->map_beg = map_beg;
|
||||
h->map_size = map_size;
|
||||
{
|
||||
SpinMutexLock l(&mutex_);
|
||||
h->next = list_;
|
||||
h->prev = 0;
|
||||
if (list_)
|
||||
list_->prev = h;
|
||||
list_ = h;
|
||||
}
|
||||
return reinterpret_cast<void*>(res);
|
||||
}
|
||||
|
||||
void Deallocate(void *p) {
|
||||
Header *h = GetHeader(p);
|
||||
{
|
||||
SpinMutexLock l(&mutex_);
|
||||
Header *prev = h->prev;
|
||||
Header *next = h->next;
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
if (next)
|
||||
next->prev = prev;
|
||||
if (h == list_)
|
||||
list_ = next;
|
||||
}
|
||||
UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
|
||||
}
|
||||
|
||||
uptr TotalMemoryUsed() {
|
||||
SpinMutexLock l(&mutex_);
|
||||
uptr res = 0;
|
||||
for (Header *l = list_; l; l = l->next) {
|
||||
res += RoundUpMapSize(l->size);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PointerIsMine(void *p) {
|
||||
// Fast check.
|
||||
if ((reinterpret_cast<uptr>(p) % kPageSize) != 0) return false;
|
||||
SpinMutexLock l(&mutex_);
|
||||
for (Header *l = list_; l; l = l->next) {
|
||||
if (GetUser(l) == p) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr GetActuallyAllocatedSize(void *p) {
|
||||
return RoundUpMapSize(GetHeader(p)->size) - kPageSize;
|
||||
}
|
||||
|
||||
// At least kPageSize/2 metadata bytes is available.
|
||||
void *GetMetaData(void *p) {
|
||||
return GetHeader(p) + 1;
|
||||
}
|
||||
|
||||
void *GetBlockBegin(void *p) {
|
||||
SpinMutexLock l(&mutex_);
|
||||
for (Header *l = list_; l; l = l->next) {
|
||||
void *b = GetUser(l);
|
||||
if (p >= b && p < (u8*)b + l->size)
|
||||
return b;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Header {
|
||||
uptr map_beg;
|
||||
uptr map_size;
|
||||
uptr size;
|
||||
Header *next;
|
||||
Header *prev;
|
||||
};
|
||||
|
||||
Header *GetHeader(uptr p) { return reinterpret_cast<Header*>(p - kPageSize); }
|
||||
Header *GetHeader(void *p) { return GetHeader(reinterpret_cast<uptr>(p)); }
|
||||
|
||||
void *GetUser(Header *h) {
|
||||
return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + kPageSize);
|
||||
}
|
||||
|
||||
uptr RoundUpMapSize(uptr size) {
|
||||
return RoundUpTo(size, kPageSize) + kPageSize;
|
||||
}
|
||||
|
||||
Header *list_;
|
||||
SpinMutex mutex_;
|
||||
};
|
||||
|
||||
// This class implements a complete memory allocator by using two
|
||||
// internal allocators:
|
||||
// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
|
||||
// When allocating 2^x bytes it should return 2^x aligned chunk.
|
||||
// PrimaryAllocator is used via a local AllocatorCache.
|
||||
// SecondaryAllocator can allocate anything, but is not efficient.
|
||||
template <class PrimaryAllocator, class AllocatorCache,
|
||||
class SecondaryAllocator> // NOLINT
|
||||
class CombinedAllocator {
|
||||
public:
|
||||
void Init() {
|
||||
primary_.Init();
|
||||
secondary_.Init();
|
||||
}
|
||||
|
||||
void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
|
||||
bool cleared = false) {
|
||||
// Returning 0 on malloc(0) may break a lot of code.
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
if (size + alignment < size)
|
||||
return 0;
|
||||
if (alignment > 8)
|
||||
size = RoundUpTo(size, alignment);
|
||||
void *res;
|
||||
if (primary_.CanAllocate(size, alignment))
|
||||
res = cache->Allocate(&primary_, primary_.ClassID(size));
|
||||
else
|
||||
res = secondary_.Allocate(size, alignment);
|
||||
if (alignment > 8)
|
||||
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
|
||||
if (cleared && res)
|
||||
internal_memset(res, 0, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Deallocate(AllocatorCache *cache, void *p) {
|
||||
if (!p) return;
|
||||
if (primary_.PointerIsMine(p))
|
||||
cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
|
||||
else
|
||||
secondary_.Deallocate(p);
|
||||
}
|
||||
|
||||
void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
|
||||
uptr alignment) {
|
||||
if (!p)
|
||||
return Allocate(cache, new_size, alignment);
|
||||
if (!new_size) {
|
||||
Deallocate(cache, p);
|
||||
return 0;
|
||||
}
|
||||
CHECK(PointerIsMine(p));
|
||||
uptr old_size = GetActuallyAllocatedSize(p);
|
||||
uptr memcpy_size = Min(new_size, old_size);
|
||||
void *new_p = Allocate(cache, new_size, alignment);
|
||||
if (new_p)
|
||||
internal_memcpy(new_p, p, memcpy_size);
|
||||
Deallocate(cache, p);
|
||||
return new_p;
|
||||
}
|
||||
|
||||
bool PointerIsMine(void *p) {
|
||||
if (primary_.PointerIsMine(p))
|
||||
return true;
|
||||
return secondary_.PointerIsMine(p);
|
||||
}
|
||||
|
||||
void *GetMetaData(void *p) {
|
||||
if (primary_.PointerIsMine(p))
|
||||
return primary_.GetMetaData(p);
|
||||
return secondary_.GetMetaData(p);
|
||||
}
|
||||
|
||||
void *GetBlockBegin(void *p) {
|
||||
if (primary_.PointerIsMine(p))
|
||||
return primary_.GetBlockBegin(p);
|
||||
return secondary_.GetBlockBegin(p);
|
||||
}
|
||||
|
||||
uptr GetActuallyAllocatedSize(void *p) {
|
||||
if (primary_.PointerIsMine(p))
|
||||
return primary_.GetActuallyAllocatedSize(p);
|
||||
return secondary_.GetActuallyAllocatedSize(p);
|
||||
}
|
||||
|
||||
uptr TotalMemoryUsed() {
|
||||
return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
|
||||
}
|
||||
|
||||
void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
|
||||
|
||||
void SwallowCache(AllocatorCache *cache) {
|
||||
cache->Drain(&primary_);
|
||||
}
|
||||
|
||||
private:
|
||||
PrimaryAllocator primary_;
|
||||
SecondaryAllocator secondary_;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_ALLOCATOR_H
|
63
libsanitizer/sanitizer_common/sanitizer_atomic.h
Normal file
63
libsanitizer/sanitizer_common/sanitizer_atomic.h
Normal file
@ -0,0 +1,63 @@
|
||||
//===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_ATOMIC_H
|
||||
#define SANITIZER_ATOMIC_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
enum memory_order {
|
||||
memory_order_relaxed = 1 << 0,
|
||||
memory_order_consume = 1 << 1,
|
||||
memory_order_acquire = 1 << 2,
|
||||
memory_order_release = 1 << 3,
|
||||
memory_order_acq_rel = 1 << 4,
|
||||
memory_order_seq_cst = 1 << 5
|
||||
};
|
||||
|
||||
struct atomic_uint8_t {
|
||||
typedef u8 Type;
|
||||
volatile Type val_dont_use;
|
||||
};
|
||||
|
||||
struct atomic_uint16_t {
|
||||
typedef u16 Type;
|
||||
volatile Type val_dont_use;
|
||||
};
|
||||
|
||||
struct atomic_uint32_t {
|
||||
typedef u32 Type;
|
||||
volatile Type val_dont_use;
|
||||
};
|
||||
|
||||
struct atomic_uint64_t {
|
||||
typedef u64 Type;
|
||||
volatile Type val_dont_use;
|
||||
};
|
||||
|
||||
struct atomic_uintptr_t {
|
||||
typedef uptr Type;
|
||||
volatile Type val_dont_use;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# include "sanitizer_atomic_clang.h"
|
||||
#elif defined(_MSC_VER)
|
||||
# include "sanitizer_atomic_msvc.h"
|
||||
#else
|
||||
# error "Unsupported compiler"
|
||||
#endif
|
||||
|
||||
#endif // SANITIZER_ATOMIC_H
|
120
libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
Normal file
120
libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
Normal file
@ -0,0 +1,120 @@
|
||||
//===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
// Not intended for direct inclusion. Include sanitizer_atomic.h.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_ATOMIC_CLANG_H
|
||||
#define SANITIZER_ATOMIC_CLANG_H
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
INLINE void atomic_signal_fence(memory_order) {
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
}
|
||||
|
||||
INLINE void atomic_thread_fence(memory_order) {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
INLINE void proc_yield(int cnt) {
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
for (int i = 0; i < cnt; i++)
|
||||
__asm__ __volatile__("pause");
|
||||
#endif
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE typename T::Type atomic_load(
|
||||
const volatile T *a, memory_order mo) {
|
||||
DCHECK(mo & (memory_order_relaxed | memory_order_consume
|
||||
| memory_order_acquire | memory_order_seq_cst));
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
typename T::Type v;
|
||||
if (mo == memory_order_relaxed) {
|
||||
v = a->val_dont_use;
|
||||
} else {
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
v = a->val_dont_use;
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
|
||||
DCHECK(mo & (memory_order_relaxed | memory_order_release
|
||||
| memory_order_seq_cst));
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
if (mo == memory_order_relaxed) {
|
||||
a->val_dont_use = v;
|
||||
} else {
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
a->val_dont_use = v;
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
}
|
||||
if (mo == memory_order_seq_cst)
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE typename T::Type atomic_fetch_add(volatile T *a,
|
||||
typename T::Type v, memory_order mo) {
|
||||
(void)mo;
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
return __sync_fetch_and_add(&a->val_dont_use, v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE typename T::Type atomic_fetch_sub(volatile T *a,
|
||||
typename T::Type v, memory_order mo) {
|
||||
(void)mo;
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
return __sync_fetch_and_add(&a->val_dont_use, -v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE typename T::Type atomic_exchange(volatile T *a,
|
||||
typename T::Type v, memory_order mo) {
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
|
||||
__sync_synchronize();
|
||||
v = __sync_lock_test_and_set(&a->val_dont_use, v);
|
||||
if (mo == memory_order_seq_cst)
|
||||
__sync_synchronize();
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE bool atomic_compare_exchange_strong(volatile T *a,
|
||||
typename T::Type *cmp,
|
||||
typename T::Type xchg,
|
||||
memory_order mo) {
|
||||
typedef typename T::Type Type;
|
||||
Type cmpv = *cmp;
|
||||
Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
|
||||
if (prev == cmpv)
|
||||
return true;
|
||||
*cmp = prev;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE bool atomic_compare_exchange_weak(volatile T *a,
|
||||
typename T::Type *cmp,
|
||||
typename T::Type xchg,
|
||||
memory_order mo) {
|
||||
return atomic_compare_exchange_strong(a, cmp, xchg, mo);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_ATOMIC_CLANG_H
|
134
libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
Normal file
134
libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
Normal file
@ -0,0 +1,134 @@
|
||||
//===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
// Not intended for direct inclusion. Include sanitizer_atomic.h.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_ATOMIC_MSVC_H
|
||||
#define SANITIZER_ATOMIC_MSVC_H
|
||||
|
||||
extern "C" void _ReadWriteBarrier();
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
extern "C" void _mm_mfence();
|
||||
#pragma intrinsic(_mm_mfence)
|
||||
extern "C" void _mm_pause();
|
||||
#pragma intrinsic(_mm_pause)
|
||||
extern "C" long _InterlockedExchangeAdd( // NOLINT
|
||||
long volatile * Addend, long Value); // NOLINT
|
||||
#pragma intrinsic(_InterlockedExchangeAdd)
|
||||
extern "C" void *InterlockedCompareExchangePointer(
|
||||
void *volatile *Destination,
|
||||
void *Exchange, void *Comparand);
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
INLINE void atomic_signal_fence(memory_order) {
|
||||
_ReadWriteBarrier();
|
||||
}
|
||||
|
||||
INLINE void atomic_thread_fence(memory_order) {
|
||||
_mm_mfence();
|
||||
}
|
||||
|
||||
INLINE void proc_yield(int cnt) {
|
||||
for (int i = 0; i < cnt; i++)
|
||||
_mm_pause();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE typename T::Type atomic_load(
|
||||
const volatile T *a, memory_order mo) {
|
||||
DCHECK(mo & (memory_order_relaxed | memory_order_consume
|
||||
| memory_order_acquire | memory_order_seq_cst));
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
typename T::Type v;
|
||||
if (mo == memory_order_relaxed) {
|
||||
v = a->val_dont_use;
|
||||
} else {
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
v = a->val_dont_use;
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
|
||||
DCHECK(mo & (memory_order_relaxed | memory_order_release
|
||||
| memory_order_seq_cst));
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
if (mo == memory_order_relaxed) {
|
||||
a->val_dont_use = v;
|
||||
} else {
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
a->val_dont_use = v;
|
||||
atomic_signal_fence(memory_order_seq_cst);
|
||||
}
|
||||
if (mo == memory_order_seq_cst)
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
}
|
||||
|
||||
INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a,
|
||||
u32 v, memory_order mo) {
|
||||
(void)mo;
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
return (u32)_InterlockedExchangeAdd(
|
||||
(volatile long*)&a->val_dont_use, (long)v); // NOLINT
|
||||
}
|
||||
|
||||
INLINE u8 atomic_exchange(volatile atomic_uint8_t *a,
|
||||
u8 v, memory_order mo) {
|
||||
(void)mo;
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
__asm {
|
||||
mov eax, a
|
||||
mov cl, v
|
||||
xchg [eax], cl // NOLINT
|
||||
mov v, cl
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
INLINE u16 atomic_exchange(volatile atomic_uint16_t *a,
|
||||
u16 v, memory_order mo) {
|
||||
(void)mo;
|
||||
DCHECK(!((uptr)a % sizeof(*a)));
|
||||
__asm {
|
||||
mov eax, a
|
||||
mov cx, v
|
||||
xchg [eax], cx // NOLINT
|
||||
mov v, cx
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
|
||||
uptr *cmp,
|
||||
uptr xchg,
|
||||
memory_order mo) {
|
||||
uptr cmpv = *cmp;
|
||||
uptr prev = (uptr)InterlockedCompareExchangePointer(
|
||||
(void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv);
|
||||
if (prev == cmpv)
|
||||
return true;
|
||||
*cmp = prev;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
INLINE bool atomic_compare_exchange_weak(volatile T *a,
|
||||
typename T::Type *cmp,
|
||||
typename T::Type xchg,
|
||||
memory_order mo) {
|
||||
return atomic_compare_exchange_strong(a, cmp, xchg, mo);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_ATOMIC_CLANG_H
|
151
libsanitizer/sanitizer_common/sanitizer_common.cc
Normal file
151
libsanitizer/sanitizer_common/sanitizer_common.cc
Normal file
@ -0,0 +1,151 @@
|
||||
//===-- sanitizer_common.cc -----------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
static fd_t report_fd = 2; // By default, dump to stderr.
|
||||
static char report_path[4096]; // Set via __sanitizer_set_report_path.
|
||||
|
||||
static void (*DieCallback)(void);
|
||||
void SetDieCallback(void (*callback)(void)) {
|
||||
DieCallback = callback;
|
||||
}
|
||||
|
||||
void NORETURN Die() {
|
||||
if (DieCallback) {
|
||||
DieCallback();
|
||||
}
|
||||
Exit(1);
|
||||
}
|
||||
|
||||
static CheckFailedCallbackType CheckFailedCallback;
|
||||
void SetCheckFailedCallback(CheckFailedCallbackType callback) {
|
||||
CheckFailedCallback = callback;
|
||||
}
|
||||
|
||||
void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2) {
|
||||
if (CheckFailedCallback) {
|
||||
CheckFailedCallback(file, line, cond, v1, v2);
|
||||
}
|
||||
Report("Sanitizer CHECK failed: %s:%d %s (%zd, %zd)\n", file, line, cond,
|
||||
v1, v2);
|
||||
Die();
|
||||
}
|
||||
|
||||
void RawWrite(const char *buffer) {
|
||||
static const char *kRawWriteError = "RawWrite can't output requested buffer!";
|
||||
uptr length = (uptr)internal_strlen(buffer);
|
||||
if (report_fd == kInvalidFd) {
|
||||
fd_t fd = internal_open(report_path, true);
|
||||
if (fd == kInvalidFd) {
|
||||
report_fd = 2;
|
||||
Report("ERROR: Can't open file: %s\n", report_path);
|
||||
Die();
|
||||
}
|
||||
report_fd = fd;
|
||||
}
|
||||
if (length != internal_write(report_fd, buffer, length)) {
|
||||
internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||
uptr *buff_size, uptr max_len) {
|
||||
const uptr kMinFileLen = kPageSize;
|
||||
uptr read_len = 0;
|
||||
*buff = 0;
|
||||
*buff_size = 0;
|
||||
// The files we usually open are not seekable, so try different buffer sizes.
|
||||
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
|
||||
fd_t fd = internal_open(file_name, /*write*/ false);
|
||||
if (fd == kInvalidFd) return 0;
|
||||
UnmapOrDie(*buff, *buff_size);
|
||||
*buff = (char*)MmapOrDie(size, __FUNCTION__);
|
||||
*buff_size = size;
|
||||
// Read up to one page at a time.
|
||||
read_len = 0;
|
||||
bool reached_eof = false;
|
||||
while (read_len + kPageSize <= size) {
|
||||
uptr just_read = internal_read(fd, *buff + read_len, kPageSize);
|
||||
if (just_read == 0) {
|
||||
reached_eof = true;
|
||||
break;
|
||||
}
|
||||
read_len += just_read;
|
||||
}
|
||||
internal_close(fd);
|
||||
if (reached_eof) // We've read the whole file.
|
||||
break;
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
// We don't want to use std::sort to avoid including <algorithm>, as
|
||||
// we may end up with two implementation of std::sort - one in instrumented
|
||||
// code, and the other in runtime.
|
||||
// qsort() from stdlib won't work as it calls malloc(), which results
|
||||
// in deadlock in ASan allocator.
|
||||
// We re-implement in-place sorting w/o recursion as straightforward heapsort.
|
||||
void SortArray(uptr *array, uptr size) {
|
||||
if (size < 2)
|
||||
return;
|
||||
// Stage 1: insert elements to the heap.
|
||||
for (uptr i = 1; i < size; i++) {
|
||||
uptr j, p;
|
||||
for (j = i; j > 0; j = p) {
|
||||
p = (j - 1) / 2;
|
||||
if (array[j] > array[p])
|
||||
Swap(array[j], array[p]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Stage 2: swap largest element with the last one,
|
||||
// and sink the new top.
|
||||
for (uptr i = size - 1; i > 0; i--) {
|
||||
Swap(array[0], array[i]);
|
||||
uptr j, max_ind;
|
||||
for (j = 0; j < i; j = max_ind) {
|
||||
uptr left = 2 * j + 1;
|
||||
uptr right = 2 * j + 2;
|
||||
max_ind = j;
|
||||
if (left < i && array[left] > array[max_ind])
|
||||
max_ind = left;
|
||||
if (right < i && array[right] > array[max_ind])
|
||||
max_ind = right;
|
||||
if (max_ind != j)
|
||||
Swap(array[j], array[max_ind]);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
void __sanitizer_set_report_path(const char *path) {
|
||||
if (!path) return;
|
||||
uptr len = internal_strlen(path);
|
||||
if (len > sizeof(__sanitizer::report_path) - 100) {
|
||||
Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
|
||||
path[0], path[1], path[2], path[3],
|
||||
path[4], path[5], path[6], path[7]);
|
||||
Die();
|
||||
}
|
||||
internal_snprintf(__sanitizer::report_path,
|
||||
sizeof(__sanitizer::report_path), "%s.%d", path, GetPid());
|
||||
__sanitizer::report_fd = kInvalidFd;
|
||||
}
|
181
libsanitizer/sanitizer_common/sanitizer_common.h
Normal file
181
libsanitizer/sanitizer_common/sanitizer_common.h
Normal file
@ -0,0 +1,181 @@
|
||||
//===-- sanitizer_common.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// It declares common functions and classes that are used in both runtimes.
|
||||
// Implementation of some functions are provided in sanitizer_common, while
|
||||
// others must be defined by run-time library itself.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_COMMON_H
|
||||
#define SANITIZER_COMMON_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// Constants.
|
||||
const uptr kWordSize = __WORDSIZE / 8;
|
||||
const uptr kWordSizeInBits = 8 * kWordSize;
|
||||
const uptr kPageSizeBits = 12;
|
||||
const uptr kPageSize = 1UL << kPageSizeBits;
|
||||
const uptr kCacheLineSize = 64;
|
||||
#ifndef _WIN32
|
||||
const uptr kMmapGranularity = kPageSize;
|
||||
#else
|
||||
const uptr kMmapGranularity = 1UL << 16;
|
||||
#endif
|
||||
|
||||
// Threads
|
||||
int GetPid();
|
||||
uptr GetTid();
|
||||
uptr GetThreadSelf();
|
||||
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
uptr *stack_bottom);
|
||||
|
||||
// Memory management
|
||||
void *MmapOrDie(uptr size, const char *mem_type);
|
||||
void UnmapOrDie(void *addr, uptr size);
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size);
|
||||
void *Mprotect(uptr fixed_addr, uptr size);
|
||||
// Used to check if we can map shadow memory to a fixed location.
|
||||
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
|
||||
|
||||
// Internal allocator
|
||||
void *InternalAlloc(uptr size);
|
||||
void InternalFree(void *p);
|
||||
// Given the pointer p into a valid allocated block,
|
||||
// returns a pointer to the beginning of the block.
|
||||
void *InternalAllocBlock(void *p);
|
||||
|
||||
// InternalScopedBuffer can be used instead of large stack arrays to
|
||||
// keep frame size low.
|
||||
// FIXME: use InternalAlloc instead of MmapOrDie once
|
||||
// InternalAlloc is made libc-free.
|
||||
template<typename T>
|
||||
class InternalScopedBuffer {
|
||||
public:
|
||||
explicit InternalScopedBuffer(uptr cnt) {
|
||||
cnt_ = cnt;
|
||||
ptr_ = (T*)MmapOrDie(cnt * sizeof(T), "InternalScopedBuffer");
|
||||
}
|
||||
~InternalScopedBuffer() {
|
||||
UnmapOrDie(ptr_, cnt_ * sizeof(T));
|
||||
}
|
||||
T &operator[](uptr i) { return ptr_[i]; }
|
||||
T *data() { return ptr_; }
|
||||
uptr size() { return cnt_ * sizeof(T); }
|
||||
|
||||
private:
|
||||
T *ptr_;
|
||||
uptr cnt_;
|
||||
// Disallow evil constructors.
|
||||
InternalScopedBuffer(const InternalScopedBuffer&);
|
||||
void operator=(const InternalScopedBuffer&);
|
||||
};
|
||||
|
||||
// Simple low-level (mmap-based) allocator for internal use. Doesn't have
|
||||
// constructor, so all instances of LowLevelAllocator should be
|
||||
// linker initialized.
|
||||
class LowLevelAllocator {
|
||||
public:
|
||||
// Requires an external lock.
|
||||
void *Allocate(uptr size);
|
||||
private:
|
||||
char *allocated_end_;
|
||||
char *allocated_current_;
|
||||
};
|
||||
typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size);
|
||||
// Allows to register tool-specific callbacks for LowLevelAllocator.
|
||||
// Passing NULL removes the callback.
|
||||
void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
|
||||
|
||||
// IO
|
||||
void RawWrite(const char *buffer);
|
||||
void Printf(const char *format, ...);
|
||||
void Report(const char *format, ...);
|
||||
void SetPrintfAndReportCallback(void (*callback)(const char *));
|
||||
|
||||
// Opens the file 'file_name" and reads up to 'max_len' bytes.
|
||||
// The resulting buffer is mmaped and stored in '*buff'.
|
||||
// The size of the mmaped region is stored in '*buff_size',
|
||||
// Returns the number of read bytes or 0 if file can not be opened.
|
||||
uptr ReadFileToBuffer(const char *file_name, char **buff,
|
||||
uptr *buff_size, uptr max_len);
|
||||
// Maps given file to virtual memory, and returns pointer to it
|
||||
// (or NULL if the mapping failes). Stores the size of mmaped region
|
||||
// in '*buff_size'.
|
||||
void *MapFileToMemory(const char *file_name, uptr *buff_size);
|
||||
|
||||
// OS
|
||||
void DisableCoreDumper();
|
||||
void DumpProcessMap();
|
||||
const char *GetEnv(const char *name);
|
||||
const char *GetPwd();
|
||||
void ReExec();
|
||||
bool StackSizeIsUnlimited();
|
||||
void SetStackSizeLimitInBytes(uptr limit);
|
||||
|
||||
// Other
|
||||
void SleepForSeconds(int seconds);
|
||||
void SleepForMillis(int millis);
|
||||
int Atexit(void (*function)(void));
|
||||
void SortArray(uptr *array, uptr size);
|
||||
|
||||
// Exit
|
||||
void NORETURN Abort();
|
||||
void NORETURN Exit(int exitcode);
|
||||
void NORETURN Die();
|
||||
void NORETURN SANITIZER_INTERFACE_ATTRIBUTE
|
||||
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
|
||||
|
||||
// Specific tools may override behavior of "Die" and "CheckFailed" functions
|
||||
// to do tool-specific job.
|
||||
void SetDieCallback(void (*callback)(void));
|
||||
typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
|
||||
u64, u64);
|
||||
void SetCheckFailedCallback(CheckFailedCallbackType callback);
|
||||
|
||||
// Math
|
||||
INLINE bool IsPowerOfTwo(uptr x) {
|
||||
return (x & (x - 1)) == 0;
|
||||
}
|
||||
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
|
||||
CHECK(IsPowerOfTwo(boundary));
|
||||
return (size + boundary - 1) & ~(boundary - 1);
|
||||
}
|
||||
// Don't use std::min, std::max or std::swap, to minimize dependency
|
||||
// on libstdc++.
|
||||
template<class T> T Min(T a, T b) { return a < b ? a : b; }
|
||||
template<class T> T Max(T a, T b) { return a > b ? a : b; }
|
||||
template<class T> void Swap(T& a, T& b) {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
// Char handling
|
||||
INLINE bool IsSpace(int c) {
|
||||
return (c == ' ') || (c == '\n') || (c == '\t') ||
|
||||
(c == '\f') || (c == '\r') || (c == '\v');
|
||||
}
|
||||
INLINE bool IsDigit(int c) {
|
||||
return (c >= '0') && (c <= '9');
|
||||
}
|
||||
INLINE int ToLower(int c) {
|
||||
return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
|
||||
}
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
# define FIRST_32_SECOND_64(a, b) (b)
|
||||
#else
|
||||
# define FIRST_32_SECOND_64(a, b) (a)
|
||||
#endif
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_COMMON_H
|
95
libsanitizer/sanitizer_common/sanitizer_flags.cc
Normal file
95
libsanitizer/sanitizer_common/sanitizer_flags.cc
Normal file
@ -0,0 +1,95 @@
|
||||
//===-- sanitizer_flags.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_flags.h"
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
static bool GetFlagValue(const char *env, const char *name,
|
||||
const char **value, int *value_length) {
|
||||
if (env == 0)
|
||||
return false;
|
||||
const char *pos = internal_strstr(env, name);
|
||||
const char *end;
|
||||
if (pos == 0)
|
||||
return false;
|
||||
pos += internal_strlen(name);
|
||||
if (pos[0] != '=') {
|
||||
end = pos;
|
||||
} else {
|
||||
pos += 1;
|
||||
if (pos[0] == '"') {
|
||||
pos += 1;
|
||||
end = internal_strchr(pos, '"');
|
||||
} else if (pos[0] == '\'') {
|
||||
pos += 1;
|
||||
end = internal_strchr(pos, '\'');
|
||||
} else {
|
||||
end = internal_strchr(pos, ' ');
|
||||
}
|
||||
if (end == 0)
|
||||
end = pos + internal_strlen(pos);
|
||||
}
|
||||
*value = pos;
|
||||
*value_length = end - pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool StartsWith(const char *flag, int flag_length, const char *value) {
|
||||
if (!flag || !value)
|
||||
return false;
|
||||
int value_length = internal_strlen(value);
|
||||
return (flag_length >= value_length) &&
|
||||
(0 == internal_strncmp(flag, value, value_length));
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, bool *flag, const char *name) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
if (StartsWith(value, value_length, "0") ||
|
||||
StartsWith(value, value_length, "no") ||
|
||||
StartsWith(value, value_length, "false"))
|
||||
*flag = false;
|
||||
if (StartsWith(value, value_length, "1") ||
|
||||
StartsWith(value, value_length, "yes") ||
|
||||
StartsWith(value, value_length, "true"))
|
||||
*flag = true;
|
||||
}
|
||||
|
||||
void ParseFlag(const char *env, int *flag, const char *name) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
*flag = internal_atoll(value);
|
||||
}
|
||||
|
||||
static LowLevelAllocator allocator_for_flags;
|
||||
|
||||
void ParseFlag(const char *env, const char **flag, const char *name) {
|
||||
const char *value;
|
||||
int value_length;
|
||||
if (!GetFlagValue(env, name, &value, &value_length))
|
||||
return;
|
||||
// Copy the flag value. Don't use locks here, as flags are parsed at
|
||||
// tool startup.
|
||||
char *value_copy = (char*)(allocator_for_flags.Allocate(value_length + 1));
|
||||
internal_memcpy(value_copy, value, value_length);
|
||||
value_copy[value_length] = '\0';
|
||||
*flag = value_copy;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
25
libsanitizer/sanitizer_common/sanitizer_flags.h
Normal file
25
libsanitizer/sanitizer_common/sanitizer_flags.h
Normal file
@ -0,0 +1,25 @@
|
||||
//===-- sanitizer_flags.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_FLAGS_H
|
||||
#define SANITIZER_FLAGS_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
void ParseFlag(const char *env, bool *flag, const char *name);
|
||||
void ParseFlag(const char *env, int *flag, const char *name);
|
||||
void ParseFlag(const char *env, const char **flag, const char *name);
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_FLAGS_H
|
186
libsanitizer/sanitizer_common/sanitizer_internal_defs.h
Normal file
186
libsanitizer/sanitizer_common/sanitizer_internal_defs.h
Normal file
@ -0,0 +1,186 @@
|
||||
//===-- sanitizer_internal_defs.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer.
|
||||
// It contains macro used in run-time libraries code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_DEFS_H
|
||||
#define SANITIZER_DEFS_H
|
||||
|
||||
#include "sanitizer/common_interface_defs.h"
|
||||
using namespace __sanitizer; // NOLINT
|
||||
// ----------- ATTENTION -------------
|
||||
// This header should NOT include any other headers to avoid portability issues.
|
||||
|
||||
// Common defs.
|
||||
#define INLINE static inline
|
||||
#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
#define WEAK SANITIZER_WEAK_ATTRIBUTE
|
||||
|
||||
// Platform-specific defs.
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long DWORD; // NOLINT
|
||||
# define ALWAYS_INLINE __declspec(forceinline)
|
||||
// FIXME(timurrrr): do we need this on Windows?
|
||||
# define ALIAS(x)
|
||||
# define ALIGNED(x) __declspec(align(x))
|
||||
# define FORMAT(f, a)
|
||||
# define NOINLINE __declspec(noinline)
|
||||
# define NORETURN __declspec(noreturn)
|
||||
# define THREADLOCAL __declspec(thread)
|
||||
# define NOTHROW
|
||||
#else // _WIN32
|
||||
# define ALWAYS_INLINE __attribute__((always_inline))
|
||||
# define ALIAS(x) __attribute__((alias(x)))
|
||||
# define ALIGNED(x) __attribute__((aligned(x)))
|
||||
# define FORMAT(f, a) __attribute__((format(printf, f, a)))
|
||||
# define NOINLINE __attribute__((noinline))
|
||||
# define NORETURN __attribute__((noreturn))
|
||||
# define THREADLOCAL __thread
|
||||
# ifdef __cplusplus
|
||||
# define NOTHROW throw()
|
||||
# else
|
||||
# define NOTHROW __attribute__((__nothrow__))
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
|
||||
// We have no equivalent of these on Windows.
|
||||
#ifndef _WIN32
|
||||
# define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define UNUSED __attribute__((unused))
|
||||
# define USED __attribute__((used))
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef DWORD thread_return_t;
|
||||
# define THREAD_CALLING_CONV __stdcall
|
||||
#else // _WIN32
|
||||
typedef void* thread_return_t;
|
||||
# define THREAD_CALLING_CONV
|
||||
#endif // _WIN32
|
||||
typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
|
||||
|
||||
// If __WORDSIZE was undefined by the platform, define it in terms of the
|
||||
// compiler built-ins __LP64__ and _WIN64.
|
||||
#ifndef __WORDSIZE
|
||||
# if __LP64__ || defined(_WIN64)
|
||||
# define __WORDSIZE 64
|
||||
# else
|
||||
# define __WORDSIZE 32
|
||||
# endif
|
||||
#endif // __WORDSIZE
|
||||
|
||||
// NOTE: Functions below must be defined in each run-time.
|
||||
namespace __sanitizer {
|
||||
void NORETURN Die();
|
||||
void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2);
|
||||
} // namespace __sanitizer
|
||||
|
||||
// Check macro
|
||||
#define RAW_CHECK_MSG(expr, msg) do { \
|
||||
if (!(expr)) { \
|
||||
RawWrite(msg); \
|
||||
Die(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr)
|
||||
|
||||
#define CHECK_IMPL(c1, op, c2) \
|
||||
do { \
|
||||
__sanitizer::u64 v1 = (u64)(c1); \
|
||||
__sanitizer::u64 v2 = (u64)(c2); \
|
||||
if (!(v1 op v2)) \
|
||||
__sanitizer::CheckFailed(__FILE__, __LINE__, \
|
||||
"(" #c1 ") " #op " (" #c2 ")", v1, v2); \
|
||||
} while (false) \
|
||||
/**/
|
||||
|
||||
#define CHECK(a) CHECK_IMPL((a), !=, 0)
|
||||
#define CHECK_EQ(a, b) CHECK_IMPL((a), ==, (b))
|
||||
#define CHECK_NE(a, b) CHECK_IMPL((a), !=, (b))
|
||||
#define CHECK_LT(a, b) CHECK_IMPL((a), <, (b))
|
||||
#define CHECK_LE(a, b) CHECK_IMPL((a), <=, (b))
|
||||
#define CHECK_GT(a, b) CHECK_IMPL((a), >, (b))
|
||||
#define CHECK_GE(a, b) CHECK_IMPL((a), >=, (b))
|
||||
|
||||
#if TSAN_DEBUG
|
||||
#define DCHECK(a) CHECK(a)
|
||||
#define DCHECK_EQ(a, b) CHECK_EQ(a, b)
|
||||
#define DCHECK_NE(a, b) CHECK_NE(a, b)
|
||||
#define DCHECK_LT(a, b) CHECK_LT(a, b)
|
||||
#define DCHECK_LE(a, b) CHECK_LE(a, b)
|
||||
#define DCHECK_GT(a, b) CHECK_GT(a, b)
|
||||
#define DCHECK_GE(a, b) CHECK_GE(a, b)
|
||||
#else
|
||||
#define DCHECK(a)
|
||||
#define DCHECK_EQ(a, b)
|
||||
#define DCHECK_NE(a, b)
|
||||
#define DCHECK_LT(a, b)
|
||||
#define DCHECK_LE(a, b)
|
||||
#define DCHECK_GT(a, b)
|
||||
#define DCHECK_GE(a, b)
|
||||
#endif
|
||||
|
||||
#define UNIMPLEMENTED() CHECK("unimplemented" && 0)
|
||||
|
||||
#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
|
||||
#define IMPL_PASTE(a, b) a##b
|
||||
#define IMPL_COMPILER_ASSERT(pred, line) \
|
||||
typedef char IMPL_PASTE(assertion_failed_##_, line)[2*(int)(pred)-1]
|
||||
|
||||
// Limits for integral types. We have to redefine it in case we don't
|
||||
// have stdint.h (like in Visual Studio 9).
|
||||
#undef __INT64_C
|
||||
#undef __UINT64_C
|
||||
#if __WORDSIZE == 64
|
||||
# define __INT64_C(c) c ## L
|
||||
# define __UINT64_C(c) c ## UL
|
||||
#else
|
||||
# define __INT64_C(c) c ## LL
|
||||
# define __UINT64_C(c) c ## ULL
|
||||
#endif // __WORDSIZE == 64
|
||||
#undef INT32_MIN
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#undef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#undef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#undef INT64_MIN
|
||||
#define INT64_MIN (-__INT64_C(9223372036854775807)-1)
|
||||
#undef INT64_MAX
|
||||
#define INT64_MAX (__INT64_C(9223372036854775807))
|
||||
#undef UINT64_MAX
|
||||
#define UINT64_MAX (__UINT64_C(18446744073709551615))
|
||||
|
||||
enum LinkerInitialized { LINKER_INITIALIZED = 0 };
|
||||
|
||||
#if !defined(_MSC_VER) || defined(__clang__)
|
||||
# define GET_CALLER_PC() (uptr)__builtin_return_address(0)
|
||||
# define GET_CURRENT_FRAME() (uptr)__builtin_frame_address(0)
|
||||
#else
|
||||
extern "C" void* _ReturnAddress(void);
|
||||
# pragma intrinsic(_ReturnAddress)
|
||||
# define GET_CALLER_PC() (uptr)_ReturnAddress()
|
||||
// CaptureStackBackTrace doesn't need to know BP on Windows.
|
||||
// FIXME: This macro is still used when printing error reports though it's not
|
||||
// clear if the BP value is needed in the ASan reports on Windows.
|
||||
# define GET_CURRENT_FRAME() (uptr)0xDEADBEEF
|
||||
#endif
|
||||
|
||||
#define HANDLE_EINTR(res, f) { \
|
||||
do { \
|
||||
res = (f); \
|
||||
} while (res == -1 && errno == EINTR); \
|
||||
}
|
||||
|
||||
#endif // SANITIZER_DEFS_H
|
189
libsanitizer/sanitizer_common/sanitizer_libc.cc
Normal file
189
libsanitizer/sanitizer_common/sanitizer_libc.cc
Normal file
@ -0,0 +1,189 @@
|
||||
//===-- sanitizer_libc.cc -------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries. See sanitizer_libc.h for details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
s64 internal_atoll(const char *nptr) {
|
||||
return internal_simple_strtoll(nptr, (char**)0, 10);
|
||||
}
|
||||
|
||||
void *internal_memchr(const void *s, int c, uptr n) {
|
||||
const char* t = (char*)s;
|
||||
for (uptr i = 0; i < n; ++i, ++t)
|
||||
if (*t == c)
|
||||
return (void*)t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_memcmp(const void* s1, const void* s2, uptr n) {
|
||||
const char* t1 = (char*)s1;
|
||||
const char* t2 = (char*)s2;
|
||||
for (uptr i = 0; i < n; ++i, ++t1, ++t2)
|
||||
if (*t1 != *t2)
|
||||
return *t1 < *t2 ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *internal_memcpy(void *dest, const void *src, uptr n) {
|
||||
char *d = (char*)dest;
|
||||
char *s = (char*)src;
|
||||
for (uptr i = 0; i < n; ++i)
|
||||
d[i] = s[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *internal_memset(void* s, int c, uptr n) {
|
||||
// The next line prevents Clang from making a call to memset() instead of the
|
||||
// loop below.
|
||||
// FIXME: building the runtime with -ffreestanding is a better idea. However
|
||||
// there currently are linktime problems due to PR12396.
|
||||
char volatile *t = (char*)s;
|
||||
for (uptr i = 0; i < n; ++i, ++t) {
|
||||
*t = c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
uptr internal_strcspn(const char *s, const char *reject) {
|
||||
uptr i;
|
||||
for (i = 0; s[i]; i++) {
|
||||
if (internal_strchr(reject, s[i]) != 0)
|
||||
return i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char* internal_strdup(const char *s) {
|
||||
uptr len = internal_strlen(s);
|
||||
char *s2 = (char*)InternalAlloc(len + 1);
|
||||
internal_memcpy(s2, s, len);
|
||||
s2[len] = 0;
|
||||
return s2;
|
||||
}
|
||||
|
||||
int internal_strcmp(const char *s1, const char *s2) {
|
||||
while (true) {
|
||||
unsigned c1 = *s1;
|
||||
unsigned c2 = *s2;
|
||||
if (c1 != c2) return (c1 < c2) ? -1 : 1;
|
||||
if (c1 == 0) break;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_strncmp(const char *s1, const char *s2, uptr n) {
|
||||
for (uptr i = 0; i < n; i++) {
|
||||
unsigned c1 = *s1;
|
||||
unsigned c2 = *s2;
|
||||
if (c1 != c2) return (c1 < c2) ? -1 : 1;
|
||||
if (c1 == 0) break;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* internal_strchr(const char *s, int c) {
|
||||
while (true) {
|
||||
if (*s == (char)c)
|
||||
return (char*)s;
|
||||
if (*s == 0)
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
char *internal_strrchr(const char *s, int c) {
|
||||
const char *res = 0;
|
||||
for (uptr i = 0; s[i]; i++) {
|
||||
if (s[i] == c) res = s + i;
|
||||
}
|
||||
return (char*)res;
|
||||
}
|
||||
|
||||
uptr internal_strlen(const char *s) {
|
||||
uptr i = 0;
|
||||
while (s[i]) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
char *internal_strncat(char *dst, const char *src, uptr n) {
|
||||
uptr len = internal_strlen(dst);
|
||||
uptr i;
|
||||
for (i = 0; i < n && src[i]; i++)
|
||||
dst[len + i] = src[i];
|
||||
dst[len + i] = 0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *internal_strncpy(char *dst, const char *src, uptr n) {
|
||||
uptr i;
|
||||
for (i = 0; i < n && src[i]; i++)
|
||||
dst[i] = src[i];
|
||||
for (; i < n; i++)
|
||||
dst[i] = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
uptr internal_strnlen(const char *s, uptr maxlen) {
|
||||
uptr i = 0;
|
||||
while (i < maxlen && s[i]) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
char *internal_strstr(const char *haystack, const char *needle) {
|
||||
// This is O(N^2), but we are not using it in hot places.
|
||||
uptr len1 = internal_strlen(haystack);
|
||||
uptr len2 = internal_strlen(needle);
|
||||
if (len1 < len2) return 0;
|
||||
for (uptr pos = 0; pos <= len1 - len2; pos++) {
|
||||
if (internal_memcmp(haystack + pos, needle, len2) == 0)
|
||||
return (char*)haystack + pos;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
|
||||
CHECK_EQ(base, 10);
|
||||
while (IsSpace(*nptr)) nptr++;
|
||||
int sgn = 1;
|
||||
u64 res = 0;
|
||||
bool have_digits = false;
|
||||
char *old_nptr = (char*)nptr;
|
||||
if (*nptr == '+') {
|
||||
sgn = 1;
|
||||
nptr++;
|
||||
} else if (*nptr == '-') {
|
||||
sgn = -1;
|
||||
nptr++;
|
||||
}
|
||||
while (IsDigit(*nptr)) {
|
||||
res = (res <= UINT64_MAX / 10) ? res * 10 : UINT64_MAX;
|
||||
int digit = ((*nptr) - '0');
|
||||
res = (res <= UINT64_MAX - digit) ? res + digit : UINT64_MAX;
|
||||
have_digits = true;
|
||||
nptr++;
|
||||
}
|
||||
if (endptr != 0) {
|
||||
*endptr = (have_digits) ? (char*)nptr : old_nptr;
|
||||
}
|
||||
if (sgn > 0) {
|
||||
return (s64)(Min((u64)INT64_MAX, res));
|
||||
} else {
|
||||
return (res > INT64_MAX) ? INT64_MIN : ((s64)res * -1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
69
libsanitizer/sanitizer_common/sanitizer_libc.h
Normal file
69
libsanitizer/sanitizer_common/sanitizer_libc.h
Normal file
@ -0,0 +1,69 @@
|
||||
//===-- sanitizer_libc.h ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// These tools can not use some of the libc functions directly because those
|
||||
// functions are intercepted. Instead, we implement a tiny subset of libc here.
|
||||
// NOTE: This file may be included into user code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_LIBC_H
|
||||
#define SANITIZER_LIBC_H
|
||||
|
||||
// ----------- ATTENTION -------------
|
||||
// This header should NOT include any other headers from sanitizer runtime.
|
||||
#include "sanitizer/common_interface_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// internal_X() is a custom implementation of X() for use in RTL.
|
||||
|
||||
// String functions
|
||||
s64 internal_atoll(const char *nptr);
|
||||
void *internal_memchr(const void *s, int c, uptr n);
|
||||
int internal_memcmp(const void* s1, const void* s2, uptr n);
|
||||
void *internal_memcpy(void *dest, const void *src, uptr n);
|
||||
// Should not be used in performance-critical places.
|
||||
void *internal_memset(void *s, int c, uptr n);
|
||||
char* internal_strchr(const char *s, int c);
|
||||
int internal_strcmp(const char *s1, const char *s2);
|
||||
uptr internal_strcspn(const char *s, const char *reject);
|
||||
char *internal_strdup(const char *s);
|
||||
uptr internal_strlen(const char *s);
|
||||
char *internal_strncat(char *dst, const char *src, uptr n);
|
||||
int internal_strncmp(const char *s1, const char *s2, uptr n);
|
||||
char *internal_strncpy(char *dst, const char *src, uptr n);
|
||||
uptr internal_strnlen(const char *s, uptr maxlen);
|
||||
char *internal_strrchr(const char *s, int c);
|
||||
// This is O(N^2), but we are not using it in hot places.
|
||||
char *internal_strstr(const char *haystack, const char *needle);
|
||||
// Works only for base=10 and doesn't set errno.
|
||||
s64 internal_simple_strtoll(const char *nptr, char **endptr, int base);
|
||||
|
||||
// Memory
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset);
|
||||
int internal_munmap(void *addr, uptr length);
|
||||
|
||||
// I/O
|
||||
typedef int fd_t;
|
||||
const fd_t kInvalidFd = -1;
|
||||
int internal_close(fd_t fd);
|
||||
fd_t internal_open(const char *filename, bool write);
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count);
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count);
|
||||
uptr internal_filesize(fd_t fd); // -1 on error.
|
||||
int internal_dup2(int oldfd, int newfd);
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
|
||||
int internal_snprintf(char *buffer, uptr length, const char *format, ...);
|
||||
|
||||
// Threading
|
||||
int internal_sched_yield();
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_LIBC_H
|
296
libsanitizer/sanitizer_common/sanitizer_linux.cc
Normal file
296
libsanitizer/sanitizer_common/sanitizer_linux.cc
Normal file
@ -0,0 +1,296 @@
|
||||
//===-- sanitizer_linux.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries and implements linux-specific functions from
|
||||
// sanitizer_libc.h.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef __linux__
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_placement_new.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// --------------- sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
#if __WORDSIZE == 64
|
||||
return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
|
||||
#else
|
||||
return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
int internal_munmap(void *addr, uptr length) {
|
||||
return syscall(__NR_munmap, addr, length);
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
return syscall(__NR_close, fd);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, bool write) {
|
||||
return syscall(__NR_open, filename,
|
||||
write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
|
||||
}
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
||||
sptr res;
|
||||
HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
|
||||
return res;
|
||||
}
|
||||
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
sptr res;
|
||||
HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
|
||||
return res;
|
||||
}
|
||||
|
||||
uptr internal_filesize(fd_t fd) {
|
||||
#if __WORDSIZE == 64
|
||||
struct stat st;
|
||||
if (syscall(__NR_fstat, fd, &st))
|
||||
return -1;
|
||||
#else
|
||||
struct stat64 st;
|
||||
if (syscall(__NR_fstat64, fd, &st))
|
||||
return -1;
|
||||
#endif
|
||||
return (uptr)st.st_size;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
return syscall(__NR_dup2, oldfd, newfd);
|
||||
}
|
||||
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
return (uptr)syscall(__NR_readlink, path, buf, bufsize);
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
return syscall(__NR_sched_yield);
|
||||
}
|
||||
|
||||
// ----------------- sanitizer_common.h
|
||||
uptr GetTid() {
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
uptr *stack_bottom) {
|
||||
static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
|
||||
CHECK(stack_top);
|
||||
CHECK(stack_bottom);
|
||||
if (at_initialization) {
|
||||
// This is the main thread. Libpthread may not be initialized yet.
|
||||
struct rlimit rl;
|
||||
CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
|
||||
|
||||
// Find the mapping that contains a stack variable.
|
||||
MemoryMappingLayout proc_maps;
|
||||
uptr start, end, offset;
|
||||
uptr prev_end = 0;
|
||||
while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
|
||||
if ((uptr)&rl < end)
|
||||
break;
|
||||
prev_end = end;
|
||||
}
|
||||
CHECK((uptr)&rl >= start && (uptr)&rl < end);
|
||||
|
||||
// Get stacksize from rlimit, but clip it so that it does not overlap
|
||||
// with other mappings.
|
||||
uptr stacksize = rl.rlim_cur;
|
||||
if (stacksize > end - prev_end)
|
||||
stacksize = end - prev_end;
|
||||
// When running with unlimited stack size, we still want to set some limit.
|
||||
// The unlimited stack size is caused by 'ulimit -s unlimited'.
|
||||
// Also, for some reason, GNU make spawns subprocesses with unlimited stack.
|
||||
if (stacksize > kMaxThreadStackSize)
|
||||
stacksize = kMaxThreadStackSize;
|
||||
*stack_top = end;
|
||||
*stack_bottom = end - stacksize;
|
||||
return;
|
||||
}
|
||||
pthread_attr_t attr;
|
||||
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
|
||||
uptr stacksize = 0;
|
||||
void *stackaddr = 0;
|
||||
pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
*stack_top = (uptr)stackaddr + stacksize;
|
||||
*stack_bottom = (uptr)stackaddr;
|
||||
CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
|
||||
}
|
||||
|
||||
// Like getenv, but reads env directly from /proc and does not use libc.
|
||||
// This function should be called first inside __asan_init.
|
||||
const char *GetEnv(const char *name) {
|
||||
static char *environ;
|
||||
static uptr len;
|
||||
static bool inited;
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
uptr environ_size;
|
||||
len = ReadFileToBuffer("/proc/self/environ",
|
||||
&environ, &environ_size, 1 << 26);
|
||||
}
|
||||
if (!environ || len == 0) return 0;
|
||||
uptr namelen = internal_strlen(name);
|
||||
const char *p = environ;
|
||||
while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
|
||||
// proc file has the format NAME=value\0NAME=value\0NAME=value\0...
|
||||
const char* endp =
|
||||
(char*)internal_memchr(p, '\0', len - (p - environ));
|
||||
if (endp == 0) // this entry isn't NUL terminated
|
||||
return 0;
|
||||
else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
|
||||
return p + namelen + 1; // point after =
|
||||
p = endp + 1;
|
||||
}
|
||||
return 0; // Not found.
|
||||
}
|
||||
|
||||
void ReExec() {
|
||||
static const int kMaxArgv = 100;
|
||||
InternalScopedBuffer<char*> argv(kMaxArgv + 1);
|
||||
static char *buff;
|
||||
uptr buff_size = 0;
|
||||
ReadFileToBuffer("/proc/self/cmdline", &buff, &buff_size, 1024 * 1024);
|
||||
argv[0] = buff;
|
||||
int argc, i;
|
||||
for (argc = 1, i = 1; ; i++) {
|
||||
if (buff[i] == 0) {
|
||||
if (buff[i+1] == 0) break;
|
||||
argv[argc] = &buff[i+1];
|
||||
CHECK_LE(argc, kMaxArgv); // FIXME: make this more flexible.
|
||||
argc++;
|
||||
}
|
||||
}
|
||||
argv[argc] = 0;
|
||||
execv(argv[0], argv.data());
|
||||
}
|
||||
|
||||
// ----------------- sanitizer_procmaps.h
|
||||
MemoryMappingLayout::MemoryMappingLayout() {
|
||||
proc_self_maps_buff_len_ =
|
||||
ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
|
||||
&proc_self_maps_buff_mmaped_size_, 1 << 26);
|
||||
CHECK_GT(proc_self_maps_buff_len_, 0);
|
||||
// internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
|
||||
Reset();
|
||||
}
|
||||
|
||||
MemoryMappingLayout::~MemoryMappingLayout() {
|
||||
UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
|
||||
}
|
||||
|
||||
void MemoryMappingLayout::Reset() {
|
||||
current_ = proc_self_maps_buff_;
|
||||
}
|
||||
|
||||
// Parse a hex value in str and update str.
|
||||
static uptr ParseHex(char **str) {
|
||||
uptr x = 0;
|
||||
char *s;
|
||||
for (s = *str; ; s++) {
|
||||
char c = *s;
|
||||
uptr v = 0;
|
||||
if (c >= '0' && c <= '9')
|
||||
v = c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
v = c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
v = c - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
x = x * 16 + v;
|
||||
}
|
||||
*str = s;
|
||||
return x;
|
||||
}
|
||||
|
||||
static bool IsOnOf(char c, char c1, char c2) {
|
||||
return c == c1 || c == c2;
|
||||
}
|
||||
|
||||
static bool IsDecimal(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
|
||||
if (current_ >= last) return false;
|
||||
uptr dummy;
|
||||
if (!start) start = &dummy;
|
||||
if (!end) end = &dummy;
|
||||
if (!offset) offset = &dummy;
|
||||
char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
|
||||
if (next_line == 0)
|
||||
next_line = last;
|
||||
// Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
|
||||
*start = ParseHex(¤t_);
|
||||
CHECK_EQ(*current_++, '-');
|
||||
*end = ParseHex(¤t_);
|
||||
CHECK_EQ(*current_++, ' ');
|
||||
CHECK(IsOnOf(*current_++, '-', 'r'));
|
||||
CHECK(IsOnOf(*current_++, '-', 'w'));
|
||||
CHECK(IsOnOf(*current_++, '-', 'x'));
|
||||
CHECK(IsOnOf(*current_++, 's', 'p'));
|
||||
CHECK_EQ(*current_++, ' ');
|
||||
*offset = ParseHex(¤t_);
|
||||
CHECK_EQ(*current_++, ' ');
|
||||
ParseHex(¤t_);
|
||||
CHECK_EQ(*current_++, ':');
|
||||
ParseHex(¤t_);
|
||||
CHECK_EQ(*current_++, ' ');
|
||||
while (IsDecimal(*current_))
|
||||
current_++;
|
||||
CHECK_EQ(*current_++, ' ');
|
||||
// Skip spaces.
|
||||
while (current_ < next_line && *current_ == ' ')
|
||||
current_++;
|
||||
// Fill in the filename.
|
||||
uptr i = 0;
|
||||
while (current_ < next_line) {
|
||||
if (filename && i < filename_size - 1)
|
||||
filename[i++] = *current_;
|
||||
current_++;
|
||||
}
|
||||
if (filename && i < filename_size)
|
||||
filename[i] = 0;
|
||||
current_ = next_line + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gets the object name and the offset by walking MemoryMappingLayout.
|
||||
bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[],
|
||||
uptr filename_size) {
|
||||
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __linux__
|
118
libsanitizer/sanitizer_common/sanitizer_list.h
Normal file
118
libsanitizer/sanitizer_common/sanitizer_list.h
Normal file
@ -0,0 +1,118 @@
|
||||
//===-- sanitizer_list.h ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains implementation of a list class to be used by
|
||||
// ThreadSanitizer, etc run-times.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_LIST_H
|
||||
#define SANITIZER_LIST_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// Intrusive singly-linked list with size(), push_back(), push_front()
|
||||
// pop_front(), append_front() and append_back().
|
||||
// This class should be a POD (so that it can be put into TLS)
|
||||
// and an object with all zero fields should represent a valid empty list.
|
||||
// This class does not have a CTOR, so clear() should be called on all
|
||||
// non-zero-initialized objects before using.
|
||||
template<class Item>
|
||||
struct IntrusiveList {
|
||||
void clear() {
|
||||
first_ = last_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
bool empty() const { return size_ == 0; }
|
||||
uptr size() const { return size_; }
|
||||
|
||||
void push_back(Item *x) {
|
||||
if (empty()) {
|
||||
x->next = 0;
|
||||
first_ = last_ = x;
|
||||
size_ = 1;
|
||||
} else {
|
||||
x->next = 0;
|
||||
last_->next = x;
|
||||
last_ = x;
|
||||
size_++;
|
||||
}
|
||||
}
|
||||
|
||||
void push_front(Item *x) {
|
||||
if (empty()) {
|
||||
x->next = 0;
|
||||
first_ = last_ = x;
|
||||
size_ = 1;
|
||||
} else {
|
||||
x->next = first_;
|
||||
first_ = x;
|
||||
size_++;
|
||||
}
|
||||
}
|
||||
|
||||
void pop_front() {
|
||||
CHECK(!empty());
|
||||
first_ = first_->next;
|
||||
if (first_ == 0)
|
||||
last_ = 0;
|
||||
size_--;
|
||||
}
|
||||
|
||||
Item *front() { return first_; }
|
||||
Item *back() { return last_; }
|
||||
|
||||
void append_front(IntrusiveList<Item> *l) {
|
||||
CHECK_NE(this, l);
|
||||
if (empty()) {
|
||||
*this = *l;
|
||||
} else if (!l->empty()) {
|
||||
l->last_->next = first_;
|
||||
first_ = l->first_;
|
||||
size_ += l->size();
|
||||
}
|
||||
l->clear();
|
||||
}
|
||||
|
||||
void append_back(IntrusiveList<Item> *l) {
|
||||
CHECK_NE(this, l);
|
||||
if (empty()) {
|
||||
*this = *l;
|
||||
} else {
|
||||
last_->next = l->first_;
|
||||
last_ = l->last_;
|
||||
size_ += l->size();
|
||||
}
|
||||
l->clear();
|
||||
}
|
||||
|
||||
void CheckConsistency() {
|
||||
if (size_ == 0) {
|
||||
CHECK_EQ(first_, 0);
|
||||
CHECK_EQ(last_, 0);
|
||||
} else {
|
||||
uptr count = 0;
|
||||
for (Item *i = first_; ; i = i->next) {
|
||||
count++;
|
||||
if (i == last_) break;
|
||||
}
|
||||
CHECK_EQ(size(), count);
|
||||
CHECK_EQ(last_->next, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// private, don't use directly.
|
||||
uptr size_;
|
||||
Item *first_;
|
||||
Item *last_;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_LIST_H
|
249
libsanitizer/sanitizer_common/sanitizer_mac.cc
Normal file
249
libsanitizer/sanitizer_common/sanitizer_mac.cc
Normal file
@ -0,0 +1,249 @@
|
||||
//===-- sanitizer_mac.cc --------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries and implements mac-specific functions from
|
||||
// sanitizer_libc.h.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
|
||||
#include <crt_externs.h> // for _NSGetEnviron
|
||||
#include <fcntl.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// ---------------------- sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
int internal_munmap(void *addr, uptr length) {
|
||||
return munmap(addr, length);
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, bool write) {
|
||||
return open(filename,
|
||||
write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
|
||||
}
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
||||
return read(fd, buf, count);
|
||||
}
|
||||
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
return write(fd, buf, count);
|
||||
}
|
||||
|
||||
uptr internal_filesize(fd_t fd) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st))
|
||||
return -1;
|
||||
return (uptr)st.st_size;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
return dup2(oldfd, newfd);
|
||||
}
|
||||
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
return readlink(path, buf, bufsize);
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
return sched_yield();
|
||||
}
|
||||
|
||||
// ----------------- sanitizer_common.h
|
||||
uptr GetTid() {
|
||||
return reinterpret_cast<uptr>(pthread_self());
|
||||
}
|
||||
|
||||
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
uptr *stack_bottom) {
|
||||
CHECK(stack_top);
|
||||
CHECK(stack_bottom);
|
||||
uptr stacksize = pthread_get_stacksize_np(pthread_self());
|
||||
void *stackaddr = pthread_get_stackaddr_np(pthread_self());
|
||||
*stack_top = (uptr)stackaddr;
|
||||
*stack_bottom = *stack_top - stacksize;
|
||||
}
|
||||
|
||||
const char *GetEnv(const char *name) {
|
||||
char ***env_ptr = _NSGetEnviron();
|
||||
CHECK(env_ptr);
|
||||
char **environ = *env_ptr;
|
||||
CHECK(environ);
|
||||
uptr name_len = internal_strlen(name);
|
||||
while (*environ != 0) {
|
||||
uptr len = internal_strlen(*environ);
|
||||
if (len > name_len) {
|
||||
const char *p = *environ;
|
||||
if (!internal_memcmp(p, name, name_len) &&
|
||||
p[name_len] == '=') { // Match.
|
||||
return *environ + name_len + 1; // String starting after =.
|
||||
}
|
||||
}
|
||||
environ++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ReExec() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// ----------------- sanitizer_procmaps.h
|
||||
|
||||
MemoryMappingLayout::MemoryMappingLayout() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
MemoryMappingLayout::~MemoryMappingLayout() {
|
||||
}
|
||||
|
||||
// More information about Mach-O headers can be found in mach-o/loader.h
|
||||
// Each Mach-O image has a header (mach_header or mach_header_64) starting with
|
||||
// a magic number, and a list of linker load commands directly following the
|
||||
// header.
|
||||
// A load command is at least two 32-bit words: the command type and the
|
||||
// command size in bytes. We're interested only in segment load commands
|
||||
// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
|
||||
// into the task's address space.
|
||||
// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
|
||||
// segment_command_64 correspond to the memory address, memory size and the
|
||||
// file offset of the current memory segment.
|
||||
// Because these fields are taken from the images as is, one needs to add
|
||||
// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
|
||||
|
||||
void MemoryMappingLayout::Reset() {
|
||||
// Count down from the top.
|
||||
// TODO(glider): as per man 3 dyld, iterating over the headers with
|
||||
// _dyld_image_count is thread-unsafe. We need to register callbacks for
|
||||
// adding and removing images which will invalidate the MemoryMappingLayout
|
||||
// state.
|
||||
current_image_ = _dyld_image_count();
|
||||
current_load_cmd_count_ = -1;
|
||||
current_load_cmd_addr_ = 0;
|
||||
current_magic_ = 0;
|
||||
current_filetype_ = 0;
|
||||
}
|
||||
|
||||
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
|
||||
// Google Perftools, http://code.google.com/p/google-perftools.
|
||||
|
||||
// NextSegmentLoad scans the current image for the next segment load command
|
||||
// and returns the start and end addresses and file offset of the corresponding
|
||||
// segment.
|
||||
// Note that the segment addresses are not necessarily sorted.
|
||||
template<u32 kLCSegment, typename SegmentCommand>
|
||||
bool MemoryMappingLayout::NextSegmentLoad(
|
||||
uptr *start, uptr *end, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
const char* lc = current_load_cmd_addr_;
|
||||
current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
|
||||
if (((const load_command *)lc)->cmd == kLCSegment) {
|
||||
const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
|
||||
const SegmentCommand* sc = (const SegmentCommand *)lc;
|
||||
if (start) *start = sc->vmaddr + dlloff;
|
||||
if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
|
||||
if (offset) {
|
||||
if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
|
||||
*offset = sc->vmaddr;
|
||||
} else {
|
||||
*offset = sc->fileoff;
|
||||
}
|
||||
}
|
||||
if (filename) {
|
||||
internal_strncpy(filename, _dyld_get_image_name(current_image_),
|
||||
filename_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
for (; current_image_ >= 0; current_image_--) {
|
||||
const mach_header* hdr = _dyld_get_image_header(current_image_);
|
||||
if (!hdr) continue;
|
||||
if (current_load_cmd_count_ < 0) {
|
||||
// Set up for this image;
|
||||
current_load_cmd_count_ = hdr->ncmds;
|
||||
current_magic_ = hdr->magic;
|
||||
current_filetype_ = hdr->filetype;
|
||||
switch (current_magic_) {
|
||||
#ifdef MH_MAGIC_64
|
||||
case MH_MAGIC_64: {
|
||||
current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case MH_MAGIC: {
|
||||
current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
|
||||
switch (current_magic_) {
|
||||
// current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
|
||||
#ifdef MH_MAGIC_64
|
||||
case MH_MAGIC_64: {
|
||||
if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
|
||||
start, end, offset, filename, filename_size))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case MH_MAGIC: {
|
||||
if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
|
||||
start, end, offset, filename, filename_size))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we get here, no more load_cmd's in this image talk about
|
||||
// segments. Go on to the next image.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[],
|
||||
uptr filename_size) {
|
||||
return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __APPLE__
|
106
libsanitizer/sanitizer_common/sanitizer_mutex.h
Normal file
106
libsanitizer/sanitizer_common/sanitizer_mutex.h
Normal file
@ -0,0 +1,106 @@
|
||||
//===-- sanitizer_mutex.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_MUTEX_H
|
||||
#define SANITIZER_MUTEX_H
|
||||
|
||||
#include "sanitizer_atomic.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
class StaticSpinMutex {
|
||||
public:
|
||||
void Init() {
|
||||
atomic_store(&state_, 0, memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Lock() {
|
||||
if (atomic_exchange(&state_, 1, memory_order_acquire) == 0)
|
||||
return;
|
||||
LockSlow();
|
||||
}
|
||||
|
||||
void Unlock() {
|
||||
atomic_store(&state_, 0, memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
atomic_uint8_t state_;
|
||||
|
||||
void NOINLINE LockSlow() {
|
||||
for (int i = 0;; i++) {
|
||||
if (i < 10)
|
||||
proc_yield(10);
|
||||
else
|
||||
internal_sched_yield();
|
||||
if (atomic_load(&state_, memory_order_relaxed) == 0
|
||||
&& atomic_exchange(&state_, 1, memory_order_acquire) == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SpinMutex : public StaticSpinMutex {
|
||||
public:
|
||||
SpinMutex() {
|
||||
Init();
|
||||
}
|
||||
|
||||
private:
|
||||
SpinMutex(const SpinMutex&);
|
||||
void operator=(const SpinMutex&);
|
||||
};
|
||||
|
||||
template<typename MutexType>
|
||||
class GenericScopedLock {
|
||||
public:
|
||||
explicit GenericScopedLock(MutexType *mu)
|
||||
: mu_(mu) {
|
||||
mu_->Lock();
|
||||
}
|
||||
|
||||
~GenericScopedLock() {
|
||||
mu_->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
MutexType *mu_;
|
||||
|
||||
GenericScopedLock(const GenericScopedLock&);
|
||||
void operator=(const GenericScopedLock&);
|
||||
};
|
||||
|
||||
template<typename MutexType>
|
||||
class GenericScopedReadLock {
|
||||
public:
|
||||
explicit GenericScopedReadLock(MutexType *mu)
|
||||
: mu_(mu) {
|
||||
mu_->ReadLock();
|
||||
}
|
||||
|
||||
~GenericScopedReadLock() {
|
||||
mu_->ReadUnlock();
|
||||
}
|
||||
|
||||
private:
|
||||
MutexType *mu_;
|
||||
|
||||
GenericScopedReadLock(const GenericScopedReadLock&);
|
||||
void operator=(const GenericScopedReadLock&);
|
||||
};
|
||||
|
||||
typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock;
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_MUTEX_H
|
31
libsanitizer/sanitizer_common/sanitizer_placement_new.h
Normal file
31
libsanitizer/sanitizer_common/sanitizer_placement_new.h
Normal file
@ -0,0 +1,31 @@
|
||||
//===-- sanitizer_placement_new.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//
|
||||
// The file provides 'placement new'.
|
||||
// Do not include it into header files, only into source files.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_PLACEMENT_NEW_H
|
||||
#define SANITIZER_PLACEMENT_NEW_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
#if (__WORDSIZE == 64) || defined(__APPLE__)
|
||||
typedef uptr operator_new_ptr_type;
|
||||
#else
|
||||
typedef u32 operator_new_ptr_type;
|
||||
#endif
|
||||
} // namespace __sanitizer
|
||||
|
||||
inline void *operator new(__sanitizer::operator_new_ptr_type sz, void *p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif // SANITIZER_PLACEMENT_NEW_H
|
187
libsanitizer/sanitizer_common/sanitizer_posix.cc
Normal file
187
libsanitizer/sanitizer_common/sanitizer_posix.cc
Normal file
@ -0,0 +1,187 @@
|
||||
//===-- sanitizer_posix.cc ------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries and implements POSIX-specific functions from
|
||||
// sanitizer_libc.h.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// ------------- sanitizer_common.h
|
||||
|
||||
int GetPid() {
|
||||
return getpid();
|
||||
}
|
||||
|
||||
uptr GetThreadSelf() {
|
||||
return (uptr)pthread_self();
|
||||
}
|
||||
|
||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
size = RoundUpTo(size, kPageSize);
|
||||
void *res = internal_mmap(0, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (res == (void*)-1) {
|
||||
static int recursion_count;
|
||||
if (recursion_count) {
|
||||
// The Report() and CHECK calls below may call mmap recursively and fail.
|
||||
// If we went into recursion, just die.
|
||||
RawWrite("AddressSanitizer is unable to mmap\n");
|
||||
Die();
|
||||
}
|
||||
recursion_count++;
|
||||
Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
|
||||
size, size, mem_type, strerror(errno));
|
||||
DumpProcessMap();
|
||||
CHECK("unable to mmap" && 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void UnmapOrDie(void *addr, uptr size) {
|
||||
if (!addr || !size) return;
|
||||
int res = internal_munmap(addr, size);
|
||||
if (res != 0) {
|
||||
Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
|
||||
size, size, addr);
|
||||
CHECK("unable to unmap" && 0);
|
||||
}
|
||||
}
|
||||
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
|
||||
return internal_mmap((void*)fixed_addr, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
void *Mprotect(uptr fixed_addr, uptr size) {
|
||||
return internal_mmap((void*)fixed_addr, size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
|
||||
fd_t fd = internal_open(file_name, false);
|
||||
CHECK_NE(fd, kInvalidFd);
|
||||
uptr fsize = internal_filesize(fd);
|
||||
CHECK_NE(fsize, (uptr)-1);
|
||||
CHECK_GT(fsize, 0);
|
||||
*buff_size = RoundUpTo(fsize, kPageSize);
|
||||
void *map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
return (map == MAP_FAILED) ? 0 : map;
|
||||
}
|
||||
|
||||
|
||||
static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
|
||||
uptr start2, uptr end2) {
|
||||
CHECK(start1 <= end1);
|
||||
CHECK(start2 <= end2);
|
||||
return (end1 < start2) || (end2 < start1);
|
||||
}
|
||||
|
||||
// FIXME: this is thread-unsafe, but should not cause problems most of the time.
|
||||
// When the shadow is mapped only a single thread usually exists (plus maybe
|
||||
// several worker threads on Mac, which aren't expected to map big chunks of
|
||||
// memory).
|
||||
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
|
||||
MemoryMappingLayout procmaps;
|
||||
uptr start, end;
|
||||
while (procmaps.Next(&start, &end,
|
||||
/*offset*/0, /*filename*/0, /*filename_size*/0)) {
|
||||
if (!IntervalsAreSeparate(start, end, range_start, range_end))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void DumpProcessMap() {
|
||||
MemoryMappingLayout proc_maps;
|
||||
uptr start, end;
|
||||
const sptr kBufSize = 4095;
|
||||
char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
|
||||
Report("Process memory map follows:\n");
|
||||
while (proc_maps.Next(&start, &end, /* file_offset */0,
|
||||
filename, kBufSize)) {
|
||||
Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
|
||||
}
|
||||
Report("End of process memory map.\n");
|
||||
UnmapOrDie(filename, kBufSize);
|
||||
}
|
||||
|
||||
const char *GetPwd() {
|
||||
return GetEnv("PWD");
|
||||
}
|
||||
|
||||
void DisableCoreDumper() {
|
||||
struct rlimit nocore;
|
||||
nocore.rlim_cur = 0;
|
||||
nocore.rlim_max = 0;
|
||||
setrlimit(RLIMIT_CORE, &nocore);
|
||||
}
|
||||
|
||||
bool StackSizeIsUnlimited() {
|
||||
struct rlimit rlim;
|
||||
CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim));
|
||||
return (rlim.rlim_cur == (uptr)-1);
|
||||
}
|
||||
|
||||
void SetStackSizeLimitInBytes(uptr limit) {
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = limit;
|
||||
rlim.rlim_max = limit;
|
||||
CHECK_EQ(0, setrlimit(RLIMIT_STACK, &rlim));
|
||||
CHECK(!StackSizeIsUnlimited());
|
||||
}
|
||||
|
||||
void SleepForSeconds(int seconds) {
|
||||
sleep(seconds);
|
||||
}
|
||||
|
||||
void SleepForMillis(int millis) {
|
||||
usleep(millis * 1000);
|
||||
}
|
||||
|
||||
void Exit(int exitcode) {
|
||||
_exit(exitcode);
|
||||
}
|
||||
|
||||
void Abort() {
|
||||
abort();
|
||||
}
|
||||
|
||||
int Atexit(void (*function)(void)) {
|
||||
#ifndef SANITIZER_GO
|
||||
return atexit(function);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __linux__ || __APPLE_
|
196
libsanitizer/sanitizer_common/sanitizer_printf.cc
Normal file
196
libsanitizer/sanitizer_common/sanitizer_printf.cc
Normal file
@ -0,0 +1,196 @@
|
||||
//===-- sanitizer_printf.cc -----------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer.
|
||||
//
|
||||
// Internal printf function, used inside run-time libraries.
|
||||
// We can't use libc printf because we intercept some of the functions used
|
||||
// inside it.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
static int AppendChar(char **buff, const char *buff_end, char c) {
|
||||
if (*buff < buff_end) {
|
||||
**buff = c;
|
||||
(*buff)++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Appends number in a given base to buffer. If its length is less than
|
||||
// "minimal_num_length", it is padded with leading zeroes.
|
||||
static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
||||
u8 base, u8 minimal_num_length) {
|
||||
uptr const kMaxLen = 30;
|
||||
RAW_CHECK(base == 10 || base == 16);
|
||||
RAW_CHECK(minimal_num_length < kMaxLen);
|
||||
uptr num_buffer[kMaxLen];
|
||||
uptr pos = 0;
|
||||
do {
|
||||
RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
|
||||
num_buffer[pos++] = num % base;
|
||||
num /= base;
|
||||
} while (num > 0);
|
||||
while (pos < minimal_num_length) num_buffer[pos++] = 0;
|
||||
int result = 0;
|
||||
while (pos-- > 0) {
|
||||
uptr digit = num_buffer[pos];
|
||||
result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
|
||||
: 'a' + digit - 10);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num) {
|
||||
int result = 0;
|
||||
if (num < 0) {
|
||||
result += AppendChar(buff, buff_end, '-');
|
||||
num = -num;
|
||||
}
|
||||
result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int AppendString(char **buff, const char *buff_end, const char *s) {
|
||||
if (s == 0)
|
||||
s = "<null>";
|
||||
int result = 0;
|
||||
for (; *s; s++) {
|
||||
result += AppendChar(buff, buff_end, *s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
|
||||
int result = 0;
|
||||
result += AppendString(buff, buff_end, "0x");
|
||||
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
|
||||
(__WORDSIZE == 64) ? 12 : 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
int VSNPrintf(char *buff, int buff_length,
|
||||
const char *format, va_list args) {
|
||||
static const char *kPrintfFormatsHelp = "Supported Printf formats: "
|
||||
"%%[z]{d,u,x}; %%p; %%s; %%c\n";
|
||||
RAW_CHECK(format);
|
||||
RAW_CHECK(buff_length > 0);
|
||||
const char *buff_end = &buff[buff_length - 1];
|
||||
const char *cur = format;
|
||||
int result = 0;
|
||||
for (; *cur; cur++) {
|
||||
if (*cur != '%') {
|
||||
result += AppendChar(&buff, buff_end, *cur);
|
||||
continue;
|
||||
}
|
||||
cur++;
|
||||
bool have_z = (*cur == 'z');
|
||||
cur += have_z;
|
||||
s64 dval;
|
||||
u64 uval;
|
||||
switch (*cur) {
|
||||
case 'd': {
|
||||
dval = have_z ? va_arg(args, sptr)
|
||||
: va_arg(args, int);
|
||||
result += AppendSignedDecimal(&buff, buff_end, dval);
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
case 'x': {
|
||||
uval = have_z ? va_arg(args, uptr)
|
||||
: va_arg(args, unsigned);
|
||||
result += AppendUnsigned(&buff, buff_end, uval,
|
||||
(*cur == 'u') ? 10 : 16, 0);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
result += AppendString(&buff, buff_end, va_arg(args, char*));
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
result += AppendChar(&buff, buff_end, va_arg(args, int));
|
||||
break;
|
||||
}
|
||||
case '%' : {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
result += AppendChar(&buff, buff_end, '%');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
RAW_CHECK_MSG(false, kPrintfFormatsHelp);
|
||||
}
|
||||
}
|
||||
}
|
||||
RAW_CHECK(buff <= buff_end);
|
||||
AppendChar(&buff, buff_end + 1, '\0');
|
||||
return result;
|
||||
}
|
||||
|
||||
static void (*PrintfAndReportCallback)(const char *);
|
||||
void SetPrintfAndReportCallback(void (*callback)(const char *)) {
|
||||
PrintfAndReportCallback = callback;
|
||||
}
|
||||
|
||||
void Printf(const char *format, ...) {
|
||||
const int kLen = 1024 * 4;
|
||||
InternalScopedBuffer<char> buffer(kLen);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int needed_length = VSNPrintf(buffer.data(), kLen, format, args);
|
||||
va_end(args);
|
||||
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
|
||||
RawWrite(buffer.data());
|
||||
if (PrintfAndReportCallback)
|
||||
PrintfAndReportCallback(buffer.data());
|
||||
}
|
||||
|
||||
// Writes at most "length" symbols to "buffer" (including trailing '\0').
|
||||
// Returns the number of symbols that should have been written to buffer
|
||||
// (not including trailing '\0'). Thus, the string is truncated
|
||||
// iff return value is not less than "length".
|
||||
int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int needed_length = VSNPrintf(buffer, length, format, args);
|
||||
va_end(args);
|
||||
return needed_length;
|
||||
}
|
||||
|
||||
// Like Printf, but prints the current PID before the output string.
|
||||
void Report(const char *format, ...) {
|
||||
const int kLen = 1024 * 4;
|
||||
InternalScopedBuffer<char> buffer(kLen);
|
||||
int needed_length = internal_snprintf(buffer.data(),
|
||||
kLen, "==%d== ", GetPid());
|
||||
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
needed_length += VSNPrintf(buffer.data() + needed_length,
|
||||
kLen - needed_length, format, args);
|
||||
va_end(args);
|
||||
RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
|
||||
RawWrite(buffer.data());
|
||||
if (PrintfAndReportCallback)
|
||||
PrintfAndReportCallback(buffer.data());
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
95
libsanitizer/sanitizer_common/sanitizer_procmaps.h
Normal file
95
libsanitizer/sanitizer_common/sanitizer_procmaps.h
Normal file
@ -0,0 +1,95 @@
|
||||
//===-- sanitizer_procmaps.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer.
|
||||
//
|
||||
// Information about the process mappings.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_PROCMAPS_H
|
||||
#define SANITIZER_PROCMAPS_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
#ifdef _WIN32
|
||||
class MemoryMappingLayout {
|
||||
public:
|
||||
MemoryMappingLayout() {}
|
||||
bool GetObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#else // _WIN32
|
||||
class MemoryMappingLayout {
|
||||
public:
|
||||
MemoryMappingLayout();
|
||||
bool Next(uptr *start, uptr *end, uptr *offset,
|
||||
char filename[], uptr filename_size);
|
||||
void Reset();
|
||||
// Gets the object file name and the offset in that object for a given
|
||||
// address 'addr'. Returns true on success.
|
||||
bool GetObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[], uptr filename_size);
|
||||
~MemoryMappingLayout();
|
||||
|
||||
private:
|
||||
// Default implementation of GetObjectNameAndOffset.
|
||||
// Quite slow, because it iterates through the whole process map for each
|
||||
// lookup.
|
||||
bool IterateForObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
Reset();
|
||||
uptr start, end, file_offset;
|
||||
for (int i = 0; Next(&start, &end, &file_offset, filename, filename_size);
|
||||
i++) {
|
||||
if (addr >= start && addr < end) {
|
||||
// Don't subtract 'start' for the first entry:
|
||||
// * If a binary is compiled w/o -pie, then the first entry in
|
||||
// process maps is likely the binary itself (all dynamic libs
|
||||
// are mapped higher in address space). For such a binary,
|
||||
// instruction offset in binary coincides with the actual
|
||||
// instruction address in virtual memory (as code section
|
||||
// is mapped to a fixed memory range).
|
||||
// * If a binary is compiled with -pie, all the modules are
|
||||
// mapped high at address space (in particular, higher than
|
||||
// shadow memory of the tool), so the module can't be the
|
||||
// first entry.
|
||||
*offset = (addr - (i ? start : 0)) + file_offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (filename_size)
|
||||
filename[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
# if defined __linux__
|
||||
char *proc_self_maps_buff_;
|
||||
uptr proc_self_maps_buff_mmaped_size_;
|
||||
uptr proc_self_maps_buff_len_;
|
||||
char *current_;
|
||||
# elif defined __APPLE__
|
||||
template<u32 kLCSegment, typename SegmentCommand>
|
||||
bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
|
||||
char filename[], uptr filename_size);
|
||||
int current_image_;
|
||||
u32 current_magic_;
|
||||
u32 current_filetype_;
|
||||
int current_load_cmd_count_;
|
||||
char *current_load_cmd_addr_;
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_PROCMAPS_H
|
194
libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
Normal file
194
libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
Normal file
@ -0,0 +1,194 @@
|
||||
//===-- sanitizer_stackdepot.cc -------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_mutex.h"
|
||||
#include "sanitizer_atomic.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
const int kTabSize = 1024 * 1024; // Hash table size.
|
||||
const int kPartBits = 8;
|
||||
const int kPartShift = sizeof(u32) * 8 - kPartBits - 1;
|
||||
const int kPartCount = 1 << kPartBits; // Number of subparts in the table.
|
||||
const int kPartSize = kTabSize / kPartCount;
|
||||
const int kMaxId = 1 << kPartShift;
|
||||
|
||||
struct StackDesc {
|
||||
StackDesc *link;
|
||||
u32 id;
|
||||
u32 hash;
|
||||
uptr size;
|
||||
uptr stack[1]; // [size]
|
||||
};
|
||||
|
||||
static struct {
|
||||
StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator.
|
||||
atomic_uintptr_t region_pos; // Region allocator for StackDesc's.
|
||||
atomic_uintptr_t region_end;
|
||||
atomic_uintptr_t tab[kTabSize]; // Hash table of StackDesc's.
|
||||
atomic_uint32_t seq[kPartCount]; // Unique id generators.
|
||||
} depot;
|
||||
|
||||
static u32 hash(const uptr *stack, uptr size) {
|
||||
// murmur2
|
||||
const u32 m = 0x5bd1e995;
|
||||
const u32 seed = 0x9747b28c;
|
||||
const u32 r = 24;
|
||||
u32 h = seed ^ (size * sizeof(uptr));
|
||||
for (uptr i = 0; i < size; i++) {
|
||||
u32 k = stack[i];
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h *= m;
|
||||
h ^= k;
|
||||
}
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
return h;
|
||||
}
|
||||
|
||||
static StackDesc *tryallocDesc(uptr memsz) {
|
||||
// Optimisic lock-free allocation, essentially try to bump the region ptr.
|
||||
for (;;) {
|
||||
uptr cmp = atomic_load(&depot.region_pos, memory_order_acquire);
|
||||
uptr end = atomic_load(&depot.region_end, memory_order_acquire);
|
||||
if (cmp == 0 || cmp + memsz > end)
|
||||
return 0;
|
||||
if (atomic_compare_exchange_weak(
|
||||
&depot.region_pos, &cmp, cmp + memsz,
|
||||
memory_order_acquire))
|
||||
return (StackDesc*)cmp;
|
||||
}
|
||||
}
|
||||
|
||||
static StackDesc *allocDesc(uptr size) {
|
||||
// Frist, try to allocate optimisitically.
|
||||
uptr memsz = sizeof(StackDesc) + (size - 1) * sizeof(uptr);
|
||||
StackDesc *s = tryallocDesc(memsz);
|
||||
if (s)
|
||||
return s;
|
||||
// If failed, lock, retry and alloc new superblock.
|
||||
SpinMutexLock l(&depot.mtx);
|
||||
for (;;) {
|
||||
s = tryallocDesc(memsz);
|
||||
if (s)
|
||||
return s;
|
||||
atomic_store(&depot.region_pos, 0, memory_order_relaxed);
|
||||
uptr allocsz = 64 * 1024;
|
||||
if (allocsz < memsz)
|
||||
allocsz = memsz;
|
||||
uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
|
||||
atomic_store(&depot.region_end, mem + allocsz, memory_order_release);
|
||||
atomic_store(&depot.region_pos, mem, memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 find(StackDesc *s, const uptr *stack, uptr size, u32 hash) {
|
||||
// Searches linked list s for the stack, returns its id.
|
||||
for (; s; s = s->link) {
|
||||
if (s->hash == hash && s->size == size) {
|
||||
uptr i = 0;
|
||||
for (; i < size; i++) {
|
||||
if (stack[i] != s->stack[i])
|
||||
break;
|
||||
}
|
||||
if (i == size)
|
||||
return s->id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static StackDesc *lock(atomic_uintptr_t *p) {
|
||||
// Uses the pointer lsb as mutex.
|
||||
for (int i = 0;; i++) {
|
||||
uptr cmp = atomic_load(p, memory_order_relaxed);
|
||||
if ((cmp & 1) == 0
|
||||
&& atomic_compare_exchange_weak(p, &cmp, cmp | 1,
|
||||
memory_order_acquire))
|
||||
return (StackDesc*)cmp;
|
||||
if (i < 10)
|
||||
proc_yield(10);
|
||||
else
|
||||
internal_sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static void unlock(atomic_uintptr_t *p, StackDesc *s) {
|
||||
DCHECK_EQ((uptr)s & 1, 0);
|
||||
atomic_store(p, (uptr)s, memory_order_release);
|
||||
}
|
||||
|
||||
u32 StackDepotPut(const uptr *stack, uptr size) {
|
||||
if (stack == 0 || size == 0)
|
||||
return 0;
|
||||
uptr h = hash(stack, size);
|
||||
atomic_uintptr_t *p = &depot.tab[h % kTabSize];
|
||||
uptr v = atomic_load(p, memory_order_consume);
|
||||
StackDesc *s = (StackDesc*)(v & ~1);
|
||||
// First, try to find the existing stack.
|
||||
u32 id = find(s, stack, size, h);
|
||||
if (id)
|
||||
return id;
|
||||
// If failed, lock, retry and insert new.
|
||||
StackDesc *s2 = lock(p);
|
||||
if (s2 != s) {
|
||||
id = find(s2, stack, size, h);
|
||||
if (id) {
|
||||
unlock(p, s2);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
uptr part = (h % kTabSize) / kPartSize;
|
||||
id = atomic_fetch_add(&depot.seq[part], 1, memory_order_relaxed) + 1;
|
||||
CHECK_LT(id, kMaxId);
|
||||
id |= part << kPartShift;
|
||||
CHECK_NE(id, 0);
|
||||
CHECK_EQ(id & (1u << 31), 0);
|
||||
s = allocDesc(size);
|
||||
s->id = id;
|
||||
s->hash = h;
|
||||
s->size = size;
|
||||
internal_memcpy(s->stack, stack, size * sizeof(uptr));
|
||||
s->link = s2;
|
||||
unlock(p, s);
|
||||
return id;
|
||||
}
|
||||
|
||||
const uptr *StackDepotGet(u32 id, uptr *size) {
|
||||
if (id == 0)
|
||||
return 0;
|
||||
CHECK_EQ(id & (1u << 31), 0);
|
||||
// High kPartBits contain part id, so we need to scan at most kPartSize lists.
|
||||
uptr part = id >> kPartShift;
|
||||
for (int i = 0; i != kPartSize; i++) {
|
||||
uptr idx = part * kPartSize + i;
|
||||
CHECK_LT(idx, kTabSize);
|
||||
atomic_uintptr_t *p = &depot.tab[idx];
|
||||
uptr v = atomic_load(p, memory_order_consume);
|
||||
StackDesc *s = (StackDesc*)(v & ~1);
|
||||
for (; s; s = s->link) {
|
||||
if (s->id == id) {
|
||||
*size = s->size;
|
||||
return s->stack;
|
||||
}
|
||||
}
|
||||
}
|
||||
*size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
27
libsanitizer/sanitizer_common/sanitizer_stackdepot.h
Normal file
27
libsanitizer/sanitizer_common/sanitizer_stackdepot.h
Normal file
@ -0,0 +1,27 @@
|
||||
//===-- sanitizer_stackdepot.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_STACKDEPOT_H
|
||||
#define SANITIZER_STACKDEPOT_H
|
||||
|
||||
#include "sanitizer/common_interface_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// StackDepot efficiently stores huge amounts of stack traces.
|
||||
|
||||
// Maps stack trace to an unique id.
|
||||
u32 StackDepotPut(const uptr *stack, uptr size);
|
||||
// Retrieves a stored stack trace by the id.
|
||||
const uptr *StackDepotGet(u32 id, uptr *size);
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_STACKDEPOT_H
|
245
libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
Normal file
245
libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
Normal file
@ -0,0 +1,245 @@
|
||||
//===-- sanitizer_stacktrace.cc -------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
#include "sanitizer_stacktrace.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
static const char *StripPathPrefix(const char *filepath,
|
||||
const char *strip_file_prefix) {
|
||||
if (filepath == internal_strstr(filepath, strip_file_prefix))
|
||||
return filepath + internal_strlen(strip_file_prefix);
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// ----------------------- StackTrace ----------------------------- {{{1
|
||||
// PCs in stack traces are actually the return addresses, that is,
|
||||
// addresses of the next instructions after the call. That's why we
|
||||
// decrement them.
|
||||
static uptr patch_pc(uptr pc) {
|
||||
#ifdef __arm__
|
||||
// Cancel Thumb bit.
|
||||
pc = pc & (~1);
|
||||
#endif
|
||||
return pc - 1;
|
||||
}
|
||||
|
||||
static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
|
||||
Printf(" #%zu 0x%zx", frame_num, pc);
|
||||
}
|
||||
|
||||
static void PrintSourceLocation(const char *file, int line, int column,
|
||||
const char *strip_file_prefix) {
|
||||
CHECK(file);
|
||||
Printf(" %s", StripPathPrefix(file, strip_file_prefix));
|
||||
if (line > 0) {
|
||||
Printf(":%d", line);
|
||||
if (column > 0)
|
||||
Printf(":%d", column);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintModuleAndOffset(const char *module, uptr offset,
|
||||
const char *strip_file_prefix) {
|
||||
Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset);
|
||||
}
|
||||
|
||||
void StackTrace::PrintStack(const uptr *addr, uptr size,
|
||||
bool symbolize, const char *strip_file_prefix,
|
||||
SymbolizeCallback symbolize_callback ) {
|
||||
MemoryMappingLayout proc_maps;
|
||||
InternalScopedBuffer<char> buff(kPageSize * 2);
|
||||
InternalScopedBuffer<AddressInfo> addr_frames(64);
|
||||
uptr frame_num = 0;
|
||||
for (uptr i = 0; i < size && addr[i]; i++) {
|
||||
uptr pc = patch_pc(addr[i]);
|
||||
uptr addr_frames_num = 0; // The number of stack frames for current
|
||||
// instruction address.
|
||||
if (symbolize_callback) {
|
||||
if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
|
||||
addr_frames_num = 1;
|
||||
PrintStackFramePrefix(frame_num, pc);
|
||||
// We can't know anything about the string returned by external
|
||||
// symbolizer, but if it starts with filename, try to strip path prefix
|
||||
// from it.
|
||||
Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix));
|
||||
frame_num++;
|
||||
}
|
||||
} else if (symbolize) {
|
||||
// Use our own (online) symbolizer, if necessary.
|
||||
addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
|
||||
addr_frames.size());
|
||||
for (uptr j = 0; j < addr_frames_num; j++) {
|
||||
AddressInfo &info = addr_frames[j];
|
||||
PrintStackFramePrefix(frame_num, pc);
|
||||
if (info.function) {
|
||||
Printf(" in %s", info.function);
|
||||
}
|
||||
if (info.file) {
|
||||
PrintSourceLocation(info.file, info.line, info.column,
|
||||
strip_file_prefix);
|
||||
} else if (info.module) {
|
||||
PrintModuleAndOffset(info.module, info.module_offset,
|
||||
strip_file_prefix);
|
||||
}
|
||||
Printf("\n");
|
||||
info.Clear();
|
||||
frame_num++;
|
||||
}
|
||||
}
|
||||
if (addr_frames_num == 0) {
|
||||
// If online symbolization failed, try to output at least module and
|
||||
// offset for instruction.
|
||||
PrintStackFramePrefix(frame_num, pc);
|
||||
uptr offset;
|
||||
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
|
||||
buff.data(), buff.size())) {
|
||||
PrintModuleAndOffset(buff.data(), offset, strip_file_prefix);
|
||||
}
|
||||
Printf("\n");
|
||||
frame_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uptr StackTrace::GetCurrentPc() {
|
||||
return GET_CALLER_PC();
|
||||
}
|
||||
|
||||
void StackTrace::FastUnwindStack(uptr pc, uptr bp,
|
||||
uptr stack_top, uptr stack_bottom) {
|
||||
CHECK(size == 0 && trace[0] == pc);
|
||||
size = 1;
|
||||
uptr *frame = (uptr*)bp;
|
||||
uptr *prev_frame = frame;
|
||||
while (frame >= prev_frame &&
|
||||
frame < (uptr*)stack_top - 2 &&
|
||||
frame > (uptr*)stack_bottom &&
|
||||
size < max_size) {
|
||||
uptr pc1 = frame[1];
|
||||
if (pc1 != pc) {
|
||||
trace[size++] = pc1;
|
||||
}
|
||||
prev_frame = frame;
|
||||
frame = (uptr*)frame[0];
|
||||
}
|
||||
}
|
||||
|
||||
// On 32-bits we don't compress stack traces.
|
||||
// On 64-bits we compress stack traces: if a given pc differes slightly from
|
||||
// the previous one, we record a 31-bit offset instead of the full pc.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
|
||||
#if __WORDSIZE == 32
|
||||
// Don't compress, just copy.
|
||||
uptr res = 0;
|
||||
for (uptr i = 0; i < stack->size && i < size; i++) {
|
||||
compressed[i] = stack->trace[i];
|
||||
res++;
|
||||
}
|
||||
if (stack->size < size)
|
||||
compressed[stack->size] = 0;
|
||||
#else // 64 bits, compress.
|
||||
uptr prev_pc = 0;
|
||||
const uptr kMaxOffset = (1ULL << 30) - 1;
|
||||
uptr c_index = 0;
|
||||
uptr res = 0;
|
||||
for (uptr i = 0, n = stack->size; i < n; i++) {
|
||||
uptr pc = stack->trace[i];
|
||||
if (!pc) break;
|
||||
if ((s64)pc < 0) break;
|
||||
// Printf("C pc[%zu] %zx\n", i, pc);
|
||||
if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) {
|
||||
uptr offset = (s64)(pc - prev_pc);
|
||||
offset |= (1U << 31);
|
||||
if (c_index >= size) break;
|
||||
// Printf("C co[%zu] offset %zx\n", i, offset);
|
||||
compressed[c_index++] = offset;
|
||||
} else {
|
||||
uptr hi = pc >> 32;
|
||||
uptr lo = (pc << 32) >> 32;
|
||||
CHECK_EQ((hi & (1 << 31)), 0);
|
||||
if (c_index + 1 >= size) break;
|
||||
// Printf("C co[%zu] hi/lo: %zx %zx\n", c_index, hi, lo);
|
||||
compressed[c_index++] = hi;
|
||||
compressed[c_index++] = lo;
|
||||
}
|
||||
res++;
|
||||
prev_pc = pc;
|
||||
}
|
||||
if (c_index < size)
|
||||
compressed[c_index] = 0;
|
||||
if (c_index + 1 < size)
|
||||
compressed[c_index + 1] = 0;
|
||||
#endif // __WORDSIZE
|
||||
|
||||
// debug-only code
|
||||
#if 0
|
||||
StackTrace check_stack;
|
||||
UncompressStack(&check_stack, compressed, size);
|
||||
if (res < check_stack.size) {
|
||||
Printf("res %zu check_stack.size %zu; c_size %zu\n", res,
|
||||
check_stack.size, size);
|
||||
}
|
||||
// |res| may be greater than check_stack.size, because
|
||||
// UncompressStack(CompressStack(stack)) eliminates the 0x0 frames.
|
||||
CHECK(res >= check_stack.size);
|
||||
CHECK_EQ(0, REAL(memcmp)(check_stack.trace, stack->trace,
|
||||
check_stack.size * sizeof(uptr)));
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void StackTrace::UncompressStack(StackTrace *stack,
|
||||
u32 *compressed, uptr size) {
|
||||
#if __WORDSIZE == 32
|
||||
// Don't uncompress, just copy.
|
||||
stack->size = 0;
|
||||
for (uptr i = 0; i < size && i < kStackTraceMax; i++) {
|
||||
if (!compressed[i]) break;
|
||||
stack->size++;
|
||||
stack->trace[i] = compressed[i];
|
||||
}
|
||||
#else // 64 bits, uncompress
|
||||
uptr prev_pc = 0;
|
||||
stack->size = 0;
|
||||
for (uptr i = 0; i < size && stack->size < kStackTraceMax; i++) {
|
||||
u32 x = compressed[i];
|
||||
uptr pc = 0;
|
||||
if (x & (1U << 31)) {
|
||||
// Printf("U co[%zu] offset: %x\n", i, x);
|
||||
// this is an offset
|
||||
s32 offset = x;
|
||||
offset = (offset << 1) >> 1; // remove the 31-byte and sign-extend.
|
||||
pc = prev_pc + offset;
|
||||
CHECK(pc);
|
||||
} else {
|
||||
// CHECK(i + 1 < size);
|
||||
if (i + 1 >= size) break;
|
||||
uptr hi = x;
|
||||
uptr lo = compressed[i+1];
|
||||
// Printf("U co[%zu] hi/lo: %zx %zx\n", i, hi, lo);
|
||||
i++;
|
||||
pc = (hi << 32) | lo;
|
||||
if (!pc) break;
|
||||
}
|
||||
// Printf("U pc[%zu] %zx\n", stack->size, pc);
|
||||
stack->trace[stack->size++] = pc;
|
||||
prev_pc = pc;
|
||||
}
|
||||
#endif // __WORDSIZE
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
73
libsanitizer/sanitizer_common/sanitizer_stacktrace.h
Normal file
73
libsanitizer/sanitizer_common/sanitizer_stacktrace.h
Normal file
@ -0,0 +1,73 @@
|
||||
//===-- sanitizer_stacktrace.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_STACKTRACE_H
|
||||
#define SANITIZER_STACKTRACE_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
static const uptr kStackTraceMax = 256;
|
||||
|
||||
struct StackTrace {
|
||||
typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
|
||||
int out_size);
|
||||
uptr size;
|
||||
uptr max_size;
|
||||
uptr trace[kStackTraceMax];
|
||||
static void PrintStack(const uptr *addr, uptr size,
|
||||
bool symbolize, const char *strip_file_prefix,
|
||||
SymbolizeCallback symbolize_callback);
|
||||
void CopyTo(uptr *dst, uptr dst_size) {
|
||||
for (uptr i = 0; i < size && i < dst_size; i++)
|
||||
dst[i] = trace[i];
|
||||
for (uptr i = size; i < dst_size; i++)
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
void CopyFrom(uptr *src, uptr src_size) {
|
||||
size = src_size;
|
||||
if (size > kStackTraceMax) size = kStackTraceMax;
|
||||
for (uptr i = 0; i < size; i++) {
|
||||
trace[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom);
|
||||
|
||||
static uptr GetCurrentPc();
|
||||
|
||||
static uptr CompressStack(StackTrace *stack,
|
||||
u32 *compressed, uptr size);
|
||||
static void UncompressStack(StackTrace *stack,
|
||||
u32 *compressed, uptr size);
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
// Use this macro if you want to print stack trace with the caller
|
||||
// of the current function in the top frame.
|
||||
#define GET_CALLER_PC_BP_SP \
|
||||
uptr bp = GET_CURRENT_FRAME(); \
|
||||
uptr pc = GET_CALLER_PC(); \
|
||||
uptr local_stack; \
|
||||
uptr sp = (uptr)&local_stack
|
||||
|
||||
// Use this macro if you want to print stack trace with the current
|
||||
// function in the top frame.
|
||||
#define GET_CURRENT_PC_BP_SP \
|
||||
uptr bp = GET_CURRENT_FRAME(); \
|
||||
uptr pc = StackTrace::GetCurrentPc(); \
|
||||
uptr local_stack; \
|
||||
uptr sp = (uptr)&local_stack
|
||||
|
||||
|
||||
#endif // SANITIZER_STACKTRACE_H
|
311
libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
Normal file
311
libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
Normal file
@ -0,0 +1,311 @@
|
||||
//===-- sanitizer_symbolizer.cc -------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries. See sanitizer_symbolizer.h for details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_placement_new.h"
|
||||
#include "sanitizer_procmaps.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
void AddressInfo::Clear() {
|
||||
InternalFree(module);
|
||||
InternalFree(function);
|
||||
InternalFree(file);
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
}
|
||||
|
||||
LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
|
||||
full_name_ = internal_strdup(module_name);
|
||||
base_address_ = base_address;
|
||||
n_ranges_ = 0;
|
||||
}
|
||||
|
||||
void LoadedModule::addAddressRange(uptr beg, uptr end) {
|
||||
CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges);
|
||||
ranges_[n_ranges_].beg = beg;
|
||||
ranges_[n_ranges_].end = end;
|
||||
n_ranges_++;
|
||||
}
|
||||
|
||||
bool LoadedModule::containsAddress(uptr address) const {
|
||||
for (uptr i = 0; i < n_ranges_; i++) {
|
||||
if (ranges_[i].beg <= address && address < ranges_[i].end)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extracts the prefix of "str" that consists of any characters not
|
||||
// present in "delims" string, and copies this prefix to "result", allocating
|
||||
// space for it.
|
||||
// Returns a pointer to "str" after skipping extracted prefix and first
|
||||
// delimiter char.
|
||||
static const char *ExtractToken(const char *str, const char *delims,
|
||||
char **result) {
|
||||
uptr prefix_len = internal_strcspn(str, delims);
|
||||
*result = (char*)InternalAlloc(prefix_len + 1);
|
||||
internal_memcpy(*result, str, prefix_len);
|
||||
(*result)[prefix_len] = '\0';
|
||||
const char *prefix_end = str + prefix_len;
|
||||
if (*prefix_end != '\0') prefix_end++;
|
||||
return prefix_end;
|
||||
}
|
||||
|
||||
// Same as ExtractToken, but converts extracted token to integer.
|
||||
static const char *ExtractInt(const char *str, const char *delims,
|
||||
int *result) {
|
||||
char *buff;
|
||||
const char *ret = ExtractToken(str, delims, &buff);
|
||||
if (buff != 0) {
|
||||
*result = internal_atoll(buff);
|
||||
}
|
||||
InternalFree(buff);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ExternalSymbolizer encapsulates communication between the tool and
|
||||
// external symbolizer program, running in a different subprocess,
|
||||
// For now we assume the following protocol:
|
||||
// For each request of the form
|
||||
// <module_name> <module_offset>
|
||||
// passed to STDIN, external symbolizer prints to STDOUT response:
|
||||
// <function_name>
|
||||
// <file_name>:<line_number>:<column_number>
|
||||
// <function_name>
|
||||
// <file_name>:<line_number>:<column_number>
|
||||
// ...
|
||||
// <empty line>
|
||||
class ExternalSymbolizer {
|
||||
public:
|
||||
ExternalSymbolizer(const char *path, int input_fd, int output_fd)
|
||||
: path_(path),
|
||||
input_fd_(input_fd),
|
||||
output_fd_(output_fd),
|
||||
times_restarted_(0) {
|
||||
CHECK(path_);
|
||||
CHECK_NE(input_fd_, kInvalidFd);
|
||||
CHECK_NE(output_fd_, kInvalidFd);
|
||||
}
|
||||
|
||||
// Returns the number of frames for a given address, or zero if
|
||||
// symbolization failed.
|
||||
uptr SymbolizeCode(uptr addr, const char *module_name, uptr module_offset,
|
||||
AddressInfo *frames, uptr max_frames) {
|
||||
CHECK(module_name);
|
||||
// FIXME: Make sure this buffer always has sufficient size to hold
|
||||
// large debug info.
|
||||
static const int kMaxBufferSize = 4096;
|
||||
InternalScopedBuffer<char> buffer(kMaxBufferSize);
|
||||
char *buffer_data = buffer.data();
|
||||
internal_snprintf(buffer_data, kMaxBufferSize, "%s 0x%zx\n",
|
||||
module_name, module_offset);
|
||||
if (!writeToSymbolizer(buffer_data, internal_strlen(buffer_data)))
|
||||
return 0;
|
||||
|
||||
if (!readFromSymbolizer(buffer_data, kMaxBufferSize))
|
||||
return 0;
|
||||
const char *str = buffer_data;
|
||||
uptr frame_id;
|
||||
CHECK_GT(max_frames, 0);
|
||||
for (frame_id = 0; frame_id < max_frames; frame_id++) {
|
||||
AddressInfo *info = &frames[frame_id];
|
||||
char *function_name = 0;
|
||||
str = ExtractToken(str, "\n", &function_name);
|
||||
CHECK(function_name);
|
||||
if (function_name[0] == '\0') {
|
||||
// There are no more frames.
|
||||
break;
|
||||
}
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
info->function = function_name;
|
||||
// Parse <file>:<line>:<column> buffer.
|
||||
char *file_line_info = 0;
|
||||
str = ExtractToken(str, "\n", &file_line_info);
|
||||
CHECK(file_line_info);
|
||||
const char *line_info = ExtractToken(file_line_info, ":", &info->file);
|
||||
line_info = ExtractInt(line_info, ":", &info->line);
|
||||
line_info = ExtractInt(line_info, "", &info->column);
|
||||
InternalFree(file_line_info);
|
||||
|
||||
// Functions and filenames can be "??", in which case we write 0
|
||||
// to address info to mark that names are unknown.
|
||||
if (0 == internal_strcmp(info->function, "??")) {
|
||||
InternalFree(info->function);
|
||||
info->function = 0;
|
||||
}
|
||||
if (0 == internal_strcmp(info->file, "??")) {
|
||||
InternalFree(info->file);
|
||||
info->file = 0;
|
||||
}
|
||||
}
|
||||
if (frame_id == 0) {
|
||||
// Make sure we return at least one frame.
|
||||
AddressInfo *info = &frames[0];
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
frame_id = 1;
|
||||
}
|
||||
return frame_id;
|
||||
}
|
||||
|
||||
bool Restart() {
|
||||
if (times_restarted_ >= kMaxTimesRestarted) return false;
|
||||
times_restarted_++;
|
||||
internal_close(input_fd_);
|
||||
internal_close(output_fd_);
|
||||
return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool readFromSymbolizer(char *buffer, uptr max_length) {
|
||||
if (max_length == 0)
|
||||
return true;
|
||||
uptr read_len = 0;
|
||||
while (true) {
|
||||
uptr just_read = internal_read(input_fd_, buffer + read_len,
|
||||
max_length - read_len);
|
||||
// We can't read 0 bytes, as we don't expect external symbolizer to close
|
||||
// its stdout.
|
||||
if (just_read == 0 || just_read == (uptr)-1) {
|
||||
Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_);
|
||||
return false;
|
||||
}
|
||||
read_len += just_read;
|
||||
// Empty line marks the end of symbolizer output.
|
||||
if (read_len >= 2 && buffer[read_len - 1] == '\n' &&
|
||||
buffer[read_len - 2] == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool writeToSymbolizer(const char *buffer, uptr length) {
|
||||
if (length == 0)
|
||||
return true;
|
||||
uptr write_len = internal_write(output_fd_, buffer, length);
|
||||
if (write_len == 0 || write_len == (uptr)-1) {
|
||||
Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *path_;
|
||||
int input_fd_;
|
||||
int output_fd_;
|
||||
|
||||
static const uptr kMaxTimesRestarted = 5;
|
||||
uptr times_restarted_;
|
||||
};
|
||||
|
||||
static LowLevelAllocator symbolizer_allocator; // Linker initialized.
|
||||
|
||||
class Symbolizer {
|
||||
public:
|
||||
uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
|
||||
if (max_frames == 0)
|
||||
return 0;
|
||||
LoadedModule *module = FindModuleForAddress(addr);
|
||||
if (module == 0)
|
||||
return 0;
|
||||
const char *module_name = module->full_name();
|
||||
uptr module_offset = addr - module->base_address();
|
||||
uptr actual_frames = 0;
|
||||
if (external_symbolizer_ == 0) {
|
||||
ReportExternalSymbolizerError(
|
||||
"WARNING: Trying to symbolize code, but external "
|
||||
"symbolizer is not initialized!\n");
|
||||
} else {
|
||||
while (true) {
|
||||
actual_frames = external_symbolizer_->SymbolizeCode(
|
||||
addr, module_name, module_offset, frames, max_frames);
|
||||
if (actual_frames > 0) {
|
||||
// Symbolization was successful.
|
||||
break;
|
||||
}
|
||||
// Try to restart symbolizer subprocess. If we don't succeed, forget
|
||||
// about it and don't try to use it later.
|
||||
if (!external_symbolizer_->Restart()) {
|
||||
ReportExternalSymbolizerError(
|
||||
"WARNING: Failed to use and restart external symbolizer!\n");
|
||||
external_symbolizer_ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (external_symbolizer_ == 0) {
|
||||
// External symbolizer was not initialized or failed. Fill only data
|
||||
// about module name and offset.
|
||||
AddressInfo *info = &frames[0];
|
||||
info->Clear();
|
||||
info->FillAddressAndModuleInfo(addr, module_name, module_offset);
|
||||
return 1;
|
||||
}
|
||||
// Otherwise, the data was filled by external symbolizer.
|
||||
return actual_frames;
|
||||
}
|
||||
bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
|
||||
int input_fd, output_fd;
|
||||
if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
|
||||
return false;
|
||||
void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
|
||||
external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
|
||||
input_fd, output_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
LoadedModule *FindModuleForAddress(uptr address) {
|
||||
if (modules_ == 0) {
|
||||
modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
|
||||
kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
|
||||
CHECK(modules_);
|
||||
n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts);
|
||||
CHECK_GT(n_modules_, 0);
|
||||
CHECK_LT(n_modules_, kMaxNumberOfModuleContexts);
|
||||
}
|
||||
for (uptr i = 0; i < n_modules_; i++) {
|
||||
if (modules_[i].containsAddress(address)) {
|
||||
return &modules_[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void ReportExternalSymbolizerError(const char *msg) {
|
||||
// Don't use atomics here for now, as SymbolizeCode can't be called
|
||||
// from multiple threads anyway.
|
||||
static bool reported;
|
||||
if (!reported) {
|
||||
Report(msg);
|
||||
reported = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const uptr kMaxNumberOfModuleContexts = 4096;
|
||||
LoadedModule *modules_; // Array of module descriptions is leaked.
|
||||
uptr n_modules_;
|
||||
|
||||
ExternalSymbolizer *external_symbolizer_; // Leaked.
|
||||
};
|
||||
|
||||
static Symbolizer symbolizer; // Linker initialized.
|
||||
|
||||
uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames) {
|
||||
return symbolizer.SymbolizeCode(address, frames, max_frames);
|
||||
}
|
||||
|
||||
bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
|
||||
return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
97
libsanitizer/sanitizer_common/sanitizer_symbolizer.h
Normal file
97
libsanitizer/sanitizer_common/sanitizer_symbolizer.h
Normal file
@ -0,0 +1,97 @@
|
||||
//===-- sanitizer_symbolizer.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Symbolizer is intended to be used by both
|
||||
// AddressSanitizer and ThreadSanitizer to symbolize a given
|
||||
// address. It is an analogue of addr2line utility and allows to map
|
||||
// instruction address to a location in source code at run-time.
|
||||
//
|
||||
// Symbolizer is planned to use debug information (in DWARF format)
|
||||
// in a binary via interface defined in "llvm/DebugInfo/DIContext.h"
|
||||
//
|
||||
// Symbolizer code should be called from the run-time library of
|
||||
// dynamic tools, and generally should not call memory allocation
|
||||
// routines or other system library functions intercepted by those tools.
|
||||
// Instead, Symbolizer code should use their replacements, defined in
|
||||
// "compiler-rt/lib/sanitizer_common/sanitizer_libc.h".
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SANITIZER_SYMBOLIZER_H
|
||||
#define SANITIZER_SYMBOLIZER_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
// WARNING: Do not include system headers here. See details above.
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
struct AddressInfo {
|
||||
uptr address;
|
||||
char *module;
|
||||
uptr module_offset;
|
||||
char *function;
|
||||
char *file;
|
||||
int line;
|
||||
int column;
|
||||
|
||||
AddressInfo() {
|
||||
internal_memset(this, 0, sizeof(AddressInfo));
|
||||
}
|
||||
// Deletes all strings and sets all fields to zero.
|
||||
void Clear();
|
||||
|
||||
void FillAddressAndModuleInfo(uptr addr, const char *mod_name,
|
||||
uptr mod_offset) {
|
||||
address = addr;
|
||||
module = internal_strdup(mod_name);
|
||||
module_offset = mod_offset;
|
||||
}
|
||||
};
|
||||
|
||||
// Fills at most "max_frames" elements of "frames" with descriptions
|
||||
// for a given address (in all inlined functions). Returns the number
|
||||
// of descriptions actually filled.
|
||||
// This function should NOT be called from two threads simultaneously.
|
||||
uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
|
||||
|
||||
// Starts external symbolizer program in a subprocess. Sanitizer communicates
|
||||
// with external symbolizer via pipes.
|
||||
bool InitializeExternalSymbolizer(const char *path_to_symbolizer);
|
||||
|
||||
class LoadedModule {
|
||||
public:
|
||||
LoadedModule(const char *module_name, uptr base_address);
|
||||
void addAddressRange(uptr beg, uptr end);
|
||||
bool containsAddress(uptr address) const;
|
||||
|
||||
const char *full_name() const { return full_name_; }
|
||||
uptr base_address() const { return base_address_; }
|
||||
|
||||
private:
|
||||
struct AddressRange {
|
||||
uptr beg;
|
||||
uptr end;
|
||||
};
|
||||
char *full_name_;
|
||||
uptr base_address_;
|
||||
static const uptr kMaxNumberOfAddressRanges = 8;
|
||||
AddressRange ranges_[kMaxNumberOfAddressRanges];
|
||||
uptr n_ranges_;
|
||||
};
|
||||
|
||||
// Creates external symbolizer connected via pipe, user should write
|
||||
// to output_fd and read from input_fd.
|
||||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd);
|
||||
|
||||
// OS-dependent function that fills array with descriptions of at most
|
||||
// "max_modules" currently loaded modules. Returns the number of
|
||||
// initialized modules.
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules);
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_SYMBOLIZER_H
|
162
libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
Normal file
162
libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc
Normal file
@ -0,0 +1,162 @@
|
||||
//===-- sanitizer_symbolizer_linux.cc -------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// Linux-specific implementation of symbolizer parts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef __linux__
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_libc.h"
|
||||
#include "sanitizer_placement_new.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(ANDROID)
|
||||
#include <link.h>
|
||||
#endif
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
int *infd = NULL;
|
||||
int *outfd = NULL;
|
||||
// The client program may close its stdin and/or stdout and/or stderr
|
||||
// thus allowing socketpair to reuse file descriptors 0, 1 or 2.
|
||||
// In this case the communication between the forked processes may be
|
||||
// broken if either the parent or the child tries to close or duplicate
|
||||
// these descriptors. The loop below produces two pairs of file
|
||||
// descriptors, each greater than 2 (stderr).
|
||||
int sock_pair[5][2];
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (pipe(sock_pair[i]) == -1) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
internal_close(sock_pair[j][0]);
|
||||
internal_close(sock_pair[j][1]);
|
||||
}
|
||||
Report("WARNING: Can't create a socket pair to start "
|
||||
"external symbolizer (errno: %d)\n", errno);
|
||||
return false;
|
||||
} else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
|
||||
if (infd == NULL) {
|
||||
infd = sock_pair[i];
|
||||
} else {
|
||||
outfd = sock_pair[i];
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sock_pair[j] == infd) continue;
|
||||
internal_close(sock_pair[j][0]);
|
||||
internal_close(sock_pair[j][1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK(infd);
|
||||
CHECK(outfd);
|
||||
|
||||
int pid = fork();
|
||||
if (pid == -1) {
|
||||
// Fork() failed.
|
||||
internal_close(infd[0]);
|
||||
internal_close(infd[1]);
|
||||
internal_close(outfd[0]);
|
||||
internal_close(outfd[1]);
|
||||
Report("WARNING: failed to fork external symbolizer "
|
||||
" (errno: %d)\n", errno);
|
||||
return false;
|
||||
} else if (pid == 0) {
|
||||
// Child subprocess.
|
||||
internal_close(STDOUT_FILENO);
|
||||
internal_close(STDIN_FILENO);
|
||||
internal_dup2(outfd[0], STDIN_FILENO);
|
||||
internal_dup2(infd[1], STDOUT_FILENO);
|
||||
internal_close(outfd[0]);
|
||||
internal_close(outfd[1]);
|
||||
internal_close(infd[0]);
|
||||
internal_close(infd[1]);
|
||||
for (int fd = getdtablesize(); fd > 2; fd--)
|
||||
internal_close(fd);
|
||||
execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
|
||||
Exit(1);
|
||||
}
|
||||
|
||||
// Continue execution in parent process.
|
||||
internal_close(outfd[0]);
|
||||
internal_close(infd[1]);
|
||||
*input_fd = infd[0];
|
||||
*output_fd = outfd[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
#else // ANDROID
|
||||
typedef ElfW(Phdr) Elf_Phdr;
|
||||
|
||||
struct DlIteratePhdrData {
|
||||
LoadedModule *modules;
|
||||
uptr current_n;
|
||||
uptr max_n;
|
||||
};
|
||||
|
||||
static const uptr kMaxPathLength = 512;
|
||||
|
||||
static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
|
||||
DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
|
||||
if (data->current_n == data->max_n)
|
||||
return 0;
|
||||
InternalScopedBuffer<char> module_name(kMaxPathLength);
|
||||
module_name.data()[0] = '\0';
|
||||
if (data->current_n == 0) {
|
||||
// First module is the binary itself.
|
||||
uptr module_name_len = internal_readlink(
|
||||
"/proc/self/exe", module_name.data(), module_name.size());
|
||||
CHECK_NE(module_name_len, (uptr)-1);
|
||||
CHECK_LT(module_name_len, module_name.size());
|
||||
module_name[module_name_len] = '\0';
|
||||
} else if (info->dlpi_name) {
|
||||
internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
|
||||
}
|
||||
if (module_name.data()[0] == '\0')
|
||||
return 0;
|
||||
void *mem = &data->modules[data->current_n];
|
||||
LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
|
||||
info->dlpi_addr);
|
||||
data->current_n++;
|
||||
for (int i = 0; i < info->dlpi_phnum; i++) {
|
||||
const Elf_Phdr *phdr = &info->dlpi_phdr[i];
|
||||
if (phdr->p_type == PT_LOAD) {
|
||||
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
|
||||
uptr cur_end = cur_beg + phdr->p_memsz;
|
||||
cur_module->addAddressRange(cur_beg, cur_end);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
CHECK(modules);
|
||||
DlIteratePhdrData data = {modules, 0, max_modules};
|
||||
dl_iterate_phdr(dl_iterate_phdr_cb, &data);
|
||||
return data.current_n;
|
||||
}
|
||||
#endif // ANDROID
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __linux__
|
31
libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
Normal file
31
libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
Normal file
@ -0,0 +1,31 @@
|
||||
//===-- sanitizer_symbolizer_mac.cc ---------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// Mac-specific implementation of symbolizer parts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef __APPLE__
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __APPLE__
|
33
libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
Normal file
33
libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
Normal file
@ -0,0 +1,33 @@
|
||||
//===-- sanitizer_symbolizer_win.cc ---------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries.
|
||||
// Windows-specific implementation of symbolizer parts.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // _WIN32
|
205
libsanitizer/sanitizer_common/sanitizer_win.cc
Normal file
205
libsanitizer/sanitizer_common/sanitizer_win.cc
Normal file
@ -0,0 +1,205 @@
|
||||
//===-- sanitizer_win.cc --------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is shared between AddressSanitizer and ThreadSanitizer
|
||||
// run-time libraries and implements windows-specific functions from
|
||||
// sanitizer_libc.h.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
#include "sanitizer_libc.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
// --------------------- sanitizer_common.h
|
||||
int GetPid() {
|
||||
return GetProcessId(GetCurrentProcess());
|
||||
}
|
||||
|
||||
uptr GetThreadSelf() {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
||||
uptr *stack_bottom) {
|
||||
CHECK(stack_top);
|
||||
CHECK(stack_bottom);
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
|
||||
// FIXME: is it possible for the stack to not be a single allocation?
|
||||
// Are these values what ASan expects to get (reserved, not committed;
|
||||
// including stack guard page) ?
|
||||
*stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
|
||||
*stack_bottom = (uptr)mbi.AllocationBase;
|
||||
}
|
||||
|
||||
|
||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (rv == 0) {
|
||||
Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s\n",
|
||||
size, size, mem_type);
|
||||
CHECK("unable to mmap" && 0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
void UnmapOrDie(void *addr, uptr size) {
|
||||
if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
|
||||
Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
|
||||
size, size, addr);
|
||||
CHECK("unable to unmap" && 0);
|
||||
}
|
||||
}
|
||||
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
|
||||
return VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
void *Mprotect(uptr fixed_addr, uptr size) {
|
||||
return VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
|
||||
// FIXME: shall we do anything here on Windows?
|
||||
return true;
|
||||
}
|
||||
|
||||
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *GetEnv(const char *name) {
|
||||
static char env_buffer[32767] = {};
|
||||
|
||||
// Note: this implementation stores the result in a static buffer so we only
|
||||
// allow it to be called just once.
|
||||
static bool called_once = false;
|
||||
if (called_once)
|
||||
UNIMPLEMENTED();
|
||||
called_once = true;
|
||||
|
||||
DWORD rv = GetEnvironmentVariableA(name, env_buffer, sizeof(env_buffer));
|
||||
if (rv > 0 && rv < sizeof(env_buffer))
|
||||
return env_buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *GetPwd() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DumpProcessMap() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void DisableCoreDumper() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void ReExec() {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
bool StackSizeIsUnlimited() {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetStackSizeLimitInBytes(uptr limit) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void SleepForSeconds(int seconds) {
|
||||
Sleep(seconds * 1000);
|
||||
}
|
||||
|
||||
void SleepForMillis(int millis) {
|
||||
Sleep(millis);
|
||||
}
|
||||
|
||||
void Exit(int exitcode) {
|
||||
_exit(exitcode);
|
||||
}
|
||||
|
||||
void Abort() {
|
||||
abort();
|
||||
_exit(-1); // abort is not NORETURN on Windows.
|
||||
}
|
||||
|
||||
int Atexit(void (*function)(void)) {
|
||||
return atexit(function);
|
||||
}
|
||||
|
||||
// ------------------ sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_munmap(void *addr, uptr length) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, bool write) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
if (fd != 2)
|
||||
UNIMPLEMENTED();
|
||||
HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (err == 0)
|
||||
return 0; // FIXME: this might not work on some apps.
|
||||
DWORD ret;
|
||||
if (!WriteFile(err, buf, count, &ret, 0))
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
uptr internal_filesize(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // _WIN32
|
Loading…
Reference in New Issue
Block a user