summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Monakov <amonakov@ispras.ru>2016-11-09 16:58:17 +0300
committerAlexander Monakov <amonakov@ispras.ru>2016-11-09 16:58:17 +0300
commit333610c1ceadf0febb112e8f9a3f405d25a0345a (patch)
tree29ee0b1fc30f8a28e916e1c06f982933a73f4f2b
parent16ca0e4e4bc093bfb2c08b167ce1f2116e37758b (diff)
parent421721dfaaddd54b376a5ac48e15ce6c7704bde3 (diff)
downloadgcc-amonakov/gomp-nvptx.tar.gz
Merge remote-tracking branch 'origin/trunk' into gomp-nvptx-branch-merge-trunkamonakov/gomp-nvptx
-rw-r--r--ChangeLog9
-rw-r--r--MAINTAINERS4
-rw-r--r--gcc/ChangeLog1386
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in5
-rw-r--r--gcc/ada/ChangeLog10
-rw-r--r--gcc/ada/adaint.c1
-rw-r--r--gcc/ada/gcc-interface/misc.c1
-rw-r--r--gcc/alias.c17
-rw-r--r--gcc/asan.c315
-rw-r--r--gcc/asan.h69
-rw-r--r--gcc/c-family/ChangeLog38
-rw-r--r--gcc/c-family/c-cppbuiltin.c6
-rw-r--r--gcc/c-family/c-opts.c29
-rw-r--r--gcc/c-family/c-pretty-print.c13
-rw-r--r--gcc/c-family/c-warn.c9
-rw-r--r--gcc/c-family/c.opt13
-rw-r--r--gcc/c/ChangeLog6
-rw-r--r--gcc/c/c-decl.c43
-rw-r--r--gcc/ccmp.c21
-rw-r--r--gcc/cfgexpand.c18
-rw-r--r--gcc/cfgrtl.c8
-rw-r--r--gcc/cfgrtl.h2
-rw-r--r--gcc/combine.c96
-rw-r--r--gcc/common.opt30
-rw-r--r--gcc/compare-elim.c2
-rw-r--r--gcc/config.gcc29
-rw-r--r--gcc/config/aarch64/aarch64-simd.md20
-rw-r--r--gcc/config/aarch64/aarch64.c47
-rw-r--r--gcc/config/aarch64/aarch64.md51
-rw-r--r--gcc/config/aarch64/driver-aarch64.c44
-rw-r--r--gcc/config/aarch64/t-aarch642
-rw-r--r--gcc/config/alpha/alpha-passes.def2
-rw-r--r--gcc/config/alpha/alpha.c117
-rw-r--r--gcc/config/arc/arc.c8
-rw-r--r--gcc/config/arc/arc.h31
-rw-r--r--gcc/config/arc/arc.md35
-rw-r--r--gcc/config/arc/constraints.md3
-rw-r--r--gcc/config/arc/fpu.md6
-rw-r--r--gcc/config/arc/fpx.md26
-rw-r--r--gcc/config/arm/arm-arches.def4
-rw-r--r--gcc/config/arm/arm-c.c3
-rw-r--r--gcc/config/arm/arm-cores.def2
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm-tables.opt6
-rw-r--r--gcc/config/arm/arm-tune.md11
-rw-r--r--gcc/config/arm/arm.c1301
-rw-r--r--gcc/config/arm/arm.h9
-rw-r--r--gcc/config/arm/arm.opt8
-rw-r--r--gcc/config/arm/arm_neon.h28
-rw-r--r--gcc/config/arm/arm_neon_builtins.def4
-rw-r--r--gcc/config/arm/bpabi.h8
-rw-r--r--gcc/config/arm/freebsd.h8
-rw-r--r--gcc/config/arm/linux-eabi.h6
-rw-r--r--gcc/config/arm/linux-elf.h2
-rw-r--r--gcc/config/arm/neon.md11
-rw-r--r--gcc/config/arm/symbian.h6
-rw-r--r--gcc/config/arm/unknown-elf.h4
-rw-r--r--gcc/config/bfin/bfin.c7
-rw-r--r--gcc/config/c6x/c6x.c9
-rw-r--r--gcc/config/frv/frv.c2
-rw-r--r--gcc/config/i386/i386.c128
-rw-r--r--gcc/config/ia64/ia64.c4
-rw-r--r--gcc/config/m32c/m32c.c4
-rw-r--r--gcc/config/m68k/m68k.md26
-rw-r--r--gcc/config/microblaze/linux.h1
-rw-r--r--gcc/config/mips/mips.c61
-rw-r--r--gcc/config/mn10300/mn10300.c2
-rw-r--r--gcc/config/nvptx/nvptx.c2
-rw-r--r--gcc/config/pa/pa.h16
-rw-r--r--gcc/config/pa/pa.md30
-rw-r--r--gcc/config/pa/pa64-hpux.h2
-rw-r--r--gcc/config/rl78/rl78.c18
-rw-r--r--gcc/config/rs6000/rs6000-protos.h5
-rw-r--r--gcc/config/rs6000/rs6000.c196
-rw-r--r--gcc/config/rs6000/rs6000.h36
-rw-r--r--gcc/config/rs6000/rs6000.md14
-rw-r--r--gcc/config/rs6000/vector.md10
-rw-r--r--gcc/config/rs6000/vsx.md145
-rw-r--r--gcc/config/rs6000/xcoff.h14
-rw-r--r--gcc/config/s390/s390.c7
-rw-r--r--gcc/config/sh/sh-mem.cc8
-rw-r--r--gcc/config/sh/sh.md18
-rw-r--r--gcc/config/sparc/sparc.c12
-rw-r--r--gcc/config/sparc/sparc.md28
-rw-r--r--gcc/config/spu/spu.h3
-rw-r--r--gcc/config/vax/vax.h2
-rw-r--r--gcc/config/xtensa/xtensa-protos.h1
-rw-r--r--gcc/config/xtensa/xtensa.c126
-rw-r--r--gcc/config/xtensa/xtensa.h6
-rw-r--r--gcc/config/xtensa/xtensa.md2
-rwxr-xr-xgcc/configure15
-rw-r--r--gcc/configure.ac16
-rw-r--r--gcc/cp/ChangeLog169
-rw-r--r--gcc/cp/call.c282
-rw-r--r--gcc/cp/class.c108
-rw-r--r--gcc/cp/constexpr.c4
-rw-r--r--gcc/cp/cp-objcp-common.c64
-rw-r--r--gcc/cp/cp-objcp-common.h8
-rw-r--r--gcc/cp/cp-tree.h34
-rw-r--r--gcc/cp/cvt.c77
-rw-r--r--gcc/cp/decl.c11
-rw-r--r--gcc/cp/error.c7
-rw-r--r--gcc/cp/init.c12
-rw-r--r--gcc/cp/lambda.c3
-rw-r--r--gcc/cp/mangle.c84
-rw-r--r--gcc/cp/method.c215
-rw-r--r--gcc/cp/name-lookup.c36
-rw-r--r--gcc/cp/optimize.c13
-rw-r--r--gcc/cp/parser.c45
-rw-r--r--gcc/cp/pt.c133
-rw-r--r--gcc/cp/rtti.c8
-rw-r--r--gcc/cp/tree.c51
-rw-r--r--gcc/cp/typeck.c58
-rw-r--r--gcc/cse.c4
-rw-r--r--gcc/dbgcnt.def1
-rw-r--r--gcc/defaults.h4
-rw-r--r--gcc/doc/invoke.texi100
-rw-r--r--gcc/doc/sourcebuild.texi15
-rw-r--r--gcc/doc/tm.texi34
-rw-r--r--gcc/doc/tm.texi.in8
-rw-r--r--gcc/dojump.c1
-rw-r--r--gcc/dse.c17
-rw-r--r--gcc/dwarf2asm.c2
-rw-r--r--gcc/dwarf2cfi.c51
-rw-r--r--gcc/dwarf2out.c2299
-rw-r--r--gcc/dwarf2out.h18
-rw-r--r--gcc/emit-rtl.c17
-rw-r--r--gcc/except.c2
-rw-r--r--gcc/expr.c33
-rw-r--r--gcc/expr.h3
-rw-r--r--gcc/final.c7
-rw-r--r--gcc/fold-const-call.c4
-rw-r--r--gcc/fold-const.c93
-rw-r--r--gcc/fortran/ChangeLog174
-rw-r--r--gcc/fortran/arith.c18
-rw-r--r--gcc/fortran/check.c121
-rw-r--r--gcc/fortran/class.c3
-rw-r--r--gcc/fortran/decl.c10
-rw-r--r--gcc/fortran/error.c20
-rw-r--r--gcc/fortran/expr.c54
-rw-r--r--gcc/fortran/frontend-passes.c6
-rw-r--r--gcc/fortran/gfortran.h2
-rw-r--r--gcc/fortran/gfortran.texi27
-rw-r--r--gcc/fortran/interface.c28
-rw-r--r--gcc/fortran/invoke.texi15
-rw-r--r--gcc/fortran/io.c50
-rw-r--r--gcc/fortran/ioparm.def1
-rw-r--r--gcc/fortran/iresolve.c8
-rw-r--r--gcc/fortran/lang.opt4
-rw-r--r--gcc/fortran/match.c6
-rw-r--r--gcc/fortran/parse.c4
-rw-r--r--gcc/fortran/primary.c58
-rw-r--r--gcc/fortran/resolve.c114
-rw-r--r--gcc/fortran/symbol.c2
-rw-r--r--gcc/fortran/trans-array.c8
-rw-r--r--gcc/fortran/trans-common.c4
-rw-r--r--gcc/fortran/trans-expr.c8
-rw-r--r--gcc/fortran/trans-io.c3
-rw-r--r--gcc/fortran/trans-stmt.c57
-rw-r--r--gcc/fortran/trans-types.c24
-rw-r--r--gcc/fwprop.c2
-rw-r--r--gcc/gimple-pretty-print.c6
-rw-r--r--gcc/gimple-ssa-store-merging.c369
-rw-r--r--gcc/gimple-ssa-strength-reduction.c233
-rw-r--r--gcc/gimple.c3
-rw-r--r--gcc/gimplify.c238
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/escape.cc63
-rw-r--r--gcc/go/gofrontend/expressions.cc700
-rw-r--r--gcc/go/gofrontend/expressions.h86
-rw-r--r--gcc/go/gofrontend/runtime.cc4
-rw-r--r--gcc/go/gofrontend/runtime.def24
-rw-r--r--gcc/incpath.c5
-rw-r--r--gcc/internal-fn.c151
-rw-r--r--gcc/internal-fn.def4
-rw-r--r--gcc/ipa-comdats.c2
-rw-r--r--gcc/ipa-cp.c59
-rw-r--r--gcc/ipa-prop.c94
-rw-r--r--gcc/ipa-prop.h1
-rw-r--r--gcc/ira.c135
-rw-r--r--gcc/jump.c4
-rw-r--r--gcc/langhooks-def.h5
-rw-r--r--gcc/langhooks.c9
-rw-r--r--gcc/langhooks.h6
-rw-r--r--gcc/loop-invariant.c18
-rw-r--r--gcc/lto/ChangeLog6
-rw-r--r--gcc/lto/lto.c4
-rw-r--r--gcc/match.pd12
-rw-r--r--gcc/optabs.c5
-rw-r--r--gcc/opts.c27
-rw-r--r--gcc/params.def6
-rw-r--r--gcc/params.h2
-rw-r--r--gcc/po/ChangeLog12
-rw-r--r--gcc/po/es.po1261
-rw-r--r--gcc/postreload.c4
-rw-r--r--gcc/print-rtl.c48
-rw-r--r--gcc/print-rtl.h1
-rw-r--r--gcc/profile.c14
-rw-r--r--gcc/reg-notes.def5
-rw-r--r--gcc/reload.c48
-rw-r--r--gcc/reload1.c19
-rw-r--r--gcc/reorg.c23
-rw-r--r--gcc/rtl-tests.c15
-rw-r--r--gcc/rtl.h5
-rw-r--r--gcc/rtlanal.c45
-rw-r--r--gcc/sanitizer.def6
-rw-r--r--gcc/sanopt.c3
-rw-r--r--gcc/sel-sched-ir.c12
-rw-r--r--gcc/selftest-rtl.h45
-rw-r--r--gcc/selftest-run-tests.c7
-rw-r--r--gcc/selftest.h1
-rw-r--r--gcc/target.def47
-rw-r--r--gcc/targhooks.c8
-rw-r--r--gcc/targhooks.h2
-rw-r--r--gcc/testsuite/ChangeLog606
-rw-r--r--gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/asan/inc.c3
-rw-r--r--gcc/testsuite/c-c++-common/asan/null-deref-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/builtin-shuffle-1.c22
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-1.C21
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-2.C40
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-3.C22
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-4.C36
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C17
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C17
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C17
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C17
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C17
-rw-r--r--gcc/testsuite/g++.dg/asan/use-after-scope-types.h30
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/addressof3.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor22.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-1.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-2.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-3.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-4.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-5.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr77948-6.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr67980.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C33
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder3.C38
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder4.C40
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder5.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder5.cc12
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder5.h16
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder6.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder6.cc14
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/launder6.h16
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C3
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C22
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/using1.C23
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/constexpr-var-1.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/inline-var-1.C27
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C9
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/ref-2.C4
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/ref-3.C56
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/ref-4.C11
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C17
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C17
-rw-r--r--gcc/testsuite/g++.dg/eh/spec2.C6
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/anon1.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/anon2.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C2
-rw-r--r--gcc/testsuite/g++.dg/init/new15.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/inline-1.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/inline-2.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/pr78188.C20
-rw-r--r--gcc/testsuite/g++.dg/lto/20080908-1_0.C2
-rw-r--r--gcc/testsuite/g++.dg/opt/pr64411.C (renamed from gcc/testsuite/gcc.target/i386/pr64411.C)5
-rw-r--r--gcc/testsuite/g++.dg/opt/pr65105-4.C (renamed from gcc/testsuite/gcc.target/i386/pr65105-4.C)6
-rw-r--r--gcc/testsuite/g++.dg/opt/pr71529.C22
-rw-r--r--gcc/testsuite/g++.dg/pr78229.C24
-rw-r--r--gcc/testsuite/g++.dg/tc1/dr20.C2
-rw-r--r--gcc/testsuite/g++.dg/template/func2.C2
-rw-r--r--gcc/testsuite/g++.dg/torture/pr77822.C30
-rw-r--r--gcc/testsuite/g++.dg/torture/pr77919-2.C10
-rw-r--r--gcc/testsuite/g++.dg/torture/pr78189.C41
-rw-r--r--gcc/testsuite/g++.dg/torture/pr78224.C51
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/inline-1.C2
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/inline-2.C2
-rw-r--r--gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C66
-rw-r--r--gcc/testsuite/g++.dg/warn/Wshadow-compatible-local-1.C63
-rw-r--r--gcc/testsuite/g++.dg/warn/Wshadow-local-1.C35
-rw-r--r--gcc/testsuite/g++.dg/warn/Wshadow-local-2.C63
-rw-r--r--gcc/testsuite/g++.old-deja/g++.eh/spec7.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.law/except1.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/vbase5.C2
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20001226-1.c1
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr78162.c10
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr78170.c39
-rw-r--r--gcc/testsuite/gcc.dg/Wshadow-compatible-local-1.c36
-rw-r--r--gcc/testsuite/gcc.dg/Wshadow-local-1.c22
-rw-r--r--gcc/testsuite/gcc.dg/Wshadow-local-2.c49
-rw-r--r--gcc/testsuite/gcc.dg/Wshadow-local-3.c9
-rw-r--r--gcc/testsuite/gcc.dg/Wtrampolines.c2
-rw-r--r--gcc/testsuite/gcc.dg/addr_equal-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-1.c18
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-2.c47
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-3.c20
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-4.c16
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-5.c27
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-6.c15
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-7.c15
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-9.c20
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c47
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c25
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c25
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c33
-rw-r--r--gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c36
-rw-r--r--gcc/testsuite/gcc.dg/cpp/trad/include.c10
-rw-r--r--gcc/testsuite/gcc.dg/cpp/trad/trad.exp2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/pr71855.c2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/prod-options.c2
-rw-r--r--gcc/testsuite/gcc.dg/divmod-1-simode.c25
-rw-r--r--gcc/testsuite/gcc.dg/divmod-1.c32
-rw-r--r--gcc/testsuite/gcc.dg/divmod-2-simode.c25
-rw-r--r--gcc/testsuite/gcc.dg/divmod-2.c32
-rw-r--r--gcc/testsuite/gcc.dg/divmod-3-simode.c23
-rw-r--r--gcc/testsuite/gcc.dg/divmod-3.c30
-rw-r--r--gcc/testsuite/gcc.dg/divmod-4-simode.c23
-rw-r--r--gcc/testsuite/gcc.dg/divmod-4.c30
-rw-r--r--gcc/testsuite/gcc.dg/divmod-5.c19
-rw-r--r--gcc/testsuite/gcc.dg/divmod-6-simode.c26
-rw-r--r--gcc/testsuite/gcc.dg/divmod-6.c33
-rw-r--r--gcc/testsuite/gcc.dg/divmod-7.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/pr78121.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/vrp7.c32
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr60449_0.c1
-rw-r--r--gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-1.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-2.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr65779.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr70405.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr77834.c18
-rw-r--r--gcc/testsuite/gcc.dg/pr77860.c13
-rw-r--r--gcc/testsuite/gcc.dg/pr78148.c31
-rw-r--r--gcc/testsuite/gcc.dg/pr78185.c28
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_1.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_2.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_4.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_5.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_6.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_7.c2
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_8.c38
-rw-r--r--gcc/testsuite/gcc.dg/torture/fp-int-convert.h3
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr77309.c14
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr78218.c24
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/time-profiler-3.c22
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/phi-opt-15.c12
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr20702.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr21086.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr54245.c48
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr58480.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr71347.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/slsr-8.c16
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp08.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp111.c13
-rw-r--r--gcc/testsuite/gcc.dg/vect/bb-slp-pr78205.c25
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr56541.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-bswap32.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-bswap64.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-cond-2.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-nb-iter-ub-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-14.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-15.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-16.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-17.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-18.c2
-rw-r--r--gcc/testsuite/gcc.dg/visibility-19.c2
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/vmaxnm_f32_1.c159
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/vmaxnmq_f32_1.c160
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/vminnm_f32_1.c159
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/vminnmq_f32_1.c159
-rw-r--r--gcc/testsuite/gcc.target/i386/pr70799-2.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr71529.C22
-rw-r--r--gcc/testsuite/gcc.target/i386/pr78035.c24
-rw-r--r--gcc/testsuite/gcc.target/i386/pr78227-1.c30
-rw-r--r--gcc/testsuite/gcc.target/i386/pr78227-2.c30
-rw-r--r--gcc/testsuite/gcc.target/mips/mips.exp4
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-1.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-2.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-3.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-4.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-5.c16
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-6.c23
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-add-7.c23
-rw-r--r--gcc/testsuite/gcc.target/powerpc/vsx-extract-4.c76
-rw-r--r--gcc/testsuite/gcc.target/powerpc/vsx-extract-5.c77
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-3.c15
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-4.c44
-rw-r--r--gcc/testsuite/gcc.target/sparc/overflow-5.c43
-rw-r--r--gcc/testsuite/gfortran.dg/allocate_with_source_14.f032
-rw-r--r--gcc/testsuite/gfortran.dg/associate_23.f9036
-rw-r--r--gcc/testsuite/gfortran.dg/class_58.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/class_59.f9025
-rw-r--r--gcc/testsuite/gfortran.dg/dec_exp_1.f9035
-rw-r--r--gcc/testsuite/gfortran.dg/dec_exp_2.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/dec_exp_3.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/dec_parameter_1.f64
-rw-r--r--gcc/testsuite/gfortran.dg/dec_parameter_2.f9063
-rw-r--r--gcc/testsuite/gfortran.dg/dec_parameter_3.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/dec_parameter_4.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/elemental_optional_args_6.f901
-rw-r--r--gcc/testsuite/gfortran.dg/fmt_l.f9032
-rw-r--r--gcc/testsuite/gfortran.dg/fmt_l0.f9012
-rw-r--r--gcc/testsuite/gfortran.dg/fmt_t_9.f41
-rw-r--r--gcc/testsuite/gfortran.dg/implicit_class_1.f901
-rw-r--r--gcc/testsuite/gfortran.dg/move_alloc_17.f9021
-rw-r--r--gcc/testsuite/gfortran.dg/move_alloc_18.f9021
-rw-r--r--gcc/testsuite/gfortran.dg/pr67219.f908
-rw-r--r--gcc/testsuite/gfortran.dg/pr70937.f901
-rw-r--r--gcc/testsuite/gfortran.dg/proc_ptr_comp_46.f9029
-rw-r--r--gcc/testsuite/gfortran.dg/select_type_39.f0320
-rw-r--r--gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f9034
-rw-r--r--gcc/testsuite/gfortran.dg/warn_conversion_9.f907
-rw-r--r--gcc/testsuite/gfortran.dg/where_5.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/where_6.f9015
-rw-r--r--gcc/testsuite/lib/scanasm.exp1
-rw-r--r--gcc/testsuite/lib/target-supports.exp398
-rw-r--r--gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm2
-rw-r--r--gcc/tree-call-cdce.c13
-rw-r--r--gcc/tree-inline.c33
-rw-r--r--gcc/tree-profile.c107
-rw-r--r--gcc/tree-ssa-alias.c17
-rw-r--r--gcc/tree-ssa-alias.h2
-rw-r--r--gcc/tree-ssa-loop-im.c13
-rw-r--r--gcc/tree-ssa-math-opts.c221
-rw-r--r--gcc/tree-ssa-phiopt.c8
-rw-r--r--gcc/tree-ssa-reassoc.c2
-rw-r--r--gcc/tree-ssa-structalias.c14
-rw-r--r--gcc/tree-vect-data-refs.c63
-rw-r--r--gcc/tree-vect-loop.c85
-rw-r--r--gcc/tree-vect-slp.c203
-rw-r--r--gcc/tree-vect-stmts.c148
-rw-r--r--gcc/tree-vectorizer.h2
-rw-r--r--gcc/tree-vrp.c122
-rw-r--r--gcc/tree.c29
-rw-r--r--gcc/tree.h9
-rw-r--r--gcc/value-prof.h5
-rw-r--r--include/ChangeLog5
-rw-r--r--include/demangle.h4
-rw-r--r--libcpp/ChangeLog4
-rw-r--r--libcpp/lex.c95
-rw-r--r--libcpp/po/ChangeLog4
-rw-r--r--libcpp/po/eo.po13
-rw-r--r--libgcc/ChangeLog23
-rw-r--r--libgcc/Makefile.in7
-rw-r--r--libgcc/libgcc-std.ver.in6
-rw-r--r--libgcc/libgcc2.c42
-rw-r--r--libgcc/libgcc2.h5
-rw-r--r--libgcc/libgcov-profiler.c23
-rw-r--r--libgfortran/ChangeLog20
-rw-r--r--libgfortran/io/format.c18
-rw-r--r--libgfortran/io/io.h1
-rw-r--r--libgfortran/io/list_read.c22
-rw-r--r--libgfortran/io/read.c8
-rw-r--r--libgfortran/io/transfer.c3
-rw-r--r--libgo/Makefile.am2301
-rw-r--r--libgo/Makefile.in2413
-rwxr-xr-xlibgo/configure2
-rw-r--r--libgo/configure.ac2
-rw-r--r--libgo/go/runtime/lfstack_32bit.go2
-rw-r--r--libgo/go/runtime/slice.go212
-rw-r--r--libgo/go/runtime/string.go17
-rw-r--r--libgo/go/runtime/stubs.go25
-rw-r--r--libgo/go/time/time_test.go7
-rwxr-xr-xlibgo/mkrsysinfo.sh2
-rwxr-xr-xlibgo/mksysinfo.sh4
-rw-r--r--libgo/runtime/go-append.c74
-rw-r--r--libgo/runtime/go-copy.c22
-rw-r--r--libgo/runtime/go-make-slice.c99
-rw-r--r--libgo/runtime/malloc.goc8
-rw-r--r--libgo/runtime/runtime.h3
-rw-r--r--libgo/runtime/runtime_c.c (renamed from libgo/runtime/runtime.c)0
-rw-r--r--libgomp/ChangeLog13
-rw-r--r--libgomp/hashtab.h34
-rw-r--r--libgomp/plugin/plugin-nvptx.c88
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c2
-rw-r--r--libiberty/ChangeLog30
-rw-r--r--libiberty/cp-demangle.c193
-rw-r--r--libiberty/cplus-dem.c8
-rw-r--r--libiberty/hashtab.c20
-rw-r--r--libiberty/regex.c8
-rw-r--r--libiberty/testsuite/demangle-expected14
-rw-r--r--libsanitizer/ChangeLog54
-rw-r--r--libsanitizer/MERGE2
-rw-r--r--libsanitizer/Makefile.in1
-rw-r--r--libsanitizer/asan/Makefile.am3
-rw-r--r--libsanitizer/asan/Makefile.in14
-rw-r--r--libsanitizer/asan/asan_activation.cc8
-rw-r--r--libsanitizer/asan/asan_allocator.cc106
-rw-r--r--libsanitizer/asan/asan_allocator.h43
-rw-r--r--libsanitizer/asan/asan_debugging.cc125
-rw-r--r--libsanitizer/asan/asan_descriptions.cc484
-rw-r--r--libsanitizer/asan/asan_descriptions.h251
-rw-r--r--libsanitizer/asan/asan_errors.cc494
-rw-r--r--libsanitizer/asan/asan_errors.h376
-rw-r--r--libsanitizer/asan/asan_fake_stack.cc6
-rw-r--r--libsanitizer/asan/asan_fake_stack.h21
-rw-r--r--libsanitizer/asan/asan_flags.cc18
-rw-r--r--libsanitizer/asan/asan_flags.inc21
-rw-r--r--libsanitizer/asan/asan_globals.cc147
-rw-r--r--libsanitizer/asan/asan_init_version.h14
-rw-r--r--libsanitizer/asan/asan_interceptors.cc106
-rw-r--r--libsanitizer/asan/asan_interceptors.h14
-rw-r--r--libsanitizer/asan/asan_interface_internal.h28
-rw-r--r--libsanitizer/asan/asan_internal.h38
-rw-r--r--libsanitizer/asan/asan_linux.cc13
-rw-r--r--libsanitizer/asan/asan_mac.cc218
-rw-r--r--libsanitizer/asan/asan_malloc_linux.cc10
-rw-r--r--libsanitizer/asan/asan_malloc_mac.cc4
-rw-r--r--libsanitizer/asan/asan_malloc_win.cc139
-rw-r--r--libsanitizer/asan/asan_mapping.h77
-rw-r--r--libsanitizer/asan/asan_memory_profile.cc98
-rw-r--r--libsanitizer/asan/asan_new_delete.cc20
-rw-r--r--libsanitizer/asan/asan_poisoning.cc44
-rw-r--r--libsanitizer/asan/asan_poisoning.h2
-rw-r--r--libsanitizer/asan/asan_posix.cc30
-rw-r--r--libsanitizer/asan/asan_report.cc989
-rw-r--r--libsanitizer/asan/asan_report.h26
-rw-r--r--libsanitizer/asan/asan_rtl.cc89
-rw-r--r--libsanitizer/asan/asan_scariness_score.h72
-rw-r--r--libsanitizer/asan/asan_stack.h5
-rw-r--r--libsanitizer/asan/asan_suppressions.cc1
-rw-r--r--libsanitizer/asan/asan_thread.cc123
-rw-r--r--libsanitizer/asan/asan_thread.h41
-rw-r--r--libsanitizer/asan/asan_win.cc206
-rw-r--r--libsanitizer/asan/asan_win_dll_thunk.cc44
-rw-r--r--libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc23
-rw-r--r--libsanitizer/asan/libtool-version2
-rw-r--r--libsanitizer/builtins/assembly.h169
-rwxr-xr-xlibsanitizer/configure6
-rw-r--r--libsanitizer/configure.ac1
-rw-r--r--libsanitizer/configure.tgt2
-rw-r--r--libsanitizer/include/sanitizer/allocator_interface.h17
-rw-r--r--libsanitizer/include/sanitizer/common_interface_defs.h58
-rw-r--r--libsanitizer/include/sanitizer/coverage_interface.h1
-rw-r--r--libsanitizer/include/sanitizer/esan_interface.h48
-rw-r--r--libsanitizer/include/sanitizer/linux_syscall_hooks.h23
-rw-r--r--libsanitizer/interception/Makefile.in1
-rw-r--r--libsanitizer/interception/interception.h6
-rw-r--r--libsanitizer/interception/interception_win.cc995
-rw-r--r--libsanitizer/interception/interception_win.h30
-rw-r--r--libsanitizer/libbacktrace/Makefile.in1
-rw-r--r--libsanitizer/lsan/Makefile.in1
-rw-r--r--libsanitizer/lsan/lsan.cc2
-rw-r--r--libsanitizer/lsan/lsan.h7
-rw-r--r--libsanitizer/lsan/lsan_allocator.cc17
-rw-r--r--libsanitizer/lsan/lsan_common.cc57
-rw-r--r--libsanitizer/lsan/lsan_common.h15
-rw-r--r--libsanitizer/lsan/lsan_common_linux.cc49
-rw-r--r--libsanitizer/lsan/lsan_flags.inc4
-rw-r--r--libsanitizer/lsan/lsan_interceptors.cc25
-rw-r--r--libsanitizer/lsan/lsan_thread.cc27
-rw-r--r--libsanitizer/lsan/lsan_thread.h7
-rwxr-xr-xlibsanitizer/merge.sh4
-rw-r--r--libsanitizer/sanitizer_common/Makefile.am5
-rw-r--r--libsanitizer/sanitizer_common/Makefile.in62
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.cc107
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.h1428
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_bytemap.h100
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_combined.h209
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_interface.h8
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_internal.h11
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h246
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h302
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h503
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h271
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h215
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_stats.h103
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_asm.h14
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h13
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.cc209
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.h215
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc966
-rwxr-xr-xlibsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc38
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc55
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc58
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc161
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc23
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cc9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_deadlock_detector_interface.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.cc56
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.h7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.inc49
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_interface_internal.h4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_internal_defs.h53
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.cc32
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.h14
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.cc283
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.h8
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc120
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_mips64.S21
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_s390.cc189
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S23
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_list.h32
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.cc406
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.h18
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc26
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform.h111
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h55
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc31
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h59
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix.cc63
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix.h9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc107
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_printf.cc9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps.h5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc22
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc26
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_quarantine.h6
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.cc15
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.h7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc44
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc29
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc34
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_suppressions.cc2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_suppressions.h3
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.cc3
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.h14
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc48
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc37
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc107
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc8
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_termination.cc84
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_thread_registry.cc4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc10
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win.cc272
-rw-r--r--libsanitizer/tsan/Makefile.am9
-rw-r--r--libsanitizer/tsan/Makefile.in78
-rw-r--r--libsanitizer/tsan/tsan_clock.cc2
-rw-r--r--libsanitizer/tsan/tsan_debugging.cc160
-rw-r--r--libsanitizer/tsan/tsan_defs.h22
-rw-r--r--libsanitizer/tsan/tsan_dense_alloc.h2
-rw-r--r--libsanitizer/tsan/tsan_flags.cc9
-rw-r--r--libsanitizer/tsan/tsan_flags.inc7
-rw-r--r--libsanitizer/tsan/tsan_interceptors.cc696
-rw-r--r--libsanitizer/tsan/tsan_interceptors.h16
-rw-r--r--libsanitizer/tsan/tsan_interceptors_mac.cc357
-rw-r--r--libsanitizer/tsan/tsan_interface.h291
-rw-r--r--libsanitizer/tsan/tsan_interface_atomic.cc43
-rw-r--r--libsanitizer/tsan/tsan_interface_java.cc2
-rw-r--r--libsanitizer/tsan/tsan_libdispatch_mac.cc613
-rw-r--r--libsanitizer/tsan/tsan_malloc_mac.cc43
-rw-r--r--libsanitizer/tsan/tsan_mman.cc118
-rw-r--r--libsanitizer/tsan/tsan_mman.h5
-rw-r--r--libsanitizer/tsan/tsan_mutex.cc1
-rw-r--r--libsanitizer/tsan/tsan_mutex.h1
-rw-r--r--libsanitizer/tsan/tsan_mutexset.h4
-rw-r--r--libsanitizer/tsan/tsan_new_delete.cc8
-rw-r--r--libsanitizer/tsan/tsan_platform.h860
-rw-r--r--libsanitizer/tsan/tsan_platform_linux.cc179
-rw-r--r--libsanitizer/tsan/tsan_platform_mac.cc49
-rw-r--r--libsanitizer/tsan/tsan_platform_posix.cc73
-rw-r--r--libsanitizer/tsan/tsan_platform_windows.cc3
-rw-r--r--libsanitizer/tsan/tsan_ppc_regs.h94
-rw-r--r--libsanitizer/tsan/tsan_preinit.cc25
-rw-r--r--libsanitizer/tsan/tsan_report.cc52
-rw-r--r--libsanitizer/tsan/tsan_report.h3
-rw-r--r--libsanitizer/tsan/tsan_rtl.cc114
-rw-r--r--libsanitizer/tsan/tsan_rtl.h90
-rw-r--r--libsanitizer/tsan/tsan_rtl_aarch64.S2
-rw-r--r--libsanitizer/tsan/tsan_rtl_amd64.S101
-rw-r--r--libsanitizer/tsan/tsan_rtl_mips64.S212
-rw-r--r--libsanitizer/tsan/tsan_rtl_mutex.cc67
-rw-r--r--libsanitizer/tsan/tsan_rtl_ppc64.S286
-rw-r--r--libsanitizer/tsan/tsan_rtl_proc.cc59
-rw-r--r--libsanitizer/tsan/tsan_rtl_report.cc71
-rw-r--r--libsanitizer/tsan/tsan_rtl_thread.cc46
-rw-r--r--libsanitizer/tsan/tsan_stat.cc1
-rw-r--r--libsanitizer/tsan/tsan_stat.h1
-rw-r--r--libsanitizer/tsan/tsan_suppressions.cc15
-rw-r--r--libsanitizer/tsan/tsan_symbolize.cc10
-rw-r--r--libsanitizer/tsan/tsan_sync.cc69
-rw-r--r--libsanitizer/tsan/tsan_sync.h20
-rw-r--r--libsanitizer/tsan/tsan_trace.h4
-rw-r--r--libsanitizer/ubsan/Makefile.in1
-rw-r--r--libsanitizer/ubsan/ubsan_checks.inc56
-rw-r--r--libsanitizer/ubsan/ubsan_diag.cc229
-rw-r--r--libsanitizer/ubsan/ubsan_diag.h21
-rw-r--r--libsanitizer/ubsan/ubsan_flags.cc2
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.cc254
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.h19
-rw-r--r--libsanitizer/ubsan/ubsan_handlers_cxx.cc105
-rw-r--r--libsanitizer/ubsan/ubsan_handlers_cxx.h14
-rw-r--r--libsanitizer/ubsan/ubsan_init.cc1
-rw-r--r--libsanitizer/ubsan/ubsan_platform.h3
-rw-r--r--libsanitizer/ubsan/ubsan_type_hash.h4
-rw-r--r--libsanitizer/ubsan/ubsan_type_hash_itanium.cc22
-rw-r--r--libsanitizer/ubsan/ubsan_value.cc4
-rw-r--r--libstdc++-v3/ChangeLog35
-rw-r--r--libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver12
-rw-r--r--libstdc++-v3/include/bits/c++config8
-rw-r--r--libstdc++-v3/include/experimental/bits/fs_path.h62
-rw-r--r--libstdc++-v3/include/std/type_traits96
-rw-r--r--libstdc++-v3/libsupc++/cxxabi.h3
-rw-r--r--libstdc++-v3/libsupc++/new8
-rw-r--r--libstdc++-v3/libsupc++/pbase_type_info.cc13
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc47
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc56
-rw-r--r--libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc2
745 files changed, 32091 insertions, 14799 deletions
diff --git a/ChangeLog b/ChangeLog
index 2d43ee55e57..69997546d4b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-11-01 Josh Conner <joshconner@google.com>
+
+ * MAINTAINERS (Write After Approval): Update email address,
+
+2016-10-27 Carl Love <cel@us.ibm.com>
+
+ * MAINTAINERS (Write After Approval): Fix my entry in the Write After
+ Approval list to make it alphabetical.
+
2016-10-27 Carl Love <cel@us.ibm.com>
* MAINTAINERS (Write After Approval): Add myself.
diff --git a/MAINTAINERS b/MAINTAINERS
index f3fa0ecec9e..343c44b5f23 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -350,7 +350,7 @@ Tamar Christina <tamar.christina@arm.com>
Eric Christopher <echristo@gmail.com>
William Cohen <wcohen@redhat.com>
Michael Collison <michael.collison@arm.com>
-Josh Conner <jconner@apple.com>
+Josh Conner <joshconner@google.com>
R. Kelley Cook <kcook@gcc.gnu.org>
Christian Cornelssen <ccorn@cs.tu-berlin.de>
Ludovic Courtès <ludo@gnu.org>
@@ -477,9 +477,9 @@ Ralph Loader <rcl@ihug.co.nz>
Gabor Loki <loki@inf.u-szeged.hu>
Sandra Loosemore <sandra@codesourcery.com>
Manuel López-Ibáñez <manu@gcc.gnu.org>
+Carl Love <cel@us.ibm.com>
Martin v. Löwis <loewis@informatik.hu-berlin.de>
H.J. Lu <hjl.tools@gmail.com>
-Carl Love <cel@us.ibm.com>
Christophe Lyon <christophe.lyon@st.com>
Luis Machado <luisgpm@br.ibm.com>
Ziga Mahkovec <ziga.mahkovec@klika.si>
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3f2ea4dfc71..cfdf5a5569f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,1373 @@
+2016-11-09 Richard Biener <rguenther@suse.de>
+
+ * common.opt (flag_evaluation_order): Remove.
+ * expr.c (expand_operands): Remove code guarded by
+ flag_evaluation_order.
+ * fold-const.c (reorder_operands_p): Remove, it always returns
+ true.
+ (negate_expr_p): Remove calls to reorder_operands_p.
+ (fold_negate_expr): Likewise.
+ (tree_swap_operands_p): Likewise.
+ (fold_binary_loc): Likewise.
+
+2016-11-09 Andreas Schwab <schwab@suse.de>
+
+ PR target/78254
+ * config/m68k/m68k.md: Reject out-of-range bit pos in bit-fields
+ insns operating on a register.
+
+2016-11-09 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78007
+ * tree-vect-stmts.c (vectorizable_bswap): New function.
+ (vectorizable_call): Call vectorizable_bswap for
+ BUILT_IN_BSWAP{16,32,64} if arguments are not promoted.
+
+2016-11-09 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-data-refs.c (vect_compute_data_ref_alignment):
+ Look at the DR_BASE_ADDRESS object for forcing alignment.
+
+2016-11-09 Kugan Vivekanandarajah <kuganv@linaro.org>
+
+ * ipa-cp.c (ipa_get_jf_pass_through_result): Handle unary expressions.
+ (propagate_vr_accross_jump_function): Likewise.
+ * ipa-prop.c (ipa_set_jf_unary_pass_through): New.
+ (load_from_param_1): New.
+ (load_from_unmodified_param): Factor common part into load_from_param_1.
+ (load_from_param): New.
+ (compute_complex_assign_jump_func): Handle unary expressions.
+ (ipa_write_jump_function): Likewise.
+ (ipa_read_jump_function): Likewise.
+
+2016-11-09 Kugan Vivekanandarajah <kuganv@linaro.org>
+
+ PR ipa/78121
+ * ipa-cp.c (propagate_vr_accross_jump_function): Pass param type.
+ Also fold constant passed as argument while computing value range.
+ (propagate_constants_accross_call): Pass param type.
+ * ipa-prop.c: export ipa_get_callee_param_type.
+ * ipa-prop.h: export ipa_get_callee_param_type.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * asan.h (asan_intercepted_p): Handle BUILT_IN_STRCSPN,
+ BUILT_IN_STRPBRK, BUILT_IN_STRSPN and BUILT_IN_STRSTR.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * asan.h (ASAN_STACK_MAGIC_PARTIAL): Remove.
+ * asan.c (ASAN_STACK_MAGIC_PARTIAL): Replace with
+ ASAN_STACK_MAGIC_MIDDLE.
+ (asan_global_struct): Increase the size of fields.
+ (asan_add_global): Add new field constructor.
+ * sanitizer.def (__asan_version_mismatch_check_v6): Replace with
+ __asan_version_mismatch_check_v8.
+
+ 2016-11-08 David Edelsohn <dje.gcc@gmail.com>
+
+ * dwarf2asm.c (USE_LINKONCE_INDIRECT): Test XCOFF_DEBUGGING_INFO
+ at runtime.
+
+2016-11-08 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/70799
+ * config/i386/i386.c (dimode_scalar_to_vector_candidate_p):
+ Handle ASHIFT and LSHIFTRT.
+ (dimode_scalar_chain::compute_convert_gain): Ditto.
+ (dimode_scalar_chain::convert_insn): Ditto.
+
+2016-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gimple-ssa-store-merging.c: Include selftest.h
+ (verify_array_eq): New function.
+ (verify_shift_bytes_in_array): Likewise.
+ (verify_shift_bytes_in_array_right): Likewise.
+ (verify_clear_bit_region): Likewise.
+ (verify_clear_bit_region_be): Likewise.
+ (store_merging_c_tests): Likewise.
+ * selftest.h (store_merging_c_tests): Declare prototype.
+ * selftest-run-tests.c (selftest::run_tests): Run
+ store_merging_c_tests.
+
+2016-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * config/arm/arm.opt (mold-rtx-costs): Delete.
+ (mnew-generic-costs): Delete.
+ * config/arm/arm-protos.h (struct tune_params): Delete rtx_costs field.
+ * config/arm/arm.c (arm_rtx_costs_1): Delete.
+ (arm_size_rtx_costs): Likewise.
+ (arm_slowmul_rtx_costs): Likewise.
+ (arm_fastmul_rtx_costs): Likewise.
+ (arm_xscale_rtx_costs): Likewise.
+ (arm_9e_rtx_costs): Likewise.
+ (arm_slowmul_tune, arm_fastmul_tune, arm_strongarm_tune,
+ arm_xscale_tune, arm_9e_tune, arm_v6t2_tune, arm_cortex_tune,
+ arm_cortex_a8_tune, arm_cortex_a7_tune, arm_cortex_a15_tune,
+ arm_cortex_a53_tune, arm_cortex_a57_tune, arm_cortex_a9_tune,
+ arm_cortex_a12_tune, arm_v7m_tune, arm_v6m_tune, arm_fa726te_tune
+ arm_cortex_a5_tune, arm_xgene1_tune, arm_marvell_pj4_tune,
+ arm_cortex_a35_tune, arm_exynosm1_tune, arm_cortex_a73_tune,
+ arm_cortex_m7_tune):
+ Delete rtx_costs field.
+ (arm_new_rtx_costs): Rename to...
+ (arm_rtx_costs_internal): ... This.
+ (arm_rtx_costs): Remove old way of doing rtx costs.
+
+2016-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * config/arm/arm.c (arm_slowmul_tune): Use generic_extra_costs.
+ (arm_fastmul_tune): Likewise.
+ (arm_strongarm_tune): Likewise.
+ (arm_xscale_tune): Likewise.
+ (arm_9e_tune): Likewise.
+ (arm_marvell_pj4_tune): Likewise.
+ (arm_v6t2_tune): Likewise.
+ (arm_v6m_tune): Likewise.
+ (arm_fa726te_tune): Likewise.
+
+2016-11-08 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR tree-optimization/78234
+ * gimple-ssa-store-merging.c (clear_bit_region): Fix off-by-one error
+ in start != 0 case.
+
+2016-11-08 Martin Liska <mliska@suse.cz>
+
+ PR testsuite/78242
+ * dbgcnt.def: Add new debug counter asan_use_after_scope.
+ * gimplify.c (gimplify_decl_expr): Do not sanitize vars
+ with a value expr. Do not add artificial variables to
+ live_switch_vars. Use the debug counter.
+ (gimplify_target_expr): Use the debug counter.
+ * internal-fn.def: Remove ECF_TM_PURE from ASAN_MARK builtin.
+ * sanitizer.def: Set ATTR_NOTHROW_LEAF_LIST to
+ BUILT_IN_ASAN_CLOBBER_N and BUILT_IN_ASAN_UNCLOBBER_N.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.c (get_group_load_store_type): If the
+ access is aligned do not trigger peeling for gaps.
+ * tree-vect-data-refs.c (vect_compute_data_ref_alignment): Do not
+ force alignment of vars with DECL_USER_ALIGN.
+
+2016-11-08 James Greenhalgh <james.greenhalgh@arm.com>
+
+ * config/aarch64/t-aarch64 (aarch64-c.o): Depend on TARGET_H.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78205
+ * tree-vect-stmts.c (vectorizable_load): Move check whether
+ we may run into gaps when BB vectorizing SLP permutations ...
+ * tree-vect-slp.c (vect_supported_load_permutation_p): ...
+ here where we can do a more precise check.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78224
+ * tree-call-cdce.c (shrink_wrap_one_built_in_call_with_conds):
+ Split the fallthru edge in case its successor may have PHIs.
+ Do not free dominance info.
+
+2016-11-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/78229
+ * config/i386/i386.c (ix86_gimple_fold_builtin): Do not adjust
+ EH info even for bzhi and pdep/pext.
+
+2016-11-07 Peter Bergner <bergner@vnet.ibm.com>
+
+ * config.gcc (powerpc*-*-*, rs6000*-*-*): Remove setting of
+ INCLUDE_EXTRA_SPEC for Advance Toolchain builds.
+
+2016-11-07 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.md (div<mode>3): Expand using rs6000_emit_swdiv
+ if appropriate.
+ * config/rs6000/vector.md (div<mode>3): Ditto.
+
+2016-11-07 David Edelsohn <dje.gcc@gmail.com>
+
+ * configure.ac (.hidden): Change to conftest_s string. Provide string
+ for AIX assembler.
+ (gcc_cv_ld_hidden): Yes for AIX.
+ * configure: Regenerate.
+
+ * dwarf2asm.c (USE_LINKONCE_INDIRECT): Don't set for AIX (XCOFF).
+
+ * config/rs6000/rs6000-protos.h (rs6000_asm_weaken_decl): Declare
+ (rs6000_xcoff_asm_output_aligned_decl_common): Declare.
+ * config/rs6000/xcoff.h (TARGET_ASM_GLOBALIZE_DECL_NAME): Define.
+ (ASM_OUTPUT_ALIGNED_DECL_COMMON): Define.
+ (ASM_OUTPUT_ALIGNED_COMMON): Delete.
+ * config/rs6000/rs6000.c (rs6000_init_builtins): Change clog rename
+ from #if to if.
+ (rs6000_xcoff_visibility): New.
+ (rs6000_xcoff_declare_function_name): Add visibility support.
+ (rs6000_xcoff_asm_globalize_decl_name): New.
+ (rs6000_xcoff_asm_output_aligned_decl_common): New.
+ (rs6000_asm_weaken_decl): New.
+ (rs6000_code_end): Disable HIDDEN_LINKONCE on XCOFF.
+ config/rs6000/rs6000.h (ASM_WEAKEN_DECL): Change definition to
+ reference function.
+
+2016-11-07 Jack Howarth <howarth.at.gcc@gmail.com>
+
+ PR driver/78206
+ * incpath.c: (remove_dup(): Also silently ignore EPERM.
+
+2016-11-07 Martin Jambor <mjambor@suse.cz>
+
+ * tree.c (verify_type_variant): Use pointer comparison to check that
+ TYPE_SIZE_UNIT match.
+
+2016-11-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/77834
+ * dse.c (dse_step5): Call scan_reads even if just
+ insn_info->frame_read. Improve and fix dump file messages.
+
+ PR target/78227
+ * config/i386/i386.c (ix86_expand_sse_cmp): Force dest into
+ cmp_mode argument even for -O0 if cmp_mode != mode and maskcmp.
+
+2016-11-07 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ PR middle-end/35691
+ * match.pd: Add following two patterns:
+ (x == 0 & y == 0) -> (x | typeof(x)(y)) == 0.
+ (x != 0 | y != 0) -> (x | typeof(x)(y)) != 0.
+
+2016-11-07 Bernd Schmidt <bschmidt@redhat.com>
+
+ * emit-rtl.c (emit_copy_of_insn_after): Duplicate notes in order.
+ * sel-sched-ir.c (create_copy_of_insn_rtx): Likewise.
+ * rtl.h (duplicate_reg_notes): Declare.
+ * rtlanal.c (duplicate_reg_note): New function.
+
+ PR rtl-optimization/77309
+ * combine.c (make_compound_operation): Allow EQ for IN_CODE, and
+ don't assume an equality comparison for plain COMPARE.
+ (simplify_comparison): Pass a more accurate code to
+ make_compound_operation.
+
+2016-11-07 Pat Haugen <pthaugen@us.ibm.com>
+
+ * target.def (compute_pressure_classes): New target hook.
+ * doc/tm.texi.in: Document it.
+ * doc/tm.texi: Regenerate.
+ * ira.c (setup_pressure_classes): Call target hook if defined.
+
+2016-11-07 David Malcolm <dmalcolm@redhat.com>
+
+ * print-rtl.c (rtx_writer::operand_has_default_value_p): New
+ method.
+ (rtx_writer::print_rtx): In compact mode, omit trailing operands
+ that have the default values.
+ * print-rtl.h (rtx_writer::operand_has_default_value_p): New
+ method.
+ * rtl-tests.c (selftest::test_dumping_insns): Remove empty
+ label string from expected dump.
+ (seltest::test_uncond_jump): Remove trailing "(nil)" for REG_NOTES
+ from expected dump.
+
+2016-11-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/77834
+ * alias.c (nonoverlapping_memrefs_p): If one decl is
+ FUNCTION_DECL or LABEL_DECL and the other is not, return 1.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR target/78229
+ * config/i386/i386.c (ix86_gimple_fold_builtin): Do not adjust
+ EH info.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78218
+ * gimple-ssa-store-merging.c
+ (pass_store_merging::terminate_all_aliasing_chains):
+ Drop unused argument, fix alias check to also consider uses.
+ (pass_store_merging::execute): Adjust.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78228
+ * tree-ssa-phiopt.c (abs_replacement): Avoid introducing
+ undefined behavior.
+
+2016-11-07 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR target/77822
+ * config/aarch64/aarch64.md (*tb<optab><mode>1): Use
+ aarch64_simd_shift_imm_<mode> predicate for operand 1.
+ (<optab>, ANY_EXTRACT): Use tighter predicates on operands 2 and 3
+ to restrict them to an appropriate range and add FAIL check if the
+ region they specify is out of range. Delete useless constraint
+ strings.
+ (*<optab><mode>, ANY_EXTRACT): Add appropriate predicates on operands
+ 2 and 3 to restrict their range and add pattern predicate.
+
+2016-11-07 Martin Liska <mliska@suse.cz>
+
+ * asan.c (enum asan_check_flags): Move the enum to header file.
+ (asan_init_shadow_ptr_types): Make type creation more generic.
+ (shadow_mem_size): New function.
+ (asan_emit_stack_protection): Use newly added ASAN_SHADOW_GRANULARITY.
+ Rewritten stack unpoisoning code.
+ (build_shadow_mem_access): Add new argument return_address.
+ (instrument_derefs): Instrument local variables if use after scope
+ sanitization is enabled.
+ (asan_store_shadow_bytes): New function.
+ (asan_expand_mark_ifn): Likewise.
+ (asan_sanitize_stack_p): Moved from asan_sanitize_stack_p.
+ * asan.h (enum asan_mark_flags): Moved here from asan.c
+ (asan_protect_stack_decl): Protect all declaration that need
+ to live in memory.
+ (asan_sanitize_use_after_scope): New function.
+ (asan_no_sanitize_address_p): Likewise.
+ * cfgexpand.c (partition_stack_vars): Consider
+ asan_sanitize_use_after_scope in condition.
+ (expand_stack_vars): Likewise.
+ * common.opt (-fsanitize-address-use-after-scope): New option.
+ * doc/invoke.texi (use-after-scope-direct-emission-threshold):
+ Explain the parameter.
+ * flag-types.h (enum sanitize_code): Define SANITIZE_USE_AFTER_SCOPE.
+ * gimplify.c (build_asan_poison_call_expr): New function.
+ (asan_poison_variable): Likewise.
+ (gimplify_bind_expr): Generate poisoning/unpoisoning for local
+ variables that have address taken.
+ (gimplify_decl_expr): Likewise.
+ (gimplify_target_expr): Likewise for C++ temporaries.
+ (sort_by_decl_uid): New function.
+ (gimplify_expr): Unpoison all variables for a label we can jump
+ from outside of a scope.
+ (gimplify_switch_expr): Unpoison variables defined in the switch
+ context.
+ (gimplify_function_tree): Clear asan_poisoned_variables.
+ (asan_poison_variables): New function.
+ (warn_switch_unreachable_r): Handle IFN_ASAN_MARK.
+ * internal-fn.c (expand_ASAN_MARK): New function.
+ * internal-fn.def (ASAN_MARK): Declare.
+ * opts.c (finish_options): Handle -fstack-reuse if
+ -fsanitize-address-use-after-scope is enabled.
+ (common_handle_option): Enable address sanitization if
+ -fsanitize-address-use-after-scope is enabled.
+ * params.def (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD):
+ New parameter.
+ * params.h: Likewise.
+ * sancov.c (pass_sanopt::execute): Handle IFN_ASAN_MARK.
+ * sanitizer.def: Define __asan_poison_stack_memory and
+ __asan_unpoison_stack_memory functions.
+ * asan.c (asan_mark_poison_p): New function.
+ (transform_statements): Handle asan_mark_poison_p calls.
+ * gimple.c (nonfreeing_call_p): Handle IFN_ASAN_MARK.
+
+2016-11-07 Tamar Christina <tamar.christina@arm.com>
+
+ PR driver/78196
+ * Makefile.in (SELFTEST_FLAGS): Added -o /dev/null.
+
+2016-11-07 Martin Liska <mliska@suse.cz>
+
+ * tree-profile.c (gimple_gen_time_profiler): Set proper type
+ to time_profiler_counter_ptr.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/37150
+ * tree-vectorizer.h (vect_transform_slp_perm_load): Add n_perms
+ parameter.
+ * tree-vect-slp.c (vect_supported_load_permutation_p): Adjust.
+ (vect_analyze_slp_cost_1): Account for the real number of
+ permutations emitted and for dead loads.
+ (vect_transform_slp_perm_load): Add n_perms parameter counting
+ the number of emitted permutations.
+ * tree-vect-stmts.c (vectorizable_load): Adjust.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78189
+ * tree-vect-data-refs.c (vect_compute_data_ref_alignment): Fix
+ alignment computation.
+
+2016-11-06 Kugan Vivekanandarajah <kuganv@linaro.org>
+
+ * ipa-cp.c (ipcp_bits_lattice::meet_with): Remove unreachable code.
+
+2016-11-05 Martin Sebor <msebor@redhat.com>
+
+ * doc/invoke.texi (Warning Options): Correct typos in -Walloca
+ documentation.
+
+2016-11-05 David Edelsohn <dje.gcc@gmail.com>
+
+ PR bootstrap/78188
+ PR c++/71848
+ * ipa-comdats.c (pass_ipa_comdats::gate): Require HAVE_COMDAT_GROUP.
+
+2016-11-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/77834
+ * alias.c (nonoverlapping_memrefs_p): Return 0 if exprx or expry
+ doesn't have rtl set.
+
+2016-11-04 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000.c (gimple-ssa.h): New #include.
+ (TARGET_GIMPLE_FOLD_BUILTIN): Define as
+ rs6000_gimple_fold_builtin.
+ (rs6000_gimple_fold_builtin): New function. Add handling for
+ early expansion of vector addition builtins.
+
+2016-11-04 Eric Botcazou <ebotcazou@adacore.com>
+
+ * expr.h (copy_blkmode_from_reg): Delete.
+ * expr.c (copy_blkmode_from_reg): Make static.
+
+2016-11-04 Eric Botcazou <ebotcazou@adacore.com>
+
+ * defaults.h (LOAD_EXTEND_OP): Define if not already defined.
+ * combine.c (LOAD_EXTEND_OP): Delete.
+ (simplify_comparison): Fix comment about LOAD_EXTEND_OP.
+ * cse.c (LOAD_EXTEND_OP): Delete.
+ * fold-const.c (LOAD_EXTEND_OP): Likewise.
+ * fwprop.c (free_load_extend): Remove #ifdef LOAD_EXTEND_OP/#endif.
+ * postreload.c (LOAD_EXTEND_OP): Delete.
+ * reload.c (push_reload): Remove #ifdef LOAD_EXTEND_OP/#endif.
+ Convert conditional compilation based on WORD_REGISTER_OPERATIONS.
+ (find_reloads): Likewise.
+ * reload1.c (eliminate_regs_1): Likewise.
+ * rtlanal.c (nonzero_bits1): Remove #ifdef LOAD_EXTEND_OP/#endif.
+ (num_sign_bit_copies1): Likewise.
+
+2016-11-04 David Malcolm <dmalcolm@redhat.com>
+
+ * config/i386/i386.c: Include "selftest.h" and "selftest-rtl.h".
+ (selftest::ix86_test_dumping_hard_regs): New function.
+ (selftest::ix86_run_selftests): New function.
+ (TARGET_RUN_TARGET_SELFTESTS): When CHECKING_P, wire this up to
+ selftest::ix86_run_selftests.
+ * doc/tm.texi.in (TARGET_RUN_TARGET_SELFTESTS): New.
+ * doc/tm.texi: Regenerate
+ * selftest-rtl.h: New file.
+ * rtl-tests.c: Include "selftest-rtl.h".
+ (selftest::assert_rtl_dump_eq): Make non-static.
+ (ASSERT_RTL_DUMP_EQ): Move to selftest-rtl.h.
+ (selftest::test_dumping_regs): Update comment.
+ * selftest-run-tests.c: Include "target.h".
+ (selftest::run_tests): If non-NULL, call
+ targetm.run_target_selftests.
+ * target.def (run_target_selftests): New hook.
+
+2016-11-04 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/arm/arm-arches.def (armv8-m.main+dsp): Set Cortex-M33 as
+ representative core for this architecture.
+ * config/arm/arm-cores.def (cortex-m33): Define new processor.
+ * config/arm/arm-tables.opt: Regenerate.
+ * config/arm/arm-tune.md: Likewise.
+ * config/arm/bpabi.h (BE8_LINK_SPEC): Add Cortex-M33 to the list of
+ valid -mcpu options.
+ * doc/invoke.texi (ARM Options): Document new Cortex-M33 processor.
+
+2016-11-04 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/arm/arm-arches.def (armv8-m.base): Set Cortex-M23 as
+ representative core for this architecture.
+ * config/arm/arm-cores.def (cortex-m23): Define new processor.
+ * config/arm/arm-tables.opt: Regenerate.
+ * config/arm/arm-tune.md: Likewise.
+ * config/arm/arm.c (arm_v6m_tune): Add Cortex-M23 to the list of cores
+ this tuning parameters apply to in the comment.
+ * config/arm/bpabi.h (BE8_LINK_SPEC): Add Cortex-M23 to the list of
+ valid -mcpu options.
+ * doc/invoke.texi (ARM Options): Document new Cortex-M23 processor.
+
+2016-11-04 Bin Cheng <bin.cheng@arm.com>
+
+ * fold-const.c (fold_cond_expr_with_comparison): Remove call
+ to pedantic_non_lvalue_loc. Remove useless code for lvalue
+ where cond_expr can't be a lvalue.
+
+2016-11-04 Claudiu Zissulescu <claziss@synopsys.com>
+
+ * config/arc/arc.c (arc_process_double_reg_moves): Use
+ gen_dexcl_2op call.
+ * config/arc/arc.md (movsi_insn): Disable unsupported move
+ instructions for ARCv2 cores.
+ (movdi): Use prepare_move_operands.
+ (movsf, movdf): Use move_dest_operand predicate.
+ * config/arc/constraints.md (Chs): Enable when barrel shifter is
+ present.
+ * config/arc/fpu.md (divsf3): Change to divsf3_fpu.
+ * config/arc/fpx.md (dexcl_3op_peep2_insn): Dx data register is
+ also a destination.
+ (dexcl_3op_peep2_insn_nores): Likewise.
+ * config/arc/arc.h (SHIFT_COUNT_TRUNCATED): Define to one.
+ (LINK_COMMAND_SPEC): Remove.
+
+2016-11-04 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/78185
+ * loop-invariant.c (find_exits): Record entering inner
+ loops as possibly exiting to handle infinite sub-loops.
+ * tree-ssa-loop-im.c: Include tree-ssa-loop-niter.h.
+ (fill_always_executed_in_1): Honor infinite child loops.
+
+2016-11-03 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ PR target/78192
+ * config/rs6000/vsx.md (vsx_extract_<mode>_di): The element number
+ has already been adjusted for endianness, so don't adjust it any
+ further.
+
+ PR target/77993
+ * config/rs6000/rs6000.h (FLOAT128_IBM_P): Do not allow IFmode or
+ ICmode unless we have standard PowerPC floating point.
+ * config/rs6000/rs6000.md (FP iterator): Likewise.
+ (FMOVE128 iterator): Likewise.
+
+2016-11-03 Jakub Jelinek <jakub@redhat.com>
+ Alexandre Oliva <aoliva@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR debug/28767
+ PR debug/56974
+ * langhooks.h (struct lang_hooks_for_types): Add type_dwarf_attribute
+ langhook.
+ * langhooks.c (lhd_type_dwarf_attribute): New function.
+ * langhooks-def.h (lhd_type_dwarf_attribute): Declare.
+ (LANG_HOOKS_TYPE_DWARF_ATTRIBUTE): Define.
+ (LANG_HOOKS_FOR_TYPES_INITIALIZER): Add
+ LANG_HOOKS_TYPE_DWARF_ATTRIBUTE.
+ (check_qualified_type, check_aligned_type): Call it.
+ * dwarf2out.c (modified_type_die): Don't use type_main_variant
+ for FUNCTION_TYPE or METHOD_TYPE, instead walk over variants with
+ check_base_type and check_lang_type.
+ (gen_ptr_to_mbr_type_die): If lookup_type_die is already non-NULL,
+ return early. For pointer-to-data-member add DW_AT_use_location
+ attribute.
+ (gen_subroutine_type_die): Add DW_AT_{,rvalue_}reference attribute
+ if needed.
+ (gen_type_die_with_usage): Don't use type_main_variant
+ for FUNCTION_TYPE or METHOD_TYPE, instead walk over variants with
+ check_base_type and check_lang_type. Formatting fixes. Call
+ get_debug_type langhook.
+
+2016-11-03 Jason Merrill <jason@redhat.com>
+
+ * tree.c (check_lang_type): New.
+ (check_qualified_type): Use it.
+ (check_aligned_type): Use it.
+ * tree.h: Declare it.
+
+2016-11-03 Richard Earnshaw <rearnsha@arm.com>
+
+ * config.gcc (arm-wrs-vxworks): Set target_cpu_cname.
+ (arm*-freebsd*): Likewise.
+ (arm*-*-netbsdelf*): Likewise.
+ (arm*-*-linux*): Likewise.
+ (arm*-*-uclinux*eabi*): Likewise.
+ (arm*-*-phoenix*): Likewise.
+ (arm*-*-eabi*, arm*-*-symbianelf*, arm*-*-rtems*): Likewise.
+ (arm*-*-*): Don't clobber target_cpu_cname when --with-cpu is not
+ specified. Default to arm6 if target_cpu_cname is not set.
+ * arm/arm.c (arm_option_override): Simplify logic. Assert that the
+ default cpu has been correctly configured.
+ * arm/arm.h (TARGET_CPU_DEFAULT): Delete.
+ (target_cpus): Delete TARGET_CPU_generic, add TARGET_CPU_num_cores.
+ * arm/freebsd.h (SUBTARGET_CPU_DEFAULT): Delete.
+ * arm/linux-eabi.h (SUBTARGET_CPU_DEFAULT): Delete.
+ * arm/linux-elf.h (SUBTARGET_CPU_DEFAULT): Delete.
+ * arm/symbian.h (SUBTARGET_CPU_DEFAULT): Delete.
+ * arm/unknown-elf.h (SUBTARGET_CPU_DEFAULT): Delete.
+
+2016-11-03 Jiong Wang <jiong.wang@arm.com>
+
+ * reg-notes.def (CFA_VAL_EXPRESSION): New entry.
+ * dwarf2cfi.c (dwarf2out_frame_debug_cfa_val_expression): New function.
+ (dwarf2out_frame_debug): Support REG_CFA_VAL_EXPRESSION.
+ (output_cfa_loc): Support DW_CFA_val_expression.
+ (output_cfa_loc_raw): Likewise.
+ (output_cfi): Likewise.
+ (output_cfi_directive): Likewise.
+ * dwarf2out.c (dw_cfi_oprnd1_desc): Support DW_CFA_val_expression.
+ (dw_cfi_oprnd2_desc): Likewise.
+ (mem_loc_descriptor): Recognize new pattern generated for value
+ expression.
+
+2016-11-03 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR rtl-optimization/78186
+ * combine.c (change_zero_ext): Mask the RHS of a zero_extract as
+ well, when converting to IOR.
+
+2016-11-03 Eric Botcazou <ebotcazou@adacore.com>
+
+ * config/sparc/sparc.md (vec_interleave_lowv8qi): Delete.
+ (vec_interleave_highv8qi): Likewise.
+
+2016-11-03 Martin Liska <mliska@suse.cz>
+
+ * profile.c (instrument_values): Fix coding style.
+ (branch_prob): Use renamed function.
+ * tree-profile.c (init_ic_make_global_vars): Likewise.
+ (gimple_init_edge_profiler): Rename to
+ gimple_init_gcov_profiler.
+ tree_time_profiler_counter variable declaration.
+ (gimple_gen_time_profiler): Rewrite to do a direct gimple code
+ emission.
+ * value-prof.h: Remove an argument.
+
+2016-11-03 Richard Biener <rguenther@suse.de>
+
+ * config/rs6000/rs6000.c (rs6000_xcoff_declare_object_name): Use
+ symtab_node::get_create.
+
+2016-11-03 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * rtlanal.c (nonzero_bits1): Fix WORD_REGISTER_OPERATIONS condition.
+ Move comments into more natural position.
+
+2016-11-03 Vineet Gupta <vgupta@synopsys.com>
+
+ * config/arc/arc.h (SIZE_TYPE): Define as unsigned int.
+ (PTRDIFF_TYPE): Define as int.
+
+2016-11-03 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * ccmp.c (expand_ccmp_expr_1): Adjust.
+ (expand_ccmp_expr): Likewise.
+ (expand_ccmp_next): Likewise.
+ * config/aarch64/aarch64.c (aarch64_gen_ccmp_next): Likewise.
+ (aarch64_gen_ccmp_first): Likewise.
+ * doc/tm.texi: Regenerate.
+ * target.def (gen_ccmp_first): Change argument types to rtx_insn *.
+ (gen_ccmp_next): Likewise.
+
+2016-11-03 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-vect-loop.c (destroy_loop_vec_info): Handle cond_expr.
+ (vect_is_simple_reduction): Swap cond_reduction by inversion.
+
+2016-11-02 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.c (ix86_init_libfuncs): New. Call
+ darwin_rename_builtins here.
+ (ix86_expand_divmod_libfunc): New.
+ (TARGET_INIT_LIBFUNCS): Unconditionally define to ix86_init_libfuncs.
+ (TARGET_EXPAND_DIVMOD_LIBFUNC): Define.
+
+2016-11-02 Cesar Philippidis <cesar@codesourcery.com>
+ Nathan Sidwell <nathan@acm.org>
+
+ * config/nvptx/nvptx.c (PTX_GANG_DEFAULT): Set to zero.
+
+2016-11-02 Max Filippov <jcmvbkbc@gmail.com>
+
+ * config/xtensa/xtensa.c (xtensa_output_integer_literal_parts):
+ New function.
+ (xtensa_output_literal): Use xtensa_output_integer_literal_parts
+ to format MODE_INT and MODE_PARTIAL_INT literals.
+
+2016-11-02 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR target/78168
+ * config/r6000/rs6000.c (rs6000_get_separate_components): Return
+ NULL if TARGET_SPE_ABI.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gimple-ssa-store-merging.c (encode_tree_to_bitpos): Don't forget to
+ clear padding bits even when they're less than a byte.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ * gimple-ssa-store-merging.c: Include gimplify-me.h.
+ (imm_store_chain_info::output_merged_stores): Force base_addr
+ to be proper GIMPLE for a MEM_REF address.
+ (pass_store_merging::execute): Restrict negative bitpos
+ handling to non-MEM_REF bases. Remove TREE_THIS_VOLATILE
+ check. Take into account non-NULL_TREE offset if the base
+ is already addressable.
+
+2016-11-26 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * config/aarch64/aarch64-simd.md (aarch64_crypto_sha1hv4si):
+ New pattern.
+ (aarch64_be_crypto_sha1hv4si): New pattern.
+
+2016-11-02 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * config/aarch64/aarch64.md (add<mode>3): Remove
+ redundant code. Don't split frame based additions.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ * gimple-ssa-store-merging.c (struct store_immediate_info): Remove
+ redundant val and dest members.
+ (store_immediate_info::store_immediate_info): Adjust.
+ (merged_store_group::merged_store_group): Adjust.
+ (merged_store_group::apply_stores): Likewise.
+ (struct imm_store_chain_info): Add base_addr field.
+ (imm_store_chain_info::imm_store_chain_info): New constructor.
+ (imm_store_chain_info::terminate_and_process_chain): Do not pass base.
+ (imm_store_chain_info::output_merged_store): Likewise. Use
+ addr_base which is already the address.
+ (imm_store_chain_info::output_merged_stores): Likewise.
+ (pass_tree_store_merging::terminate_all_aliasing_chains): Take
+ imm_store_chain_info instead of base. Fix alias check.
+ (pass_tree_store_merging::terminate_and_release_chain): Likewise.
+ (imm_store_chain_info::coalesce_immediate_stores): Adjust.
+ (pass_store_merging::execute): Refuse to operate on TARGET_MEM_REF.
+ use the address of the base and adjust for other changes.
+
+2016-11-02 Martin Liska <mliska@suse.cz>
+
+ * fold-const-call.c (host_size_t_cst_p): Test whether
+ t is convertible to size_t.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR tree-optimization/78170
+ * gimple-ssa-store-merging.c (encode_tree_to_bitpos): Truncate padding
+ introduced by native_encode_expr on little-endian as well.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR tree-optimization/78162
+ * gimple-ssa-store-merging.c (execute): Mark stores with bitpos < 0
+ as invalid.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * config/aarch64/aarch64.c (aarch64_register_saved_on_entry): Add
+ function comment.
+ (aarch64_next_callee_save): Likewise.
+ (aarch64_pushwb_single_reg): Likewise.
+ (aarch64_gen_storewb_pair): Likewise.
+ (aarch64_push_regs): Likewise.
+ (aarch64_gen_loadwb_pair): Likewise.
+ (aarch64_pop_regs): Likewise.
+ (aarch64_gen_store_pair): Likewise.
+ (aarch64_gen_load_pair): Likewise.
+ (aarch64_save_callee_saves): Likewise.
+ (aarch64_restore_callee_saves): Likewise.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78035
+ PR tree-optimization/77964
+ * gimple-pretty-print.c (pp_points_to_solution): Print
+ vars_contains_interposable.
+ * tree-ssa-alias.c: Include varasm.h.
+ (ptrs_compare_unequal): Check vars_contains_interposable and
+ decl_binds_to_current_def_p.
+ (dump_points_to_solution): Dump vars_contains_interposable.
+ * tree-ssa-alias.h (struct pt_solution): Add vars_contains_interposable
+ flag.
+ * tree-ssa-structalias.c: Include varasm.h.
+ (set_uids_in_ptset): Record whether vars contains a
+ not decl_binds_to_current_def_p variable in vars_contains_interposable.
+ (ipa_escaped_pt): Update initializer.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78047
+ * tree-ssa-structalias.c (push_fields_onto_fieldstack): Initialize
+ fake field at offset zero conservatively regarding to may_have_pointers.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ * tree-vrp.c (evrp_dom_walker::before_dom_children): Call
+ infer_value_range on stmt ops and update value-ranges.
+ Dump visited stmts and blocks.
+ (evrp_dom_walker::push_value_range): Dump changes.
+ (evrp_dom_walker::pop_value_range): Likewise.
+ (evrp_dom_walker::try_find_new_range): Avoid noop changes.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * emit-rtl.c (prev_nonnote_insn_bb): Change argument type to
+ rtx_insn *.
+ * rtl.h (prev_nonnote_insn_bb): Adjust prototype.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * cfgrtl.c (delete_insn_chain): Change argument type to rtx_insn *
+ and adjust for that.
+ * cfgrtl.h (delete_insn_chain): Adjust prototype.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * config/rl78/rl78.c (gen-and_emit_move): Change argument type
+ to rtx_insn *.
+ (transcode_memory_rtx): Likewise.
+ (move_to_acc): Likewise.
+ (move_from_acc): Likewise.
+ (move_acc_to_reg): Likewise.
+ (move_to_x): Likewise.
+ (move_to_hl): Likewise.
+ (move_to_de): Likewise.
+ * config/rs6000/rs6000.c (emit_frame_save): Likewise.
+ (rs6000_emit_savres_rtx): Likewise.
+ (rs6000_emit_prologue): Likewise.
+ * reorg.c (update_reg_unused_notes): Likewise.
+ * rtl.h (remove_note): Adjust prototype.
+ * rtlanal.c (remove_note): Make argument type rtx_insn *.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * config/alpha/alpha.c (alpha_legitimize_address_1): Split up
+ variables so some can be rtx_insn *.
+ (alpha_emit_xfloating_libcall): Likewise.
+ * config/mips/mips.c (mips_call_tls_get_addr): Likewise.
+ (mips_legitimize_tls_address): Likewise.
+ * optabs.c (expand_binop): Likewise.
+ * reload1.c (gen_reload): Likewise.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * reorg.c (relax_delay_slots): Split up the trial variable.
+
+2016-11-01 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+
+ * config/arc/arc.c (arc_emit_call_tls_get_addr): Make the type
+ of variables rtx_insn *.
+ * config/arm/arm.c (arm_call_tls_get_addr): Likewise.
+ (legitimize_tls_address): Likewise.
+ * config/bfin/bfin.c (hwloop_optimize): Likewise.
+ (bfin_gen_bundles): Likewise.
+ * config/c6x/c6x.c (reorg_split_calls): Likewise.
+ (c6x_reorg): Likewise.
+ * config/frv/frv.c (frv_reorder_packet): Likewise.
+ * config/i386/i386.c (ix86_split_idivmod): Likewise.
+ * config/ia64/ia64.c (ia64_expand_compare): Likewise.
+ * config/m32c/m32c.c (m32c_prepare_shift): Likewise.
+ * config/mn10300/mn10300.c: Likewise.
+ * config/rl78/rl78.c: Likewise.
+ * config/s390/s390.c (s390_fix_long_loop_prediction): Likewise.
+ * config/sh/sh-mem.cc (sh_expand_cmpstr): Likewise.
+ (sh_expand_cmpnstr): Likewise.
+ (sh_expand_strlen): Likewise.
+ (sh_expand_setmem): Likewise.
+ * config/sh/sh.md: Likewise.
+ * emit-rtl.c (emit_pattern_before): Likewise.
+ * except.c: Likewise.
+ * final.c: Likewise.
+ * jump.c: Likewise.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * tree-inline.c (copy_tree_body_r): Only copy the taken branch of
+ a COND_EXPR with constant condition.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (gen_variable_die): Remove again origin_die variable
+ and its initialization.
+
+2016-11-01 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * dwarf2out.c (output_rnglists): Wrap basebuf, len in
+ HAVE_AS_LEB128.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (add_name_and_src_coords_attributes): Add NO_LINKAGE_NAME
+ argument, don't call add_linkage_name if it is true.
+ (gen_variable_die): For C++ inline static data members, consider the
+ initial call when old_die is NULL to be declaration and call
+ add_name_and_src_coords_attributes in that case with true as
+ NO_LINKAGE_NAME. Add DW_AT_inline attribute if needed.
+ (gen_member_die): For C++ inline static data members, emit a
+ definition DIE right away in DW_TAG_compile_unit context.
+
+2016-11-01 John David Anglin <danglin@gcc.gnu.org>
+
+ PR target/78166
+ * config/pa/pa.md: Add new shift/add patterns to handle
+ (plus (mult (reg) (mem_shadd_operand)) (reg)) source operand.
+
+2016-11-01 Max Filippov <jcmvbkbc@gmail.com>
+
+ * config/xtensa/xtensa-protos.h
+ (xtensa_use_return_instruction_p): New prototype.
+ * config/xtensa/xtensa.c (xtensa_current_frame_size,
+ xtensa_callee_save_size): Remove.
+ (struct machine_function): Add new fields: current_frame_size,
+ callee_save_size, frame_laid_out and epilogue_done.
+ (compute_frame_size, xtensa_expand_prologue,
+ xtensa_expand_epilogue): Replace xtensa_callee_save_size with
+ cfun->machine->callee_save_size and xtensa_current_frame_size
+ with cfun->machine->current_frame_size.
+ (compute_frame_size): Update cfun->machine->frame_laid_out and
+ don't update frame layout after reload completion.
+ (xtensa_expand_epilogue): Set cfun->machine->epilogue_done
+ instead of zeroing xtensa_current_frame_size.
+ (xtensa_use_return_instruction_p): New function.
+ * config/xtensa/xtensa.h (xtensa_current_frame_size): Remove
+ declaration.
+ (INITIAL_ELIMINATION_OFFSET): Use return value of
+ compute_frame_size instead of xtensa_current_frame_size value.
+ * config/xtensa/xtensa.md ("return" pattern): Use new predicate
+ function xtensa_use_return_instruction_p instead of inline code.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * tree.h (BLOCK_IN_COLD_SECTION_P): Define.
+ * final.c (final_scan_insn): Set BLOCK_IN_COLD_SECTION_P.
+ * dwarf2out.c (rnglist_idx): New variable.
+ (struct dw_ranges): Add label, idx and maybe_new_sec fields.
+ (DEBUG_RNGLISTS_SECTION): Define.
+ (ranges_base_label): New variable.
+ (size_of_die) <case dw_val_class_range_list>: If using
+ DW_FORM_rnglistx, count size of uleb128 of range list index.
+ (value_format) <case dw_val_class_range_list>: For
+ -gdwarf-5 -gsplit-dwarf return DW_FORM_rnglistx.
+ (output_range_list_offset): Handle -gdwarf-5 .debug_rnglists
+ offsets. Multiply dwarf < 5 offsets by 2 * DWARF_ADDR_SIZE.
+ (add_ranges_num): Remove useless prototype. Don't multiply
+ by 2 * DWARF2_ADDR_SIZE. Add maybe_new_sec argument, adjust
+ for new fields added to dw_ranges struct.
+ (add_ranges): Add maybe_new_sec argument and pass it
+ through to add_ranges_num.
+ (note_rnglist_head): New function.
+ (add_ranges_by_labels): Pass true as maybe_new_sec to
+ add_ranges_num, call note_rnglist_head on the head of the list.
+ (output_ranges): Add function comment. Switch to
+ .debug_ranges section here and emit .Ldebug_ranges0 label.
+ (index_rnglists, output_rnglists): New functions.
+ (gen_subprogram_die): Formatting fixes.
+ (add_high_low_attributes): Don't divide offsets
+ by 2 * DWARF2_ADDR_SIZE. Call note_rnglist_head on the
+ first list element or when pointing into the middle of
+ a list. Pass true as second argument to add_ranges on the
+ first block fragment after cold/hot section switch.
+ (init_sections_and_labels): For -gdwarf-5 use .debug_rnglists
+ section instead of .debug_ranges. Initialize
+ ranges_base_label if -gdwarf-5 -gsplit-dwarf.
+ (dwarf2out_finish): For -gdwarf-5 -gsplit-dwarf call
+ index_rnglists and add DW_AT_rnglists_base attr. Don't switch
+ to dwarf_ranges_section here or emit .Ldebug_ranges0 label.
+ Call output_rnglists for -gdwarf-5.
+ (dwarf2out_c_finalize): Clear rnglist_idx.
+
+2016-11-01 Fritz Reese <fritzoreese@gmail.com>
+
+ * combine.c (simplify_compare_const): Add gcc_fallthrough.
+
+2016-11-01 Bilyan Borisov <bilyan.borisov@arm.com>
+ Tamar Christina <tamar.christina@arm.com>
+
+ * config/arm/arm-c.c (arm_cpu_builtins): New macro definition.
+ * config/arm/arm_neon.h (vmaxnm_f32): New intrinsinc.
+ (vmaxnmq_f32): Likewise.
+ (vminnm_f32): Likewise.
+ (vminnmq_f32): Likewise.
+ * config/arm/arm_neon_builtins.def (vmaxnm): New builtin.
+ (vminnm): Likewise.
+ * config/arm/neon.md (neon_<fmaxmin_op><mode>, VCVTF): New
+ expander.
+
+2016-10-31 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/vsx.md (VSX_EXTRACT_FL): New iterator for all
+ binary floating point types supported by the hardware except for
+ double.
+ (vsx_xvcvsxwdp_df): Provide scalar result alternative to the
+ vector instruction for optimizing extracting a SImode from a
+ V4SImode vector and converting it to floating point.
+ (vsx_xvcvuxwdp_df): Likewise.
+ (vsx_extract_si): On ISA 3.0, allow extract target and temporary
+ registers to be any VSX register. Move stores to the end of the
+ constraints.
+ (vsx_extract_si_<uns>float_df): New combiner pattern and splitter
+ to optimize extracting a SImode from a V4SImode vector and
+ converting it to a binary floating point type supported by the
+ hardware. Use the vector converts instead of extracting the
+ element, sign extending it, and then converting it to double.
+ Other floating point types than double first convert to double,
+ then the double is converted to that type.
+ (vsx_extract_si_<uns>float_<mode>): Likewise.
+
+2016-10-31 Andrew Pinski <apinski@cavium.com>
+
+ * config/aarch64/driver-aarch64.c (host_detect_local_cpu):
+ Rewrite handling of part num to handle the case where
+ multiple implementers share the same part num.
+
+2016-10-31 Jan Kratochvil <jan.kratochvil@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (DWARF_COMPILE_UNIT_HEADER_SIZE): Adjust for -gdwarf-5.
+ (DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE): Likewise.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (dwarf_AT): Handle DW_AT_dwo_name.
+ (use_debug_types): Adjust comment for DWARF5 DW_UT_type units.
+ (new_die): Handle DW_TAG_skeleton_unit like DW_TAG_compile_unit.
+ (is_cu_die, is_unit_die): Likewise.
+ (should_move_die_to_comdat, break_out_comdat_types): Adjust
+ comments for DWARF5 DW_UT_type units.
+ (output_compilation_unit_header): Add UT argument, output
+ start of DWARF5 .debug_info section header.
+ (output_comp_unit): Add dwo_id argument. Adjust
+ output_compilation_unit_header caller, for DW_UT_split_compile
+ emit dwo_id field, otherwise padding1. Emit padding2 field.
+ (add_top_level_skeleton_die_attrs): Add DW_AT_dwo_name
+ rather than DW_AT_GNU_dwo_name attr for -gdwarf-5.
+ (output_skeleton_debug_sections): Add dwo_id argument, for
+ -gdwarf-5 emit DWARF 5 DW_UT_skeleton header.
+ (output_comdat_type_unit): For -gdwarf-5 emit .debug_info
+ DW_UT_type or DW_UT_split_type units rather than .debug_types.
+ (dwarf2out_finish): Use DW_TAG_skeleton_unit rather than
+ DW_TAG_compile_unit for skeleton unit die. Don't add
+ DW_AT_GNU_dwo_id attributes for -gdwarf-5, instead pass checksum
+ address to output_comp_unit and output_skeleton_debug_sections.
+
+ * dwarf2out.c (debug_line_str_section): New variable.
+ (debug_line_str_hash): Likewise.
+ (DEBUG_LINE_STR_SECTION): Define.
+ (set_indirect_string): Handle DW_FORM_line_strp like
+ DW_FORM_strp.
+ (find_string_form): Fix up formatting.
+ (size_of_die): Handle DW_FORM_line_strp like DW_FORM_strp.
+ Fix up indentation.
+ (output_die): Handle DW_FORM_line_strp.
+ (DWARF5_USE_DEBUG_LINE_STR): Define.
+ (output_line_string): New function.
+ (output_file_names): Add -gdwarf-5 support.
+ (output_line_info): Likewise.
+ (init_sections_and_labels): Initialize debug_line_str_section.
+ (output_indirect_string): Change 2nd argument from void *
+ to enum dwarf_form form, compare with form rather than
+ DW_FORM_strp.
+ (output_indirect_strings): Pass DW_FORM_strp to
+ output_indirect_string traversion.
+ (dwarf2out_finish): Output .debug_line_str strings.
+ (dwarf2out_c_finalize): Clear debug_line_str_section and
+ debug_line_str_hash.
+
+2016-10-31 Tom Tromey <tom@tromey.com>
+
+ PR debug/77315
+ * dwarf2out.c (mem_loc_descriptor): Use DW_OP_form_tls_address.
+ (resolve_args_picking_1): Move DW_OP_form_tls_address case next to
+ DW_OP_GNU_push_tls_address case.
+ (loc_list_from_tree_1): Use DW_OP_form_tls_address.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.h (struct dw_loc_descr_node): Adjust comment
+ for frame_offset_rel bit.
+ (struct array_descr_info): Add rank field.
+ * dwarf2out.c (struct loc_descr_context): Add placeholder_arg
+ and placeholder_seen fields.
+ (resolve_args_picking_1): Handle also frame_offset_rel DW_OP_dup
+ and DW_OP_over. Optimize DW_OP_pick 0 into DW_OP_dup and
+ DW_OP_pick 1 into DW_OP_over.
+ (function_to_dwarf_procedure, type_byte_size, field_byte_offset,
+ gen_variant_part): Clear placeholder_{arg,seen}.
+ (loc_list_from_tree_1): Drop const from context argument.
+ Handle integral PLACEHOLDER_EXPR if context->placeholder_arg.
+ (loc_list_for_address_of_addr_expr_of_indirect_ref,
+ loc_list_from_tree, loc_descriptor_from_tree): Drop const from
+ context argument.
+ (add_scalar_info): Drop const from context argument. Handle
+ context->placeholder_arg.
+ (add_bound_info): Drop const from context argument.
+ (gen_descr_array_type_die): Drop const from ctx variable.
+ Initialize placeholder_arg and placeholder_seen. Add DW_AT_rank
+ attribute and use a single DW_TAG_generic_subrange instead of
+ 7 DW_TAG_subrange_type for assumed rank arrays.
+
+ * dwarf2out.h (enum dw_val_class): Add dw_val_class_loclistsptr.
+ * dwarf2out.c (struct dw_loc_list_struct): Change emitted field
+ from bool to 1-bit uchar bitfield. Add num_assigned and
+ offset_emitted bitfields.
+ (dw_val_equal_p): Compare v.val_lbl_id rather than v.val_unsigned
+ for dw_val_class_lineptr and dw_val_class_macptr. Handle
+ dw_val_class_loclistsptr.
+ (new_addr_loc_descr): Fix up formatting.
+ (DEBUG_LOCLISTS_SECTION, DEBUG_DWO_LOCLISTS_SECTION): Define.
+ (add_AT_low_high_pc): Fix up formatting.
+ (add_AT_loclistsptr): New function.
+ (AT_lbl): Allow dw_val_class_loclistsptr.
+ (print_dw_val, attr_checksum, attr_checksum_ordered, same_dw_val_p):
+ Handle dw_val_class_loclistsptr.
+ (loc_list_idx): New variable.
+ (output_loclists_offsets, assign_location_list_indexes): New
+ functions.
+ (size_of_die): For dw_val_class_loc_list -gsplit-dwarf -gdwarf-5
+ add size_of_uleb128 of the index. Drop never used
+ dwarf_split_debug_info AT_index handling. Handle
+ dw_val_class_loclistsptr.
+ (value_format): Return DW_FORM_loclistsx for dw_val_class_loc_list
+ if -gsplit-dwarf -gdwarf-5. Handle dw_val_class_loclistsptr.
+ (output_loc_list): Handle DWARF 5 .debug_loclists* format.
+ (output_loc_list_offset): Handle -gsplit-dwarf -gdwarf-5
+ DW_FORM_loclistx indexes.
+ (output_attr_index_or_value): Fix up formatting. Don't handle
+ dw_val_class_loc_list here.
+ (output_die): Formatting fixes. Handle dw_val_class_loclistsptr.
+ For dw_val_class_loc_list call output_loc_list_offset rather than
+ output_attr_index_or_value.
+ (init_sections_and_labels): For -gdwarf-5 use .debug_loclists
+ or .debug_loclists.dwo section name for debug_loc_section.
+ (resolve_addr_in_expr): Formatting fix.
+ (index_location_lists): Likewise.
+ (dwarf2out_finish): If there are any location lists, for
+ -gsplit-dwarf -gdwarf-5 add DW_AT_loclists_base attribute. Call
+ index_location_lists only if have_location_lists. Call
+ assign_location_list_indexes for -gsplit-dwarf -gdwarf-5. Emit
+ .debug_loclists{,.dwo} section header for -gdwarf-5, for -gdwarf-5
+ -gsplit-dwarf also emit offset table.
+
+ * dwarf2out.c (DWARF_LARGEST_DATA_FORM_BITS): Define.
+ (size_of_die, value_format, output_die): Use
+ DW_FORM_data16 for 128-bit dw_val_class_const_double or
+ dw_val_class_wide_int.
+
+ * dwarf2out.c (dwarf_op): Renamed to ...
+ (dwarf_OP): ... this.
+ (convert_descriptor_to_mode, scompare_loc_descriptor,
+ minmax_loc_descriptor, typed_binop, mem_loc_descriptor,
+ implicit_ptr_descriptor, optimize_one_addr_into_implicit_ptr): Adjust
+ callers.
+ (dwarf_AT, dwarf_TAG): New functions.
+ (check_die): Disallow DW_AT_call_all_calls next to
+ DW_AT_GNU_all_call_sites.
+ (gen_call_site_die): Use dwarf_TAG and dwarf_AT with DWARF 5 tag
+ and attributes instead of the corresponding GNU tag and attributes.
+ (gen_subprogram_die): Likewise. Emit call site information even
+ for -gdwarf-5 -gstrict-dwarf. Replace DW_AT_GNU_defaulted with
+ DW_AT_defaulted in comment.
+ (resolve_addr): Handle DW_AT_call_origin attribute on
+ DW_TAG_call_site DIE like DW_AT_abstract_origin on
+ DW_TAG_GNU_call_site DIE.
+
+ * dwarf2out.c (dwarf_op): New function.
+ (size_of_loc_descr): Handle DW_OP_{implicit_pointer,entry_value},
+ DW_OP_{const,regval,deref}_type and DW_OP_{convert,reinterpret}.
+ (output_loc_operands, output_loc_operands_raw): Likewise.
+ (resolve_args_picking_1, prune_unused_types_walk_loc_descr,
+ mark_base_types, hash_loc_operands, compare_loc_operands): Likewise.
+ (resolve_addr_in_expr): Likewise. Only punt for !dwarf_strict
+ if dwarf_version < 5.
+ (convert_descriptor_to_mode): Use dwarf_op (DW_OP_xxx) instead of
+ DW_OP_GNU_xxx.
+ (scompare_loc_descriptor, ucompare_loc_descriptor,
+ minmax_loc_descriptor, typed_binop, mem_loc_descriptor,
+ implicit_ptr_descriptor, optimize_one_addr_into_implicit_ptr,
+ optimize_location_into_implicit_ptr): Likewise. Only punt for
+ !dwarf_strict if dwarf_version < 5.
+ (string_cst_pool_decl): Adjust comment.
+ (non_dwarf_expression): Handle DW_OP_implicit_pointer.
+
+ * dwarf2out.h (enum dw_val_class): Add dw_val_class_const_implicit,
+ dw_val_class_unsigned_const_implicit and dw_val_class_file_implicit.
+ (struct dw_val_node): Add val_file_implicit field.
+ * dwarf2out.c (dw_val_equal_p, print_dw_val, attr_checksum,
+ attr_checksum_ordered, same_dw_val_p, size_of_die, value_format,
+ output_die): Handle dw_val_class_const_implicit,
+ dw_val_class_unsigned_const_implicit and dw_val_class_file_implicit.
+ (abbrev_die_table): Change into va_gc vec.
+ (abbrev_die_table_allocated, abbrev_die_table_in_use,
+ ABBREV_DIE_TABLE_INCREMENT): Remove.
+ (AT_int, AT_unsigned, AT_file): Allow dw_val_class_*_implicit.
+ (abbrev_opt_start, abbrev_usage_count, sorted_abbrev_dies): New
+ variables.
+ (build_abbrev_table): Adjust for abbrev_die_table being a va_gc vec.
+ If abbrev_opt_start, fill in abbrev_usage_count and abbrev_dies
+ vectors.
+ (die_abbrev_cmp, optimize_implicit_const, optimize_abbrev_table): New
+ functions.
+ (output_die_abbrevs): For DW_FORM_implicit_const emit sleb128 with
+ the implicit value.
+ (output_abbrev_section): Adjust for abbrev_die_table being a va_gc
+ vec.
+ (output_comp_unit): Initialize abbrev_opt_start if emitting the main
+ unit. Call optimize_abbrev_table.
+ (dwarf2out_init, dwarf2out_finish, dwarf2out_c_finalize): Adjust for
+ abbrev_die_table being a va_gc vec.
+
+ PR tree-optimization/77860
+ * tree-ssa-reassoc.c (eliminate_using_constants): Handle
+ also integral complex and vector constants.
+
+ * dwarf2out.c (dwarf2out_define, dwarf2out_undef, output_macinfo_op,
+ optimize_macinfo_range, save_macinfo_strings): Replace
+ DW_MACRO_GNU_* constants with corresponding DW_MACRO_* constants.
+ (output_macinfo): Likewise. Emit .debug_macro* rather than
+ .debug_macinfo* even for -gstrict-dwarf -gdwarf-5.
+ (init_sections_and_labels): Use .debug_macro* labels rather than
+ .debug_macinfo* labels even for -gstrict-dwarf -gdwarf-5.
+ (dwarf2out_finish): Use DW_AT_macros instead of DW_AT_macro_info
+ or DW_AT_GNU_macros for -gdwarf-5.
+
+2016-10-31 Waldemar Brodkorb <wbx@openadk.org>
+
+ * config/microblaze/linux.h (UCLIBC_DYNAMIC_LINKER): Define.
+
+2016-09-11 Le-Chun Wu <lcwu@google.com>
+ Mark Wielaard <mjw@redhat.com>
+
+ * common.opt (Wshadow=global): New option. Default for -Wshadow.
+ (Wshadow=local): New option.
+ (Wshadow-local): Hidden alias for -Wshadow=local.
+ (Wshadow=compatible-local): New option.
+ (Wshadow-compatible-local): Hidden alias for
+ -Wshadow=compatible-local.
+ * doc/invoke.texi: Document Wshadow=global, Wshadow=local and
+ Wshadow=compatible-local.
+
+2016-10-31 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-vect-slp.c (vect_get_and_check_slp_defs): New parameter SWAP.
+ Check slp defs for COND_EXPR by swapping/inverting operands if the
+ new parameter SWAP indicates so.
+ (vect_build_slp_tree_1): New parameter SWAP. Check COND_EXPR stmt
+ is isomorphic to the first stmt via swapping/inverting. Store swap
+ information in the new parameter SWAP.
+ (vect_build_slp_tree): New local array SWAP and pass it to function
+ vect_build_slp_tree_1. Cleanup result handling code for function
+ call to vect_get_and_check_slp_defs. Skip operand swapping if the
+ order of operands has been fixed as indicated by SWAP[i].
+
+2016-10-31 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-vect-data-refs.c (vect_slp_analyze_node_dependences): Skip
+ unnecessary data dependence check after visited store stmt.
+
+2016-10-30 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/71915
+ PR tree-optimization/71490
+ * gimple-ssa-strength-reduction.c (struct slsr_cand_d): Add
+ stride_type field.
+ (find_basis_for_base_expr): Require stride types to match when
+ seeking a basis.
+ (alloc_cand_and_find_basis): Record the stride type.
+ (slsr_process_phi): Pass stride type to alloc_cand_and_find_basis.
+ (backtrace_base_for_ref): Pass types to legal_cast_p_1 rather than
+ the expressions having those types.
+ (slsr_process_ref): Pass stride type to alloc_cand_and_find_basis.
+ (create_mul_ssa_cand): Likewise.
+ (create_mul_imm_cand): Likewise.
+ (create_add_ssa_cand): Likewise.
+ (create_add_imm_cand): Likewise.
+ (legal_cast_p_1): Change interface to accept types rather than the
+ expressions having those types.
+ (legal_cast_p): Pass types to legal_cast_p_1.
+ (slsr_process_cast): Pass stride type to
+ alloc_cand_and_find_basis.
+ (slsr_process_copy): Likewise.
+ (dump_candidate): Display stride type when a cast exists.
+ (create_add_on_incoming_edge): Introduce a cast when necessary for
+ the stride type.
+ (analyze_increments): Change the code checking for invalid casts
+ to rely on the stride type, and update the documentation and
+ example. Change the code checking for pointer multiplies to rely
+ on the stride type.
+ (insert_initializers): Introduce a cast when necessary for the
+ stride type. Use the stride type for the type of the initializer.
+
+2016-10-30 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * config/arm/arm.c (arm_const_not_ok_for_debug_p): Use VAR_P.
+
+2016-10-29 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/77919
+ * expr.c (expand_expr_real_1) <normal_inner_ref>: Only avoid forcing
+ into memory if both modes are complex and their inner modes have the
+ same precision. If the two modes are different complex modes, convert
+ each part separately and generate a new CONCAT.
+
+2016-10-29 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/pa64-hpux.h (FINI_SECTION_ASM_OP): Define to null string.
+
+2016-10-29 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/78148
+ * gimple-ssa-store-merging.c
+ (imm_store_chain_info::output_merged_store): Use build_aligned_type
+ instead of SET_TYPE_ALIGN on shared integral type.
+
+2016-10-29 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/pa.h (BIGGEST_ALIGNMENT): Adjust comment.
+ (MALLOC_ABI_ALIGNMENT): Define to 128 on all targets except SOM.
+ Adjust comment.
+
+2016-10-28 Jeff Law <law@redhat.com>
+
+ * config/vax/vax.h (REGNO_REG_CLASS): Access the REGNO argument.
+ * config/spu/spu.h (REGNO_REG_CLASS): Likewise.
+
+2016-10-28 Eric Botcazou <ebotcazou@adacore.com>
+
+ * doc/sourcebuild.texi (Ada Tests): Remove mention of gcc chapter.
+
+2016-10-28 Eric Botcazou <ebotcazou@adacore.com>
+
+ * target.def (min_arithmetic_precision): New hook.
+ * doc/tm.texi.in (Misc): Add TARGET_MIN_ARITHMETIC_PRECISION.
+ * doc/tm.texi: Regenerate.
+ * internal-fn.c (expand_arith_overflow): Adjust handling of target
+ dependent support by means of TARGET_MIN_ARITHMETIC_PRECISION.
+ * targhooks.c (default_min_arithmetic_precision): New function.
+ * targhooks.h (default_min_arithmetic_precision): Declare.
+ * config/sparc/sparc.c (TARGET_MIN_ARITHMETIC_PRECISION): Define.
+ (sparc_min_arithmetic_precision): New function.
+
+2016-10-28 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR target/71847
+ * combine.c (change_zero_ext): Handle zero_ext of hard registers.
+ Swap commutative operands in new RTL if needed. Handle zero_ext
+ in the set_dest.
+ (recog_for_combine): Pass *pnewpat to change_zero_ext instead of
+ PATTERN (insn).
+
+2016-10-28 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+ Kugan Vivekanandarajah <kuganv@linaro.org>
+ Jim Wilson <jim.wilson@linaro.org>
+
+ PR tree-optimization/43721
+ * target.def: New hook expand_divmod_libfunc.
+ * doc/tm.texi.in: Add hook for TARGET_EXPAND_DIVMOD_LIBFUNC.
+ * doc/tm.texi: Regenerate.
+ * internal-fn.def: Add new entry for DIVMOD ifn.
+ * internal-fn.c (expand_DIVMOD): New.
+ * tree-ssa-math-opts.c: Include optabs-libfuncs.h, tree-eh.h,
+ targhooks.h.
+ (widen_mul_stats): Add new field divmod_calls_inserted.
+ (target_supports_divmod_p): New.
+ (divmod_candidate_p): Likewise.
+ (convert_to_divmod): Likewise.
+ (pass_optimize_widening_mul::execute): Call calculate_dominance_info,
+ renumber_gimple_stmt_uids at beginning of function. Call
+ convert_to_divmod and record stats for divmod.
+ * config/arm/arm.c (arm_expand_divmod_libfunc): Override hook
+ TARGET_EXPAND_DIVMOD_LIBFUNC.
+ * doc/sourcebuild.texi: Add items for arm_divmod_simode, divmod,
+ divmod_simode.
+
+2016-10-28 Eric Botcazou <ebotcazou@adacore.com>
+ Segher Boessenkool <segher@kernel.crashing.org>
+
+ * dojump.c (do_jump_by_parts_greater_rtx): Invert probability when
+ swapping the arms of the branch.
+ * internal-fn.c (expand_addsub_overflow): Use a straight-line code
+ sequence for the generic signed-signed-signed case.
+
2016-10-28 Jeff Law <law@redhat.com>
* config/bfin/bfin.c (bfin_legitimate_address_p): Add missing
@@ -339,7 +1709,7 @@
2016-10-26 Jakub Jelinek <jakub@redhat.com>
- * gen-pass-instances.awk (adjust_linenos): INcrement pass_lines[p]
+ * gen-pass-instances.awk (adjust_linenos): Increment pass_lines[p]
by increment rather than double it.
(insert_remove_pass): Strip leading whitespace from args[3]. Don't
emit a space before args[4].
@@ -1838,7 +3208,7 @@
2016-10-14 Catherine Moore <clm@codesourcery.com>
- * gcc/config/mips/mips.c (mips_prepare_pch_save): Initialize
+ * config/mips/mips.c (mips_prepare_pch_save): Initialize
micromips_globals to zero.
2016-10-14 Richard Biener <rguenther@suse.de>
@@ -4989,8 +6359,8 @@
(arm_elf_section_type_flags): New.
* config/arm/elf.h (JUMP_TABLES_IN_TEXT_SECTION): Disable
for -mpure-code.
- * gcc/doc/texi (TARGET_ASM_ELF_FLAGS_NUMERIC): New.
- * gcc/doc/texi.in (TARGET_ASM_ELF_FLAGS_NUMERIC): Likewise.
+ * doc/texi (TARGET_ASM_ELF_FLAGS_NUMERIC): New.
+ * doc/texi.in (TARGET_ASM_ELF_FLAGS_NUMERIC): Likewise.
2016-09-22 Jan Hubicka <hubicka@ucw.cz>
@@ -6255,7 +7625,7 @@
* genmatch.c (parser::parse_expr): Increase buffer size to guarantee
it fits the output of the formatted function regardless of its
arguments.
- * gcc/genmodes.c (parser::parse_expr): Same.
+ * genmodes.c (parser::parse_expr): Same.
* gimplify.c (gimplify_asm_expr): Same.
* passes.c (pass_manager::register_one_dump_file): Same.
* print-tree.c (print_node): Same.
@@ -6466,7 +7836,7 @@
2016-08-30 Tamar Christina <tamar.christina@arm.com>
- * gcc/config/aarch64/aarch64-simd.md
+ * config/aarch64/aarch64-simd.md
(aarch64_ld2<mode>_dreg_le): New.
(aarch64_ld2<mode>_dreg_be): New.
(aarch64_ld2<mode>_dreg): Removed.
@@ -9932,7 +11302,7 @@
2016-07-20 Georg-Johann Lay <avr@gjlay.de>
- * gcc/config/avr.c (avr_legitimize_address) [AVR_TINY]: Force
+ * config/avr.c (avr_legitimize_address) [AVR_TINY]: Force
constant addresses outside [0,0xc0] into a register.
(avr_out_movhi_r_mr_reg_no_disp_tiny): Pass insn. And handle
cases where the base address register is unused after.
@@ -10354,7 +11724,7 @@
2016-07-14 Alan Modra <amodra@gmail.com>
- * gcc/config/rs6000/altivec.md (altivec_mov<mode>): Disparage
+ * config/rs6000/altivec.md (altivec_mov<mode>): Disparage
gpr alternatives. Correct '*' placement on Y,r alternative.
Add '*' on operand 1 of r,r alternative.
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index fef34538447..162d8f6bb0f 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20161028
+20161109
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 622d038f6fb..7ecd1e4e726 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1879,7 +1879,10 @@ rest.cross: specs
# Specify a dummy input file to placate the driver.
# Specify -nostdinc to work around missing WIND_BASE environment variable
# required for *-wrs-vxworks-* targets.
-SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -fself-test
+# Specify -o /dev/null so the output of -S is discarded. More importantly
+# It does not try to create a file with the name "null.s" on POSIX and
+# "nul.s" on Windows. Because on Windows "nul" is a reserved file name.
+SELFTEST_FLAGS = -nostdinc -x c /dev/null -S -fself-test -o /dev/null
# Run the selftests during the build once we have a driver and a cc1,
# so that self-test failures are caught as early as possible.
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 14782a7b578..e37a0000fb8 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,11 @@
+2016-11-07 Tamar Christina <tamar.christina@arm.com>
+
+ * adaint.c: Added signal.h for Windows.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc-interface/misc.c (gnat_get_array_descr_info): Clear rank field.
+
2016-10-24 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* gcc-interface/Make-lang.in (lang_checks_parallelized): New target.
@@ -5,7 +13,7 @@
2016-10-20 Nicolas Roche <roche@adacore.com>
- * gcc-interface/Makefile (x86-64/Linux): Restore missing pairs.
+ * gcc-interface/Makefile (x86-64/Darwin): Restore missing pairs.
(x86/Darwin): Likewise.
2016-10-19 Eric Botcazou <ebotcazou@adacore.com>
diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c
index 353914708ad..819ea47e449 100644
--- a/gcc/ada/adaint.c
+++ b/gcc/ada/adaint.c
@@ -190,6 +190,7 @@ UINT CurrentCCSEncoding;
#include <accctrl.h>
#include <aclapi.h>
#include <tlhelp32.h>
+#include <signal.h>
#undef DIR_SEPARATOR
#define DIR_SEPARATOR '\\'
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 76ad06c6e8d..1fed72a0520 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -898,6 +898,7 @@ gnat_get_array_descr_info (const_tree const_type,
}
info->ndimensions = i;
+ info->rank = NULL_TREE;
/* Too many dimensions? Give up generating proper description: yield instead
nested arrays. Note that in this case, this hook is invoked once on each
diff --git a/gcc/alias.c b/gcc/alias.c
index ca475ff92af..1ea2417bed1 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -2755,6 +2755,21 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y, bool loop_invariant)
|| TREE_CODE (expry) == CONST_DECL)
return 1;
+ /* If one decl is known to be a function or label in a function and
+ the other is some kind of data, they can't overlap. */
+ if ((TREE_CODE (exprx) == FUNCTION_DECL
+ || TREE_CODE (exprx) == LABEL_DECL)
+ != (TREE_CODE (expry) == FUNCTION_DECL
+ || TREE_CODE (expry) == LABEL_DECL))
+ return 1;
+
+ /* If either of the decls doesn't have DECL_RTL set (e.g. marked as
+ living in multiple places), we can't tell anything. Exception
+ are FUNCTION_DECLs for which we can create DECL_RTL on demand. */
+ if ((!DECL_RTL_SET_P (exprx) && TREE_CODE (exprx) != FUNCTION_DECL)
+ || (!DECL_RTL_SET_P (expry) && TREE_CODE (expry) != FUNCTION_DECL))
+ return 0;
+
rtlx = DECL_RTL (exprx);
rtly = DECL_RTL (expry);
@@ -2797,7 +2812,7 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y, bool loop_invariant)
/* Offset based disambiguation not appropriate for loop invariant */
if (loop_invariant)
- return 0;
+ return 0;
/* Offset based disambiguation is OK even if we do not know that the
declarations are necessarily different
diff --git a/gcc/asan.c b/gcc/asan.c
index c6d924014b6..6e93ea3aba5 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -245,6 +245,22 @@ static unsigned HOST_WIDE_INT asan_shadow_offset_value;
static bool asan_shadow_offset_computed;
static vec<char *> sanitized_sections;
+/* Return true if STMT is ASAN_MARK poisoning internal function call. */
+static inline bool
+asan_mark_poison_p (gimple *stmt)
+{
+ return (gimple_call_internal_p (stmt, IFN_ASAN_MARK)
+ && tree_to_uhwi (gimple_call_arg (stmt, 0)) == ASAN_MARK_CLOBBER);
+
+}
+
+/* Set of variable declarations that are going to be guarded by
+ use-after-scope sanitizer. */
+
+static hash_set<tree> *asan_handled_variables = NULL;
+
+hash_set <tree> *asan_used_labels = NULL;
+
/* Sets shadow offset to value in string VAL. */
bool
@@ -287,6 +303,14 @@ set_sanitized_sections (const char *sections)
}
}
+bool
+asan_sanitize_stack_p (void)
+{
+ return ((flag_sanitize & SANITIZE_ADDRESS)
+ && ASAN_STACK
+ && !asan_no_sanitize_address_p ());
+}
+
/* Checks whether section SEC should be sanitized. */
static bool
@@ -315,22 +339,13 @@ asan_shadow_offset ()
alias_set_type asan_shadow_set = -1;
-/* Pointer types to 1 resp. 2 byte integers in shadow memory. A separate
+/* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate
alias set is used for all shadow memory accesses. */
-static GTY(()) tree shadow_ptr_types[2];
+static GTY(()) tree shadow_ptr_types[3];
/* Decl for __asan_option_detect_stack_use_after_return. */
static GTY(()) tree asan_detect_stack_use_after_return;
-/* Various flags for Asan builtins. */
-enum asan_check_flags
-{
- ASAN_CHECK_STORE = 1 << 0,
- ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
- ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
- ASAN_CHECK_LAST = 1 << 3
-};
-
/* Hashtable support for memory references used by gimple
statements. */
@@ -933,12 +948,16 @@ static void
asan_init_shadow_ptr_types (void)
{
asan_shadow_set = new_alias_set ();
- shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node);
- TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set;
- shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]);
- shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node);
- TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set;
- shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]);
+ tree types[3] = { signed_char_type_node, short_integer_type_node,
+ integer_type_node };
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ shadow_ptr_types[i] = build_distinct_type_copy (types[i]);
+ TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set;
+ shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]);
+ }
+
initialize_sanitizer_builtins ();
}
@@ -1022,6 +1041,15 @@ asan_function_start (void)
current_function_funcdef_no);
}
+/* Return number of shadow bytes that are occupied by a local variable
+ of SIZE bytes. */
+
+static unsigned HOST_WIDE_INT
+shadow_mem_size (unsigned HOST_WIDE_INT size)
+{
+ return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY;
+}
+
/* Insert code to protect stack vars. The prologue sequence should be emitted
directly, epilogue sequence returned. BASE is the register holding the
stack base, against which OFFSETS array offsets are relative to, OFFSETS
@@ -1047,7 +1075,7 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
HOST_WIDE_INT base_offset = offsets[length - 1];
HOST_WIDE_INT base_align_bias = 0, offset, prev_offset;
HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset;
- HOST_WIDE_INT last_offset, last_size;
+ HOST_WIDE_INT last_offset;
int l;
unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT;
tree str_cst, decl, id;
@@ -1205,16 +1233,16 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
(aoff - prev_offset)
>> ASAN_SHADOW_SHIFT);
prev_offset = aoff;
- for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT))
+ for (i = 0; i < 4; i++, aoff += ASAN_SHADOW_GRANULARITY)
if (aoff < offset)
{
- if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1)
+ if (aoff < offset - (HOST_WIDE_INT)ASAN_SHADOW_GRANULARITY + 1)
shadow_bytes[i] = 0;
else
shadow_bytes[i] = offset - aoff;
}
else
- shadow_bytes[i] = ASAN_STACK_MAGIC_PARTIAL;
+ shadow_bytes[i] = ASAN_STACK_MAGIC_MIDDLE;
emit_move_insn (shadow_mem, asan_shadow_cst (shadow_bytes));
offset = aoff;
}
@@ -1282,35 +1310,66 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb,
if (STRICT_ALIGNMENT)
set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode)));
- prev_offset = base_offset;
+ /* Unpoison shadow memory of a stack at the very end of a function.
+ As we're poisoning stack variables at the end of their scope,
+ shadow memory must be properly unpoisoned here. The easiest approach
+ would be to collect all variables that should not be unpoisoned and
+ we unpoison shadow memory of the whole stack except ranges
+ occupied by these variables. */
last_offset = base_offset;
- last_size = 0;
- for (l = length; l; l -= 2)
+ HOST_WIDE_INT current_offset = last_offset;
+ if (length)
{
- offset = base_offset + ((offsets[l - 1] - base_offset)
- & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1));
- if (last_offset + last_size != offset)
+ HOST_WIDE_INT var_end_offset = 0;
+ HOST_WIDE_INT stack_start = offsets[length - 1];
+ gcc_assert (last_offset == stack_start);
+
+ for (int l = length - 2; l > 0; l -= 2)
{
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (last_offset - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- prev_offset = last_offset;
- asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
- last_offset = offset;
- last_size = 0;
+ HOST_WIDE_INT var_offset = offsets[l];
+ current_offset = var_offset;
+ var_end_offset = offsets[l - 1];
+ HOST_WIDE_INT rounded_size = ROUND_UP (var_end_offset - var_offset,
+ BITS_PER_UNIT);
+
+ /* Should we unpoison the variable? */
+ if (asan_handled_variables != NULL
+ && asan_handled_variables->contains (decl))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ const char *n = (DECL_NAME (decl)
+ ? IDENTIFIER_POINTER (DECL_NAME (decl))
+ : "<unknown>");
+ fprintf (dump_file, "Unpoisoning shadow stack for variable: "
+ "%s (%" PRId64 "B)\n", n,
+ var_end_offset - var_offset);
+ }
+
+ unsigned HOST_WIDE_INT s
+ = shadow_mem_size (current_offset - last_offset);
+ asan_clear_shadow (shadow_mem, s);
+ HOST_WIDE_INT shift
+ = shadow_mem_size (current_offset - last_offset + rounded_size);
+ shadow_mem = adjust_address (shadow_mem, VOIDmode, shift);
+ last_offset = var_offset + rounded_size;
+ current_offset = last_offset;
+ }
+
}
- last_size += base_offset + ((offsets[l - 2] - base_offset)
- & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1))
- - offset;
- }
- if (last_size)
- {
- shadow_mem = adjust_address (shadow_mem, VOIDmode,
- (last_offset - prev_offset)
- >> ASAN_SHADOW_SHIFT);
- asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT);
+
+ /* Handle last redzone. */
+ current_offset = offsets[0];
+ asan_clear_shadow (shadow_mem,
+ shadow_mem_size (current_offset - last_offset));
}
+ /* Clean-up set with instrumented stack variables. */
+ delete asan_handled_variables;
+ asan_handled_variables = NULL;
+ delete asan_used_labels;
+ asan_used_labels = NULL;
+
do_pending_stack_adjust ();
if (lab)
emit_label (lab);
@@ -1590,12 +1649,14 @@ insert_if_then_before_iter (gcond *cond,
gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT);
}
-/* Build
- (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */
+/* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset ().
+ If RETURN_ADDRESS is set to true, return memory location instread
+ of a value in the shadow memory. */
static tree
build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
- tree base_addr, tree shadow_ptr_type)
+ tree base_addr, tree shadow_ptr_type,
+ bool return_address = false)
{
tree t, uintptr_type = TREE_TYPE (base_addr);
tree shadow_type = TREE_TYPE (shadow_ptr_type);
@@ -1618,11 +1679,15 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location,
gimple_set_location (g, location);
gsi_insert_after (gsi, g, GSI_NEW_STMT);
- t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
- build_int_cst (shadow_ptr_type, 0));
- g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
- gimple_set_location (g, location);
- gsi_insert_after (gsi, g, GSI_NEW_STMT);
+ if (!return_address)
+ {
+ t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g),
+ build_int_cst (shadow_ptr_type, 0));
+ g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t);
+ gimple_set_location (g, location);
+ gsi_insert_after (gsi, g, GSI_NEW_STMT);
+ }
+
return gimple_assign_lhs (g);
}
@@ -1826,7 +1891,9 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
{
/* Automatic vars in the current function will be always
accessible. */
- if (decl_function_context (inner) == current_function_decl)
+ if (decl_function_context (inner) == current_function_decl
+ && (!asan_sanitize_use_after_scope ()
+ || !TREE_ADDRESSABLE (inner)))
return;
}
/* Always instrument external vars, they might be dynamically
@@ -2141,8 +2208,10 @@ transform_statements (void)
If the current instruction is a function call that
might free something, let's forget about the memory
references that got instrumented. Otherwise we might
- miss some instrumentation opportunities. */
- if (is_gimple_call (s) && !nonfreeing_call_p (s))
+ miss some instrumentation opportunities. Do the same
+ for a ASAN_MARK poisoning internal function. */
+ if (is_gimple_call (s)
+ && (!nonfreeing_call_p (s) || asan_mark_poison_p (s)))
empty_mem_ref_hash_table ();
gsi_next (&i);
@@ -2191,19 +2260,20 @@ asan_dynamic_init_call (bool after_p)
const void *__module_name;
uptr __has_dynamic_init;
__asan_global_source_location *__location;
+ char *__odr_indicator;
} type. */
static tree
asan_global_struct (void)
{
- static const char *field_names[7]
+ static const char *field_names[8]
= { "__beg", "__size", "__size_with_redzone",
- "__name", "__module_name", "__has_dynamic_init", "__location"};
- tree fields[7], ret;
+ "__name", "__module_name", "__has_dynamic_init", "__location", "__odr_indicator"};
+ tree fields[8], ret;
int i;
ret = make_node (RECORD_TYPE);
- for (i = 0; i < 7; i++)
+ for (i = 0; i < 8; i++)
{
fields[i]
= build_decl (UNKNOWN_LOCATION, FIELD_DECL,
@@ -2312,6 +2382,8 @@ asan_add_global (tree decl, tree type, vec<constructor_elt, va_gc> *v)
else
locptr = build_int_cst (uptr, 0);
CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, locptr);
+ /* TODO: support ODR indicators. */
+ CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0));
init = build_constructor (type, vinner);
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
}
@@ -2576,6 +2648,131 @@ asan_finish_file (void)
flag_sanitize |= SANITIZE_ADDRESS;
}
+/* Poison or unpoison (depending on IS_CLOBBER variable) shadow memory based
+ on SHADOW address. Newly added statements will be added to ITER with
+ given location LOC. We mark SIZE bytes in shadow memory, where
+ LAST_CHUNK_SIZE is greater than zero in situation where we are at the
+ end of a variable. */
+
+static void
+asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc,
+ tree shadow,
+ unsigned HOST_WIDE_INT base_addr_offset,
+ bool is_clobber, unsigned size,
+ unsigned last_chunk_size)
+{
+ tree shadow_ptr_type;
+
+ switch (size)
+ {
+ case 1:
+ shadow_ptr_type = shadow_ptr_types[0];
+ break;
+ case 2:
+ shadow_ptr_type = shadow_ptr_types[1];
+ break;
+ case 4:
+ shadow_ptr_type = shadow_ptr_types[2];
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ unsigned char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0;
+ unsigned HOST_WIDE_INT val = 0;
+ for (unsigned i = 0; i < size; ++i)
+ {
+ unsigned char shadow_c = c;
+ if (i == size - 1 && last_chunk_size && !is_clobber)
+ shadow_c = last_chunk_size;
+ val |= (unsigned HOST_WIDE_INT) shadow_c << (BITS_PER_UNIT * i);
+ }
+
+ /* Handle last chunk in unpoisoning. */
+ tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val);
+
+ tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow,
+ build_int_cst (shadow_ptr_type, base_addr_offset));
+
+ gimple *g = gimple_build_assign (dest, magic);
+ gimple_set_location (g, loc);
+ gsi_insert_after (iter, g, GSI_NEW_STMT);
+}
+
+/* Expand the ASAN_MARK builtins. */
+
+bool
+asan_expand_mark_ifn (gimple_stmt_iterator *iter)
+{
+ gimple *g = gsi_stmt (*iter);
+ location_t loc = gimple_location (g);
+ HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+ gcc_assert (flags < ASAN_MARK_LAST);
+ bool is_clobber = (flags & ASAN_MARK_CLOBBER) != 0;
+
+ tree base = gimple_call_arg (g, 1);
+ gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
+ tree decl = TREE_OPERAND (base, 0);
+ gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
+ if (asan_handled_variables == NULL)
+ asan_handled_variables = new hash_set<tree> (16);
+ asan_handled_variables->add (decl);
+ tree len = gimple_call_arg (g, 2);
+
+ gcc_assert (tree_fits_shwi_p (len));
+ unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
+ gcc_assert (size_in_bytes);
+
+ g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+ NOP_EXPR, base);
+ gimple_set_location (g, loc);
+ gsi_replace (iter, g, false);
+ tree base_addr = gimple_assign_lhs (g);
+
+ /* Generate direct emission if size_in_bytes is small. */
+ if (size_in_bytes <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD)
+ {
+ unsigned HOST_WIDE_INT shadow_size = shadow_mem_size (size_in_bytes);
+
+ tree shadow = build_shadow_mem_access (iter, loc, base_addr,
+ shadow_ptr_types[0], true);
+
+ for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;)
+ {
+ unsigned size = 1;
+ if (shadow_size - offset >= 4)
+ size = 4;
+ else if (shadow_size - offset >= 2)
+ size = 2;
+
+ unsigned HOST_WIDE_INT last_chunk_size = 0;
+ unsigned HOST_WIDE_INT s = (offset + size) * ASAN_SHADOW_GRANULARITY;
+ if (s > size_in_bytes)
+ last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes);
+
+ asan_store_shadow_bytes (iter, loc, shadow, offset, is_clobber,
+ size, last_chunk_size);
+ offset += size;
+ }
+ }
+ else
+ {
+ g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+ NOP_EXPR, len);
+ gimple_set_location (g, loc);
+ gsi_insert_before (iter, g, GSI_SAME_STMT);
+ tree sz_arg = gimple_assign_lhs (g);
+
+ tree fun = builtin_decl_implicit (is_clobber ? BUILT_IN_ASAN_CLOBBER_N
+ : BUILT_IN_ASAN_UNCLOBBER_N);
+ g = gimple_build_call (fun, 2, base_addr, sz_arg);
+ gimple_set_location (g, loc);
+ gsi_insert_after (iter, g, GSI_NEW_STMT);
+ }
+
+ return false;
+}
+
/* Expand the ASAN_{LOAD,STORE} builtins. */
bool
diff --git a/gcc/asan.h b/gcc/asan.h
index 7ec693f2b3c..9cf5904618b 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -29,6 +29,7 @@ extern bool asan_protect_global (tree);
extern void initialize_sanitizer_builtins (void);
extern tree asan_dynamic_init_call (bool);
extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
+extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
extern gimple_stmt_iterator create_cond_insert_point
(gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
@@ -36,9 +37,14 @@ extern gimple_stmt_iterator create_cond_insert_point
/* Alias set for accessing the shadow memory. */
extern alias_set_type asan_shadow_set;
+/* Hash set of labels that are either used in a goto, or their address
+ has been taken. */
+extern hash_set <tree> *asan_used_labels;
+
/* Shadow memory is found at
(address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */
#define ASAN_SHADOW_SHIFT 3
+#define ASAN_SHADOW_GRANULARITY (1UL << ASAN_SHADOW_SHIFT)
/* Red zone size, stack and global variables are padded by ASAN_RED_ZONE_SIZE
up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes. */
@@ -50,22 +56,31 @@ extern alias_set_type asan_shadow_set;
the frame. Middle is for padding in between variables, right is
above the last protected variable and partial immediately after variables
up to ASAN_RED_ZONE_SIZE alignment. */
-#define ASAN_STACK_MAGIC_LEFT 0xf1
-#define ASAN_STACK_MAGIC_MIDDLE 0xf2
-#define ASAN_STACK_MAGIC_RIGHT 0xf3
-#define ASAN_STACK_MAGIC_PARTIAL 0xf4
-#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5
+#define ASAN_STACK_MAGIC_LEFT 0xf1
+#define ASAN_STACK_MAGIC_MIDDLE 0xf2
+#define ASAN_STACK_MAGIC_RIGHT 0xf3
+#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5
+#define ASAN_STACK_MAGIC_USE_AFTER_SCOPE 0xf8
#define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
#define ASAN_STACK_RETIRED_MAGIC 0x45e0360e
-/* Return true if DECL should be guarded on the stack. */
-
-static inline bool
-asan_protect_stack_decl (tree decl)
+/* Various flags for Asan builtins. */
+enum asan_check_flags
{
- return DECL_P (decl) && !DECL_ARTIFICIAL (decl);
-}
+ ASAN_CHECK_STORE = 1 << 0,
+ ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
+ ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
+ ASAN_CHECK_LAST = 1 << 3
+};
+
+/* Flags for Asan check builtins. */
+enum asan_mark_flags
+{
+ ASAN_MARK_CLOBBER = 1 << 0,
+ ASAN_MARK_UNCLOBBER = 1 << 1,
+ ASAN_MARK_LAST = 1 << 2
+};
/* Return the size of padding needed to insert after a protected
decl of SIZE. */
@@ -81,6 +96,8 @@ extern bool set_asan_shadow_offset (const char *);
extern void set_sanitized_sections (const char *);
+extern bool asan_sanitize_stack_p (void);
+
/* Return TRUE if builtin with given FCODE will be intercepted by
libasan. */
@@ -103,6 +120,36 @@ asan_intercepted_p (enum built_in_function fcode)
|| fcode == BUILT_IN_STRNCASECMP
|| fcode == BUILT_IN_STRNCAT
|| fcode == BUILT_IN_STRNCMP
+ || fcode == BUILT_IN_STRCSPN
+ || fcode == BUILT_IN_STRPBRK
+ || fcode == BUILT_IN_STRSPN
+ || fcode == BUILT_IN_STRSTR
|| fcode == BUILT_IN_STRNCPY;
}
+
+/* Return TRUE if we should instrument for use-after-scope sanity checking. */
+
+static inline bool
+asan_sanitize_use_after_scope (void)
+{
+ return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
+}
+
+static inline bool
+asan_no_sanitize_address_p (void)
+{
+ return lookup_attribute ("no_sanitize_address",
+ DECL_ATTRIBUTES (current_function_decl));
+}
+
+/* Return true if DECL should be guarded on the stack. */
+
+static inline bool
+asan_protect_stack_decl (tree decl)
+{
+ return DECL_P (decl)
+ && (!DECL_ARTIFICIAL (decl)
+ || (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl)));
+}
+
#endif /* TREE_ASAN */
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 15d7488ba04..5207c34c912 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,41 @@
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ * c.opt (Wc++1z-compat): New.
+ * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_noexcept_function_type.
+
+2016-11-07 Martin Liska <mliska@suse.cz>
+
+ * c-warn.c (warn_for_unused_label): Save all labels used
+ in goto or in &label.
+
+2016-11-03 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Correct
+ __cpp_inheriting_constructors.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * c-cppbuiltin.c (c_cpp_builtins): Update
+ __cpp_inheriting_constructors.
+
+ * c.opt (-fnew-inheriting-ctors): New.
+ * c-opts.c: Default to on for ABI 11+.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77948
+ * c.opt (fext-numeric-literals): Add Var and Init.
+ * c-opts.c (c_common_handle_option): Don't clear
+ cpp_opts->ext_numeric_literals for -std=c++{11,14,1z}.
+ (c_common_post_options): Clear it here if not set
+ explicitly.
+
+2016-10-28 Aldy Hernandez <aldyh@redhat.com>
+
+ PR debug/77773
+ * c-pretty-print.c (simple_type_specifier): Do not dereference `t'
+ if NULL.
+
2016-10-25 Jakub Jelinek <jakub@redhat.com>
* c-common.h (enum rid): Add RID_BUILTIN_LAUNDER.
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 7d689a9c0ff..55dbf44d34f 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -904,7 +904,10 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_initializer_lists=200806");
cpp_define (pfile, "__cpp_delegating_constructors=200604");
cpp_define (pfile, "__cpp_nsdmi=200809");
- cpp_define (pfile, "__cpp_inheriting_constructors=200802");
+ if (!flag_new_inheriting_ctors)
+ cpp_define (pfile, "__cpp_inheriting_constructors=200802");
+ else
+ cpp_define (pfile, "__cpp_inheriting_constructors=201511");
cpp_define (pfile, "__cpp_ref_qualifiers=200710");
cpp_define (pfile, "__cpp_alias_templates=200704");
}
@@ -938,6 +941,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_inline_variables=201606");
cpp_define (pfile, "__cpp_aggregate_bases=201603");
cpp_define (pfile, "__cpp_deduction_guides=201606");
+ cpp_define (pfile, "__cpp_noexcept_function_type=201510");
}
if (flag_concepts)
cpp_define (pfile, "__cpp_concepts=201507");
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index c39930708d6..de260e7dcee 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -624,31 +624,19 @@ c_common_handle_option (size_t scode, const char *arg, int value,
case OPT_std_c__11:
case OPT_std_gnu__11:
if (!preprocessing_asm_p)
- {
- set_std_cxx11 (code == OPT_std_c__11 /* ISO */);
- if (code == OPT_std_c__11)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx11 (code == OPT_std_c__11 /* ISO */);
break;
case OPT_std_c__14:
case OPT_std_gnu__14:
if (!preprocessing_asm_p)
- {
- set_std_cxx14 (code == OPT_std_c__14 /* ISO */);
- if (code == OPT_std_c__14)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx14 (code == OPT_std_c__14 /* ISO */);
break;
case OPT_std_c__1z:
case OPT_std_gnu__1z:
if (!preprocessing_asm_p)
- {
- set_std_cxx1z (code == OPT_std_c__1z /* ISO */);
- if (code == OPT_std_c__1z)
- cpp_opts->ext_numeric_literals = 0;
- }
+ set_std_cxx1z (code == OPT_std_c__1z /* ISO */);
break;
case OPT_std_c90:
@@ -914,6 +902,12 @@ c_common_post_options (const char **pfilename)
if (flag_abi_version == 0)
flag_abi_version = 11;
+ /* By default, enable the new inheriting constructor semantics along with ABI
+ 11. New and old should coexist fine, but it is a change in what
+ artificial symbols are generated. */
+ if (!global_options_set.x_flag_new_inheriting_ctors)
+ flag_new_inheriting_ctors = abi_version_at_least (11);
+
if (cxx_dialect >= cxx11)
{
/* If we're allowing C++0x constructs, don't warn about C++98
@@ -923,6 +917,11 @@ c_common_post_options (const char **pfilename)
if (warn_narrowing == -1)
warn_narrowing = 1;
+
+ /* Unless -f{,no-}ext-numeric-literals has been used explicitly,
+ for -std=c++{11,14,1z} default to -fno-ext-numeric-literals. */
+ if (flag_iso && !global_options_set.x_flag_ext_numeric_literals)
+ cpp_opts->ext_numeric_literals = 0;
}
else if (warn_narrowing == -1)
warn_narrowing = 0;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index 90428cac183..7ad59003456 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -344,14 +344,17 @@ c_pretty_printer::simple_type_specifier (tree t)
else
{
int prec = TYPE_PRECISION (t);
+ tree common_t;
if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (t)))
- t = c_common_type_for_mode (TYPE_MODE (t), TYPE_SATURATING (t));
+ common_t = c_common_type_for_mode (TYPE_MODE (t),
+ TYPE_SATURATING (t));
else
- t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t));
- if (TYPE_NAME (t))
+ common_t = c_common_type_for_mode (TYPE_MODE (t),
+ TYPE_UNSIGNED (t));
+ if (common_t && TYPE_NAME (common_t))
{
- simple_type_specifier (t);
- if (TYPE_PRECISION (t) != prec)
+ simple_type_specifier (common_t);
+ if (TYPE_PRECISION (common_t) != prec)
{
pp_colon (this);
pp_decimal_int (this, prec);
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 904f6d3cf4f..18ee24787a9 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "diagnostic.h"
#include "intl.h"
-
+#include "asan.h"
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
@@ -1627,6 +1627,13 @@ warn_for_unused_label (tree label)
else
warning (OPT_Wunused_label, "label %q+D declared but not defined", label);
}
+ else if (asan_sanitize_use_after_scope ())
+ {
+ if (asan_used_labels == NULL)
+ asan_used_labels = new hash_set<tree> (16);
+
+ asan_used_labels->add (label);
+ }
}
/* Warn for division by zero according to the value of DIVISOR. LOC
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 458d453cdd8..213353b9abd 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -360,6 +360,13 @@ Wc++14-compat
C++ ObjC++ Var(warn_cxx14_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014.
+Wc++1z-compat
+C++ ObjC++ Var(warn_cxx1z_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
+Warn about C++ constructs whose meaning differs between ISO C++ 2014 and (forthcoming) ISO C++ 201z(7?).
+
+Wc++17-compat
+C++ ObjC++ Warning Alias(Wc++1z-compat) Undocumented
+
Wcast-qual
C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
Warn about casts which discard qualifiers.
@@ -1362,6 +1369,10 @@ fimplicit-templates
C++ ObjC++ Var(flag_implicit_templates) Init(1)
Emit implicit instantiations of templates.
+fnew-inheriting-ctors
+C++ ObjC++ Var(flag_new_inheriting_ctors) Init(1)
+Implement C++17 inheriting constructor semantics.
+
ffriend-injection
C++ ObjC++ Var(flag_friend_injection)
Inject friend functions into enclosing namespace.
@@ -1705,7 +1716,7 @@ C ObjC C++ ObjC++ Joined
-femit-struct-debug-detailed=<spec-list> Detailed reduced debug info for structs.
fext-numeric-literals
-C++ ObjC++
+C++ ObjC++ Var(flag_ext_numeric_literals) Init(1)
Interpret imaginary, fixed-point, or other gnu number suffix as the corresponding
number literal rather than a user-defined number literal.
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 725afcfefa0..ee50c304b5f 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,9 @@
+2016-09-11 Le-Chun Wu <lcwu@google.com>
+ Mark Wielaard <mjw@redhat.com>
+
+ * c-decl.c (warn_if_shadowing): Use the warning code corresponding
+ to the given -Wshadow= variant.
+
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* c-typeck.c: Include memmodel.h.
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 136f304ca30..3e1b7a4016b 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2735,7 +2735,9 @@ warn_if_shadowing (tree new_decl)
struct c_binding *b;
/* Shadow warnings wanted? */
- if (!warn_shadow
+ if (!(warn_shadow
+ || warn_shadow_local
+ || warn_shadow_compatible_local)
/* No shadow warnings for internally generated vars. */
|| DECL_IS_BUILTIN (new_decl)
/* No shadow warnings for vars made for inlining. */
@@ -2759,9 +2761,23 @@ warn_if_shadowing (tree new_decl)
break;
}
else if (TREE_CODE (old_decl) == PARM_DECL)
- warned = warning (OPT_Wshadow,
- "declaration of %q+D shadows a parameter",
- new_decl);
+ {
+ enum opt_code warning_code;
+
+ /* If '-Wshadow=compatible-local' is specified without other
+ -Wshadow= flags, we will warn only when the types of the
+ shadowing variable (i.e. new_decl) and the shadowed variable
+ (old_decl) are compatible. */
+ if (warn_shadow)
+ warning_code = OPT_Wshadow;
+ else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
+ warning_code = OPT_Wshadow_compatible_local;
+ else
+ warning_code = OPT_Wshadow_local;
+ warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
+ "declaration of %qD shadows a parameter",
+ new_decl);
+ }
else if (DECL_FILE_SCOPE_P (old_decl))
{
/* Do not warn if a variable shadows a function, unless
@@ -2784,8 +2800,23 @@ warn_if_shadowing (tree new_decl)
break;
}
else
- warned = warning (OPT_Wshadow, "declaration of %q+D shadows a "
- "previous local", new_decl);
+ {
+ enum opt_code warning_code;
+
+ /* If '-Wshadow=compatible-local' is specified without other
+ -Wshadow= flags, we will warn only when the types of the
+ shadowing variable (i.e. new_decl) and the shadowed variable
+ (old_decl) are compatible. */
+ if (warn_shadow)
+ warning_code = OPT_Wshadow;
+ else if (comptypes (TREE_TYPE (old_decl), TREE_TYPE (new_decl)))
+ warning_code = OPT_Wshadow_compatible_local;
+ else
+ warning_code = OPT_Wshadow_local;
+ warned = warning_at (DECL_SOURCE_LOCATION (new_decl), warning_code,
+ "declaration of %qD shadows a previous local",
+ new_decl);
+ }
if (warned)
inform (DECL_SOURCE_LOCATION (old_decl),
diff --git a/gcc/ccmp.c b/gcc/ccmp.c
index 615b7e653f2..14222ca5942 100644
--- a/gcc/ccmp.c
+++ b/gcc/ccmp.c
@@ -122,7 +122,7 @@ ccmp_candidate_p (gimple *g)
GEN_SEQ returns all compare insns. */
static rtx
expand_ccmp_next (gimple *g, tree_code code, rtx prev,
- rtx *prep_seq, rtx *gen_seq)
+ rtx_insn **prep_seq, rtx_insn **gen_seq)
{
rtx_code rcode;
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (g)));
@@ -149,10 +149,8 @@ expand_ccmp_next (gimple *g, tree_code code, rtx prev,
PREP_SEQ returns all insns to prepare opearand.
GEN_SEQ returns all compare insns. */
static rtx
-expand_ccmp_expr_1 (gimple *g, rtx *prep_seq, rtx *gen_seq)
+expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq)
{
- rtx prep_seq_1, gen_seq_1;
- rtx prep_seq_2, gen_seq_2;
tree exp = gimple_assign_rhs_to_tree (g);
tree_code code = TREE_CODE (exp);
gimple *gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0));
@@ -180,6 +178,7 @@ expand_ccmp_expr_1 (gimple *g, rtx *prep_seq, rtx *gen_seq)
rcode0 = get_rtx_code (code0, unsignedp0);
rcode1 = get_rtx_code (code1, unsignedp1);
+ rtx_insn *prep_seq_1, *gen_seq_1;
tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0,
gimple_assign_rhs1 (gs0),
gimple_assign_rhs2 (gs0));
@@ -187,14 +186,15 @@ expand_ccmp_expr_1 (gimple *g, rtx *prep_seq, rtx *gen_seq)
if (tmp != NULL)
{
ret = expand_ccmp_next (gs1, code, tmp, &prep_seq_1, &gen_seq_1);
- cost1 = seq_cost (safe_as_a <rtx_insn *> (prep_seq_1), speed_p);
- cost1 += seq_cost (safe_as_a <rtx_insn *> (gen_seq_1), speed_p);
+ cost1 = seq_cost (prep_seq_1, speed_p);
+ cost1 += seq_cost (gen_seq_1, speed_p);
}
/* FIXME: Temporary workaround for PR69619.
Avoid exponential compile time due to expanding gs0 and gs1 twice.
If gs0 and gs1 are complex, the cost will be high, so avoid
reevaluation if above an arbitrary threshold. */
+ rtx_insn *prep_seq_2, *gen_seq_2;
if (tmp == NULL || cost1 < COSTS_N_INSNS (25))
tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1,
gimple_assign_rhs1 (gs1),
@@ -207,8 +207,8 @@ expand_ccmp_expr_1 (gimple *g, rtx *prep_seq, rtx *gen_seq)
{
ret2 = expand_ccmp_next (gs0, code, tmp2, &prep_seq_2,
&gen_seq_2);
- cost2 = seq_cost (safe_as_a <rtx_insn *> (prep_seq_2), speed_p);
- cost2 += seq_cost (safe_as_a <rtx_insn *> (gen_seq_2), speed_p);
+ cost2 = seq_cost (prep_seq_2, speed_p);
+ cost2 += seq_cost (gen_seq_2, speed_p);
}
if (cost2 < cost1)
@@ -262,14 +262,13 @@ expand_ccmp_expr (gimple *g)
{
rtx_insn *last;
rtx tmp;
- rtx prep_seq, gen_seq;
-
- prep_seq = gen_seq = NULL_RTX;
if (!ccmp_candidate_p (g))
return NULL_RTX;
last = get_last_insn ();
+
+ rtx_insn *prep_seq = NULL, *gen_seq = NULL;
tmp = expand_ccmp_expr_1 (g, &prep_seq, &gen_seq);
if (tmp)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 430ad38f096..7ffb5585b76 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -868,18 +868,6 @@ union_stack_vars (size_t a, size_t b)
}
}
-/* Return true if the current function should have its stack frame
- protected by address sanitizer. */
-
-static inline bool
-asan_sanitize_stack_p (void)
-{
- return ((flag_sanitize & SANITIZE_ADDRESS)
- && ASAN_STACK
- && !lookup_attribute ("no_sanitize_address",
- DECL_ATTRIBUTES (current_function_decl)));
-}
-
/* A subroutine of expand_used_vars. Binpack the variables into
partitions constrained by the interference graph. The overall
algorithm used is as follows:
@@ -941,7 +929,8 @@ partition_stack_vars (void)
sizes, as the shorter vars wouldn't be adequately protected.
Don't do that for "large" (unsupported) alignment objects,
those aren't protected anyway. */
- if (asan_sanitize_stack_p () && isize != jsize
+ if ((asan_sanitize_stack_p ())
+ && isize != jsize
&& ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
break;
@@ -1128,7 +1117,8 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
{
base = virtual_stack_vars_rtx;
- if (asan_sanitize_stack_p () && pred)
+ if ((asan_sanitize_stack_p ())
+ && pred)
{
HOST_WIDE_INT prev_offset
= align_base (frame_offset,
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 813f7cee092..d2719db0019 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -240,17 +240,15 @@ delete_insn_and_edges (rtx_insn *insn)
insns that cannot be removed to NULL. */
void
-delete_insn_chain (rtx start, rtx finish, bool clear_bb)
+delete_insn_chain (rtx start, rtx_insn *finish, bool clear_bb)
{
- rtx_insn *prev, *current;
-
/* Unchain the insns one by one. It would be quicker to delete all of these
with a single unchaining, rather than one at a time, but we need to keep
the NOTE's. */
- current = safe_as_a <rtx_insn *> (finish);
+ rtx_insn *current = finish;
while (1)
{
- prev = PREV_INSN (current);
+ rtx_insn *prev = PREV_INSN (current);
if (NOTE_P (current) && !can_delete_note_p (as_a <rtx_note *> (current)))
;
else
diff --git a/gcc/cfgrtl.h b/gcc/cfgrtl.h
index d81928a6ebf..f4c139605a2 100644
--- a/gcc/cfgrtl.h
+++ b/gcc/cfgrtl.h
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
extern void delete_insn (rtx);
extern bool delete_insn_and_edges (rtx_insn *);
-extern void delete_insn_chain (rtx, rtx, bool);
+extern void delete_insn_chain (rtx, rtx_insn *, bool);
extern basic_block create_basic_block_structure (rtx_insn *, rtx_insn *,
rtx_note *, basic_block);
extern void compute_bb_for_insn (void);
diff --git a/gcc/combine.c b/gcc/combine.c
index 64413b4436e..69020561c31 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -104,10 +104,6 @@ along with GCC; see the file COPYING3. If not see
#include "rtl-iter.h"
#include "print-rtl.h"
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
/* Number of attempts to combine instructions in this function. */
static int combine_attempts;
@@ -7757,7 +7753,8 @@ extract_left_shift (rtx x, int count)
IN_CODE says what kind of expression we are processing. Normally, it is
SET. In a memory address it is MEM. When processing the arguments of
- a comparison or a COMPARE against zero, it is COMPARE. */
+ a comparison or a COMPARE against zero, it is COMPARE, or EQ if more
+ precisely it is an equality comparison against zero. */
rtx
make_compound_operation (rtx x, enum rtx_code in_code)
@@ -7771,6 +7768,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
rtx new_rtx = 0;
rtx tem;
const char *fmt;
+ bool equality_comparison = false;
/* PR rtl-optimization/70944. */
if (VECTOR_MODE_P (mode))
@@ -7780,6 +7778,11 @@ make_compound_operation (rtx x, enum rtx_code in_code)
address, we stay there. If we have a comparison, set to COMPARE,
but once inside, go back to our default of SET. */
+ if (in_code == EQ)
+ {
+ equality_comparison = true;
+ in_code = COMPARE;
+ }
next_code = (code == MEM ? MEM
: ((code == COMPARE || COMPARISON_P (x))
&& XEXP (x, 1) == const0_rtx) ? COMPARE
@@ -7988,11 +7991,12 @@ make_compound_operation (rtx x, enum rtx_code in_code)
/* If we are in a comparison and this is an AND with a power of two,
convert this into the appropriate bit extract. */
else if (in_code == COMPARE
- && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0)
+ && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0
+ && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1))
new_rtx = make_extraction (mode,
- make_compound_operation (XEXP (x, 0),
- next_code),
- i, NULL_RTX, 1, 1, 0, 1);
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ i, NULL_RTX, 1, 1, 0, 1);
/* If the one operand is a paradoxical subreg of a register or memory and
the constant (limited to the smaller mode) has only zero bits where
@@ -11106,9 +11110,10 @@ recog_for_combine_1 (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
Return whether anything was so changed. */
static bool
-change_zero_ext (rtx *src)
+change_zero_ext (rtx pat)
{
bool changed = false;
+ rtx *src = &SET_SRC (pat);
subrtx_ptr_iterator::array_type array;
FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
@@ -11140,6 +11145,14 @@ change_zero_ext (rtx *src)
size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)));
x = SUBREG_REG (XEXP (x, 0));
}
+ else if (GET_CODE (x) == ZERO_EXTEND
+ && SCALAR_INT_MODE_P (mode)
+ && REG_P (XEXP (x, 0))
+ && HARD_REGISTER_P (XEXP (x, 0)))
+ {
+ size = GET_MODE_PRECISION (GET_MODE (XEXP (x, 0)));
+ x = gen_rtx_REG (mode, REGNO (XEXP (x, 0)));
+ }
else
continue;
@@ -11150,6 +11163,47 @@ change_zero_ext (rtx *src)
changed = true;
}
+ if (changed)
+ FOR_EACH_SUBRTX_PTR (iter, array, src, NONCONST)
+ {
+ rtx x = **iter;
+ if (COMMUTATIVE_ARITH_P (x)
+ && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+ {
+ rtx tem = XEXP (x, 0);
+ SUBST (XEXP (x, 0), XEXP (x, 1));
+ SUBST (XEXP (x, 1), tem);
+ }
+ }
+
+ rtx *dst = &SET_DEST (pat);
+ if (GET_CODE (*dst) == ZERO_EXTRACT
+ && REG_P (XEXP (*dst, 0))
+ && CONST_INT_P (XEXP (*dst, 1))
+ && CONST_INT_P (XEXP (*dst, 2)))
+ {
+ rtx reg = XEXP (*dst, 0);
+ int width = INTVAL (XEXP (*dst, 1));
+ int offset = INTVAL (XEXP (*dst, 2));
+ machine_mode mode = GET_MODE (reg);
+ int reg_width = GET_MODE_PRECISION (mode);
+ if (BITS_BIG_ENDIAN)
+ offset = reg_width - width - offset;
+
+ wide_int mask = wi::shifted_mask (offset, width, true, reg_width);
+ rtx x = gen_rtx_AND (mode, reg, immed_wide_int_const (mask, mode));
+ rtx y = simplify_gen_binary (ASHIFT, mode, SET_SRC (pat),
+ GEN_INT (offset));
+ wide_int mask2 = wi::shifted_mask (offset, width, false, reg_width);
+ y = simplify_gen_binary (AND, mode, y,
+ immed_wide_int_const (mask2, mode));
+ rtx z = simplify_gen_binary (IOR, mode, x, y);
+ SUBST (SET_DEST (pat), reg);
+ SUBST (SET_SRC (pat), z);
+
+ changed = true;
+ }
+
return changed;
}
@@ -11172,7 +11226,7 @@ change_zero_ext (rtx *src)
static int
recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
{
- rtx pat = PATTERN (insn);
+ rtx pat = *pnewpat;
int insn_code_number = recog_for_combine_1 (pnewpat, insn, pnotes);
if (insn_code_number >= 0 || check_asm_operands (pat))
return insn_code_number;
@@ -11181,7 +11235,7 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
bool changed = false;
if (GET_CODE (pat) == SET)
- changed = change_zero_ext (&SET_SRC (pat));
+ changed = change_zero_ext (pat);
else if (GET_CODE (pat) == PARALLEL)
{
int i;
@@ -11189,7 +11243,7 @@ recog_for_combine (rtx *pnewpat, rtx_insn *insn, rtx *pnotes)
{
rtx set = XVECEXP (pat, 0, i);
if (GET_CODE (set) == SET)
- changed |= change_zero_ext (&SET_SRC (set));
+ changed |= change_zero_ext (set);
}
}
@@ -11367,6 +11421,7 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
const_op -= 1;
code = LE;
/* ... fall through to LE case below. */
+ gcc_fallthrough ();
}
else
break;
@@ -11396,6 +11451,7 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
const_op -= 1;
code = GT;
/* ... fall through to GT below. */
+ gcc_fallthrough ();
}
else
break;
@@ -12413,19 +12469,23 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
care bits and we can assume they have any convenient value. So
making the transformation is safe.
- 2. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is not defined.
+ 2. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is UNKNOWN.
In this case the upper bits of op0 are undefined. We should not make
the simplification in that case as we do not know the contents of
those bits.
- 3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is defined and not
- UNKNOWN. In that case we know those bits are zeros or ones. We must
- also be sure that they are the same as the upper bits of op1.
+ 3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is not UNKNOWN.
+ In that case we know those bits are zeros or ones. We must also be
+ sure that they are the same as the upper bits of op1.
We can never remove a SUBREG for a non-equality comparison because
the sign bit is in a different place in the underlying object. */
- op0 = make_compound_operation (op0, op1 == const0_rtx ? COMPARE : SET);
+ rtx_code op0_mco_code = SET;
+ if (op1 == const0_rtx)
+ op0_mco_code = code == NE || code == EQ ? EQ : COMPARE;
+
+ op0 = make_compound_operation (op0, op0_mco_code);
op1 = make_compound_operation (op1, SET);
if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
diff --git a/gcc/common.opt b/gcc/common.opt
index 20dbfc1d6a1..314145a09d3 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -58,10 +58,6 @@ int flag_incremental_link = 0
Variable
int flag_complex_method = 1
-; Nonzero if subexpressions must be evaluated from left-to-right.
-Variable
-int flag_evaluation_order = 0
-
; Language specific warning pass for unused results.
Variable
bool flag_warn_unused_result = false
@@ -668,7 +664,25 @@ Warn about returning a pointer/reference to a local or temporary variable.
Wshadow
Common Var(warn_shadow) Warning
-Warn when one local variable shadows another.
+Warn when one variable shadows another. Same as -Wshadow=global.
+
+Wshadow=global
+Common Warning Alias(Wshadow)
+Warn when one variable shadows another (globally).
+
+Wshadow=local
+Common Var(warn_shadow_local) Warning EnabledBy(Wshadow)
+Warn when one local variable shadows another local variable or parameter.
+
+Wshadow-local
+Common Warning Undocumented Alias(Wshadow=local)
+
+Wshadow=compatible-local
+Common Var(warn_shadow_compatible_local) Warning EnabledBy(Wshadow=local)
+Warn when one local variable shadows another local variable or parameter of compatible type.
+
+Wshadow-compatible-local
+Common Warning Undocumented Alias(Wshadow=compatible-local)
Wstack-protector
Common Var(warn_stack_protect) Warning
@@ -889,7 +903,8 @@ Driver Undocumented
; identity, such as ia32 calling convention attributes (stdcall, etc.)
; Default in G++ 6 (set in c_common_post_options).
;
-; 11: The version of the ABI that corrects mangling of sizeof... expressions.
+; 11: The version of the ABI that corrects mangling of sizeof... expressions
+; and introduces new inheriting constructor handling.
; Default in G++ 7.
;
; Additional positive integers will be assigned as new versions of
@@ -967,6 +982,9 @@ fsanitize-recover
Common Report
This switch is deprecated; use -fsanitize-recover= instead.
+fsanitize-address-use-after-scope
+Common Driver Report Var(flag_sanitize_address_use_after_scope) Init(0)
+
fsanitize-undefined-trap-on-error
Common Driver Report Var(flag_sanitize_undefined_trap_on_error) Init(0)
Use trap instead of a library function for undefined behavior sanitization.
diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
index 2820de9ae8d..c66f13152ce 100644
--- a/gcc/compare-elim.c
+++ b/gcc/compare-elim.c
@@ -627,7 +627,7 @@ try_eliminate_compare (struct comparison *cmp)
/* We've reached PREV_CLOBBER without finding a modification of IN_A.
Validate that PREV_CLOBBER itself does in fact refer to IN_A. Do
recall that we've already validated the shape of PREV_CLOBBER. */
- rtx insn = cmp->prev_clobber;
+ rtx_insn *insn = cmp->prev_clobber;
x = XVECEXP (PATTERN (insn), 0, 0);
if (rtx_equal_p (SET_DEST (x), in_a))
cmp_src = SET_SRC (x);
diff --git a/gcc/config.gcc b/gcc/config.gcc
index f9148dd95ce..3e0be229765 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1049,6 +1049,7 @@ arm-wrs-vxworks)
tm_file="elfos.h arm/elf.h arm/aout.h ${tm_file} vx-common.h vxworks.h arm/vxworks.h"
extra_options="${extra_options} arm/vxworks.opt"
tmake_file="${tmake_file} arm/t-arm arm/t-vxworks"
+ target_cpu_cname="arm6"
;;
arm*-*-freebsd*) # ARM FreeBSD EABI
tm_file="dbxelf.h elfos.h ${fbsd_tm_file} arm/elf.h"
@@ -1061,11 +1062,15 @@ arm*-*-freebsd*) # ARM FreeBSD EABI
tm_file="${tm_file} arm/bpabi.h arm/freebsd.h arm/aout.h arm/arm.h"
case $target in
armv6*-*-freebsd*)
+ target_cpu_cname="arm1176jzfs"
tm_defines="${tm_defines} TARGET_FREEBSD_ARMv6=1"
if test $fbsd_major -ge 11; then
tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1"
fi
;;
+ *)
+ target_cpu_cname="arm9"
+ ;;
esac
with_tls=${with_tls:-gnu}
;;
@@ -1073,6 +1078,7 @@ arm*-*-netbsdelf*)
tm_file="dbxelf.h elfos.h netbsd.h netbsd-elf.h arm/elf.h arm/aout.h ${tm_file} arm/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
tmake_file="${tmake_file} arm/t-arm"
+ target_cpu_cname="arm6"
;;
arm*-*-linux-*) # ARM GNU/Linux with ELF
tm_file="dbxelf.h elfos.h gnu-user.h linux.h linux-android.h glibc-stdint.h arm/elf.h arm/linux-gas.h arm/linux-elf.h"
@@ -1084,6 +1090,7 @@ arm*-*-linux-*) # ARM GNU/Linux with ELF
esac
tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi"
tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h arm/aout.h vxworks-dummy.h arm/arm.h"
+ target_cpu_cname="arm10tdmi"
# Define multilib configuration for arm-linux-androideabi.
case ${target} in
*-androideabi)
@@ -1098,6 +1105,7 @@ arm*-*-uclinux*eabi*) # ARM ucLinux
tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/linux-gas.h arm/uclinux-elf.h glibc-stdint.h"
tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf arm/t-bpabi"
tm_file="$tm_file arm/bpabi.h arm/uclinux-eabi.h arm/aout.h vxworks-dummy.h arm/arm.h"
+ target_cpu_cname="arm7tdmi"
# The EABI requires the use of __cxa_atexit.
default_use_cxa_atexit=yes
;;
@@ -1106,6 +1114,7 @@ arm*-*-phoenix*)
tm_file="${tm_file} newlib-stdint.h phoenix.h"
tm_file="${tm_file} arm/aout.h arm/arm.h"
tmake_file="${tmake_file} arm/t-arm arm/t-bpabi arm/t-phoenix"
+ target_cpu_cname="arm7tdmi"
;;
arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*)
case ${target} in
@@ -1115,6 +1124,7 @@ arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*)
default_use_cxa_atexit=yes
tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/bpabi.h"
tmake_file="${tmake_file} arm/t-arm arm/t-arm-elf"
+ target_cpu_cname="arm7tdmi"
case ${target} in
arm*-*-eabi*)
tm_file="$tm_file newlib-stdint.h"
@@ -1130,6 +1140,7 @@ arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*)
# We do not include t-bpabi for Symbian OS because the system
# provides its own implementation of the BPABI functions.
tmake_file="${tmake_file} arm/t-symbian"
+ target_cpu_cname="arm10tdmi"
;;
esac
tm_file="${tm_file} arm/aout.h vxworks-dummy.h arm/arm.h"
@@ -3638,8 +3649,10 @@ case "${target}" in
${srcdir}/config/arm/arm-cores.def | \
sed -e 's/^[^,]*,[ ]*//' | \
sed -e 's/,.*$//'`
- eval "target_${which}_cname=$new_val"
- echo "For $val real value is $new_val"
+ if [ x"$val" != x ] ; then
+ eval "target_${which}_cname=$new_val"
+ echo "For $val real value is $new_val"
+ fi
true
else
echo "Unknown CPU used in --with-$which=$val" 1>&2
@@ -4124,16 +4137,6 @@ case "${target}" in
(at="/opt/$with_advance_toolchain"
echo "/* Use Advance Toolchain $at */"
echo
- echo "#ifndef USE_AT_INCLUDE_FILES"
- echo "#define USE_AT_INCLUDE_FILES 1"
- echo "#endif"
- echo
- echo "#if USE_AT_INCLUDE_FILES"
- echo "#undef INCLUDE_EXTRA_SPEC"
- echo "#define INCLUDE_EXTRA_SPEC" \
- "\"-isystem $at/include\""
- echo "#endif"
- echo
echo "#undef LINK_OS_EXTRA_SPEC32"
echo "#define LINK_OS_EXTRA_SPEC32" \
"\"%(link_os_new_dtags)" \
@@ -4313,7 +4316,7 @@ case ${target} in
arm*-*-*)
if test x$target_cpu_cname = x
then
- target_cpu_default2=TARGET_CPU_generic
+ target_cpu_default2=TARGET_CPU_arm6
else
target_cpu_default2=TARGET_CPU_$target_cpu_cname
fi
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 9ce7f000509..89bdcb3f7ed 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -5705,6 +5705,26 @@
[(set_attr "type" "crypto_sha1_fast")]
)
+(define_insn "aarch64_crypto_sha1hv4si"
+ [(set (match_operand:SI 0 "register_operand" "=w")
+ (unspec:SI [(vec_select:SI (match_operand:V4SI 1 "register_operand" "w")
+ (parallel [(const_int 0)]))]
+ UNSPEC_SHA1H))]
+ "TARGET_SIMD && TARGET_CRYPTO && !BYTES_BIG_ENDIAN"
+ "sha1h\\t%s0, %s1"
+ [(set_attr "type" "crypto_sha1_fast")]
+)
+
+(define_insn "aarch64_be_crypto_sha1hv4si"
+ [(set (match_operand:SI 0 "register_operand" "=w")
+ (unspec:SI [(vec_select:SI (match_operand:V4SI 1 "register_operand" "w")
+ (parallel [(const_int 3)]))]
+ UNSPEC_SHA1H))]
+ "TARGET_SIMD && TARGET_CRYPTO && BYTES_BIG_ENDIAN"
+ "sha1h\\t%s0, %s1"
+ [(set_attr "type" "crypto_sha1_fast")]
+)
+
(define_insn "aarch64_crypto_sha1su1v4si"
[(set (match_operand:V4SI 0 "register_operand" "=w")
(unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0")
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index df74ad96949..b7d4640826a 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -2936,12 +2936,18 @@ aarch64_layout_frame (void)
cfun->machine->frame.laid_out = true;
}
+/* Return true if the register REGNO is saved on entry to
+ the current function. */
+
static bool
aarch64_register_saved_on_entry (int regno)
{
return cfun->machine->frame.reg_offset[regno] >= 0;
}
+/* Return the next register up from REGNO up to LIMIT for the callee
+ to save. */
+
static unsigned
aarch64_next_callee_save (unsigned regno, unsigned limit)
{
@@ -2950,6 +2956,9 @@ aarch64_next_callee_save (unsigned regno, unsigned limit)
return regno;
}
+/* Push the register number REGNO of mode MODE to the stack with write-back
+ adjusting the stack by ADJUSTMENT. */
+
static void
aarch64_pushwb_single_reg (machine_mode mode, unsigned regno,
HOST_WIDE_INT adjustment)
@@ -2966,6 +2975,10 @@ aarch64_pushwb_single_reg (machine_mode mode, unsigned regno,
RTX_FRAME_RELATED_P (insn) = 1;
}
+/* Generate and return an instruction to store the pair of registers
+ REG and REG2 of mode MODE to location BASE with write-back adjusting
+ the stack location BASE by ADJUSTMENT. */
+
static rtx
aarch64_gen_storewb_pair (machine_mode mode, rtx base, rtx reg, rtx reg2,
HOST_WIDE_INT adjustment)
@@ -2985,6 +2998,9 @@ aarch64_gen_storewb_pair (machine_mode mode, rtx base, rtx reg, rtx reg2,
}
}
+/* Push registers numbered REGNO1 and REGNO2 to the stack, adjusting the
+ stack pointer by ADJUSTMENT. */
+
static void
aarch64_push_regs (unsigned regno1, unsigned regno2, HOST_WIDE_INT adjustment)
{
@@ -3004,6 +3020,9 @@ aarch64_push_regs (unsigned regno1, unsigned regno2, HOST_WIDE_INT adjustment)
RTX_FRAME_RELATED_P (insn) = 1;
}
+/* Load the pair of register REG, REG2 of mode MODE from stack location BASE,
+ adjusting it by ADJUSTMENT afterwards. */
+
static rtx
aarch64_gen_loadwb_pair (machine_mode mode, rtx base, rtx reg, rtx reg2,
HOST_WIDE_INT adjustment)
@@ -3021,6 +3040,10 @@ aarch64_gen_loadwb_pair (machine_mode mode, rtx base, rtx reg, rtx reg2,
}
}
+/* Pop the two registers numbered REGNO1, REGNO2 from the stack, adjusting it
+ afterwards by ADJUSTMENT and writing the appropriate REG_CFA_RESTORE notes
+ into CFI_OPS. */
+
static void
aarch64_pop_regs (unsigned regno1, unsigned regno2, HOST_WIDE_INT adjustment,
rtx *cfi_ops)
@@ -3045,6 +3068,9 @@ aarch64_pop_regs (unsigned regno1, unsigned regno2, HOST_WIDE_INT adjustment,
}
}
+/* Generate and return a store pair instruction of mode MODE to store
+ register REG1 to MEM1 and register REG2 to MEM2. */
+
static rtx
aarch64_gen_store_pair (machine_mode mode, rtx mem1, rtx reg1, rtx mem2,
rtx reg2)
@@ -3062,6 +3088,9 @@ aarch64_gen_store_pair (machine_mode mode, rtx mem1, rtx reg1, rtx mem2,
}
}
+/* Generate and regurn a load pair isntruction of mode MODE to load register
+ REG1 from MEM1 and register REG2 from MEM2. */
+
static rtx
aarch64_gen_load_pair (machine_mode mode, rtx reg1, rtx mem1, rtx reg2,
rtx mem2)
@@ -3079,6 +3108,9 @@ aarch64_gen_load_pair (machine_mode mode, rtx reg1, rtx mem1, rtx reg2,
}
}
+/* Emit code to save the callee-saved registers from register number START
+ to LIMIT to the stack at the location starting at offset START_OFFSET,
+ skipping any write-back candidates if SKIP_WB is true. */
static void
aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
@@ -3137,6 +3169,11 @@ aarch64_save_callee_saves (machine_mode mode, HOST_WIDE_INT start_offset,
}
}
+/* Emit code to restore the callee registers of mode MODE from register
+ number START up to and including LIMIT. Restore from the stack offset
+ START_OFFSET, skipping any write-back candidates if SKIP_WB is true.
+ Write the appropriate REG_CFA_RESTORE notes into CFI_OPS. */
+
static void
aarch64_restore_callee_saves (machine_mode mode,
HOST_WIDE_INT start_offset, unsigned start,
@@ -13197,7 +13234,7 @@ aarch64_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_INT size,
}
static rtx
-aarch64_gen_ccmp_first (rtx *prep_seq, rtx *gen_seq,
+aarch64_gen_ccmp_first (rtx_insn **prep_seq, rtx_insn **gen_seq,
int code, tree treeop0, tree treeop1)
{
machine_mode op_mode, cmp_mode, cc_mode = CCmode;
@@ -13271,8 +13308,8 @@ aarch64_gen_ccmp_first (rtx *prep_seq, rtx *gen_seq,
}
static rtx
-aarch64_gen_ccmp_next (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code,
- tree treeop0, tree treeop1, int bit_code)
+aarch64_gen_ccmp_next (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev,
+ int cmp_code, tree treeop0, tree treeop1, int bit_code)
{
rtx op0, op1, target;
machine_mode op_mode, cmp_mode, cc_mode = CCmode;
@@ -13281,7 +13318,7 @@ aarch64_gen_ccmp_next (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code,
struct expand_operand ops[6];
int aarch64_cond;
- push_to_sequence ((rtx_insn*) *prep_seq);
+ push_to_sequence (*prep_seq);
expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
op_mode = GET_MODE (op0);
@@ -13347,7 +13384,7 @@ aarch64_gen_ccmp_next (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code,
create_fixed_operand (&ops[4], prev);
create_fixed_operand (&ops[5], GEN_INT (aarch64_cond));
- push_to_sequence ((rtx_insn*) *gen_seq);
+ push_to_sequence (*gen_seq);
if (!maybe_expand_insn (icode, 6, ops))
{
end_sequence ();
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 6afaf906915..46eaa30b159 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -639,7 +639,8 @@
[(set (pc) (if_then_else
(EQL (zero_extract:DI (match_operand:GPI 0 "register_operand" "r")
(const_int 1)
- (match_operand 1 "const_int_operand" "n"))
+ (match_operand 1
+ "aarch64_simd_shift_imm_<mode>" "n"))
(const_int 0))
(label_ref (match_operand 2 "" ""))
(pc)))
@@ -1605,25 +1606,12 @@
(match_operand:GPI 2 "aarch64_pluslong_operand" "")))]
""
{
- if (aarch64_pluslong_strict_immedate (operands[2], <MODE>mode))
- {
- /* Give CSE the opportunity to share this constant across additions. */
- if (!cse_not_expected && can_create_pseudo_p ())
- operands[2] = force_reg (<MODE>mode, operands[2]);
-
- /* Split will refuse to operate on a modification to the stack pointer.
- Aid the prologue and epilogue expanders by splitting this now. */
- else if (reload_completed && operands[0] == stack_pointer_rtx)
- {
- HOST_WIDE_INT i = INTVAL (operands[2]);
- HOST_WIDE_INT s = (i >= 0 ? i & 0xfff : -(-i & 0xfff));
- emit_insn (gen_rtx_SET (operands[0],
- gen_rtx_PLUS (<MODE>mode, operands[1],
- GEN_INT (i - s))));
- operands[1] = operands[0];
- operands[2] = GEN_INT (s);
- }
- }
+ /* If the constant is too large for a single instruction and isn't frame
+ based, split off the immediate so it is available for CSE. */
+ if (!aarch64_plus_immediate (operands[2], <MODE>mode)
+ && can_create_pseudo_p ()
+ && !REGNO_PTR_FRAME_P (REGNO (operands[1])))
+ operands[2] = force_reg (<MODE>mode, operands[2]);
})
(define_insn "*add<mode>3_aarch64"
@@ -4281,19 +4269,28 @@
(define_expand "<optab>"
[(set (match_operand:DI 0 "register_operand" "=r")
- (ANY_EXTRACT:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand 2 "const_int_operand" "n")
- (match_operand 3 "const_int_operand" "n")))]
- ""
+ (ANY_EXTRACT:DI (match_operand:DI 1 "register_operand")
+ (match_operand 2
+ "aarch64_simd_shift_imm_offset_di")
+ (match_operand 3 "aarch64_simd_shift_imm_di")))]
""
+ {
+ if (!IN_RANGE (INTVAL (operands[2]) + INTVAL (operands[3]),
+ 1, GET_MODE_BITSIZE (DImode) - 1))
+ FAIL;
+ }
)
+
(define_insn "*<optab><mode>"
[(set (match_operand:GPI 0 "register_operand" "=r")
(ANY_EXTRACT:GPI (match_operand:GPI 1 "register_operand" "r")
- (match_operand 2 "const_int_operand" "n")
- (match_operand 3 "const_int_operand" "n")))]
- ""
+ (match_operand 2
+ "aarch64_simd_shift_imm_offset_<mode>" "n")
+ (match_operand 3
+ "aarch64_simd_shift_imm_<mode>" "n")))]
+ "IN_RANGE (INTVAL (operands[2]) + INTVAL (operands[3]),
+ 1, GET_MODE_BITSIZE (<MODE>mode) - 1)"
"<su>bfx\\t%<w>0, %<w>1, %3, %2"
[(set_attr "type" "bfm")]
)
diff --git a/gcc/config/aarch64/driver-aarch64.c b/gcc/config/aarch64/driver-aarch64.c
index 658a4cd72e9..c21942c1aab 100644
--- a/gcc/config/aarch64/driver-aarch64.c
+++ b/gcc/config/aarch64/driver-aarch64.c
@@ -169,7 +169,6 @@ host_detect_local_cpu (int argc, const char **argv)
bool tune = false;
bool cpu = false;
unsigned int i = 0;
- unsigned int core_idx = 0;
unsigned char imp = INVALID_IMP;
unsigned int cores[2] = { INVALID_CORE, INVALID_CORE };
unsigned int n_cores = 0;
@@ -219,18 +218,13 @@ host_detect_local_cpu (int argc, const char **argv)
if (strstr (buf, "part") != NULL)
{
unsigned ccore = parse_field (buf);
- for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
- if (ccore == aarch64_cpu_data[i].part_no
- && !contains_core_p (cores, ccore))
- {
- if (n_cores == 2)
- goto not_found;
-
- cores[n_cores++] = ccore;
- core_idx = i;
- arch_id = aarch64_cpu_data[i].arch;
- break;
- }
+ if (!contains_core_p (cores, ccore))
+ {
+ if (n_cores == 2)
+ goto not_found;
+
+ cores[n_cores++] = ccore;
+ }
continue;
}
if (!tune && !processed_exts && strstr (buf, "Features") != NULL)
@@ -276,11 +270,19 @@ host_detect_local_cpu (int argc, const char **argv)
if (n_cores == 0 || n_cores > 2 || imp == INVALID_IMP)
goto not_found;
- if (arch && !arch_id)
- goto not_found;
-
if (arch)
{
+ /* Search for one of the cores in the list. */
+ for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
+ if (aarch64_cpu_data[i].implementer_id == imp
+ && contains_core_p (cores, aarch64_cpu_data[i].part_no))
+ {
+ arch_id = aarch64_cpu_data[i].arch;
+ break;
+ }
+ if (!arch_id)
+ goto not_found;
+
struct aarch64_arch_driver_info* arch_info = get_arch_from_id (arch_id);
/* We got some arch indentifier that's not in aarch64-arches.def? */
@@ -312,7 +314,15 @@ host_detect_local_cpu (int argc, const char **argv)
/* The simple, non-big.LITTLE case. */
else
{
- if (aarch64_cpu_data[core_idx].implementer_id != imp)
+ int core_idx = -1;
+ for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
+ if (cores[0] == aarch64_cpu_data[i].part_no
+ && aarch64_cpu_data[i].implementer_id == imp)
+ {
+ core_idx = i;
+ break;
+ }
+ if (core_idx == -1)
goto not_found;
res = concat ("-m", cpu ? "cpu" : "tune", "=",
diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64
index 04eb63666e8..b461eb5bede 100644
--- a/gcc/config/aarch64/t-aarch64
+++ b/gcc/config/aarch64/t-aarch64
@@ -52,7 +52,7 @@ aarch-common.o: $(srcdir)/config/arm/aarch-common.c $(CONFIG_H) $(SYSTEM_H) \
$(srcdir)/config/arm/aarch-common.c
aarch64-c.o: $(srcdir)/config/aarch64/aarch64-c.c $(CONFIG_H) $(SYSTEM_H) \
- coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H)
+ coretypes.h $(TM_H) $(TREE_H) output.h $(C_COMMON_H) $(TARGET_H)
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
$(srcdir)/config/aarch64/aarch64-c.c
diff --git a/gcc/config/alpha/alpha-passes.def b/gcc/config/alpha/alpha-passes.def
index d960e7cfc06..977605a105a 100644
--- a/gcc/config/alpha/alpha-passes.def
+++ b/gcc/config/alpha/alpha-passes.def
@@ -17,5 +17,5 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
- INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_align_insns);
INSERT_PASS_AFTER (pass_convert_to_eh_region_ranges, 1, pass_handle_trap_shadows);
+ INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_align_insns);
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 7f5396725b0..6d390ae6dfa 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -1017,7 +1017,8 @@ alpha_legitimize_address_1 (rtx x, rtx scratch, machine_mode mode)
&& GET_MODE_SIZE (mode) <= UNITS_PER_WORD
&& symbolic_operand (x, Pmode))
{
- rtx r0, r16, eqv, tga, tp, insn, dest, seq;
+ rtx r0, r16, eqv, tga, tp, dest, seq;
+ rtx_insn *insn;
switch (tls_symbolic_operand_type (x))
{
@@ -1025,66 +1026,70 @@ alpha_legitimize_address_1 (rtx x, rtx scratch, machine_mode mode)
break;
case TLS_MODEL_GLOBAL_DYNAMIC:
- start_sequence ();
+ {
+ start_sequence ();
- r0 = gen_rtx_REG (Pmode, 0);
- r16 = gen_rtx_REG (Pmode, 16);
- tga = get_tls_get_addr ();
- dest = gen_reg_rtx (Pmode);
- seq = GEN_INT (alpha_next_sequence_number++);
+ r0 = gen_rtx_REG (Pmode, 0);
+ r16 = gen_rtx_REG (Pmode, 16);
+ tga = get_tls_get_addr ();
+ dest = gen_reg_rtx (Pmode);
+ seq = GEN_INT (alpha_next_sequence_number++);
- emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
- insn = gen_call_value_osf_tlsgd (r0, tga, seq);
- insn = emit_call_insn (insn);
- RTL_CONST_CALL_P (insn) = 1;
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
+ emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
+ rtx val = gen_call_value_osf_tlsgd (r0, tga, seq);
+ insn = emit_call_insn (val);
+ RTL_CONST_CALL_P (insn) = 1;
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
- insn = get_insns ();
- end_sequence ();
+ insn = get_insns ();
+ end_sequence ();
- emit_libcall_block (insn, dest, r0, x);
- return dest;
+ emit_libcall_block (insn, dest, r0, x);
+ return dest;
+ }
case TLS_MODEL_LOCAL_DYNAMIC:
- start_sequence ();
+ {
+ start_sequence ();
- r0 = gen_rtx_REG (Pmode, 0);
- r16 = gen_rtx_REG (Pmode, 16);
- tga = get_tls_get_addr ();
- scratch = gen_reg_rtx (Pmode);
- seq = GEN_INT (alpha_next_sequence_number++);
+ r0 = gen_rtx_REG (Pmode, 0);
+ r16 = gen_rtx_REG (Pmode, 16);
+ tga = get_tls_get_addr ();
+ scratch = gen_reg_rtx (Pmode);
+ seq = GEN_INT (alpha_next_sequence_number++);
- emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
- insn = gen_call_value_osf_tlsldm (r0, tga, seq);
- insn = emit_call_insn (insn);
- RTL_CONST_CALL_P (insn) = 1;
- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
+ emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
+ rtx val = gen_call_value_osf_tlsldm (r0, tga, seq);
+ insn = emit_call_insn (val);
+ RTL_CONST_CALL_P (insn) = 1;
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
- insn = get_insns ();
- end_sequence ();
+ insn = get_insns ();
+ end_sequence ();
- eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
- UNSPEC_TLSLDM_CALL);
- emit_libcall_block (insn, scratch, r0, eqv);
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_TLSLDM_CALL);
+ emit_libcall_block (insn, scratch, r0, eqv);
- eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL);
- eqv = gen_rtx_CONST (Pmode, eqv);
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL);
+ eqv = gen_rtx_CONST (Pmode, eqv);
- if (alpha_tls_size == 64)
- {
- dest = gen_reg_rtx (Pmode);
- emit_insn (gen_rtx_SET (dest, eqv));
- emit_insn (gen_adddi3 (dest, dest, scratch));
- return dest;
- }
- if (alpha_tls_size == 32)
- {
- insn = gen_rtx_HIGH (Pmode, eqv);
- insn = gen_rtx_PLUS (Pmode, scratch, insn);
- scratch = gen_reg_rtx (Pmode);
- emit_insn (gen_rtx_SET (scratch, insn));
- }
- return gen_rtx_LO_SUM (Pmode, scratch, eqv);
+ if (alpha_tls_size == 64)
+ {
+ dest = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (dest, eqv));
+ emit_insn (gen_adddi3 (dest, dest, scratch));
+ return dest;
+ }
+ if (alpha_tls_size == 32)
+ {
+ rtx temp = gen_rtx_HIGH (Pmode, eqv);
+ temp = gen_rtx_PLUS (Pmode, scratch, temp);
+ scratch = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (scratch, temp));
+ }
+ return gen_rtx_LO_SUM (Pmode, scratch, eqv);
+ }
case TLS_MODEL_INITIAL_EXEC:
eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
@@ -1106,10 +1111,10 @@ alpha_legitimize_address_1 (rtx x, rtx scratch, machine_mode mode)
emit_insn (gen_get_thread_pointerdi (tp));
if (alpha_tls_size == 32)
{
- insn = gen_rtx_HIGH (Pmode, eqv);
- insn = gen_rtx_PLUS (Pmode, tp, insn);
+ rtx temp = gen_rtx_HIGH (Pmode, eqv);
+ temp = gen_rtx_PLUS (Pmode, tp, temp);
tp = gen_reg_rtx (Pmode);
- emit_insn (gen_rtx_SET (tp, insn));
+ emit_insn (gen_rtx_SET (tp, temp));
}
return gen_rtx_LO_SUM (Pmode, tp, eqv);
@@ -3059,7 +3064,7 @@ static void
alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
int noperands, rtx equiv)
{
- rtx usage = NULL_RTX, tmp, reg;
+ rtx usage = NULL_RTX, reg;
int regno = 16, i;
start_sequence ();
@@ -3109,9 +3114,9 @@ alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
gcc_unreachable ();
}
- tmp = gen_rtx_MEM (QImode, func);
- tmp = emit_call_insn (gen_call_value (reg, tmp, const0_rtx,
- const0_rtx, const0_rtx));
+ rtx mem = gen_rtx_MEM (QImode, func);
+ rtx_insn *tmp = emit_call_insn (gen_call_value (reg, mem, const0_rtx,
+ const0_rtx, const0_rtx));
CALL_INSN_FUNCTION_USAGE (tmp) = usage;
RTL_CONST_CALL_P (tmp) = 1;
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 0e7b63dc6f7..5ba7ccc776f 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -4830,7 +4830,6 @@ static rtx
arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
{
rtx r0 = gen_rtx_REG (Pmode, R0_REG);
- rtx insns;
rtx call_fusage = NULL_RTX;
start_sequence ();
@@ -4847,7 +4846,7 @@ arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
RTL_PURE_CALL_P (call_insn) = 1;
add_function_usage_to (call_insn, call_fusage);
- insns = get_insns ();
+ rtx_insn *insns = get_insns ();
end_sequence ();
rtx dest = gen_reg_rtx (Pmode);
@@ -9021,10 +9020,7 @@ arc_process_double_reg_moves (rtx *operands)
rtx srcLow = simplify_gen_subreg (SImode, src, DFmode,
TARGET_BIG_ENDIAN ? 4 : 0);
- emit_insn (gen_rtx_UNSPEC_VOLATILE (Pmode,
- gen_rtvec (3, dest, srcHigh, srcLow),
- VUNSPEC_ARC_DEXCL_NORES));
-
+ emit_insn (gen_dexcl_2op (dest, srcHigh, srcLow));
}
else
gcc_unreachable ();
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index b146f3a9a05..a4adce0812e 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -128,24 +128,6 @@ along with GCC; see the file COPYING3. If not see
%{!marclinux*: %{pg|p|profile:-marclinux_prof;: -marclinux}} \
%{!z:-z max-page-size=0x2000 -z common-page-size=0x2000} \
%{shared:-shared}"
-/* Like the standard LINK_COMMAND_SPEC, but add %G when building
- a shared library with -nostdlib, so that the hidden functions of libgcc
- will be incorporated.
- N.B., we don't want a plain -lgcc, as this would lead to re-exporting
- non-hidden functions, so we have to consider libgcc_s.so.* first, which in
- turn should be wrapped with --as-needed. */
-#define LINK_COMMAND_SPEC "\
-%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\
- %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
- %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
- %{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):\
- %:include(libgomp.spec)%(link_gomp)}\
- %(mflib)\
- %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
- %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
- %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
-
#else
#define LINK_SPEC "%{mbig-endian:-EB} %{EB} %{EL}\
%{pg|p:-marcelf_prof;mA7|mARC700|mcpu=arc700|mcpu=ARC700: -marcelf}"
@@ -409,8 +391,8 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 0
-#define SIZE_TYPE "long unsigned int"
-#define PTRDIFF_TYPE "long int"
+#define SIZE_TYPE "unsigned int"
+#define PTRDIFF_TYPE "int"
#define WCHAR_TYPE "int"
#define WCHAR_TYPE_SIZE 32
@@ -1570,13 +1552,10 @@ extern int arc_return_address_regs[4];
/* Undo the effects of the movmem pattern presence on STORE_BY_PIECES_P . */
#define MOVE_RATIO(SPEED) ((SPEED) ? 15 : 3)
-/* Define this to be nonzero if shift instructions ignore all but the low-order
- few bits. Changed from 1 to 0 for rotate pattern testcases
- (e.g. 20020226-1.c). This change truncates the upper 27 bits of a word
- while rotating a word. Came to notice through a combine phase
- optimization viz. a << (32-b) is equivalent to a << (-b).
+/* Define this to be nonzero if shift instructions ignore all but the
+ low-order few bits.
*/
-#define SHIFT_COUNT_TRUNCATED 0
+#define SHIFT_COUNT_TRUNCATED 1
/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
is done just by pretending it is already truncated. */
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index e127d5b0352..7147fbdb244 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -704,9 +704,9 @@
; the iscompact attribute allows the epilogue expander to know for which
; insns it should lengthen the return insn.
; N.B. operand 1 of alternative 7 expands into pcl,symbol@gotpc .
-(define_insn "*movsi_insn" ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
- [(set (match_operand:SI 0 "move_dest_operand" "=Rcq,Rcq#q, w, h, w,w, w, w, w, w,???w, ?w, w,Rcq#q, w,Rcq, S, Us<,RcqRck,!*x, r,!*Rsd,!*Rcd,r,Ucm, Usd,m,???m,VUsc,VUsc")
- (match_operand:SI 1 "move_src_operand" " cL, cP,Rcq#q,hCm1,cL,I,Crr,Clo,Chi,Cbi,?Rac,Cpc,Clb, ?Cal,?Cal, T,Rcq,RcqRck, Us>,Usd,Ucm, Usd, Ucd,m, w,!*Rzd,c,?Rac, Cm3, C32"))]
+(define_insn "*movsi_insn" ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
+ [(set (match_operand:SI 0 "move_dest_operand" "=Rcq,Rcq#q, w, h, w,w, w, w, w, w,???w, ?w, w,Rcq#q, w,Rcq, S, Us<,RcqRck,!*x, r,!*Rsd,!*Rcd,r,Ucm, Usd,m,???m,VUsc,VUsc")
+ (match_operand:SI 1 "move_src_operand" " cL, cP,Rcq#q,hPCm1,cL,I,Crr,Clo,Chi,Cbi,?Rac,Cpc,Clb, ?Cal,?Cal, T,Rcq,RcqRck, Us>,Usd,Ucm, Usd, Ucd,m, w,!*Rzd,c,?Rac, Cm3, C32"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
|| (CONSTANT_P (operands[1])
@@ -751,7 +751,7 @@
; of Crr to 4.
(set_attr "length" "*,*,*,*,4,4,4,4,4,4,4,8,8,*,8,*,*,*,*,*,4,*,4,*,*,*,*,*,4,8")
(set_attr "predicable" "yes,no,yes,no,yes,no,no,no,no,no,yes,no,no,yes,yes,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no")
- (set_attr "cpu_facility" "*,*,av1,av2,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,av2,av2,*,*,av2,*,*,av2,*")])
+ (set_attr "cpu_facility" "av1,av1,av1,av2,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,av2,av2,*,*,av2,*,*,av2,*")])
;; Sometimes generated by the epilogue code. We don't want to
;; recognize these addresses in general, because the limm is costly,
@@ -1088,12 +1088,9 @@
(match_operand:DI 1 "general_operand" ""))]
""
"
-{
- /* Everything except mem = const or mem = mem can be done easily. */
-
- if (GET_CODE (operands[0]) == MEM)
- operands[1] = force_reg (DImode, operands[1]);
-}")
+ if (prepare_move_operands (operands, DImode))
+ DONE;
+ ")
(define_insn_and_split "*movdi_insn"
[(set (match_operand:DI 0 "move_dest_operand" "=w, w,r,m")
@@ -1140,7 +1137,7 @@
;; Floating point move insns.
(define_expand "movsf"
- [(set (match_operand:SF 0 "general_operand" "")
+ [(set (match_operand:SF 0 "move_dest_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
"if (prepare_move_operands (operands, SFmode)) DONE;")
@@ -1161,7 +1158,7 @@
(set_attr "iscompact" "true,false,false,false,false")])
(define_expand "movdf"
- [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ [(set (match_operand:DF 0 "move_dest_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
"if (prepare_move_operands (operands, DFmode)) DONE;")
@@ -1231,12 +1228,18 @@
; second time to put back the contents which the first DEXCLx
; will have overwritten
; dexcl2 r0, r1, r0
- (set (match_dup 4) ; aka r0result
- ; aka DF, r1, r0
- (unspec_volatile:SI [(match_dup 1) (match_dup 5) (match_dup 4)] VUNSPEC_ARC_DEXCL ))
+ (parallel [
+ (set (match_dup 4) ; aka r0result
+ ; aka DF, r1, r0
+ (unspec_volatile:SI [(match_dup 5) (match_dup 4)]
+ VUNSPEC_ARC_DEXCL))
+ (clobber (match_dup 1))
+ ])
; Generate the second, which makes sure operand5 and operand4 values
; are put back in the Dx register properly.
- (unspec_volatile:SI [(match_dup 1) (match_dup 5) (match_dup 4)] VUNSPEC_ARC_DEXCL_NORES )
+ (set (match_dup 1) (unspec_volatile:DF
+ [(match_dup 5) (match_dup 4)]
+ VUNSPEC_ARC_DEXCL_NORES))
; Note: we cannot use a (clobber (match_scratch)) here because
; the combine pass will end up replacing uses of it with 0
diff --git a/gcc/config/arc/constraints.md b/gcc/config/arc/constraints.md
index b7bf2d39c4e..8eccb2fdfe3 100644
--- a/gcc/config/arc/constraints.md
+++ b/gcc/config/arc/constraints.md
@@ -256,7 +256,8 @@
"@internal
constant for a highpart that can be checked with a shift (asr.f 0,rn,m)"
(and (match_code "const_int")
- (match_test "IS_POWEROF2_P (-ival)")))
+ (match_test "IS_POWEROF2_P (-ival)")
+ (match_test "TARGET_BARREL_SHIFTER")))
(define_constraint "Clo"
"@internal
diff --git a/gcc/config/arc/fpu.md b/gcc/config/arc/fpu.md
index 9b0a65d9386..e43047ce1d6 100644
--- a/gcc/config/arc/fpu.md
+++ b/gcc/config/arc/fpu.md
@@ -193,11 +193,13 @@
(set_attr "type" "fpu")])
;; Division
-(define_insn "divsf3"
+(define_insn "*divsf3_fpu"
[(set (match_operand:SF 0 "register_operand" "=r,r,r,r,r")
(div:SF (match_operand:SF 1 "nonmemory_operand" "0,r,0,r,F")
(match_operand:SF 2 "nonmemory_operand" "r,r,F,F,r")))]
- "TARGET_FP_SP_SQRT"
+ "TARGET_FP_SP_SQRT
+ && (register_operand (operands[1], SFmode)
+ || register_operand (operands[2], SFmode))"
"fsdiv%? %0,%1,%2"
[(set_attr "length" "4,4,8,8,8")
(set_attr "iscompact" "false")
diff --git a/gcc/config/arc/fpx.md b/gcc/config/arc/fpx.md
index 2e11157cabf..9ed2b7c683a 100644
--- a/gcc/config/arc/fpx.md
+++ b/gcc/config/arc/fpx.md
@@ -168,28 +168,26 @@
(set_attr "type" "lr")]
)
-
(define_insn "*dexcl_3op_peep2_insn"
[(set (match_operand:SI 0 "dest_reg_operand" "=r") ; not register_operand, to accept SUBREG
- (unspec_volatile:SI [
- (match_operand:DF 1 "arc_double_register_operand" "D")
- (match_operand:SI 2 "shouldbe_register_operand" "r") ; r1
- (match_operand:SI 3 "shouldbe_register_operand" "r") ; r0
- ] VUNSPEC_ARC_DEXCL ))
- ]
+ (unspec_volatile:SI
+ [(match_operand:SI 1 "shouldbe_register_operand" "r") ; r1
+ (match_operand:SI 2 "shouldbe_register_operand" "r") ; r0
+ ] VUNSPEC_ARC_DEXCL ))
+ (clobber (match_operand:DF 3 "arc_double_register_operand" "=&D"))]
"TARGET_DPFP"
- "dexcl%F1 %0, %2, %3"
+ "dexcl%F3 %0, %1, %2"
[(set_attr "type" "move")
(set_attr "length" "4")]
)
;; version which will not overwrite operand0
-(define_insn "*dexcl_3op_peep2_insn_nores"
- [ (unspec_volatile:SI [
- (match_operand:DF 0 "arc_double_register_operand" "D")
- (match_operand:SI 1 "shouldbe_register_operand" "r") ; r1
- (match_operand:SI 2 "shouldbe_register_operand" "r") ; r0
- ] VUNSPEC_ARC_DEXCL_NORES )
+(define_insn "dexcl_2op"
+ [(set (match_operand:DF 0 "arc_double_register_operand" "=D")
+ (unspec_volatile:DF
+ [(match_operand:SI 1 "shouldbe_register_operand" "r") ; r1
+ (match_operand:SI 2 "shouldbe_register_operand" "r") ; r0
+ ] VUNSPEC_ARC_DEXCL_NORES))
]
"TARGET_DPFP"
"dexcl%F0 0, %1, %2"
diff --git a/gcc/config/arm/arm-arches.def b/gcc/config/arm/arm-arches.def
index 4b196a7d118..cd79bc50585 100644
--- a/gcc/config/arm/arm-arches.def
+++ b/gcc/config/arm/arm-arches.def
@@ -69,11 +69,11 @@ ARM_ARCH ("armv8.2-a", cortexa53, 8A,
ARM_ARCH ("armv8.2-a+fp16", cortexa53, 8A,
ARM_FSET_MAKE (FL_CO_PROC | FL_CRC32 | FL_FOR_ARCH8A,
FL2_FOR_ARCH8_2A | FL2_FP16INST))
-ARM_ARCH("armv8-m.base", cortexm0, 8M_BASE,
+ARM_ARCH("armv8-m.base", cortexm23, 8M_BASE,
ARM_FSET_MAKE_CPU1 ( FL_FOR_ARCH8M_BASE))
ARM_ARCH("armv8-m.main", cortexm7, 8M_MAIN,
ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_FOR_ARCH8M_MAIN))
-ARM_ARCH("armv8-m.main+dsp", cortexm7, 8M_MAIN,
+ARM_ARCH("armv8-m.main+dsp", cortexm33, 8M_MAIN,
ARM_FSET_MAKE_CPU1(FL_CO_PROC | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN))
ARM_ARCH("iwmmxt", iwmmxt, 5TE, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT))
ARM_ARCH("iwmmxt2", iwmmxt2, 5TE, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT | FL_IWMMXT2))
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index df930f44801..74417a6446d 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -87,6 +87,9 @@ arm_cpu_builtins (struct cpp_reader* pfile)
((TARGET_ARM_ARCH >= 5 && !TARGET_THUMB)
|| TARGET_ARM_ARCH_ISA_THUMB >=2));
+ def_or_undef_macro (pfile, "__ARM_FEATURE_NUMERIC_MAXMIN",
+ TARGET_ARM_ARCH >= 8 && TARGET_NEON && TARGET_FPU_ARMV8);
+
def_or_undef_macro (pfile, "__ARM_FEATURE_SIMD32", TARGET_INT_SIMD);
builtin_define_with_int_value ("__ARM_SIZEOF_MINIMAL_ENUM",
diff --git a/gcc/config/arm/arm-cores.def b/gcc/config/arm/arm-cores.def
index 2072e1e6f8d..ec63ee4abe5 100644
--- a/gcc/config/arm/arm-cores.def
+++ b/gcc/config/arm/arm-cores.def
@@ -166,7 +166,9 @@ ARM_CORE("cortex-a15.cortex-a7", cortexa15cortexa7, cortexa7, 7A, ARM_FSET_MAKE_
ARM_CORE("cortex-a17.cortex-a7", cortexa17cortexa7, cortexa7, 7A, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV | FL_FOR_ARCH7A), cortex_a12)
/* V8 Architecture Processors */
+ARM_CORE("cortex-m23", cortexm23, cortexm23, 8M_BASE, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_FOR_ARCH8M_BASE), v6m)
ARM_CORE("cortex-a32", cortexa32, cortexa53, 8A, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_CRC32 | FL_FOR_ARCH8A), cortex_a35)
+ARM_CORE("cortex-m33", cortexm33, cortexm33, 8M_MAIN, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_ARCH7EM | FL_FOR_ARCH8M_MAIN), v7m)
ARM_CORE("cortex-a35", cortexa35, cortexa53, 8A, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_CRC32 | FL_FOR_ARCH8A), cortex_a35)
ARM_CORE("cortex-a53", cortexa53, cortexa53, 8A, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_CRC32 | FL_FOR_ARCH8A), cortex_a53)
ARM_CORE("cortex-a57", cortexa57, cortexa57, 8A, ARM_FSET_MAKE_CPU1 (FL_LDSCHED | FL_CRC32 | FL_FOR_ARCH8A), cortex_a57)
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index fd8b6d106d1..95bae5ef57b 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -260,7 +260,6 @@ struct cpu_cost_table;
struct tune_params
{
- bool (*rtx_costs) (rtx, RTX_CODE, RTX_CODE, int *, bool);
const struct cpu_cost_table *insn_extra_cost;
bool (*sched_adjust_cost) (rtx_insn *, int, rtx_insn *, int *);
int (*branch_cost) (bool, bool);
diff --git a/gcc/config/arm/arm-tables.opt b/gcc/config/arm/arm-tables.opt
index ee9e3bb7ec5..f7886b94be7 100644
--- a/gcc/config/arm/arm-tables.opt
+++ b/gcc/config/arm/arm-tables.opt
@@ -307,9 +307,15 @@ EnumValue
Enum(processor_type) String(cortex-a17.cortex-a7) Value(cortexa17cortexa7)
EnumValue
+Enum(processor_type) String(cortex-m23) Value(cortexm23)
+
+EnumValue
Enum(processor_type) String(cortex-a32) Value(cortexa32)
EnumValue
+Enum(processor_type) String(cortex-m33) Value(cortexm33)
+
+EnumValue
Enum(processor_type) String(cortex-a35) Value(cortexa35)
EnumValue
diff --git a/gcc/config/arm/arm-tune.md b/gcc/config/arm/arm-tune.md
index 594ce9d1734..e782baccf42 100644
--- a/gcc/config/arm/arm-tune.md
+++ b/gcc/config/arm/arm-tune.md
@@ -32,9 +32,10 @@
cortexr4f,cortexr5,cortexr7,
cortexr8,cortexm7,cortexm4,
cortexm3,marvell_pj4,cortexa15cortexa7,
- cortexa17cortexa7,cortexa32,cortexa35,
- cortexa53,cortexa57,cortexa72,
- cortexa73,exynosm1,qdf24xx,
- xgene1,cortexa57cortexa53,cortexa72cortexa53,
- cortexa73cortexa35,cortexa73cortexa53"
+ cortexa17cortexa7,cortexm23,cortexa32,
+ cortexm33,cortexa35,cortexa53,
+ cortexa57,cortexa72,cortexa73,
+ exynosm1,qdf24xx,xgene1,
+ cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,
+ cortexa73cortexa53"
(const (symbol_ref "((enum attr_tune) arm_tune)")))
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 3c4c7042d9c..13f61f49ff8 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -62,6 +62,7 @@
#include "builtins.h"
#include "tm-constrs.h"
#include "rtl-iter.h"
+#include "optabs-libfuncs.h"
/* This file should be included last. */
#include "target-def.h"
@@ -164,12 +165,6 @@ static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
static bool arm_have_conditional_execution (void);
static bool arm_cannot_force_const_mem (machine_mode, rtx);
static bool arm_legitimate_constant_p (machine_mode, rtx);
-static bool arm_rtx_costs_1 (rtx, enum rtx_code, int*, bool);
-static bool arm_size_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
-static bool arm_slowmul_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool);
-static bool arm_fastmul_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool);
-static bool arm_xscale_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool);
-static bool arm_9e_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool);
static bool arm_rtx_costs (rtx, machine_mode, int, int, int *, bool);
static int arm_address_cost (rtx, machine_mode, addr_space_t, bool);
static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t);
@@ -304,6 +299,7 @@ static section *arm_function_section (tree, enum node_frequency, bool, bool);
static bool arm_asm_elf_flags_numeric (unsigned int flags, unsigned int *num);
static unsigned int arm_elf_section_type_flags (tree decl, const char *name,
int reloc);
+static void arm_expand_divmod_libfunc (rtx, machine_mode, rtx, rtx, rtx *, rtx *);
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -739,6 +735,9 @@ static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_SECTION_TYPE_FLAGS
#define TARGET_SECTION_TYPE_FLAGS arm_elf_section_type_flags
+#undef TARGET_EXPAND_DIVMOD_LIBFUNC
+#define TARGET_EXPAND_DIVMOD_LIBFUNC arm_expand_divmod_libfunc
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Obstack for minipool constant handling. */
@@ -1698,8 +1697,7 @@ const struct cpu_cost_table v7m_extra_costs =
const struct tune_params arm_slowmul_tune =
{
- arm_slowmul_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1721,8 +1719,7 @@ const struct tune_params arm_slowmul_tune =
const struct tune_params arm_fastmul_tune =
{
- arm_fastmul_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1747,8 +1744,7 @@ const struct tune_params arm_fastmul_tune =
const struct tune_params arm_strongarm_tune =
{
- arm_fastmul_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1770,8 +1766,7 @@ const struct tune_params arm_strongarm_tune =
const struct tune_params arm_xscale_tune =
{
- arm_xscale_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
xscale_sched_adjust_cost,
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1793,8 +1788,7 @@ const struct tune_params arm_xscale_tune =
const struct tune_params arm_9e_tune =
{
- arm_9e_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1816,8 +1810,7 @@ const struct tune_params arm_9e_tune =
const struct tune_params arm_marvell_pj4_tune =
{
- arm_9e_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1839,8 +1832,7 @@ const struct tune_params arm_marvell_pj4_tune =
const struct tune_params arm_v6t2_tune =
{
- arm_9e_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -1864,7 +1856,6 @@ const struct tune_params arm_v6t2_tune =
/* Generic Cortex tuning. Use more specific tunings if appropriate. */
const struct tune_params arm_cortex_tune =
{
- arm_9e_rtx_costs,
&generic_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -1887,7 +1878,6 @@ const struct tune_params arm_cortex_tune =
const struct tune_params arm_cortex_a8_tune =
{
- arm_9e_rtx_costs,
&cortexa8_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -1910,7 +1900,6 @@ const struct tune_params arm_cortex_a8_tune =
const struct tune_params arm_cortex_a7_tune =
{
- arm_9e_rtx_costs,
&cortexa7_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -1933,7 +1922,6 @@ const struct tune_params arm_cortex_a7_tune =
const struct tune_params arm_cortex_a15_tune =
{
- arm_9e_rtx_costs,
&cortexa15_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -1956,7 +1944,6 @@ const struct tune_params arm_cortex_a15_tune =
const struct tune_params arm_cortex_a35_tune =
{
- arm_9e_rtx_costs,
&cortexa53_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -1979,7 +1966,6 @@ const struct tune_params arm_cortex_a35_tune =
const struct tune_params arm_cortex_a53_tune =
{
- arm_9e_rtx_costs,
&cortexa53_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2002,7 +1988,6 @@ const struct tune_params arm_cortex_a53_tune =
const struct tune_params arm_cortex_a57_tune =
{
- arm_9e_rtx_costs,
&cortexa57_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2025,7 +2010,6 @@ const struct tune_params arm_cortex_a57_tune =
const struct tune_params arm_exynosm1_tune =
{
- arm_9e_rtx_costs,
&exynosm1_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2048,7 +2032,6 @@ const struct tune_params arm_exynosm1_tune =
const struct tune_params arm_xgene1_tune =
{
- arm_9e_rtx_costs,
&xgene1_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2071,7 +2054,6 @@ const struct tune_params arm_xgene1_tune =
const struct tune_params arm_qdf24xx_tune =
{
- arm_9e_rtx_costs,
&qdf24xx_extra_costs,
NULL, /* Scheduler cost adjustment. */
arm_default_branch_cost,
@@ -2097,7 +2079,6 @@ const struct tune_params arm_qdf24xx_tune =
const struct tune_params arm_cortex_a5_tune =
{
- arm_9e_rtx_costs,
&cortexa5_extra_costs,
NULL, /* Sched adj cost. */
arm_cortex_a5_branch_cost,
@@ -2120,7 +2101,6 @@ const struct tune_params arm_cortex_a5_tune =
const struct tune_params arm_cortex_a9_tune =
{
- arm_9e_rtx_costs,
&cortexa9_extra_costs,
cortex_a9_sched_adjust_cost,
arm_default_branch_cost,
@@ -2143,7 +2123,6 @@ const struct tune_params arm_cortex_a9_tune =
const struct tune_params arm_cortex_a12_tune =
{
- arm_9e_rtx_costs,
&cortexa12_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2166,7 +2145,6 @@ const struct tune_params arm_cortex_a12_tune =
const struct tune_params arm_cortex_a73_tune =
{
- arm_9e_rtx_costs,
&cortexa57_extra_costs,
NULL, /* Sched adj cost. */
arm_default_branch_cost,
@@ -2196,7 +2174,6 @@ const struct tune_params arm_cortex_a73_tune =
const struct tune_params arm_v7m_tune =
{
- arm_9e_rtx_costs,
&v7m_extra_costs,
NULL, /* Sched adj cost. */
arm_cortex_m_branch_cost,
@@ -2221,7 +2198,6 @@ const struct tune_params arm_v7m_tune =
const struct tune_params arm_cortex_m7_tune =
{
- arm_9e_rtx_costs,
&v7m_extra_costs,
NULL, /* Sched adj cost. */
arm_cortex_m7_branch_cost,
@@ -2243,11 +2219,11 @@ const struct tune_params arm_cortex_m7_tune =
};
/* The arm_v6m_tune is duplicated from arm_cortex_tune, rather than
- arm_v6t2_tune. It is used for cortex-m0, cortex-m1 and cortex-m0plus. */
+ arm_v6t2_tune. It is used for cortex-m0, cortex-m1, cortex-m0plus and
+ cortex-m23. */
const struct tune_params arm_v6m_tune =
{
- arm_9e_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
NULL, /* Sched adj cost. */
arm_default_branch_cost,
&arm_default_vec_cost, /* Vectorizer costs. */
@@ -2269,8 +2245,7 @@ const struct tune_params arm_v6m_tune =
const struct tune_params arm_fa726te_tune =
{
- arm_9e_rtx_costs,
- NULL, /* Insn extra costs. */
+ &generic_extra_costs, /* Insn extra costs. */
fa726te_sched_adjust_cost,
arm_default_branch_cost,
&arm_default_vec_cost,
@@ -3099,17 +3074,7 @@ arm_option_override (void)
arm_feature_set sought = ARM_FSET_EMPTY;;
arm_selected_cpu = &all_cores[TARGET_CPU_DEFAULT];
- if (!arm_selected_cpu->name)
- {
-#ifdef SUBTARGET_CPU_DEFAULT
- /* Use the subtarget default CPU if none was specified by
- configure. */
- arm_selected_cpu = &all_cores[SUBTARGET_CPU_DEFAULT];
-#endif
- /* Default to ARM6. */
- if (!arm_selected_cpu->name)
- arm_selected_cpu = &all_cores[arm6];
- }
+ gcc_assert (arm_selected_cpu->name);
sel = arm_selected_cpu;
insn_flags = sel->flags;
@@ -7900,10 +7865,10 @@ load_tls_operand (rtx x, rtx reg)
return reg;
}
-static rtx
+static rtx_insn *
arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
{
- rtx insns, label, labelno, sum;
+ rtx label, labelno, sum;
gcc_assert (reloc != TLS_DESCSEQ);
start_sequence ();
@@ -7927,7 +7892,7 @@ arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
LCT_PURE, /* LCT_CONST? */
Pmode, 1, reg, Pmode);
- insns = get_insns ();
+ rtx_insn *insns = get_insns ();
end_sequence ();
return insns;
@@ -7959,7 +7924,8 @@ arm_tls_descseq_addr (rtx x, rtx reg)
rtx
legitimize_tls_address (rtx x, rtx reg)
{
- rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
+ rtx dest, tp, label, labelno, sum, ret, eqv, addend;
+ rtx_insn *insns;
unsigned int model = SYMBOL_REF_TLS_MODEL (x);
switch (model)
@@ -8477,621 +8443,6 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
}
}
-static inline bool
-arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
-{
- machine_mode mode = GET_MODE (x);
- enum rtx_code subcode;
- rtx operand;
- enum rtx_code code = GET_CODE (x);
- *total = 0;
-
- switch (code)
- {
- case MEM:
- /* Memory costs quite a lot for the first word, but subsequent words
- load at the equivalent of a single insn each. */
- *total = COSTS_N_INSNS (2 + ARM_NUM_REGS (mode));
- return true;
-
- case DIV:
- case MOD:
- case UDIV:
- case UMOD:
- if (TARGET_HARD_FLOAT && mode == SFmode)
- *total = COSTS_N_INSNS (2);
- else if (TARGET_HARD_FLOAT && mode == DFmode && !TARGET_VFP_SINGLE)
- *total = COSTS_N_INSNS (4);
- else
- *total = COSTS_N_INSNS (20);
- return false;
-
- case ROTATE:
- if (REG_P (XEXP (x, 1)))
- *total = COSTS_N_INSNS (1); /* Need to subtract from 32 */
- else if (!CONST_INT_P (XEXP (x, 1)))
- *total = rtx_cost (XEXP (x, 1), mode, code, 1, speed);
-
- /* Fall through */
- case ROTATERT:
- if (mode != SImode)
- {
- *total += COSTS_N_INSNS (4);
- return true;
- }
-
- /* Fall through */
- case ASHIFT: case LSHIFTRT: case ASHIFTRT:
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- if (mode == DImode)
- {
- *total += COSTS_N_INSNS (3);
- return true;
- }
-
- *total += COSTS_N_INSNS (1);
- /* Increase the cost of complex shifts because they aren't any faster,
- and reduce dual issue opportunities. */
- if (arm_tune_cortex_a9
- && outer != SET && !CONST_INT_P (XEXP (x, 1)))
- ++*total;
-
- return true;
-
- case MINUS:
- if (mode == DImode)
- {
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- if (CONST_INT_P (XEXP (x, 0))
- && const_ok_for_arm (INTVAL (XEXP (x, 0))))
- {
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
- }
-
- if (CONST_INT_P (XEXP (x, 1))
- && const_ok_for_arm (INTVAL (XEXP (x, 1))))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
-
- return false;
- }
-
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- if (CONST_DOUBLE_P (XEXP (x, 0))
- && arm_const_double_rtx (XEXP (x, 0)))
- {
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
- }
-
- if (CONST_DOUBLE_P (XEXP (x, 1))
- && arm_const_double_rtx (XEXP (x, 1)))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
-
- return false;
- }
- *total = COSTS_N_INSNS (20);
- return false;
- }
-
- *total = COSTS_N_INSNS (1);
- if (CONST_INT_P (XEXP (x, 0))
- && const_ok_for_arm (INTVAL (XEXP (x, 0))))
- {
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
- }
-
- subcode = GET_CODE (XEXP (x, 1));
- if (subcode == ASHIFT || subcode == ASHIFTRT
- || subcode == LSHIFTRT
- || subcode == ROTATE || subcode == ROTATERT)
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- *total += rtx_cost (XEXP (XEXP (x, 1), 0), mode, subcode, 0, speed);
- return true;
- }
-
- /* A shift as a part of RSB costs no more than RSB itself. */
- if (GET_CODE (XEXP (x, 0)) == MULT
- && power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode))
- {
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, code, 0, speed);
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
- }
-
- if (subcode == MULT
- && power_of_two_operand (XEXP (XEXP (x, 1), 1), SImode))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- *total += rtx_cost (XEXP (XEXP (x, 1), 0), mode, subcode, 0, speed);
- return true;
- }
-
- if (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == RTX_COMPARE
- || GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == RTX_COMM_COMPARE)
- {
- *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), mode, code,
- 0, speed);
- if (REG_P (XEXP (XEXP (x, 1), 0))
- && REGNO (XEXP (XEXP (x, 1), 0)) != CC_REGNUM)
- *total += COSTS_N_INSNS (1);
-
- return true;
- }
-
- /* Fall through */
-
- case PLUS:
- if (code == PLUS && arm_arch6 && mode == SImode
- && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
- {
- *total = COSTS_N_INSNS (1);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), VOIDmode,
- GET_CODE (XEXP (x, 0)), 0, speed);
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
- }
-
- /* MLA: All arguments must be registers. We filter out
- multiplication by a power of two, so that we fall down into
- the code below. */
- if (GET_CODE (XEXP (x, 0)) == MULT
- && !power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode))
- {
- /* The cost comes from the cost of the multiply. */
- return false;
- }
-
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- if (CONST_DOUBLE_P (XEXP (x, 1))
- && arm_const_double_rtx (XEXP (x, 1)))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
-
- return false;
- }
-
- *total = COSTS_N_INSNS (20);
- return false;
- }
-
- if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == RTX_COMPARE
- || GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == RTX_COMM_COMPARE)
- {
- *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 1), mode, code,
- 1, speed);
- if (REG_P (XEXP (XEXP (x, 0), 0))
- && REGNO (XEXP (XEXP (x, 0), 0)) != CC_REGNUM)
- *total += COSTS_N_INSNS (1);
- return true;
- }
-
- /* Fall through */
-
- case AND: case XOR: case IOR:
-
- /* Normally the frame registers will be spilt into reg+const during
- reload, so it is a bad idea to combine them with other instructions,
- since then they might not be moved outside of loops. As a compromise
- we allow integration with ops that have a constant as their second
- operand. */
- if (REG_OR_SUBREG_REG (XEXP (x, 0))
- && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
- && !CONST_INT_P (XEXP (x, 1)))
- *total = COSTS_N_INSNS (1);
-
- if (mode == DImode)
- {
- *total += COSTS_N_INSNS (2);
- if (CONST_INT_P (XEXP (x, 1))
- && const_ok_for_op (INTVAL (XEXP (x, 1)), code))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
-
- return false;
- }
-
- *total += COSTS_N_INSNS (1);
- if (CONST_INT_P (XEXP (x, 1))
- && const_ok_for_op (INTVAL (XEXP (x, 1)), code))
- {
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
- subcode = GET_CODE (XEXP (x, 0));
- if (subcode == ASHIFT || subcode == ASHIFTRT
- || subcode == LSHIFTRT
- || subcode == ROTATE || subcode == ROTATERT)
- {
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, subcode, 0, speed);
- return true;
- }
-
- if (subcode == MULT
- && power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode))
- {
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, subcode, 0, speed);
- return true;
- }
-
- if (subcode == UMIN || subcode == UMAX
- || subcode == SMIN || subcode == SMAX)
- {
- *total = COSTS_N_INSNS (3);
- return true;
- }
-
- return false;
-
- case MULT:
- /* This should have been handled by the CPU specific routines. */
- gcc_unreachable ();
-
- case TRUNCATE:
- if (arm_arch3m && mode == SImode
- && GET_CODE (XEXP (x, 0)) == LSHIFTRT
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
- && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
- == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
- && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
- {
- *total = rtx_cost (XEXP (XEXP (x, 0), 0), VOIDmode, LSHIFTRT,
- 0, speed);
- return true;
- }
- *total = COSTS_N_INSNS (2); /* Plus the cost of the MULT */
- return false;
-
- case NEG:
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
- *total = COSTS_N_INSNS (2);
- return false;
- }
-
- /* Fall through */
- case NOT:
- *total = COSTS_N_INSNS (ARM_NUM_REGS(mode));
- if (mode == SImode && code == NOT)
- {
- subcode = GET_CODE (XEXP (x, 0));
- if (subcode == ASHIFT || subcode == ASHIFTRT
- || subcode == LSHIFTRT
- || subcode == ROTATE || subcode == ROTATERT
- || (subcode == MULT
- && power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode)))
- {
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, subcode,
- 0, speed);
- /* Register shifts cost an extra cycle. */
- if (!CONST_INT_P (XEXP (XEXP (x, 0), 1)))
- *total += COSTS_N_INSNS (1) + rtx_cost (XEXP (XEXP (x, 0), 1),
- mode, subcode,
- 1, speed);
- return true;
- }
- }
-
- return false;
-
- case IF_THEN_ELSE:
- if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
- {
- *total = COSTS_N_INSNS (4);
- return true;
- }
-
- operand = XEXP (x, 0);
-
- if (!((GET_RTX_CLASS (GET_CODE (operand)) == RTX_COMPARE
- || GET_RTX_CLASS (GET_CODE (operand)) == RTX_COMM_COMPARE)
- && REG_P (XEXP (operand, 0))
- && REGNO (XEXP (operand, 0)) == CC_REGNUM))
- *total += COSTS_N_INSNS (1);
- *total += rtx_cost (XEXP (x, 1), VOIDmode, code, 1, speed);
- *total += rtx_cost (XEXP (x, 2), VOIDmode, code, 2, speed);
- return true;
-
- case NE:
- if (mode == SImode && XEXP (x, 1) == const0_rtx)
- {
- *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), mode, code,
- 0, speed);
- return true;
- }
- goto scc_insn;
-
- case GE:
- if ((!REG_P (XEXP (x, 0)) || REGNO (XEXP (x, 0)) != CC_REGNUM)
- && mode == SImode && XEXP (x, 1) == const0_rtx)
- {
- *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), mode, code,
- 0, speed);
- return true;
- }
- goto scc_insn;
-
- case LT:
- if ((!REG_P (XEXP (x, 0)) || REGNO (XEXP (x, 0)) != CC_REGNUM)
- && mode == SImode && XEXP (x, 1) == const0_rtx)
- {
- *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), mode, code,
- 0, speed);
- return true;
- }
- goto scc_insn;
-
- case EQ:
- case GT:
- case LE:
- case GEU:
- case LTU:
- case GTU:
- case LEU:
- case UNORDERED:
- case ORDERED:
- case UNEQ:
- case UNGE:
- case UNLT:
- case UNGT:
- case UNLE:
- scc_insn:
- /* SCC insns. In the case where the comparison has already been
- performed, then they cost 2 instructions. Otherwise they need
- an additional comparison before them. */
- *total = COSTS_N_INSNS (2);
- if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) == CC_REGNUM)
- {
- return true;
- }
-
- /* Fall through */
- case COMPARE:
- if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) == CC_REGNUM)
- {
- *total = 0;
- return true;
- }
-
- *total += COSTS_N_INSNS (1);
- if (CONST_INT_P (XEXP (x, 1))
- && const_ok_for_op (INTVAL (XEXP (x, 1)), code))
- {
- *total += rtx_cost (XEXP (x, 0), VOIDmode, code, 0, speed);
- return true;
- }
-
- subcode = GET_CODE (XEXP (x, 0));
- if (subcode == ASHIFT || subcode == ASHIFTRT
- || subcode == LSHIFTRT
- || subcode == ROTATE || subcode == ROTATERT)
- {
- mode = GET_MODE (XEXP (x, 0));
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, subcode, 0, speed);
- return true;
- }
-
- if (subcode == MULT
- && power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode))
- {
- mode = GET_MODE (XEXP (x, 0));
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, subcode, 0, speed);
- return true;
- }
-
- return false;
-
- case UMIN:
- case UMAX:
- case SMIN:
- case SMAX:
- *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- if (!CONST_INT_P (XEXP (x, 1))
- || !const_ok_for_arm (INTVAL (XEXP (x, 1))))
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed);
- return true;
-
- case ABS:
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
- *total = COSTS_N_INSNS (20);
- return false;
- }
- *total = COSTS_N_INSNS (1);
- if (mode == DImode)
- *total += COSTS_N_INSNS (3);
- return false;
-
- case SIGN_EXTEND:
- case ZERO_EXTEND:
- *total = 0;
- if (GET_MODE_CLASS (mode) == MODE_INT)
- {
- rtx op = XEXP (x, 0);
- machine_mode opmode = GET_MODE (op);
-
- if (mode == DImode)
- *total += COSTS_N_INSNS (1);
-
- if (opmode != SImode)
- {
- if (MEM_P (op))
- {
- /* If !arm_arch4, we use one of the extendhisi2_mem
- or movhi_bytes patterns for HImode. For a QImode
- sign extension, we first zero-extend from memory
- and then perform a shift sequence. */
- if (!arm_arch4 && (opmode != QImode || code == SIGN_EXTEND))
- *total += COSTS_N_INSNS (2);
- }
- else if (arm_arch6)
- *total += COSTS_N_INSNS (1);
-
- /* We don't have the necessary insn, so we need to perform some
- other operation. */
- else if (TARGET_ARM && code == ZERO_EXTEND && mode == QImode)
- /* An and with constant 255. */
- *total += COSTS_N_INSNS (1);
- else
- /* A shift sequence. Increase costs slightly to avoid
- combining two shifts into an extend operation. */
- *total += COSTS_N_INSNS (2) + 1;
- }
-
- return false;
- }
-
- switch (GET_MODE (XEXP (x, 0)))
- {
- case V8QImode:
- case V4HImode:
- case V2SImode:
- case V4QImode:
- case V2HImode:
- *total = COSTS_N_INSNS (1);
- return false;
-
- default:
- gcc_unreachable ();
- }
- gcc_unreachable ();
-
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- mode = GET_MODE (XEXP (x, 0));
- *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
-
- case CONST_INT:
- if (const_ok_for_arm (INTVAL (x))
- || const_ok_for_arm (~INTVAL (x)))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (arm_gen_constant (SET, mode, NULL_RTX,
- INTVAL (x), NULL_RTX,
- NULL_RTX, 0, 0));
- return true;
-
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- *total = COSTS_N_INSNS (3);
- return true;
-
- case HIGH:
- *total = COSTS_N_INSNS (1);
- return true;
-
- case LO_SUM:
- *total = COSTS_N_INSNS (1);
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
-
- case CONST_DOUBLE:
- if (TARGET_HARD_FLOAT && vfp3_const_double_rtx (x)
- && (mode == SFmode || !TARGET_VFP_SINGLE))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (4);
- return true;
-
- case SET:
- /* The vec_extract patterns accept memory operands that require an
- address reload. Account for the cost of that reload to give the
- auto-inc-dec pass an incentive to try to replace them. */
- if (TARGET_NEON && MEM_P (SET_DEST (x))
- && GET_CODE (SET_SRC (x)) == VEC_SELECT)
- {
- mode = GET_MODE (SET_DEST (x));
- *total = rtx_cost (SET_DEST (x), mode, code, 0, speed);
- if (!neon_vector_mem_operand (SET_DEST (x), 2, true))
- *total += COSTS_N_INSNS (1);
- return true;
- }
- /* Likewise for the vec_set patterns. */
- if (TARGET_NEON && GET_CODE (SET_SRC (x)) == VEC_MERGE
- && GET_CODE (XEXP (SET_SRC (x), 0)) == VEC_DUPLICATE
- && MEM_P (XEXP (XEXP (SET_SRC (x), 0), 0)))
- {
- rtx mem = XEXP (XEXP (SET_SRC (x), 0), 0);
- mode = GET_MODE (SET_DEST (x));
- *total = rtx_cost (mem, mode, code, 0, speed);
- if (!neon_vector_mem_operand (mem, 2, true))
- *total += COSTS_N_INSNS (1);
- return true;
- }
- return false;
-
- case UNSPEC:
- /* We cost this as high as our memory costs to allow this to
- be hoisted from loops. */
- if (XINT (x, 1) == UNSPEC_PIC_UNIFIED)
- {
- *total = COSTS_N_INSNS (2 + ARM_NUM_REGS (mode));
- }
- return true;
-
- case CONST_VECTOR:
- if (TARGET_NEON
- && TARGET_HARD_FLOAT
- && outer == SET
- && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))
- && neon_immediate_valid_for_move (x, mode, NULL, NULL))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (4);
- return true;
-
- default:
- *total = COSTS_N_INSNS (4);
- return false;
- }
-}
-
/* Estimates the size cost of thumb1 instructions.
For now most of the code is copied from thumb1_rtx_costs. We need more
fine grain tuning when we have more related test cases. */
@@ -9251,245 +8602,6 @@ thumb1_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
}
}
-/* RTX costs when optimizing for size. */
-static bool
-arm_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
- int *total)
-{
- machine_mode mode = GET_MODE (x);
- if (TARGET_THUMB1)
- {
- *total = thumb1_size_rtx_costs (x, code, outer_code);
- return true;
- }
-
- /* FIXME: This makes no attempt to prefer narrow Thumb-2 instructions. */
- switch (code)
- {
- case MEM:
- /* A memory access costs 1 insn if the mode is small, or the address is
- a single register, otherwise it costs one insn per word. */
- if (REG_P (XEXP (x, 0)))
- *total = COSTS_N_INSNS (1);
- else if (flag_pic
- && GET_CODE (XEXP (x, 0)) == PLUS
- && will_be_in_index_register (XEXP (XEXP (x, 0), 1)))
- /* This will be split into two instructions.
- See arm.md:calculate_pic_address. */
- *total = COSTS_N_INSNS (2);
- else
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- return true;
-
- case DIV:
- case MOD:
- case UDIV:
- case UMOD:
- /* Needs a libcall, so it costs about this. */
- *total = COSTS_N_INSNS (2);
- return false;
-
- case ROTATE:
- if (mode == SImode && REG_P (XEXP (x, 1)))
- {
- *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), mode, code,
- 0, false);
- return true;
- }
- /* Fall through */
- case ROTATERT:
- case ASHIFT:
- case LSHIFTRT:
- case ASHIFTRT:
- if (mode == DImode && CONST_INT_P (XEXP (x, 1)))
- {
- *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), mode, code,
- 0, false);
- return true;
- }
- else if (mode == SImode)
- {
- *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), mode, code,
- 0, false);
- /* Slightly disparage register shifts, but not by much. */
- if (!CONST_INT_P (XEXP (x, 1)))
- *total += 1 + rtx_cost (XEXP (x, 1), mode, code, 1, false);
- return true;
- }
-
- /* Needs a libcall. */
- *total = COSTS_N_INSNS (2);
- return false;
-
- case MINUS:
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
- && (mode == SFmode || !TARGET_VFP_SINGLE))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
-
- if (mode == SImode)
- {
- enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
- enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
-
- if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
- || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
- || subcode1 == ROTATE || subcode1 == ROTATERT
- || subcode1 == ASHIFT || subcode1 == LSHIFTRT
- || subcode1 == ASHIFTRT)
- {
- /* It's just the cost of the two operands. */
- *total = 0;
- return false;
- }
-
- *total = COSTS_N_INSNS (1);
- return false;
- }
-
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- return false;
-
- case PLUS:
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
- && (mode == SFmode || !TARGET_VFP_SINGLE))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
-
- /* A shift as a part of ADD costs nothing. */
- if (GET_CODE (XEXP (x, 0)) == MULT
- && power_of_two_operand (XEXP (XEXP (x, 0), 1), SImode))
- {
- *total = COSTS_N_INSNS (TARGET_THUMB2 ? 2 : 1);
- *total += rtx_cost (XEXP (XEXP (x, 0), 0), mode, code, 0, false);
- *total += rtx_cost (XEXP (x, 1), mode, code, 1, false);
- return true;
- }
-
- /* Fall through */
- case AND: case XOR: case IOR:
- if (mode == SImode)
- {
- enum rtx_code subcode = GET_CODE (XEXP (x, 0));
-
- if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
- || subcode == LSHIFTRT || subcode == ASHIFTRT
- || (code == AND && subcode == NOT))
- {
- /* It's just the cost of the two operands. */
- *total = 0;
- return false;
- }
- }
-
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- return false;
-
- case MULT:
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- return false;
-
- case NEG:
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
- && (mode == SFmode || !TARGET_VFP_SINGLE))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
-
- /* Fall through */
- case NOT:
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
-
- return false;
-
- case IF_THEN_ELSE:
- *total = 0;
- return false;
-
- case COMPARE:
- if (cc_register (XEXP (x, 0), VOIDmode))
- * total = 0;
- else
- *total = COSTS_N_INSNS (1);
- return false;
-
- case ABS:
- if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
- && (mode == SFmode || !TARGET_VFP_SINGLE))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
- return false;
-
- case SIGN_EXTEND:
- case ZERO_EXTEND:
- return arm_rtx_costs_1 (x, outer_code, total, 0);
-
- case CONST_INT:
- if (const_ok_for_arm (INTVAL (x)))
- /* A multiplication by a constant requires another instruction
- to load the constant to a register. */
- *total = COSTS_N_INSNS ((outer_code == SET || outer_code == MULT)
- ? 1 : 0);
- else if (const_ok_for_arm (~INTVAL (x)))
- *total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
- else if (const_ok_for_arm (-INTVAL (x)))
- {
- if (outer_code == COMPARE || outer_code == PLUS
- || outer_code == MINUS)
- *total = 0;
- else
- *total = COSTS_N_INSNS (1);
- }
- else
- *total = COSTS_N_INSNS (2);
- return true;
-
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- *total = COSTS_N_INSNS (2);
- return true;
-
- case CONST_DOUBLE:
- *total = COSTS_N_INSNS (4);
- return true;
-
- case CONST_VECTOR:
- if (TARGET_NEON
- && TARGET_HARD_FLOAT
- && outer_code == SET
- && (VALID_NEON_DREG_MODE (mode) || VALID_NEON_QREG_MODE (mode))
- && neon_immediate_valid_for_move (x, mode, NULL, NULL))
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (4);
- return true;
-
- case HIGH:
- case LO_SUM:
- /* We prefer constant pool entries to MOVW/MOVT pairs, so bump the
- cost of these slightly. */
- *total = COSTS_N_INSNS (1) + 1;
- return true;
-
- case SET:
- return false;
-
- default:
- if (mode != VOIDmode)
- *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
- else
- *total = COSTS_N_INSNS (4); /* How knows? */
- return false;
- }
-}
-
/* Helper function for arm_rtx_costs. If the operand is a valid shift
operand, then return the operand that is being shifted. If the shift
is not by a constant, then set SHIFT_REG to point to the operand.
@@ -9613,7 +8725,7 @@ arm_unspec_cost (rtx x, enum rtx_code /* outer_code */, bool speed_p, int *cost)
flags are live or not, and thus no realistic way to determine what
the size will eventually be. */
static bool
-arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
+arm_rtx_costs_internal (rtx x, enum rtx_code code, enum rtx_code outer_code,
const struct cpu_cost_table *extra_cost,
int *cost, bool speed_p)
{
@@ -11296,41 +10408,20 @@ arm_new_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
#undef HANDLE_NARROW_SHIFT_ARITH
-/* RTX costs when optimizing for size. */
+/* RTX costs entry point. */
+
static bool
arm_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
int opno ATTRIBUTE_UNUSED, int *total, bool speed)
{
bool result;
int code = GET_CODE (x);
+ gcc_assert (current_tune->insn_extra_cost);
- if (TARGET_OLD_RTX_COSTS
- || (!current_tune->insn_extra_cost && !TARGET_NEW_GENERIC_COSTS))
- {
- /* Old way. (Deprecated.) */
- if (!speed)
- result = arm_size_rtx_costs (x, (enum rtx_code) code,
- (enum rtx_code) outer_code, total);
- else
- result = current_tune->rtx_costs (x, (enum rtx_code) code,
- (enum rtx_code) outer_code, total,
- speed);
- }
- else
- {
- /* New way. */
- if (current_tune->insn_extra_cost)
- result = arm_new_rtx_costs (x, (enum rtx_code) code,
- (enum rtx_code) outer_code,
- current_tune->insn_extra_cost,
- total, speed);
- /* TARGET_NEW_GENERIC_COSTS && !TARGET_OLD_RTX_COSTS
- && current_tune->insn_extra_cost != NULL */
- else
- result = arm_new_rtx_costs (x, (enum rtx_code) code,
- (enum rtx_code) outer_code,
- &generic_extra_costs, total, speed);
- }
+ result = arm_rtx_costs_internal (x, (enum rtx_code) code,
+ (enum rtx_code) outer_code,
+ current_tune->insn_extra_cost,
+ total, speed);
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -11341,305 +10432,6 @@ arm_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code,
return result;
}
-/* RTX costs for cores with a slow MUL implementation. Thumb-2 is not
- supported on any "slowmul" cores, so it can be ignored. */
-
-static bool
-arm_slowmul_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
- int *total, bool speed)
-{
- machine_mode mode = GET_MODE (x);
-
- if (TARGET_THUMB)
- {
- *total = thumb1_rtx_costs (x, code, outer_code);
- return true;
- }
-
- switch (code)
- {
- case MULT:
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- || mode == DImode)
- {
- *total = COSTS_N_INSNS (20);
- return false;
- }
-
- if (CONST_INT_P (XEXP (x, 1)))
- {
- unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
- & (unsigned HOST_WIDE_INT) 0xffffffff);
- int cost, const_ok = const_ok_for_arm (i);
- int j, booth_unit_size;
-
- /* Tune as appropriate. */
- cost = const_ok ? 4 : 8;
- booth_unit_size = 2;
- for (j = 0; i && j < 32; j += booth_unit_size)
- {
- i >>= booth_unit_size;
- cost++;
- }
-
- *total = COSTS_N_INSNS (cost);
- *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed);
- return true;
- }
-
- *total = COSTS_N_INSNS (20);
- return false;
-
- default:
- return arm_rtx_costs_1 (x, outer_code, total, speed);;
- }
-}
-
-
-/* RTX cost for cores with a fast multiply unit (M variants). */
-
-static bool
-arm_fastmul_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
- int *total, bool speed)
-{
- machine_mode mode = GET_MODE (x);
-
- if (TARGET_THUMB1)
- {
- *total = thumb1_rtx_costs (x, code, outer_code);
- return true;
- }
-
- /* ??? should thumb2 use different costs? */
- switch (code)
- {
- case MULT:
- /* There is no point basing this on the tuning, since it is always the
- fast variant if it exists at all. */
- if (mode == DImode
- && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
- && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
- {
- *total = COSTS_N_INSNS(2);
- return false;
- }
-
-
- if (mode == DImode)
- {
- *total = COSTS_N_INSNS (5);
- return false;
- }
-
- if (CONST_INT_P (XEXP (x, 1)))
- {
- unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
- & (unsigned HOST_WIDE_INT) 0xffffffff);
- int cost, const_ok = const_ok_for_arm (i);
- int j, booth_unit_size;
-
- /* Tune as appropriate. */
- cost = const_ok ? 4 : 8;
- booth_unit_size = 8;
- for (j = 0; i && j < 32; j += booth_unit_size)
- {
- i >>= booth_unit_size;
- cost++;
- }
-
- *total = COSTS_N_INSNS(cost);
- return false;
- }
-
- if (mode == SImode)
- {
- *total = COSTS_N_INSNS (4);
- return false;
- }
-
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
- }
-
- /* Requires a lib call */
- *total = COSTS_N_INSNS (20);
- return false;
-
- default:
- return arm_rtx_costs_1 (x, outer_code, total, speed);
- }
-}
-
-
-/* RTX cost for XScale CPUs. Thumb-2 is not supported on any xscale cores,
- so it can be ignored. */
-
-static bool
-arm_xscale_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
- int *total, bool speed)
-{
- machine_mode mode = GET_MODE (x);
-
- if (TARGET_THUMB)
- {
- *total = thumb1_rtx_costs (x, code, outer_code);
- return true;
- }
-
- switch (code)
- {
- case COMPARE:
- if (GET_CODE (XEXP (x, 0)) != MULT)
- return arm_rtx_costs_1 (x, outer_code, total, speed);
-
- /* A COMPARE of a MULT is slow on XScale; the muls instruction
- will stall until the multiplication is complete. */
- *total = COSTS_N_INSNS (3);
- return false;
-
- case MULT:
- /* There is no point basing this on the tuning, since it is always the
- fast variant if it exists at all. */
- if (mode == DImode
- && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
- && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
- {
- *total = COSTS_N_INSNS (2);
- return false;
- }
-
-
- if (mode == DImode)
- {
- *total = COSTS_N_INSNS (5);
- return false;
- }
-
- if (CONST_INT_P (XEXP (x, 1)))
- {
- /* If operand 1 is a constant we can more accurately
- calculate the cost of the multiply. The multiplier can
- retire 15 bits on the first cycle and a further 12 on the
- second. We do, of course, have to load the constant into
- a register first. */
- unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
- /* There's a general overhead of one cycle. */
- int cost = 1;
- unsigned HOST_WIDE_INT masked_const;
-
- if (i & 0x80000000)
- i = ~i;
-
- i &= (unsigned HOST_WIDE_INT) 0xffffffff;
-
- masked_const = i & 0xffff8000;
- if (masked_const != 0)
- {
- cost++;
- masked_const = i & 0xf8000000;
- if (masked_const != 0)
- cost++;
- }
- *total = COSTS_N_INSNS (cost);
- return false;
- }
-
- if (mode == SImode)
- {
- *total = COSTS_N_INSNS (3);
- return false;
- }
-
- /* Requires a lib call */
- *total = COSTS_N_INSNS (20);
- return false;
-
- default:
- return arm_rtx_costs_1 (x, outer_code, total, speed);
- }
-}
-
-
-/* RTX costs for 9e (and later) cores. */
-
-static bool
-arm_9e_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
- int *total, bool speed)
-{
- machine_mode mode = GET_MODE (x);
-
- if (TARGET_THUMB1)
- {
- switch (code)
- {
- case MULT:
- /* Small multiply: 32 cycles for an integer multiply inst. */
- if (arm_arch6m && arm_m_profile_small_mul)
- *total = COSTS_N_INSNS (32);
- else
- *total = COSTS_N_INSNS (3);
- return true;
-
- default:
- *total = thumb1_rtx_costs (x, code, outer_code);
- return true;
- }
- }
-
- switch (code)
- {
- case MULT:
- /* There is no point basing this on the tuning, since it is always the
- fast variant if it exists at all. */
- if (mode == DImode
- && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
- && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
- || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
- {
- *total = COSTS_N_INSNS (2);
- return false;
- }
-
-
- if (mode == DImode)
- {
- *total = COSTS_N_INSNS (5);
- return false;
- }
-
- if (mode == SImode)
- {
- *total = COSTS_N_INSNS (2);
- return false;
- }
-
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
- {
- if (TARGET_HARD_FLOAT
- && (mode == SFmode
- || (mode == DFmode && !TARGET_VFP_SINGLE)))
- {
- *total = COSTS_N_INSNS (1);
- return false;
- }
- }
-
- *total = COSTS_N_INSNS (20);
- return false;
-
- default:
- return arm_rtx_costs_1 (x, outer_code, total, speed);
- }
-}
/* All address computations that can be done are free, but rtx cost returns
the same for practically all of them. So we weight the different types
of address here in the order (most pref first):
@@ -30150,9 +28942,9 @@ arm_const_not_ok_for_debug_p (rtx p)
&& GET_CODE (XEXP (p, 0)) == SYMBOL_REF
&& (decl_op0 = SYMBOL_REF_DECL (XEXP (p, 0))))
{
- if ((TREE_CODE (decl_op1) == VAR_DECL
+ if ((VAR_P (decl_op1)
|| TREE_CODE (decl_op1) == CONST_DECL)
- && (TREE_CODE (decl_op0) == VAR_DECL
+ && (VAR_P (decl_op0)
|| TREE_CODE (decl_op0) == CONST_DECL))
return (get_variable_section (decl_op1, false)
!= get_variable_section (decl_op0, false));
@@ -30845,4 +29637,33 @@ arm_elf_section_type_flags (tree decl, const char *name, int reloc)
return flags;
}
+/* Generate call to __aeabi_[mode]divmod (op0, op1). */
+
+static void
+arm_expand_divmod_libfunc (rtx libfunc, machine_mode mode,
+ rtx op0, rtx op1,
+ rtx *quot_p, rtx *rem_p)
+{
+ if (mode == SImode)
+ gcc_assert (!TARGET_IDIV);
+
+ machine_mode libval_mode = smallest_mode_for_size (2 * GET_MODE_BITSIZE (mode),
+ MODE_INT);
+
+ rtx libval = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+ libval_mode, 2,
+ op0, GET_MODE (op0),
+ op1, GET_MODE (op1));
+
+ rtx quotient = simplify_gen_subreg (mode, libval, libval_mode, 0);
+ rtx remainder = simplify_gen_subreg (mode, libval, libval_mode,
+ GET_MODE_SIZE (mode));
+
+ gcc_assert (quotient);
+ gcc_assert (remainder);
+
+ *quot_p = quotient;
+ *rem_p = remainder;
+}
+
#include "gt-arm.h"
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index b2d8422d494..3d11555d647 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -55,7 +55,8 @@ enum target_cpus
TARGET_CPU_##INTERNAL_IDENT,
#include "arm-cores.def"
#undef ARM_CORE
- TARGET_CPU_generic
+ /* Total number of CPUs we handle. */
+ TARGET_CPU_num_cores
};
/* The processor for which instructions should be scheduled. */
@@ -83,12 +84,6 @@ extern GTY(()) rtx arm_target_insn;
/* Callback to output language specific object attributes. */
extern void (*arm_lang_output_object_attributes_hook)(void);
-/* Just in case configure has failed to define anything. */
-#ifndef TARGET_CPU_DEFAULT
-#define TARGET_CPU_DEFAULT TARGET_CPU_generic
-#endif
-
-
#undef CPP_SPEC
#define CPP_SPEC "%(subtarget_cpp_spec) \
%{mfloat-abi=soft:%{mfloat-abi=hard: \
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index 35f047e2de1..54d84dc9f3a 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -253,14 +253,6 @@ mrestrict-it
Target Report Var(arm_restrict_it) Init(2) Save
Generate IT blocks appropriate for ARMv8.
-mold-rtx-costs
-Target Report Mask(OLD_RTX_COSTS)
-Use the old RTX costing tables (transitional).
-
-mnew-generic-costs
-Target Report Mask(NEW_GENERIC_COSTS)
-Use the new generic RTX cost tables if new core-specific cost table not available (transitional).
-
mfix-cortex-m3-ldrd
Target Report Var(fix_cm3_ldrd) Init(2)
Avoid overlapping destination and address registers on LDRD instructions
diff --git a/gcc/config/arm/arm_neon.h b/gcc/config/arm/arm_neon.h
index 54bbc7dd83c..3898ff7302d 100644
--- a/gcc/config/arm/arm_neon.h
+++ b/gcc/config/arm/arm_neon.h
@@ -2956,6 +2956,34 @@ vmaxq_f32 (float32x4_t __a, float32x4_t __b)
return (float32x4_t)__builtin_neon_vmaxfv4sf (__a, __b);
}
+#pragma GCC push_options
+#pragma GCC target ("fpu=neon-fp-armv8")
+__extension__ static __inline float32x2_t __attribute__ ((__always_inline__))
+vmaxnm_f32 (float32x2_t a, float32x2_t b)
+{
+ return (float32x2_t)__builtin_neon_vmaxnmv2sf (a, b);
+}
+
+__extension__ static __inline float32x4_t __attribute__ ((__always_inline__))
+vmaxnmq_f32 (float32x4_t a, float32x4_t b)
+{
+ return (float32x4_t)__builtin_neon_vmaxnmv4sf (a, b);
+}
+
+__extension__ static __inline float32x2_t __attribute__ ((__always_inline__))
+vminnm_f32 (float32x2_t a, float32x2_t b)
+{
+ return (float32x2_t)__builtin_neon_vminnmv2sf (a, b);
+}
+
+__extension__ static __inline float32x4_t __attribute__ ((__always_inline__))
+vminnmq_f32 (float32x4_t a, float32x4_t b)
+{
+ return (float32x4_t)__builtin_neon_vminnmv4sf (a, b);
+}
+#pragma GCC pop_options
+
+
__extension__ static __inline uint8x16_t __attribute__ ((__always_inline__))
vmaxq_u8 (uint8x16_t __a, uint8x16_t __b)
{
diff --git a/gcc/config/arm/arm_neon_builtins.def b/gcc/config/arm/arm_neon_builtins.def
index b29aa91a64e..58b10207c1f 100644
--- a/gcc/config/arm/arm_neon_builtins.def
+++ b/gcc/config/arm/arm_neon_builtins.def
@@ -147,12 +147,12 @@ VAR6 (BINOP, vmaxs, v8qi, v4hi, v2si, v16qi, v8hi, v4si)
VAR6 (BINOP, vmaxu, v8qi, v4hi, v2si, v16qi, v8hi, v4si)
VAR2 (BINOP, vmaxf, v2sf, v4sf)
VAR2 (BINOP, vmaxf, v8hf, v4hf)
-VAR2 (BINOP, vmaxnm, v4hf, v8hf)
+VAR4 (BINOP, vmaxnm, v2sf, v4sf, v4hf, v8hf)
VAR6 (BINOP, vmins, v8qi, v4hi, v2si, v16qi, v8hi, v4si)
VAR6 (BINOP, vminu, v8qi, v4hi, v2si, v16qi, v8hi, v4si)
VAR2 (BINOP, vminf, v2sf, v4sf)
VAR2 (BINOP, vminf, v4hf, v8hf)
-VAR2 (BINOP, vminnm, v8hf, v4hf)
+VAR4 (BINOP, vminnm, v2sf, v4sf, v8hf, v4hf)
VAR3 (BINOP, vpmaxs, v8qi, v4hi, v2si)
VAR3 (BINOP, vpmaxu, v8qi, v4hi, v2si)
diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h
index 0da98fb711b..d45a1ca4219 100644
--- a/gcc/config/arm/bpabi.h
+++ b/gcc/config/arm/bpabi.h
@@ -95,9 +95,9 @@
|march=armv8.1-a+crc \
|march=armv8.2-a \
|march=armv8.2-a+fp16 \
- |march=armv8-m.base \
+ |march=armv8-m.base|mcpu=cortex-m23 \
|march=armv8-m.main \
- |march=armv8-m.main+dsp \
+ |march=armv8-m.main+dsp|mcpu=cortex-m33 \
:%{!r:--be8}}}"
#else
#define BE8_LINK_SPEC \
@@ -134,9 +134,9 @@
|march=armv8.1-a+crc \
|march=armv8.2-a \
|march=armv8.2-a+fp16 \
- |march=armv8-m.base \
+ |march=armv8-m.base|mcpu=cortex-m23 \
|march=armv8-m.main \
- |march=armv8-m.main+dsp \
+ |march=armv8-m.main+dsp|mcpu=cortex-m33 \
:%{!r:--be8}}}"
#endif
diff --git a/gcc/config/arm/freebsd.h b/gcc/config/arm/freebsd.h
index 0ade4e99be1..949c397521c 100644
--- a/gcc/config/arm/freebsd.h
+++ b/gcc/config/arm/freebsd.h
@@ -112,14 +112,6 @@
#undef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE BITS_PER_WORD
-#if defined (TARGET_FREEBSD_ARMv6)
-#undef SUBTARGET_CPU_DEFAULT
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm1176jzs
-#else
-#undef SUBTARGET_CPU_DEFAULT
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm9
-#endif
-
/* FreeBSD 10 does not support unaligned access for armv6 and up.
Unaligned access support was added in FreeBSD 11. */
#if FBSD_MAJOR < 11
diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h
index ace84816e06..9cfcf9fffd9 100644
--- a/gcc/config/arm/linux-eabi.h
+++ b/gcc/config/arm/linux-eabi.h
@@ -41,12 +41,6 @@
#undef ARM_DEFAULT_ABI
#define ARM_DEFAULT_ABI ARM_ABI_AAPCS_LINUX
-/* Default to armv5t so that thumb shared libraries work.
- The ARM10TDMI core is the default for armv5t, so set
- SUBTARGET_CPU_DEFAULT to achieve this. */
-#undef SUBTARGET_CPU_DEFAULT
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
-
/* TARGET_BIG_ENDIAN_DEFAULT is set in
config.gcc for big endian configurations. */
#undef TARGET_LINKER_EMULATION
diff --git a/gcc/config/arm/linux-elf.h b/gcc/config/arm/linux-elf.h
index a94bd2d2f8d..cc17b51eeab 100644
--- a/gcc/config/arm/linux-elf.h
+++ b/gcc/config/arm/linux-elf.h
@@ -45,8 +45,6 @@
#undef TARGET_DEFAULT
#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT)
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6
-
#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p"
/* We do not have any MULTILIB_OPTIONS specified, so there are no
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 59316de0041..4297511c186 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -2845,6 +2845,17 @@
[(set_attr "type" "neon_fp_minmax_s<q>")]
)
+;; v<maxmin>nm intrinsics.
+(define_insn "neon_<fmaxmin_op><mode>"
+ [(set (match_operand:VCVTF 0 "s_register_operand" "=w")
+ (unspec:VCVTF [(match_operand:VCVTF 1 "s_register_operand" "w")
+ (match_operand:VCVTF 2 "s_register_operand" "w")]
+ VMAXMINFNM))]
+ "TARGET_NEON && TARGET_FPU_ARMV8"
+ "<fmaxmin_op>.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
+ [(set_attr "type" "neon_fp_minmax_s<q>")]
+)
+
;; Vector forms for the IEEE-754 fmax()/fmin() functions
(define_insn "<fmaxmin><mode>3"
[(set (match_operand:VCVTF 0 "s_register_operand" "=w")
diff --git a/gcc/config/arm/symbian.h b/gcc/config/arm/symbian.h
index fc9c350cd08..af078d57a2c 100644
--- a/gcc/config/arm/symbian.h
+++ b/gcc/config/arm/symbian.h
@@ -59,12 +59,6 @@
/* Support the "dllimport" attribute. */
#define TARGET_DLLIMPORT_DECL_ATTRIBUTES 1
-/* Symbian OS assumes ARM V5 or above. Since -march=armv5 is
- equivalent to making the ARM 10TDMI core the default, we can set
- SUBTARGET_CPU_DEFAULT and get an equivalent effect. */
-#undef SUBTARGET_CPU_DEFAULT
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi
-
/* The assembler should assume VFP FPU format, and armv5t. */
#undef SUBTARGET_ASM_FLOAT_SPEC
#define SUBTARGET_ASM_FLOAT_SPEC \
diff --git a/gcc/config/arm/unknown-elf.h b/gcc/config/arm/unknown-elf.h
index fafe0574ee1..e5c050785a6 100644
--- a/gcc/config/arm/unknown-elf.h
+++ b/gcc/config/arm/unknown-elf.h
@@ -88,10 +88,6 @@
} \
while (0)
-#ifndef SUBTARGET_CPU_DEFAULT
-#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm7tdmi
-#endif
-
/* The libgcc udivmod functions may throw exceptions. If newlib is
configured to support long longs in I/O, then printf will depend on
udivmoddi4, which will depend on the exception unwind routines,
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 2dfd03865d9..5f0efd9b544 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -3432,7 +3432,8 @@ hwloop_optimize (hwloop_info loop)
basic_block bb;
rtx_insn *insn, *last_insn;
rtx loop_init, start_label, end_label;
- rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
+ rtx iter_reg, scratchreg, scratch_init;
+ rtx_insn *scratch_init_insn;
rtx lc_reg, lt_reg, lb_reg;
rtx seq_end;
rtx_insn *seq;
@@ -3453,7 +3454,7 @@ hwloop_optimize (hwloop_info loop)
scratchreg = NULL_RTX;
scratch_init = iter_reg;
- scratch_init_insn = NULL_RTX;
+ scratch_init_insn = NULL;
if (!PREG_P (iter_reg) && loop->incoming_src)
{
basic_block bb_in = loop->incoming_src;
@@ -3977,7 +3978,7 @@ bfin_gen_bundles (void)
for (insn = BB_HEAD (bb);; insn = next)
{
int at_end;
- rtx delete_this = NULL_RTX;
+ rtx_insn *delete_this = NULL;
if (NONDEBUG_INSN_P (insn))
{
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
index f8c3d668dbe..6cb9185ca02 100644
--- a/gcc/config/c6x/c6x.c
+++ b/gcc/config/c6x/c6x.c
@@ -4856,7 +4856,7 @@ find_last_same_clock (rtx_insn *insn)
the SEQUENCEs that represent execute packets. */
static void
-reorg_split_calls (rtx *call_labels)
+reorg_split_calls (rtx_insn **call_labels)
{
unsigned int reservation_mask = 0;
rtx_insn *insn = get_insns ();
@@ -4878,7 +4878,7 @@ reorg_split_calls (rtx *call_labels)
if (returning_call_p (insn))
{
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
rtx labelref = gen_rtx_LABEL_REF (Pmode, label);
rtx reg = gen_rtx_REG (SImode, RETURN_ADDR_REGNO);
@@ -5029,7 +5029,7 @@ reorg_split_calls (rtx *call_labels)
scheduling was run earlier. */
static void
-reorg_emit_nops (rtx *call_labels)
+reorg_emit_nops (rtx_insn **call_labels)
{
bool first;
rtx last_call;
@@ -5921,7 +5921,6 @@ static void
c6x_reorg (void)
{
basic_block bb;
- rtx *call_labels;
bool do_selsched = (c6x_flag_schedule_insns2 && flag_selective_scheduling2
&& !maybe_skip_selective_scheduling ());
@@ -5967,7 +5966,7 @@ c6x_reorg (void)
}
sched_no_dce = false;
- call_labels = XCNEWVEC (rtx, get_max_uid () + 1);
+ rtx_insn **call_labels = XCNEWVEC (rtx_insn *, get_max_uid () + 1);
reorg_split_calls (call_labels);
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 50899a7e487..fb01685fb89 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -7594,7 +7594,7 @@ static void
frv_reorder_packet (void)
{
unsigned int cursor[NUM_GROUPS];
- rtx insns[ARRAY_SIZE (frv_unit_groups)];
+ rtx_insn *insns[ARRAY_SIZE (frv_unit_groups)];
unsigned int unit, to, from;
enum frv_insn_group group;
struct frv_packet_group *packet_group;
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f70eb43c922..a5c4ba7b630 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -80,6 +80,8 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const-call.h"
#include "tree-vrp.h"
#include "tree-ssanames.h"
+#include "selftest.h"
+#include "selftest-rtl.h"
/* This file should be included last. */
#include "target-def.h"
@@ -2803,11 +2805,24 @@ dimode_scalar_to_vector_candidate_p (rtx_insn *insn)
switch (GET_CODE (src))
{
+ case ASHIFT:
+ case LSHIFTRT:
+ /* Consider only non-variable shifts narrower
+ than general register width. */
+ if (!(CONST_INT_P (XEXP (src, 1))
+ && IN_RANGE (INTVAL (XEXP (src, 1)), 0, 31)))
+ return false;
+ break;
+
case PLUS:
case MINUS:
case IOR:
case XOR:
case AND:
+ if (!REG_P (XEXP (src, 1))
+ && !MEM_P (XEXP (src, 1))
+ && !CONST_INT_P (XEXP (src, 1)))
+ return false;
break;
case REG:
@@ -2830,11 +2845,6 @@ dimode_scalar_to_vector_candidate_p (rtx_insn *insn)
|| !REG_P (XEXP (XEXP (src, 0), 0))))
return false;
- if (!REG_P (XEXP (src, 1))
- && !MEM_P (XEXP (src, 1))
- && !CONST_INT_P (XEXP (src, 1)))
- return false;
-
if ((GET_MODE (XEXP (src, 0)) != DImode
&& !CONST_INT_P (XEXP (src, 0)))
|| (GET_MODE (XEXP (src, 1)) != DImode
@@ -3385,6 +3395,13 @@ dimode_scalar_chain::compute_convert_gain ()
gain += 2 * ix86_cost->int_store[2] - ix86_cost->sse_store[1];
else if (MEM_P (src) && REG_P (dst))
gain += 2 * ix86_cost->int_load[2] - ix86_cost->sse_load[1];
+ else if (GET_CODE (src) == ASHIFT
+ || GET_CODE (src) == LSHIFTRT)
+ {
+ gain += ix86_cost->add;
+ if (CONST_INT_P (XEXP (src, 0)))
+ gain -= vector_const_cost (XEXP (src, 0));
+ }
else if (GET_CODE (src) == PLUS
|| GET_CODE (src) == MINUS
|| GET_CODE (src) == IOR
@@ -3736,6 +3753,12 @@ dimode_scalar_chain::convert_insn (rtx_insn *insn)
switch (GET_CODE (src))
{
+ case ASHIFT:
+ case LSHIFTRT:
+ convert_op (&XEXP (src, 0), insn);
+ PUT_MODE (src, V2DImode);
+ break;
+
case PLUS:
case MINUS:
case IOR:
@@ -20376,7 +20399,8 @@ ix86_split_idivmod (machine_mode mode, rtx operands[],
bool signed_p)
{
rtx_code_label *end_label, *qimode_label;
- rtx insn, div, mod;
+ rtx div, mod;
+ rtx_insn *insn;
rtx scratch, tmp0, tmp1, tmp2;
rtx (*gen_divmod4_1) (rtx, rtx, rtx, rtx);
rtx (*gen_zero_extend) (rtx, rtx);
@@ -23558,6 +23582,7 @@ ix86_expand_sse_cmp (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1,
cmp_op1 = force_reg (cmp_ops_mode, cmp_op1);
if (optimize
+ || (maskcmp && cmp_mode != mode)
|| (op_true && reg_overlap_mentioned_p (dest, op_true))
|| (op_false && reg_overlap_mentioned_p (dest, op_false)))
dest = gen_reg_rtx (maskcmp ? cmp_mode : mode);
@@ -33515,7 +33540,7 @@ ix86_gimple_fold_builtin (gimple_stmt_iterator *gsi)
gsi_insert_before (gsi, g, GSI_SAME_STMT);
g = gimple_build_assign (gimple_call_lhs (stmt), NOP_EXPR, lhs);
gimple_set_location (g, loc);
- gsi_replace (gsi, g, true);
+ gsi_replace (gsi, g, false);
return true;
}
break;
@@ -33533,7 +33558,7 @@ ix86_gimple_fold_builtin (gimple_stmt_iterator *gsi)
location_t loc = gimple_location (stmt);
gimple *g = gimple_build_assign (gimple_call_lhs (stmt), arg0);
gimple_set_location (g, loc);
- gsi_replace (gsi, g, true);
+ gsi_replace (gsi, g, false);
return true;
}
break;
@@ -33550,7 +33575,7 @@ ix86_gimple_fold_builtin (gimple_stmt_iterator *gsi)
arg0 = gimple_call_arg (stmt, 0);
gimple *g = gimple_build_assign (gimple_call_lhs (stmt), arg0);
gimple_set_location (g, loc);
- gsi_replace (gsi, g, true);
+ gsi_replace (gsi, g, false);
return true;
}
break;
@@ -50571,8 +50596,70 @@ ix86_addr_space_zero_address_valid (addr_space_t as)
{
return as != ADDR_SPACE_GENERIC;
}
-#undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID
-#define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ix86_addr_space_zero_address_valid
+
+static void
+ix86_init_libfuncs (void)
+{
+ if (TARGET_64BIT)
+ {
+ set_optab_libfunc (sdivmod_optab, TImode, "__divmodti4");
+ set_optab_libfunc (udivmod_optab, TImode, "__udivmodti4");
+ }
+ else
+ {
+ set_optab_libfunc (sdivmod_optab, DImode, "__divmoddi4");
+ set_optab_libfunc (udivmod_optab, DImode, "__udivmoddi4");
+ }
+
+#if TARGET_MACHO
+ darwin_rename_builtins ();
+#endif
+}
+
+/* Generate call to __divmoddi4. */
+
+static void
+ix86_expand_divmod_libfunc (rtx libfunc, machine_mode mode,
+ rtx op0, rtx op1,
+ rtx *quot_p, rtx *rem_p)
+{
+ rtx rem = assign_386_stack_local (mode, SLOT_TEMP);
+
+ rtx quot = emit_library_call_value (libfunc, NULL_RTX, LCT_NORMAL,
+ mode, 3,
+ op0, GET_MODE (op0),
+ op1, GET_MODE (op1),
+ XEXP (rem, 0), Pmode);
+ *quot_p = quot;
+ *rem_p = rem;
+}
+
+/* Target-specific selftests. */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that hard regs are dumped as expected (in compact mode). */
+
+static void
+ix86_test_dumping_hard_regs ()
+{
+ ASSERT_RTL_DUMP_EQ ("(reg:SI ax)", gen_raw_REG (SImode, 0));
+ ASSERT_RTL_DUMP_EQ ("(reg:SI dx)", gen_raw_REG (SImode, 1));
+}
+
+/* Run all target-specific selftests. */
+
+static void
+ix86_run_selftests (void)
+{
+ ix86_test_dumping_hard_regs ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
@@ -50957,11 +51044,6 @@ ix86_addr_space_zero_address_valid (addr_space_t as)
#undef TARGET_CONDITIONAL_REGISTER_USAGE
#define TARGET_CONDITIONAL_REGISTER_USAGE ix86_conditional_register_usage
-#if TARGET_MACHO
-#undef TARGET_INIT_LIBFUNCS
-#define TARGET_INIT_LIBFUNCS darwin_rename_builtins
-#endif
-
#undef TARGET_LOOP_UNROLL_ADJUST
#define TARGET_LOOP_UNROLL_ADJUST ix86_loop_unroll_adjust
@@ -51052,6 +51134,20 @@ ix86_addr_space_zero_address_valid (addr_space_t as)
#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1
+#undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID
+#define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ix86_addr_space_zero_address_valid
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS ix86_init_libfuncs
+
+#undef TARGET_EXPAND_DIVMOD_LIBFUNC
+#define TARGET_EXPAND_DIVMOD_LIBFUNC ix86_expand_divmod_libfunc
+
+#if CHECKING_P
+#undef TARGET_RUN_TARGET_SELFTESTS
+#define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
+#endif /* #if CHECKING_P */
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-i386.h"
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 31a2267a0f8..85571571599 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -1803,7 +1803,7 @@ ia64_expand_compare (rtx *expr, rtx *op0, rtx *op1)
};
int magic;
enum rtx_code ncode;
- rtx ret, insns;
+ rtx ret;
gcc_assert (cmptf_libfunc && GET_MODE (*op1) == TFmode);
switch (code)
@@ -1842,7 +1842,7 @@ ia64_expand_compare (rtx *expr, rtx *op0, rtx *op1)
emit_insn (gen_rtx_SET (cmp, gen_rtx_fmt_ee (ncode, BImode,
ret, const0_rtx)));
- insns = get_insns ();
+ rtx_insn *insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, cmp, cmp,
diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c
index ccd9675d3ba..6077201a3b0 100644
--- a/gcc/config/m32c/m32c.c
+++ b/gcc/config/m32c/m32c.c
@@ -3781,13 +3781,13 @@ m32c_prepare_shift (rtx * operands, int scale, int shift_code)
undefined to skip one of the comparisons. */
rtx count;
- rtx label, tempvar;
+ rtx tempvar;
rtx_insn *insn;
emit_move_insn (operands[0], operands[1]);
count = temp;
- label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
LABEL_NUSES (label) ++;
tempvar = gen_reg_rtx (mode);
diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index ec37bd76f55..3d7895d264c 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -706,7 +706,7 @@
(minus:SI (const_int 31)
(match_operand:SI 1 "general_operand" "di")))
(const_int 0)))]
- ""
+ "!(CONST_INT_P (operands[1]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))"
{
return output_btst (operands, operands[1], operands[0], insn, 31);
})
@@ -765,9 +765,10 @@
(cc0)
(compare (zero_extract:SI (match_operand:SI 0 "register_operand" "do")
(const_int 1)
- (match_operand:SI 1 "const_int_operand" "n"))
+ (match_operand:SI 1 "const_int_operand" "n"))
(const_int 0)))]
- "!TARGET_COLDFIRE"
+ "!TARGET_COLDFIRE
+ && !(REG_P (operands[0]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))"
{
if (GET_CODE (operands[0]) == MEM)
{
@@ -790,7 +791,8 @@
(const_int 1)
(match_operand:SI 1 "const_int_operand" "n"))
(const_int 0)))]
- "TARGET_COLDFIRE"
+ "TARGET_COLDFIRE
+ && !(REG_P (operands[0]) && !IN_RANGE (INTVAL (operands[1]), 0, 31))"
{
if (GET_CODE (operands[0]) == MEM)
{
@@ -5397,6 +5399,7 @@
(match_operand:SI 2 "const_int_operand" "n"))
(match_operand:SI 3 "register_operand" "d"))]
"TARGET_68020 && TARGET_BITFIELD
+ && IN_RANGE (INTVAL (operands[2]), 0, 31)
&& (INTVAL (operands[1]) == 8 || INTVAL (operands[1]) == 16)
&& INTVAL (operands[2]) % INTVAL (operands[1]) == 0"
{
@@ -5438,6 +5441,7 @@
(match_operand:SI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"TARGET_68020 && TARGET_BITFIELD
+ && IN_RANGE (INTVAL (operands[3]), 0, 31)
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0"
{
@@ -5480,6 +5484,7 @@
(match_operand:SI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"TARGET_68020 && TARGET_BITFIELD
+ && IN_RANGE (INTVAL (operands[3]), 0, 31)
&& (INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0"
{
@@ -5610,7 +5615,7 @@
(sign_extract:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)"
"bfexts %1{%b3:%b2},%0")
(define_insn "*extv_bfextu_reg"
@@ -5618,7 +5623,7 @@
(zero_extract:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[3]), 0, 31)"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
@@ -5637,7 +5642,7 @@
(match_operand:SI 1 "const_int_operand" "n")
(match_operand:SI 2 "const_int_operand" "n"))
(const_int 0))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)"
{
CC_STATUS_INIT;
return "bfclr %0{%b2:%b1}";
@@ -5648,7 +5653,7 @@
(match_operand:SI 1 "const_int_operand" "n")
(match_operand:SI 2 "const_int_operand" "n"))
(const_int -1))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)"
{
CC_STATUS_INIT;
return "bfset %0{%b2:%b1}";
@@ -5659,7 +5664,7 @@
(match_operand:SI 1 "const_int_operand" "n")
(match_operand:SI 2 "const_int_operand" "n"))
(match_operand:SI 3 "register_operand" "d"))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD && IN_RANGE (INTVAL (operands[2]), 0, 31)"
{
#if 0
/* These special cases are now recognized by a specific pattern. */
@@ -5707,7 +5712,8 @@
(match_operand:SI 1 "const_int_operand" "n")
(match_operand:SI 2 "general_operand" "dn"))
(const_int 0)))]
- "TARGET_68020 && TARGET_BITFIELD"
+ "TARGET_68020 && TARGET_BITFIELD
+ && !(CONST_INT_P (operands[2]) && !IN_RANGE (INTVAL (operands[2]), 0, 31))"
{
if (operands[1] == const1_rtx
&& GET_CODE (operands[2]) == CONST_INT)
diff --git a/gcc/config/microblaze/linux.h b/gcc/config/microblaze/linux.h
index ae8523c19c3..b3bf43a8a84 100644
--- a/gcc/config/microblaze/linux.h
+++ b/gcc/config/microblaze/linux.h
@@ -29,6 +29,7 @@
#define TLS_NEEDS_GOT 1
#define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
+#define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
#if TARGET_BIG_ENDIAN_DEFAULT == 0 /* LE */
#define MUSL_DYNAMIC_LINKER_E "%{mbig-endian:;:el}"
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 5c1a35a4f86..552b73adaf7 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -3396,10 +3396,11 @@ static GTY(()) rtx mips_tls_symbol;
(either global dynamic or local dynamic). V0 is an RTX for the
return value location. */
-static rtx
+static rtx_insn *
mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
{
- rtx insn, loc, a0;
+ rtx loc, a0;
+ rtx_insn *insn;
a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
@@ -3455,7 +3456,7 @@ mips_get_tp (void)
static rtx
mips_legitimize_tls_address (rtx loc)
{
- rtx dest, insn, v0, tp, tmp1, tmp2, eqv, offset;
+ rtx dest, v0, tp, tmp1, tmp2, eqv, offset;
enum tls_model model;
model = SYMBOL_REF_TLS_MODEL (loc);
@@ -3468,33 +3469,37 @@ mips_legitimize_tls_address (rtx loc)
switch (model)
{
case TLS_MODEL_GLOBAL_DYNAMIC:
- v0 = gen_rtx_REG (Pmode, GP_RETURN);
- insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
- dest = gen_reg_rtx (Pmode);
- emit_libcall_block (insn, dest, v0, loc);
- break;
+ {
+ v0 = gen_rtx_REG (Pmode, GP_RETURN);
+ rtx_insn *insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insn, dest, v0, loc);
+ break;
+ }
case TLS_MODEL_LOCAL_DYNAMIC:
- v0 = gen_rtx_REG (Pmode, GP_RETURN);
- insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
- tmp1 = gen_reg_rtx (Pmode);
-
- /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
- share the LDM result with other LD model accesses. */
- eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
- UNSPEC_TLS_LDM);
- emit_libcall_block (insn, tmp1, v0, eqv);
-
- offset = mips_unspec_address (loc, SYMBOL_DTPREL);
- if (mips_split_p[SYMBOL_DTPREL])
- {
- tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
- dest = gen_rtx_LO_SUM (Pmode, tmp2, offset);
- }
- else
- dest = expand_binop (Pmode, add_optab, tmp1, offset,
- 0, 0, OPTAB_DIRECT);
- break;
+ {
+ v0 = gen_rtx_REG (Pmode, GP_RETURN);
+ rtx_insn *insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
+ tmp1 = gen_reg_rtx (Pmode);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_TLS_LDM);
+ emit_libcall_block (insn, tmp1, v0, eqv);
+
+ offset = mips_unspec_address (loc, SYMBOL_DTPREL);
+ if (mips_split_p[SYMBOL_DTPREL])
+ {
+ tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+ dest = gen_rtx_LO_SUM (Pmode, tmp2, offset);
+ }
+ else
+ dest = expand_binop (Pmode, add_optab, tmp1, offset,
+ 0, 0, OPTAB_DIRECT);
+ break;
+ }
case TLS_MODEL_INITIAL_EXEC:
tp = mips_get_tp ();
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index dbbc4db1410..e61bf408d5a 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -3163,7 +3163,7 @@ mn10300_bundle_liw (void)
Insert a SETLB insn just before LABEL. */
static void
-mn10300_insert_setlb_lcc (rtx label, rtx branch)
+mn10300_insert_setlb_lcc (rtx_insn *label, rtx branch)
{
rtx lcc, comparison, cmp_reg;
diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index 8d86aa87545..68bf0a89a81 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -4515,7 +4515,7 @@ nvptx_expand_builtin (tree exp, rtx target, rtx ARG_UNUSED (subtarget),
/* Define dimension sizes for known hardware. */
#define PTX_VECTOR_LENGTH 32
#define PTX_WORKER_LENGTH 32
-#define PTX_GANG_DEFAULT 32
+#define PTX_GANG_DEFAULT 0 /* Defer to runtime. */
/* Implement TARGET_SIMT_VF target hook: number of threads in a warp. */
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index f0aa1ae68c6..77874821314 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -295,17 +295,19 @@ typedef struct GTY(()) machine_function
/* No data type wants to be aligned rounder than this. The long double
type has 16-byte alignment on the 64-bit target even though it was never
implemented in hardware. The software implementation only needs 8-byte
- alignment. This is to match the HP compilers. */
+ alignment. This matches the biggest alignment of the HP compilers. */
#define BIGGEST_ALIGNMENT (2 * BITS_PER_WORD)
/* Alignment, in bits, a C conformant malloc implementation has to provide.
The HP-UX malloc implementation provides a default alignment of 8 bytes.
- This can be increased with mallopt. The glibc implementation also provides
- 8-byte alignment. Note that this isn't enough for various POSIX types such
- as pthread_mutex_t. However, since we no longer need the 16-byte alignment
- for atomic operations, we ignore the nominal alignment specified for these
- types. The same is true for long double on 64-bit HP-UX. */
-#define MALLOC_ABI_ALIGNMENT (64)
+ It should be 16 bytes on the 64-bit target since long double has 16-byte
+ alignment. It can be increased with mallopt but it's non critical since
+ long double was never implemented in hardware. The glibc implementation
+ currently provides 8-byte alignment. It should be 16 bytes since various
+ POSIX types such as pthread_mutex_t require 16-byte alignment. Again,
+ this is non critical since 16-byte alignment is no longer needed for
+ atomic operations. */
+#define MALLOC_ABI_ALIGNMENT (TARGET_SOM ? 64 : 128)
/* Get around hp-ux assembler bug, and make strcpy of constants fast. */
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index e4c806f84a8..6725504fce9 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -6249,6 +6249,21 @@
(set_attr "length" "4")])
(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "mem_shadd_operand" ""))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "*
+{
+ int shift_val = exact_log2 (INTVAL (operands[3]));
+ operands[3] = GEN_INT (shift_val);
+ return \"{sh%o3addl %2,%1,%0|shladd,l %2,%o3,%1,%0}\";
+}"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
+(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (ashift:DI (match_operand:DI 2 "register_operand" "r")
(match_operand:DI 3 "shadd_operand" ""))
@@ -6258,6 +6273,21 @@
[(set_attr "type" "binary")
(set_attr "length" "4")])
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (mult:DI (match_operand:DI 2 "register_operand" "r")
+ (match_operand:DI 3 "mem_shadd_operand" ""))
+ (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_64BIT"
+ "*
+{
+ int shift_val = exact_log2 (INTVAL (operands[3]));
+ operands[3] = GEN_INT (shift_val);
+ return \"shladd,l %2,%o3,%1,%0\";
+}"
+ [(set_attr "type" "binary")
+ (set_attr "length" "4")])
+
(define_expand "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:SI 1 "lhs_lshift_operand" "")
diff --git a/gcc/config/pa/pa64-hpux.h b/gcc/config/pa/pa64-hpux.h
index c6cbc5f582c..8c09ede6104 100644
--- a/gcc/config/pa/pa64-hpux.h
+++ b/gcc/config/pa/pa64-hpux.h
@@ -336,7 +336,7 @@ do { \
#undef INIT_SECTION_ASM_OP
#define INIT_SECTION_ASM_OP ""
#undef FINI_SECTION_ASM_OP
-#define FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP ""
/* We are using array initializers and don't want calls in the INIT
and FINI sections. */
diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c
index 5375e18dd95..b8fe4c97550 100644
--- a/gcc/config/rl78/rl78.c
+++ b/gcc/config/rl78/rl78.c
@@ -2778,7 +2778,7 @@ process_postponed_content_update (void)
after WHERE. If TO already contains FROM then do nothing. Returns TO if
BEFORE is true, FROM otherwise. */
static rtx
-gen_and_emit_move (rtx to, rtx from, rtx where, bool before)
+gen_and_emit_move (rtx to, rtx from, rtx_insn *where, bool before)
{
machine_mode mode = GET_MODE (to);
@@ -2833,7 +2833,7 @@ gen_and_emit_move (rtx to, rtx from, rtx where, bool before)
copy it into NEWBASE and return the updated MEM. Otherwise just
return M. Any needed insns are emitted before BEFORE. */
static rtx
-transcode_memory_rtx (rtx m, rtx newbase, rtx before)
+transcode_memory_rtx (rtx m, rtx newbase, rtx_insn *before)
{
rtx base, index, addendr;
int addend = 0;
@@ -2934,7 +2934,7 @@ transcode_memory_rtx (rtx m, rtx newbase, rtx before)
/* Copy SRC to accumulator (A or AX), placing any generated insns
before BEFORE. Returns accumulator RTX. */
static rtx
-move_to_acc (int opno, rtx before)
+move_to_acc (int opno, rtx_insn *before)
{
rtx src = OP (opno);
machine_mode mode = GET_MODE (src);
@@ -2949,7 +2949,7 @@ move_to_acc (int opno, rtx before)
}
static void
-force_into_acc (rtx src, rtx before)
+force_into_acc (rtx src, rtx_insn *before)
{
machine_mode mode = GET_MODE (src);
rtx move;
@@ -2968,7 +2968,7 @@ force_into_acc (rtx src, rtx before)
/* Copy accumulator (A or AX) to DEST, placing any generated insns
after AFTER. Returns accumulator RTX. */
static rtx
-move_from_acc (unsigned int opno, rtx after)
+move_from_acc (unsigned int opno, rtx_insn *after)
{
rtx dest = OP (opno);
machine_mode mode = GET_MODE (dest);
@@ -2982,7 +2982,7 @@ move_from_acc (unsigned int opno, rtx after)
/* Copy accumulator (A or AX) to REGNO, placing any generated insns
before BEFORE. Returns reg RTX. */
static rtx
-move_acc_to_reg (rtx acc, int regno, rtx before)
+move_acc_to_reg (rtx acc, int regno, rtx_insn *before)
{
machine_mode mode = GET_MODE (acc);
rtx reg;
@@ -2995,7 +2995,7 @@ move_acc_to_reg (rtx acc, int regno, rtx before)
/* Copy SRC to X, placing any generated insns before BEFORE.
Returns X RTX. */
static rtx
-move_to_x (int opno, rtx before)
+move_to_x (int opno, rtx_insn *before)
{
rtx src = OP (opno);
machine_mode mode = GET_MODE (src);
@@ -3018,7 +3018,7 @@ move_to_x (int opno, rtx before)
/* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
Returns H/HL RTX. */
static rtx
-move_to_hl (int opno, rtx before)
+move_to_hl (int opno, rtx_insn *before)
{
rtx src = OP (opno);
machine_mode mode = GET_MODE (src);
@@ -3041,7 +3041,7 @@ move_to_hl (int opno, rtx before)
/* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
Returns E/DE RTX. */
static rtx
-move_to_de (int opno, rtx before)
+move_to_de (int opno, rtx_insn *before)
{
rtx src = OP (opno);
machine_mode mode = GET_MODE (src);
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 8f07450d72b..989557f76c9 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -187,8 +187,13 @@ extern rtx rs6000_libcall_value (machine_mode);
extern rtx rs6000_va_arg (tree, tree);
extern int function_ok_for_sibcall (tree);
extern int rs6000_reg_parm_stack_space (tree, bool);
+extern void rs6000_asm_weaken_decl (FILE *, tree, const char *, const char *);
extern void rs6000_xcoff_declare_function_name (FILE *, const char *, tree);
extern void rs6000_xcoff_declare_object_name (FILE *, const char *, tree);
+extern void rs6000_xcoff_asm_output_aligned_decl_common (FILE *, tree,
+ const char *,
+ unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT);
extern void rs6000_elf_declare_function_name (FILE *, const char *, tree);
extern bool rs6000_elf_in_small_data_p (const_tree);
#ifdef ARGS_SIZE_RTX
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index f9e47393288..b0c2b2e69ee 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -56,6 +56,7 @@
#include "sched-int.h"
#include "gimplify.h"
#include "gimple-iterator.h"
+#include "gimple-ssa.h"
#include "gimple-walk.h"
#include "intl.h"
#include "params.h"
@@ -1632,6 +1633,8 @@ static const struct attribute_spec rs6000_attribute_table[] =
#undef TARGET_FOLD_BUILTIN
#define TARGET_FOLD_BUILTIN rs6000_fold_builtin
+#undef TARGET_GIMPLE_FOLD_BUILTIN
+#define TARGET_GIMPLE_FOLD_BUILTIN rs6000_gimple_fold_builtin
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
@@ -16391,6 +16394,46 @@ rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
#endif
}
+/* Fold a machine-dependent built-in in GIMPLE. (For folding into
+ a constant, use rs6000_fold_builtin.) */
+
+bool
+rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+ tree fndecl = gimple_call_fndecl (stmt);
+ gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD);
+ enum rs6000_builtins fn_code
+ = (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl);
+ tree arg0, arg1, lhs;
+
+ switch (fn_code)
+ {
+ /* Flavors of vec_add. We deliberately don't expand
+ P8V_BUILTIN_VADDUQM as it gets lowered from V1TImode to
+ TImode, resulting in much poorer code generation. */
+ case ALTIVEC_BUILTIN_VADDUBM:
+ case ALTIVEC_BUILTIN_VADDUHM:
+ case ALTIVEC_BUILTIN_VADDUWM:
+ case P8V_BUILTIN_VADDUDM:
+ case ALTIVEC_BUILTIN_VADDFP:
+ case VSX_BUILTIN_XVADDDP:
+ {
+ arg0 = gimple_call_arg (stmt, 0);
+ arg1 = gimple_call_arg (stmt, 1);
+ lhs = gimple_call_lhs (stmt);
+ gimple *g = gimple_build_assign (lhs, PLUS_EXPR, arg0, arg1);
+ gimple_set_location (g, gimple_location (stmt));
+ gsi_replace (gsi, g, true);
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
(and in mode MODE if that's convenient).
@@ -16939,11 +16982,10 @@ rs6000_init_builtins (void)
def_builtin ("__builtin_cpu_is", ftype, RS6000_BUILTIN_CPU_IS);
def_builtin ("__builtin_cpu_supports", ftype, RS6000_BUILTIN_CPU_SUPPORTS);
-#if TARGET_XCOFF
/* AIX libm provides clog as __clog. */
- if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
+ if (TARGET_XCOFF &&
+ (tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
set_user_assembler_name (tdecl, "__clog");
-#endif
#ifdef SUBTARGET_INIT_BUILTINS
SUBTARGET_INIT_BUILTINS;
@@ -26996,8 +27038,8 @@ output_probe_stack_range (rtx reg1, rtx reg2)
pointer. That fails when saving regs off r1, and sched moves the
r31 setup past the reg saves. */
-static rtx
-rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
+static rtx_insn *
+rs6000_frame_related (rtx_insn *insn, rtx reg, HOST_WIDE_INT val,
rtx reg2, rtx repl2)
{
rtx repl;
@@ -27161,11 +27203,11 @@ gen_frame_store (rtx reg, rtx frame_reg, int offset)
/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
Save REGNO into [FRAME_REG + OFFSET] in mode MODE. */
-static rtx
+static rtx_insn *
emit_frame_save (rtx frame_reg, machine_mode mode,
unsigned int regno, int offset, HOST_WIDE_INT frame_reg_to_sp)
{
- rtx reg, insn;
+ rtx reg;
/* Some cases that need register indexed addressing. */
gcc_checking_assert (!((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
@@ -27176,7 +27218,7 @@ emit_frame_save (rtx frame_reg, machine_mode mode,
&& !SPE_CONST_OFFSET_OK (offset))));
reg = gen_rtx_REG (mode, regno);
- insn = emit_insn (gen_frame_store (reg, frame_reg, offset));
+ rtx_insn *insn = emit_insn (gen_frame_store (reg, frame_reg, offset));
return rs6000_frame_related (insn, frame_reg, frame_reg_to_sp,
NULL_RTX, NULL_RTX);
}
@@ -27444,7 +27486,7 @@ ptr_regno_for_savres (int sel)
out-of-line register save/restore routine, and emit the insn
or jump_insn as appropriate. */
-static rtx
+static rtx_insn *
rs6000_emit_savres_rtx (rs6000_stack_t *info,
rtx frame_reg_rtx, int save_area_offset, int lr_offset,
machine_mode reg_mode, int sel)
@@ -27454,7 +27496,8 @@ rs6000_emit_savres_rtx (rs6000_stack_t *info,
int reg_size = GET_MODE_SIZE (reg_mode);
rtx sym;
rtvec p;
- rtx par, insn;
+ rtx par;
+ rtx_insn *insn;
offset = 0;
start_reg = ((sel & SAVRES_REG) == SAVRES_GPR
@@ -27633,6 +27676,9 @@ rs6000_get_separate_components (void)
if (WORLD_SAVE_P (info))
return NULL;
+ if (TARGET_SPE_ABI)
+ return NULL;
+
sbitmap components = sbitmap_alloc (32);
bitmap_clear (components);
@@ -27854,7 +27900,7 @@ rs6000_emit_prologue (void)
rtx frame_reg_rtx = sp_reg_rtx;
unsigned int cr_save_regno;
rtx cr_save_rtx = NULL_RTX;
- rtx insn;
+ rtx_insn *insn;
int strategy;
int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
&& df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
@@ -28360,12 +28406,12 @@ rs6000_emit_prologue (void)
if (regno == INVALID_REGNUM)
break;
- insn
+ rtx set
= gen_frame_store (gen_rtx_REG (reg_mode, regno),
sp_reg_rtx,
info->ehrd_offset + sp_off + reg_size * (int) i);
- RTVEC_ELT (p, i) = insn;
- RTX_FRAME_RELATED_P (insn) = 1;
+ RTVEC_ELT (p, i) = set;
+ RTX_FRAME_RELATED_P (set) = 1;
}
insn = emit_insn (gen_blockage ());
@@ -28377,7 +28423,8 @@ rs6000_emit_prologue (void)
if (TARGET_AIX && crtl->calls_eh_return)
{
rtx tmp_reg, tmp_reg_si, hi, lo, compare_result, toc_save_done, jump;
- rtx save_insn, join_insn, note;
+ rtx join_insn, note;
+ rtx_insn *save_insn;
long toc_restore_insn;
tmp_reg = gen_rtx_REG (Pmode, 11);
@@ -35316,6 +35363,31 @@ rs6000_declare_alias (struct symtab_node *n, void *d)
return false;
}
+
+#ifdef HAVE_GAS_HIDDEN
+/* Helper function to calculate visibility of a DECL
+ and return the value as a const string. */
+
+static const char *
+rs6000_xcoff_visibility (tree decl)
+{
+ static const char * const visibility_types[] = {
+ "", ",protected", ",hidden", ",internal"
+ };
+
+ enum symbol_visibility vis = DECL_VISIBILITY (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && cgraph_node::get (decl)
+ && cgraph_node::get (decl)->instrumentation_clone
+ && cgraph_node::get (decl)->instrumented_version)
+ vis = DECL_VISIBILITY (cgraph_node::get (decl)->instrumented_version->decl);
+
+ return visibility_types[vis];
+}
+#endif
+
+
/* This macro produces the initial definition of a function name.
On the RS/6000, we need to place an extra '.' in the function name and
output the function descriptor.
@@ -35355,6 +35427,9 @@ rs6000_xcoff_declare_function_name (FILE *file, const char *name, tree decl)
}
fputs ("\t.globl .", file);
RS6000_OUTPUT_BASENAME (file, buffer);
+#ifdef HAVE_GAS_HIDDEN
+ fputs (rs6000_xcoff_visibility (decl), file);
+#endif
putc ('\n', file);
}
}
@@ -35399,6 +35474,52 @@ rs6000_xcoff_declare_function_name (FILE *file, const char *name, tree decl)
return;
}
+
+/* Output assembly language to globalize a symbol from a DECL,
+ possibly with visibility. */
+
+void
+rs6000_xcoff_asm_globalize_decl_name (FILE *stream, tree decl)
+{
+ const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ fputs (GLOBAL_ASM_OP, stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+#ifdef HAVE_GAS_HIDDEN
+ fputs (rs6000_xcoff_visibility (decl), stream);
+#endif
+ putc ('\n', stream);
+}
+
+/* Output assembly language to define a symbol as COMMON from a DECL,
+ possibly with visibility. */
+
+void
+rs6000_xcoff_asm_output_aligned_decl_common (FILE *stream,
+ tree decl ATTRIBUTE_UNUSED,
+ const char *name,
+ unsigned HOST_WIDE_INT size,
+ unsigned HOST_WIDE_INT align)
+{
+ unsigned HOST_WIDE_INT align2 = 2;
+
+ if (align > 32)
+ align2 = floor_log2 (align / BITS_PER_UNIT);
+ else if (size > 4)
+ align2 = 3;
+
+ fputs (COMMON_ASM_OP, stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+
+ fprintf (stream,
+ "," HOST_WIDE_INT_PRINT_UNSIGNED "," HOST_WIDE_INT_PRINT_UNSIGNED,
+ size, align2);
+
+#ifdef HAVE_GAS_HIDDEN
+ fputs (rs6000_xcoff_visibility (decl), stream);
+#endif
+ putc ('\n', stream);
+}
+
/* This macro produces the initial definition of a object (variable) name.
Because AIX assembler's .set command has unexpected semantics, we output
all aliases as alternative labels in front of the definition. */
@@ -35409,8 +35530,8 @@ rs6000_xcoff_declare_object_name (FILE *file, const char *name, tree decl)
struct declare_alias_data data = {file, false};
RS6000_OUTPUT_BASENAME (file, name);
fputs (":\n", file);
- symtab_node::get (decl)->call_for_symbol_and_aliases (rs6000_declare_alias,
- &data, true);
+ symtab_node::get_create (decl)->call_for_symbol_and_aliases (rs6000_declare_alias,
+ &data, true);
}
/* Overide the default 'SYMBOL-.' syntax with AIX compatible 'SYMBOL-$'. */
@@ -35480,6 +35601,45 @@ rs6000_xcoff_encode_section_info (tree decl, rtx rtl, int first)
#endif /* HAVE_AS_TLS */
#endif /* TARGET_XCOFF */
+void
+rs6000_asm_weaken_decl (FILE *stream, tree decl,
+ const char *name, const char *val)
+{
+ fputs ("\t.weak\t", stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+ if (decl && TREE_CODE (decl) == FUNCTION_DECL
+ && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS)
+ {
+ if (TARGET_XCOFF)
+ fputs ("[DS]", stream);
+#if TARGET_XCOFF && HAVE_GAS_HIDDEN
+ if (TARGET_XCOFF)
+ fputs (rs6000_xcoff_visibility (decl), stream);
+#endif
+ fputs ("\n\t.weak\t.", stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+ }
+#if TARGET_XCOFF && HAVE_GAS_HIDDEN
+ if (TARGET_XCOFF)
+ fputs (rs6000_xcoff_visibility (decl), stream);
+#endif
+ fputc ('\n', stream);
+ if (val)
+ {
+ ASM_OUTPUT_DEF (stream, name, val);
+ if (decl && TREE_CODE (decl) == FUNCTION_DECL
+ && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS)
+ {
+ fputs ("\t.set\t.", stream);
+ RS6000_OUTPUT_BASENAME (stream, name);
+ fputs (",.", stream);
+ RS6000_OUTPUT_BASENAME (stream, val);
+ fputc ('\n', stream);
+ }
+ }
+}
+
+
/* Return true if INSN should not be copied. */
static bool
@@ -38651,7 +38811,7 @@ rs6000_code_end (void)
TREE_STATIC (decl) = 1;
#if RS6000_WEAK
- if (USE_HIDDEN_LINKONCE)
+ if (USE_HIDDEN_LINKONCE && !TARGET_XCOFF)
{
cgraph_node::create (decl)->set_comdat_group (DECL_ASSEMBLER_NAME (decl));
targetm.asm_out.unique_section (decl, 0);
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 4b83abdf753..1148212c7ff 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -442,14 +442,15 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
point. KFmode was added as a way to represent IEEE 128-bit floating point,
even if the default for long double is the IBM long double format.
Similarly IFmode is the IBM long double format even if the default is IEEE
- 128-bit. */
+ 128-bit. Don't allow IFmode if -msoft-float. */
#define FLOAT128_IEEE_P(MODE) \
((TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \
|| ((MODE) == KFmode) || ((MODE) == KCmode))
#define FLOAT128_IBM_P(MODE) \
((!TARGET_IEEEQUAD && ((MODE) == TFmode || (MODE) == TCmode)) \
- || ((MODE) == IFmode) || ((MODE) == ICmode))
+ || (TARGET_HARD_FLOAT && TARGET_FPRS \
+ && ((MODE) == IFmode || (MODE) == ICmode)))
/* Helper macros to say whether a 128-bit floating point type can go in a
single vector register, or whether it needs paired scalar values. */
@@ -2281,35 +2282,8 @@ extern int toc_initialized;
#if RS6000_WEAK
/* Used in lieu of ASM_WEAKEN_LABEL. */
-#define ASM_WEAKEN_DECL(FILE, DECL, NAME, VAL) \
- do \
- { \
- fputs ("\t.weak\t", (FILE)); \
- RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
- if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL \
- && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) \
- { \
- if (TARGET_XCOFF) \
- fputs ("[DS]", (FILE)); \
- fputs ("\n\t.weak\t.", (FILE)); \
- RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
- } \
- fputc ('\n', (FILE)); \
- if (VAL) \
- { \
- ASM_OUTPUT_DEF ((FILE), (NAME), (VAL)); \
- if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL \
- && DEFAULT_ABI == ABI_AIX && DOT_SYMBOLS) \
- { \
- fputs ("\t.set\t.", (FILE)); \
- RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
- fputs (",.", (FILE)); \
- RS6000_OUTPUT_BASENAME ((FILE), (VAL)); \
- fputc ('\n', (FILE)); \
- } \
- } \
- } \
- while (0)
+#define ASM_WEAKEN_DECL(FILE, DECL, NAME, VAL) \
+ rs6000_asm_weaken_decl ((FILE), (DECL), (NAME), (VAL))
#endif
#if HAVE_GAS_WEAKREF
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index bc8e52d6f6a..d4095498981 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -376,7 +376,7 @@
(TF "TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128")
- (IF "TARGET_LONG_DOUBLE_128")
+ (IF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128")
(KF "TARGET_FLOAT128_TYPE")
(DD "TARGET_DFP")
(TD "TARGET_DFP")])
@@ -398,7 +398,7 @@
(define_mode_iterator FMOVE64 [DF DD])
(define_mode_iterator FMOVE64X [DI DF DD])
(define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128")
- (IF "TARGET_LONG_DOUBLE_128")
+ (IF "FLOAT128_IBM_P (IFmode)")
(TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)")
@@ -4460,7 +4460,15 @@
(div:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "")
(match_operand:SFDF 2 "gpc_reg_operand" "")))]
"TARGET_<MODE>_INSN && !TARGET_SIMPLE_FPU"
- "")
+{
+ if (RS6000_RECIP_AUTO_RE_P (<MODE>mode)
+ && can_create_pseudo_p () && flag_finite_math_only
+ && !flag_trapping_math && flag_reciprocal_math)
+ {
+ rs6000_emit_swdiv (operands[0], operands[1], operands[2], true);
+ DONE;
+ }
+})
(define_insn "*div<mode>3_fpr"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Ff>,<Fv2>")
diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md
index 7240345bce0..05f3bdbee56 100644
--- a/gcc/config/rs6000/vector.md
+++ b/gcc/config/rs6000/vector.md
@@ -248,7 +248,15 @@
(div:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "")
(match_operand:VEC_F 2 "vfloat_operand" "")))]
"VECTOR_UNIT_VSX_P (<MODE>mode)"
- "")
+{
+ if (RS6000_RECIP_AUTO_RE_P (<MODE>mode)
+ && can_create_pseudo_p () && flag_finite_math_only
+ && !flag_trapping_math && flag_reciprocal_math)
+ {
+ rs6000_emit_swdiv (operands[0], operands[1], operands[2], true);
+ DONE;
+ }
+})
(define_expand "neg<mode>2"
[(set (match_operand:VEC_F 0 "vfloat_operand" "")
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 18f3e86e29f..2c74a8ebbe2 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -288,6 +288,16 @@
(V8HI "v")
(V4SI "wa")])
+;; Mode iterator for binary floating types other than double to
+;; optimize convert to that floating point type from an extract
+;; of an integer type
+(define_mode_iterator VSX_EXTRACT_FL [SF
+ (IF "FLOAT128_2REG_P (IFmode)")
+ (KF "TARGET_FLOAT128_HW")
+ (TF "FLOAT128_2REG_P (TFmode)
+ || (FLOAT128_IEEE_P (TFmode)
+ && TARGET_FLOAT128_HW)")])
+
;; Iterator for the 2 short vector types to do a splat from an integer
(define_mode_iterator VSX_SPLAT_I [V16QI V8HI])
@@ -1907,6 +1917,7 @@
[(set_attr "type" "vecdouble")])
;; Convert from 32-bit to 64-bit types
+;; Provide both vector and scalar targets
(define_insn "vsx_xvcvsxwdp"
[(set (match_operand:V2DF 0 "vsx_register_operand" "=wd,?wa")
(unspec:V2DF [(match_operand:V4SI 1 "vsx_register_operand" "wf,wa")]
@@ -1915,6 +1926,14 @@
"xvcvsxwdp %x0,%x1"
[(set_attr "type" "vecdouble")])
+(define_insn "vsx_xvcvsxwdp_df"
+ [(set (match_operand:DF 0 "vsx_register_operand" "=ws")
+ (unspec:DF [(match_operand:V4SI 1 "vsx_register_operand" "wa")]
+ UNSPEC_VSX_CVSXWDP))]
+ "TARGET_VSX"
+ "xvcvsxwdp %x0,%x1"
+ [(set_attr "type" "vecdouble")])
+
(define_insn "vsx_xvcvuxwdp"
[(set (match_operand:V2DF 0 "vsx_register_operand" "=wd,?wa")
(unspec:V2DF [(match_operand:V4SI 1 "vsx_register_operand" "wf,wa")]
@@ -1923,6 +1942,14 @@
"xvcvuxwdp %x0,%x1"
[(set_attr "type" "vecdouble")])
+(define_insn "vsx_xvcvuxwdp_df"
+ [(set (match_operand:DF 0 "vsx_register_operand" "=ws")
+ (unspec:DF [(match_operand:V4SI 1 "vsx_register_operand" "wa")]
+ UNSPEC_VSX_CVUXWDP))]
+ "TARGET_VSX"
+ "xvcvuxwdp %x0,%x1"
+ [(set_attr "type" "vecdouble")])
+
(define_insn "vsx_xvcvspsxds"
[(set (match_operand:V2DI 0 "vsx_register_operand" "=v,?wa")
(unspec:V2DI [(match_operand:V4SF 1 "vsx_register_operand" "wd,wa")]
@@ -2559,11 +2586,10 @@
(parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n")]))))]
"VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB"
{
- int element = INTVAL (operands[2]);
+ /* Note, the element number has already been adjusted for endianness, so we
+ don't have to adjust it here. */
int unit_size = GET_MODE_UNIT_SIZE (<MODE>mode);
- int offset = ((VECTOR_ELT_ORDER_BIG)
- ? unit_size * element
- : unit_size * (GET_MODE_NUNITS (<MODE>mode) - 1 - element));
+ HOST_WIDE_INT offset = unit_size * INTVAL (operands[2]);
operands[2] = GEN_INT (offset);
if (unit_size == 4)
@@ -2574,11 +2600,11 @@
[(set_attr "type" "vecsimple")])
(define_insn_and_split "*vsx_extract_si"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Z,Z,wJwK")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,wHwI,Z")
(vec_select:SI
- (match_operand:V4SI 1 "gpc_reg_operand" "v,wJwK,v,v")
- (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n,n")])))
- (clobber (match_scratch:V4SI 3 "=v,wJwK,v,v"))]
+ (match_operand:V4SI 1 "gpc_reg_operand" "wJv,wJv,wJv")
+ (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n,n,n")])))
+ (clobber (match_scratch:V4SI 3 "=wJv,wJv,wJv"))]
"VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT"
"#"
"&& reload_completed"
@@ -2628,7 +2654,7 @@
DONE;
}
- [(set_attr "type" "mftgpr,fpstore,fpstore,vecsimple")
+ [(set_attr "type" "mftgpr,vecperm,fpstore")
(set_attr "length" "8")])
(define_insn_and_split "*vsx_extract_<mode>_p8"
@@ -2714,6 +2740,107 @@
DONE;
})
+;; VSX_EXTRACT optimizations
+;; Optimize double d = (double) vec_extract (vi, <n>)
+;; Get the element into the top position and use XVCVSWDP/XVCVUWDP
+(define_insn_and_split "*vsx_extract_si_<uns>float_df"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=ws")
+ (any_float:DF
+ (vec_select:SI
+ (match_operand:V4SI 1 "gpc_reg_operand" "v")
+ (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n")]))))
+ (clobber (match_scratch:V4SI 3 "=v"))]
+ "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx element = operands[2];
+ rtx v4si_tmp = operands[3];
+ int value;
+
+ if (!VECTOR_ELT_ORDER_BIG)
+ element = GEN_INT (GET_MODE_NUNITS (V4SImode) - 1 - INTVAL (element));
+
+ /* If the value is in the correct position, we can avoid doing the VSPLT<x>
+ instruction. */
+ value = INTVAL (element);
+ if (value != 0)
+ {
+ if (GET_CODE (v4si_tmp) == SCRATCH)
+ v4si_tmp = gen_reg_rtx (V4SImode);
+ emit_insn (gen_altivec_vspltw_direct (v4si_tmp, src, element));
+ }
+ else
+ v4si_tmp = src;
+
+ emit_insn (gen_vsx_xvcv<su>xwdp_df (dest, v4si_tmp));
+ DONE;
+})
+
+;; Optimize <type> f = (<type>) vec_extract (vi, <n>)
+;; where <type> is a floating point type that supported by the hardware that is
+;; not double. First convert the value to double, and then to the desired
+;; type.
+(define_insn_and_split "*vsx_extract_si_<uns>float_<mode>"
+ [(set (match_operand:VSX_EXTRACT_FL 0 "gpc_reg_operand" "=ww")
+ (any_float:VSX_EXTRACT_FL
+ (vec_select:SI
+ (match_operand:V4SI 1 "gpc_reg_operand" "v")
+ (parallel [(match_operand:QI 2 "const_0_to_3_operand" "n")]))))
+ (clobber (match_scratch:V4SI 3 "=v"))
+ (clobber (match_scratch:DF 4 "=ws"))]
+ "VECTOR_MEM_VSX_P (V4SImode) && TARGET_DIRECT_MOVE_64BIT"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx element = operands[2];
+ rtx v4si_tmp = operands[3];
+ rtx df_tmp = operands[4];
+ int value;
+
+ if (!VECTOR_ELT_ORDER_BIG)
+ element = GEN_INT (GET_MODE_NUNITS (V4SImode) - 1 - INTVAL (element));
+
+ /* If the value is in the correct position, we can avoid doing the VSPLT<x>
+ instruction. */
+ value = INTVAL (element);
+ if (value != 0)
+ {
+ if (GET_CODE (v4si_tmp) == SCRATCH)
+ v4si_tmp = gen_reg_rtx (V4SImode);
+ emit_insn (gen_altivec_vspltw_direct (v4si_tmp, src, element));
+ }
+ else
+ v4si_tmp = src;
+
+ if (GET_CODE (df_tmp) == SCRATCH)
+ df_tmp = gen_reg_rtx (DFmode);
+
+ emit_insn (gen_vsx_xvcv<su>xwdp_df (df_tmp, v4si_tmp));
+
+ if (<MODE>mode == SFmode)
+ emit_insn (gen_truncdfsf2 (dest, df_tmp));
+ else if (<MODE>mode == TFmode && FLOAT128_IBM_P (TFmode))
+ emit_insn (gen_extenddftf2_vsx (dest, df_tmp));
+ else if (<MODE>mode == TFmode && FLOAT128_IEEE_P (TFmode)
+ && TARGET_FLOAT128_HW)
+ emit_insn (gen_extenddftf2_hw (dest, df_tmp));
+ else if (<MODE>mode == IFmode && FLOAT128_IBM_P (IFmode))
+ emit_insn (gen_extenddfif2 (dest, df_tmp));
+ else if (<MODE>mode == KFmode && TARGET_FLOAT128_HW)
+ emit_insn (gen_extenddfkf2_hw (dest, df_tmp));
+ else
+ gcc_unreachable ();
+
+ DONE;
+})
+
;; Expanders for builtins
(define_expand "vsx_mergel_<mode>"
[(use (match_operand:VSX_D 0 "vsx_register_operand" ""))
diff --git a/gcc/config/rs6000/xcoff.h b/gcc/config/rs6000/xcoff.h
index cfdc528ef95..f63d28720ce 100644
--- a/gcc/config/rs6000/xcoff.h
+++ b/gcc/config/rs6000/xcoff.h
@@ -89,6 +89,7 @@
#undef TARGET_DEBUG_UNWIND_INFO
#define TARGET_DEBUG_UNWIND_INFO rs6000_xcoff_debug_unwind_info
#define TARGET_ASM_OUTPUT_ANCHOR rs6000_xcoff_asm_output_anchor
+#define TARGET_ASM_GLOBALIZE_DECL_NAME rs6000_xcoff_asm_globalize_decl_name
#define TARGET_ASM_GLOBALIZE_LABEL rs6000_xcoff_asm_globalize_label
#define TARGET_ASM_INIT_SECTIONS rs6000_xcoff_asm_init_sections
#define TARGET_ASM_RELOC_RW_MASK rs6000_xcoff_reloc_rw_mask
@@ -102,6 +103,7 @@
#ifdef HAVE_AS_TLS
#define TARGET_ENCODE_SECTION_INFO rs6000_xcoff_encode_section_info
#endif
+#define ASM_OUTPUT_ALIGNED_DECL_COMMON rs6000_xcoff_asm_output_aligned_decl_common
/* FP save and restore routines. */
#define SAVE_FP_PREFIX "._savef"
@@ -217,18 +219,6 @@
#define COMMON_ASM_OP "\t.comm "
-#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
- do { fputs (COMMON_ASM_OP, (FILE)); \
- RS6000_OUTPUT_BASENAME ((FILE), (NAME)); \
- if ((ALIGN) > 32) \
- fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), \
- floor_log2 ((ALIGN) / BITS_PER_UNIT)); \
- else if ((SIZE) > 4) \
- fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED",3\n", (SIZE)); \
- else \
- fprintf ((FILE), "," HOST_WIDE_INT_PRINT_UNSIGNED"\n", (SIZE)); \
- } while (0)
-
/* This says how to output an assembler line
to define a local common symbol.
The assembler in AIX 6.1 and later supports an alignment argument.
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 3554f339f3f..3f98cd820d5 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -4840,7 +4840,8 @@ s390_emit_tls_call_insn (rtx result_reg, rtx tls_call)
static rtx
legitimize_tls_address (rtx addr, rtx reg)
{
- rtx new_rtx, tls_call, temp, base, r2, insn;
+ rtx new_rtx, tls_call, temp, base, r2;
+ rtx_insn *insn;
if (GET_CODE (addr) == SYMBOL_REF)
switch (tls_symbolic_operand (addr))
@@ -13280,7 +13281,7 @@ static bool
s390_fix_long_loop_prediction (rtx_insn *insn)
{
rtx set = single_set (insn);
- rtx code_label, label_ref, new_label;
+ rtx code_label, label_ref;
rtx_insn *uncond_jump;
rtx_insn *cur_insn;
rtx tmp;
@@ -13317,7 +13318,7 @@ s390_fix_long_loop_prediction (rtx_insn *insn)
if (!cur_insn || JUMP_P (cur_insn) || LABEL_P (cur_insn))
return false;
- new_label = gen_label_rtx ();
+ rtx_code_label *new_label = gen_label_rtx ();
uncond_jump = emit_jump_insn_after (
gen_rtx_SET (pc_rtx,
gen_rtx_LABEL_REF (VOIDmode, code_label)),
diff --git a/gcc/config/sh/sh-mem.cc b/gcc/config/sh/sh-mem.cc
index 1773f1df4d3..b965aed1684 100644
--- a/gcc/config/sh/sh-mem.cc
+++ b/gcc/config/sh/sh-mem.cc
@@ -204,7 +204,7 @@ sh_expand_cmpstr (rtx *operands)
rtx tmp2 = gen_reg_rtx (SImode);
rtx tmp3 = gen_reg_rtx (SImode);
- rtx jump;
+ rtx_insn *jump;
rtx_code_label *L_return = gen_label_rtx ();
rtx_code_label *L_loop_byte = gen_label_rtx ();
rtx_code_label *L_end_loop_byte = gen_label_rtx ();
@@ -342,7 +342,7 @@ sh_expand_cmpnstr (rtx *operands)
rtx tmp1 = gen_reg_rtx (SImode);
rtx tmp2 = gen_reg_rtx (SImode);
- rtx jump;
+ rtx_insn *jump;
rtx_code_label *L_return = gen_label_rtx ();
rtx_code_label *L_loop_byte = gen_label_rtx ();
rtx_code_label *L_end_loop_byte = gen_label_rtx ();
@@ -583,7 +583,7 @@ sh_expand_strlen (rtx *operands)
rtx_code_label *L_return = gen_label_rtx ();
rtx_code_label *L_loop_byte = gen_label_rtx ();
- rtx jump;
+ rtx_insn *jump;
rtx_code_label *L_loop_long = gen_label_rtx ();
rtx_code_label *L_end_loop_long = gen_label_rtx ();
@@ -669,7 +669,7 @@ sh_expand_setmem (rtx *operands)
rtx_code_label *L_loop_byte = gen_label_rtx ();
rtx_code_label *L_loop_word = gen_label_rtx ();
rtx_code_label *L_return = gen_label_rtx ();
- rtx jump;
+ rtx_insn *jump;
rtx dest = copy_rtx (operands[0]);
rtx dest_addr = copy_addr_to_reg (XEXP (dest, 0));
rtx val = force_reg (SImode, operands[2]);
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index e80ef581b2d..c6956a056b4 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -3044,7 +3044,7 @@
"&& 1"
[(const_int 0)]
{
- rtx prev_set_t_insn = NULL_RTX;
+ rtx_insn *prev_set_t_insn = NULL;
if (!arith_reg_operand (operands[3], SImode))
{
@@ -3105,7 +3105,7 @@
&& ! reg_referenced_p (get_t_reg_rtx (),
PATTERN (prev_set_t_insn))))
{
- prev_set_t_insn = NULL_RTX;
+ prev_set_t_insn = NULL;
tmp_t_reg = gen_reg_rtx (SImode);
emit_insn (gen_move_insn (tmp_t_reg, get_t_reg_rtx ()));
}
@@ -3174,7 +3174,7 @@
if (INTVAL (operands[2]) > 1)
{
const rtx shift_count = GEN_INT (INTVAL (operands[2]) - 1);
- rtx prev_set_t_insn = NULL_RTX;
+ rtx_insn *prev_set_t_insn = NULL;
rtx tmp_t_reg = NULL_RTX;
/* If we're going to emit a shift sequence that clobbers the T_REG,
@@ -3205,7 +3205,7 @@
&& ! reg_referenced_p (get_t_reg_rtx (),
PATTERN (prev_set_t_insn))))
{
- prev_set_t_insn = NULL_RTX;
+ prev_set_t_insn = NULL;
tmp_t_reg = gen_reg_rtx (SImode);
emit_insn (gen_move_insn (tmp_t_reg, get_t_reg_rtx ()));
}
@@ -4518,7 +4518,7 @@
"TARGET_SH1 && ! TARGET_ZDCBRANCH"
[(const_int 0)]
{
- rtx skip_neg_label = gen_label_rtx ();
+ rtx_code_label *skip_neg_label = gen_label_rtx ();
emit_move_insn (operands[0], operands[1]);
@@ -4545,7 +4545,7 @@
"&& can_create_pseudo_p ()"
[(const_int 0)]
{
- rtx skip_neg_label = gen_label_rtx ();
+ rtx_code_label *skip_neg_label = gen_label_rtx ();
emit_move_insn (operands[0], operands[1]);
@@ -7456,7 +7456,7 @@
[(match_operand 0 "" "") (match_operand 1 "" "")]
""
{
- rtx gotoffsym, insn;
+ rtx gotoffsym;
rtx t = (!can_create_pseudo_p ()
? operands[0]
: gen_reg_rtx (GET_MODE (operands[0])));
@@ -7467,7 +7467,7 @@
gotoffsym = gen_sym2GOTOFF (operands[1]);
PUT_MODE (gotoffsym, Pmode);
emit_move_insn (t, gotoffsym);
- insn = emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg));
+ rtx_insn *insn = emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg));
set_unique_reg_note (insn, REG_EQUAL, operands[1]);
@@ -8825,7 +8825,7 @@
"&& 1"
[(const_int 0)]
{
- rtx skip_label = gen_label_rtx ();
+ rtx_code_label *skip_label = gen_label_rtx ();
emit_move_insn (operands[0], operands[1]);
rtx cmp_val = operands[2];
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index c5638ccd2aa..2d1f598434b 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -648,6 +648,7 @@ static reg_class_t sparc_secondary_reload (bool, rtx, reg_class_t,
static machine_mode sparc_cstore_mode (enum insn_code icode);
static void sparc_atomic_assign_expand_fenv (tree *, tree *, tree *);
static bool sparc_fixed_condition_code_regs (unsigned int *, unsigned int *);
+static unsigned int sparc_min_arithmetic_precision (void);
#ifdef SUBTARGET_ATTRIBUTE_TABLE
/* Table of valid machine attributes. */
@@ -866,6 +867,9 @@ char sparc_hard_reg_printed[8];
#undef TARGET_FIXED_CONDITION_CODE_REGS
#define TARGET_FIXED_CONDITION_CODE_REGS sparc_fixed_condition_code_regs
+#undef TARGET_MIN_ARITHMETIC_PRECISION
+#define TARGET_MIN_ARITHMETIC_PRECISION sparc_min_arithmetic_precision
+
#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1
@@ -2749,6 +2753,14 @@ sparc_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
return true;
}
+/* Implement TARGET_MIN_ARITHMETIC_PRECISION. */
+
+static unsigned int
+sparc_min_arithmetic_precision (void)
+{
+ return 32;
+}
+
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point,
CCFP[E]mode is used. CCNZmode should be used when the first operand
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 3fbc23cb6e7..b5793d3c053 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -8844,34 +8844,6 @@
[(set_attr "type" "fga")
(set_attr "fptype" "double")])
-(define_insn "vec_interleave_lowv8qi"
- [(set (match_operand:V8QI 0 "register_operand" "=e")
- (vec_select:V8QI
- (vec_concat:V16QI (match_operand:V8QI 1 "register_operand" "f")
- (match_operand:V8QI 2 "register_operand" "f"))
- (parallel [(const_int 0) (const_int 8)
- (const_int 1) (const_int 9)
- (const_int 2) (const_int 10)
- (const_int 3) (const_int 11)])))]
- "TARGET_VIS"
- "fpmerge\t%L1, %L2, %0"
- [(set_attr "type" "fga")
- (set_attr "fptype" "double")])
-
-(define_insn "vec_interleave_highv8qi"
- [(set (match_operand:V8QI 0 "register_operand" "=e")
- (vec_select:V8QI
- (vec_concat:V16QI (match_operand:V8QI 1 "register_operand" "f")
- (match_operand:V8QI 2 "register_operand" "f"))
- (parallel [(const_int 4) (const_int 12)
- (const_int 5) (const_int 13)
- (const_int 6) (const_int 14)
- (const_int 7) (const_int 15)])))]
- "TARGET_VIS"
- "fpmerge\t%H1, %H2, %0"
- [(set_attr "type" "fga")
- (set_attr "fptype" "double")])
-
;; Partitioned multiply instructions
(define_insn "fmul8x16_vis"
[(set (match_operand:V4HI 0 "register_operand" "=e")
diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h
index c2c31e78900..7b6bad1500d 100644
--- a/gcc/config/spu/spu.h
+++ b/gcc/config/spu/spu.h
@@ -205,7 +205,8 @@ enum reg_class {
{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3}, /* general regs */ \
{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x3}} /* all regs */
-#define REGNO_REG_CLASS(REGNO) (GENERAL_REGS)
+#define REGNO_REG_CLASS(REGNO) ((void)(REGNO), GENERAL_REGS)
+
#define BASE_REG_CLASS GENERAL_REGS
diff --git a/gcc/config/vax/vax.h b/gcc/config/vax/vax.h
index 427c352bc22..dc77aa99223 100644
--- a/gcc/config/vax/vax.h
+++ b/gcc/config/vax/vax.h
@@ -226,7 +226,7 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES };
reg number REGNO. This could be a conditional expression
or could index an array. */
-#define REGNO_REG_CLASS(REGNO) ALL_REGS
+#define REGNO_REG_CLASS(REGNO) ((void)(REGNO), ALL_REGS)
/* The class value for index registers, and the one for base regs. */
diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h
index f2ca526aa17..873557f03f6 100644
--- a/gcc/config/xtensa/xtensa-protos.h
+++ b/gcc/config/xtensa/xtensa-protos.h
@@ -68,6 +68,7 @@ extern rtx xtensa_return_addr (int, rtx);
extern void xtensa_setup_frame_addresses (void);
extern int xtensa_dbx_register_number (int);
extern long compute_frame_size (int);
+extern bool xtensa_use_return_instruction_p (void);
extern void xtensa_expand_prologue (void);
extern void xtensa_expand_epilogue (void);
extern void order_regs_for_local_alloc (void);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 60e50296d34..6e8a25d0307 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -79,11 +79,6 @@ enum internal_test
can support a given mode. */
char xtensa_hard_regno_mode_ok[(int) MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
-/* Current frame size calculated by compute_frame_size. */
-unsigned xtensa_current_frame_size;
-/* Callee-save area size in the current frame calculated by compute_frame_size. */
-int xtensa_callee_save_size;
-
/* Largest block move to handle in-line. */
#define LARGEST_MOVE_RATIO 15
@@ -95,6 +90,13 @@ struct GTY(()) machine_function
bool vararg_a7;
rtx vararg_a7_copy;
rtx_insn *set_frame_ptr_insn;
+ /* Current frame size calculated by compute_frame_size. */
+ unsigned current_frame_size;
+ /* Callee-save area size in the current frame calculated by
+ compute_frame_size. */
+ int callee_save_size;
+ bool frame_laid_out;
+ bool epilogue_done;
};
/* Vector, indexed by hard register number, which contains 1 for a
@@ -2533,13 +2535,32 @@ xtensa_output_addr_const_extra (FILE *fp, rtx x)
return false;
}
+static void
+xtensa_output_integer_literal_parts (FILE *file, rtx x, int size)
+{
+ if (size > 4 && !(size & (size - 1)))
+ {
+ rtx first, second;
+
+ split_double (x, &first, &second);
+ xtensa_output_integer_literal_parts (file, first, size / 2);
+ fputs (", ", file);
+ xtensa_output_integer_literal_parts (file, second, size / 2);
+ }
+ else if (size == 4)
+ {
+ output_addr_const (file, x);
+ }
+ else
+ {
+ gcc_unreachable();
+ }
+}
void
xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno)
{
long value_long[2];
- int size;
- rtx first, second;
fprintf (file, "\t.literal .LC%u, ", (unsigned) labelno);
@@ -2578,25 +2599,8 @@ xtensa_output_literal (FILE *file, rtx x, machine_mode mode, int labelno)
case MODE_INT:
case MODE_PARTIAL_INT:
- size = GET_MODE_SIZE (mode);
- switch (size)
- {
- case 4:
- output_addr_const (file, x);
- fputs ("\n", file);
- break;
-
- case 8:
- split_double (x, &first, &second);
- output_addr_const (file, first);
- fputs (", ", file);
- output_addr_const (file, second);
- fputs ("\n", file);
- break;
-
- default:
- gcc_unreachable ();
- }
+ xtensa_output_integer_literal_parts (file, x, GET_MODE_SIZE (mode));
+ fputs ("\n", file);
break;
default:
@@ -2632,24 +2636,29 @@ compute_frame_size (int size)
{
int regno;
+ if (reload_completed && cfun->machine->frame_laid_out)
+ return cfun->machine->current_frame_size;
+
/* Add space for the incoming static chain value. */
if (cfun->static_chain_decl != NULL)
size += (1 * UNITS_PER_WORD);
- xtensa_callee_save_size = 0;
+ cfun->machine->callee_save_size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; ++regno)
{
if (xtensa_call_save_reg(regno))
- xtensa_callee_save_size += UNITS_PER_WORD;
+ cfun->machine->callee_save_size += UNITS_PER_WORD;
}
- xtensa_current_frame_size =
+ cfun->machine->current_frame_size =
XTENSA_STACK_ALIGN (size
- + xtensa_callee_save_size
+ + cfun->machine->callee_save_size
+ crtl->outgoing_args_size
+ (WINDOW_SIZE * UNITS_PER_WORD));
- xtensa_callee_save_size = XTENSA_STACK_ALIGN (xtensa_callee_save_size);
- return xtensa_current_frame_size;
+ cfun->machine->callee_save_size =
+ XTENSA_STACK_ALIGN (cfun->machine->callee_save_size);
+ cfun->machine->frame_laid_out = true;
+ return cfun->machine->current_frame_size;
}
@@ -2703,6 +2712,7 @@ xtensa_expand_prologue (void)
{
int regno;
HOST_WIDE_INT offset = 0;
+ int callee_save_size = cfun->machine->callee_save_size;
/* -128 is a limit of single addi instruction. */
if (total_size > 0 && total_size <= 128)
@@ -2716,7 +2726,7 @@ xtensa_expand_prologue (void)
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
offset = total_size - UNITS_PER_WORD;
}
- else if (xtensa_callee_save_size)
+ else if (callee_save_size)
{
/* 1020 is maximal s32i offset, if the frame is bigger than that
* we move sp to the end of callee-saved save area, save and then
@@ -2724,13 +2734,13 @@ xtensa_expand_prologue (void)
if (total_size > 1024)
{
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
- GEN_INT (-xtensa_callee_save_size)));
+ GEN_INT (-callee_save_size)));
RTX_FRAME_RELATED_P (insn) = 1;
note_rtx = gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
- -xtensa_callee_save_size));
+ -callee_save_size));
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
- offset = xtensa_callee_save_size - UNITS_PER_WORD;
+ offset = callee_save_size - UNITS_PER_WORD;
}
else
{
@@ -2766,13 +2776,13 @@ xtensa_expand_prologue (void)
{
rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
emit_move_insn (tmp_reg, GEN_INT (total_size -
- xtensa_callee_save_size));
+ callee_save_size));
insn = emit_insn (gen_subsi3 (stack_pointer_rtx,
stack_pointer_rtx, tmp_reg));
RTX_FRAME_RELATED_P (insn) = 1;
note_rtx = gen_rtx_SET (stack_pointer_rtx,
plus_constant (Pmode, stack_pointer_rtx,
- xtensa_callee_save_size -
+ callee_save_size -
total_size));
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note_rtx);
}
@@ -2840,21 +2850,21 @@ xtensa_expand_epilogue (void)
int regno;
HOST_WIDE_INT offset;
- if (xtensa_current_frame_size > (frame_pointer_needed ? 127 : 1024))
+ if (cfun->machine->current_frame_size > (frame_pointer_needed ? 127 : 1024))
{
rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
- emit_move_insn (tmp_reg, GEN_INT (xtensa_current_frame_size -
- xtensa_callee_save_size));
+ emit_move_insn (tmp_reg, GEN_INT (cfun->machine->current_frame_size -
+ cfun->machine->callee_save_size));
emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_needed ?
hard_frame_pointer_rtx : stack_pointer_rtx,
tmp_reg));
- offset = xtensa_callee_save_size - UNITS_PER_WORD;
+ offset = cfun->machine->callee_save_size - UNITS_PER_WORD;
}
else
{
if (frame_pointer_needed)
emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
- offset = xtensa_current_frame_size - UNITS_PER_WORD;
+ offset = cfun->machine->current_frame_size - UNITS_PER_WORD;
}
/* Prevent reordering of saved a0 update and loading it back from
@@ -2874,16 +2884,16 @@ xtensa_expand_epilogue (void)
}
}
- if (xtensa_current_frame_size > 0)
+ if (cfun->machine->current_frame_size > 0)
{
if (frame_pointer_needed || /* always reachable with addi */
- xtensa_current_frame_size > 1024 ||
- xtensa_current_frame_size <= 127)
+ cfun->machine->current_frame_size > 1024 ||
+ cfun->machine->current_frame_size <= 127)
{
- if (xtensa_current_frame_size <= 127)
- offset = xtensa_current_frame_size;
+ if (cfun->machine->current_frame_size <= 127)
+ offset = cfun->machine->current_frame_size;
else
- offset = xtensa_callee_save_size;
+ offset = cfun->machine->callee_save_size;
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
@@ -2892,7 +2902,8 @@ xtensa_expand_epilogue (void)
else
{
rtx tmp_reg = gen_rtx_REG (Pmode, A9_REG);
- emit_move_insn (tmp_reg, GEN_INT (xtensa_current_frame_size));
+ emit_move_insn (tmp_reg,
+ GEN_INT (cfun->machine->current_frame_size));
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
tmp_reg));
}
@@ -2903,11 +2914,22 @@ xtensa_expand_epilogue (void)
stack_pointer_rtx,
EH_RETURN_STACKADJ_RTX));
}
- xtensa_current_frame_size = 0;
- xtensa_callee_save_size = 0;
+ cfun->machine->epilogue_done = true;
emit_jump_insn (gen_return ());
}
+bool
+xtensa_use_return_instruction_p (void)
+{
+ if (!reload_completed)
+ return false;
+ if (TARGET_WINDOWED_ABI)
+ return true;
+ if (compute_frame_size (get_frame_size ()) == 0)
+ return true;
+ return cfun->machine->epilogue_done;
+}
+
void
xtensa_set_return_address (rtx address, rtx scratch)
{
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index 82e9900b42a..58eb1b2604a 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -23,8 +23,6 @@ along with GCC; see the file COPYING3. If not see
/* External variables defined in xtensa.c. */
-extern unsigned xtensa_current_frame_size;
-
/* Macros used in the machine description to select various Xtensa
configuration options. */
#ifndef XCHAL_HAVE_MUL32_HIGH
@@ -477,14 +475,14 @@ enum reg_class
/* Specify the initial difference between the specified pair of registers. */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do { \
- compute_frame_size (get_frame_size ()); \
+ long frame_size = compute_frame_size (get_frame_size ()); \
switch (FROM) \
{ \
case FRAME_POINTER_REGNUM: \
(OFFSET) = 0; \
break; \
case ARG_POINTER_REGNUM: \
- (OFFSET) = xtensa_current_frame_size; \
+ (OFFSET) = frame_size; \
break; \
default: \
gcc_unreachable (); \
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index db54a12b7bc..fcdb6c8ecad 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1663,7 +1663,7 @@
(define_insn "return"
[(return)
(use (reg:SI A0_REG))]
- "(TARGET_WINDOWED_ABI || !xtensa_current_frame_size) && reload_completed"
+ "xtensa_use_return_instruction_p ()"
{
return TARGET_WINDOWED_ABI ?
(TARGET_DENSITY ? "retw.n" : "retw") :
diff --git a/gcc/configure b/gcc/configure
index 80fc5c71a0e..0f04033bc1d 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -22662,6 +22662,15 @@ fi
# ld, we don't know its patchlevel version, so we set the baseline at 2.13
# to be safe.
# The gcc_GAS_CHECK_FEATURE call just sets a cache variable.
+case "${target}" in
+ *-*-aix*)
+ conftest_s=' .globl foobar,hidden'
+ ;;
+ *)
+ conftest_s=' .hidden foobar
+foobar:'
+ ;;
+esac
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .hidden" >&5
$as_echo_n "checking assembler for .hidden... " >&6; }
if test "${gcc_cv_as_hidden+set}" = set; then :
@@ -22674,8 +22683,7 @@ else
then gcc_cv_as_hidden=yes
fi
elif test x$gcc_cv_as != x; then
- $as_echo ' .hidden foobar
-foobar:' > conftest.s
+ $as_echo "$conftest_s" > conftest.s
if { ac_try='$gcc_cv_as $gcc_cv_as_flags -o conftest.o conftest.s >&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
@@ -22809,6 +22817,9 @@ else
fi
else
case "${target}" in
+ *-*-aix[789]*)
+ gcc_cv_ld_hidden=yes
+ ;;
*-*-darwin*)
# Darwin ld has some visibility support.
gcc_cv_ld_hidden=yes
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 338956f644a..2f9b859eafb 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2537,10 +2537,17 @@ gcc_GAS_CHECK_FEATURE([.nsubspa comdat], gcc_cv_as_nsubspa_comdat,
# ld, we don't know its patchlevel version, so we set the baseline at 2.13
# to be safe.
# The gcc_GAS_CHECK_FEATURE call just sets a cache variable.
+case "${target}" in
+ *-*-aix*)
+ conftest_s=' .globl foobar,hidden'
+ ;;
+ *)
+ conftest_s=' .hidden foobar
+foobar:'
+ ;;
+esac
gcc_GAS_CHECK_FEATURE([.hidden], gcc_cv_as_hidden,
- [elf,2,13,0],,
-[ .hidden foobar
-foobar:])
+ [elf,2,13,0],, [$conftest_s])
case "${target}" in
*-*-darwin*)
# Darwin as has some visibility support, though with a different syntax.
@@ -2649,6 +2656,9 @@ else
fi
else
case "${target}" in
+ *-*-aix[789]*)
+ gcc_cv_ld_hidden=yes
+ ;;
*-*-darwin*)
# Darwin ld has some visibility support.
gcc_cv_ld_hidden=yes
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index efce361f880..f325ccc8932 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,172 @@
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ Implement P0012R1, Make exception specifications part of the type
+ system.
+ * cp-tree.h (enum tsubst_flags): Add tf_fndecl_type.
+ (flag_noexcept_type, ce_type): New.
+ * call.c (build_conv): Add ck_fnptr.
+ (enum conversion_kind): Change ck_tsafe to ck_fnptr.
+ (convert_like_real): Likewise.
+ (standard_conversion): Likewise. Allow function pointer
+ conversions for pointers to member functions.
+ (reference_compatible_p): Allow function pointer conversions.
+ (direct_reference_binding): Likewise.
+ (reference_binding): Reference-compatible is no longer a subset of
+ reference-related.
+ (is_subseq): Also strip ck_lvalue after next_conversion.
+ * class.c (instantiate_type): Check fnptr_conv_p.
+ (resolve_address_of_overloaded_function): Likewise.
+ * cvt.c (can_convert_tx_safety): Now static.
+ (noexcept_conv_p, fnptr_conv_p, strip_fnptr_conv): New.
+ * decl.c (flag_noexcept_type): Define.
+ (cxx_init_decl_processing): Set it.
+ (bad_specifiers): Check it.
+ (grokdeclarator) [cdk_function]: Add exception-spec to type here.
+ * lambda.c (maybe_add_lambda_conv_op): Add exception-spec to
+ returned pointer.
+ * mangle.c (struct globals): Add need_cxx1z_warning.
+ (mangle_decl): Check it.
+ (write_exception_spec): New.
+ (write_function_type): Call it.
+ (canonicalize_for_substitution): Handle exception spec.
+ (write_type): Likewise.
+ (write_encoding): Set processing_template_decl across mangling of
+ partially-instantiated type.
+ * pt.c (determine_specialization): Pass tf_fndecl_type.
+ (tsubst_decl, fn_type_unification): Likewise.
+ (tsubst): Strip tf_fndecl_type, pass it to
+ tsubst_exception_specification.
+ (convert_nontype_argument_function): Handle function pointer
+ conversion.
+ (convert_nontype_argument): Likewise.
+ (unify, for_each_template_parm_r): Walk into noexcept-specifier.
+ * rtti.c (ptr_initializer): Encode noexcept.
+ * tree.c (canonical_eh_spec): New.
+ (build_exception_variant): Use it.
+ * typeck.c (composite_pointer_type): Handle fnptr conversion.
+ (comp_except_specs): Compare canonical EH specs.
+ (structural_comptypes): Call it.
+
+ * call.c (standard_conversion): Reorganize pointer conversions.
+ * pt.c (convert_nontype_argument_function): Convert to ref here.
+ (convert_nontype_argument): Not here.
+ (convert_template_argument): Add original type to error message.
+ (RECUR_AND_CHECK_FAILURE): Remove trailing semicolon.
+ (unify): Compare function-qualifiers.
+ * typeck.c (same_type_ignoring_top_level_qualifiers_p): Use
+ cp_build_qualified_type rather than TYPE_MAIN_VARIANT.
+
+ * pt.c (push_tinst_level_loc): Add template instantiations to the
+ announce_function stream.
+
+2016-11-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/67980
+ * pt.c (tsubst_expr, case IF_STMT): Use fold_non_dependent_expr
+ to suppress unwanted warnings.
+
+2016-11-03 Jason Merrill <jason@redhat.com>
+
+ PR c++/78198
+ * call.c (convert_default_arg): Look through inheriting ctors.
+
+2016-11-03 Jakub Jelinek <jakub@redhat.com>
+ Alexandre Oliva <aoliva@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR debug/28767
+ PR debug/56974
+ * tree.c (cp_check_qualified_type): Use check_base_type and
+ TYPE_QUALS comparison instead of check_qualified_type.
+ (cxx_type_hash_eq): Return false if type_memfn_rqual don't match.
+ * cp-objcp-common.c (cp_get_debug_type): New function.
+ (cp_decl_dwarf_attribute): Don't handle types here.
+ (cp_type_dwarf_attribute): New function.
+ * cp-objcp-common.h (cp_get_debug_type, cp_type_dwarf_attribute):
+ Declare.
+ (LANG_HOOKS_GET_DEBUG_TYPE, LANG_HOOKS_TYPE_DWARF_ATTRIBUTE):
+ Define.
+
+2016-11-03 Jason Merrill <jason@redhat.com>
+
+ * tree.c (cp_check_qualified_type): Call check_base_type instead
+ of check_qualified_type.
+ (cxx_type_hash_eq): Check ref-qualifiers.
+ * typeck.c (apply_memfn_quals): No need to mess with TYPE_CANONICAL.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ Implement P0136R1, Rewording inheriting constructors.
+ * call.c (enum rejection_reason_code): Add rr_inherited_ctor.
+ (inherited_ctor_rejection): New.
+ (add_function_candidate): Reject inherited ctors for copying.
+ (enforce_access): Use strip_inheriting_ctors.
+ (print_z_candidate): Likewise. Handle rr_inherited_ctor.
+ (convert_like_real): Avoid copying inheriting ctor parameters.
+ (build_over_call): Likewise. A base ctor inheriting from vbase
+ has no parms. Sorry about varargs.
+ (joust): A local constructor beats inherited with the same convs.
+ * class.c (add_method): Handle hiding inheriting ctors.
+ (one_inherited_ctor): Handle new semantics.
+ (add_implicitly_declared_members): Pass using_decl down.
+ (build_clone): A base ctor inheriting from vbase has no parms.
+ * cp-tree.h (DECL_INHERITED_CTOR): Store this instead of the base.
+ (SET_DECL_INHERITED_CTOR): Likewise.
+ (DECL_INHERITED_CTOR_BASE): Adjust.
+ * constexpr.c: Adjust.
+ * error.c (dump_function_decl): Decorate inheriting ctors.
+ * init.c (emit_mem_initializers): Suppress access control in
+ inheriting ctor.
+ * mangle.c (write_special_name_constructor): Handle new inheriting
+ ctor mangling.
+ * method.c (strip_inheriting_ctors, inherited_ctor_binfo)
+ (ctor_omit_inherited_parms, binfo_inherited_from): New.
+ (synthesized_method_walk): Use binfo_inherited_from. Suppress
+ access control in inheriting ctor.
+ (deduce_inheriting_ctor): Deleted if ambiguous ctor inheritance.
+ (maybe_explain_implicit_delete): Explain ambigous ctor inheritance.
+ (add_one_base_init, do_build_copy_constructor): Adjust.
+ (locate_fn_flags, explain_implicit_non_constexpr): Adjust.
+ (implicitly_declare_fn): Adjust.
+ (get_inherited_ctor): Remove.
+ * name-lookup.c (do_class_using_decl): Check for indirect ctor
+ inheritance.
+ * optimize.c (cdtor_comdat_group): Adjust for new mangling.
+ (maybe_clone_body): Handle omitted parms in base clone.
+ (maybe_thunk_body): Don't thunk if base clone omits parms.
+ * pt.c (tsubst_decl): Adjust.
+ (instantiate_template_1): Suppress access control in inheriting
+ ctor.
+ (fn_type_unification): Do deduction with inherited ctor.
+ * tree.c (special_function_p): Adjust.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * cp-objcp-common.c (cp_decl_dwarf_attribute): Handle DW_AT_inline.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * class.c (declared_access): Split out from handle_using_decl.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/78089
+ * parser.c (cp_parser_postfix_expression): Replace return statement in
+ the first switch with setting postfix_expression to the return
+ expression and break;.
+
+ PR c++/77886
+ * pt.c (tsubst_expr) <case CASE_LABEL_EXPR> Copy over
+ FALLTHROUGH_LABEL_P flag to the new LABEL_DECL.
+ (tsubst_expr) <case LABEL_EXPR>: Likewise.
+
+2016-09-11 Le-Chun Wu <lcwu@google.com>
+ Mark Wielaard <mjw@redhat.com>
+
+ * name-lookup.c (pushdecl_maybe_friend): When emitting a
+ shadowing warning, use the code corresponding to the
+ given -Wshadow= variant.
+
2016-10-26 Jason Merrill <jason@redhat.com>
* class.c (add_method): Allow using-declarations to coexist.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4c19d2ffcd3..0dcf322344c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -45,7 +45,7 @@ along with GCC; see the file COPYING3. If not see
enum conversion_kind {
ck_identity,
ck_lvalue,
- ck_tsafe,
+ ck_fnptr,
ck_qual,
ck_std,
ck_ptr,
@@ -414,6 +414,7 @@ enum rejection_reason_code {
rr_bad_arg_conversion,
rr_template_unification,
rr_invalid_copy,
+ rr_inherited_ctor,
rr_constraint_failure
};
@@ -689,6 +690,13 @@ invalid_copy_with_fn_template_rejection (void)
return r;
}
+static struct rejection_reason *
+inherited_ctor_rejection (void)
+{
+ struct rejection_reason *r = alloc_rejection (rr_inherited_ctor);
+ return r;
+}
+
// Build a constraint failure record, saving information into the
// template_instantiation field of the rejection. If FN is not a template
// declaration, the TMPL member is the FN declaration and TARGS is empty.
@@ -763,6 +771,7 @@ build_conv (conversion_kind code, tree type, conversion *from)
break;
case ck_qual:
+ case ck_fnptr:
if (rank < cr_exact)
rank = cr_exact;
break;
@@ -1204,19 +1213,40 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
tree to_pointee;
tree from_pointee;
+ if (tcode == POINTER_TYPE)
+ {
+ to_pointee = TREE_TYPE (to);
+ from_pointee = TREE_TYPE (from);
+
+ /* Since this is the target of a pointer, it can't have function
+ qualifiers, so any TYPE_QUALS must be for attributes const or
+ noreturn. Strip them. */
+ if (TREE_CODE (to_pointee) == FUNCTION_TYPE
+ && TYPE_QUALS (to_pointee))
+ to_pointee = build_qualified_type (to_pointee, TYPE_UNQUALIFIED);
+ if (TREE_CODE (from_pointee) == FUNCTION_TYPE
+ && TYPE_QUALS (from_pointee))
+ from_pointee = build_qualified_type (from_pointee, TYPE_UNQUALIFIED);
+ }
+ else
+ {
+ to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to);
+ from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from);
+ }
+
if (tcode == POINTER_TYPE
- && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
- TREE_TYPE (to)))
+ && same_type_ignoring_top_level_qualifiers_p (from_pointee,
+ to_pointee))
;
- else if (VOID_TYPE_P (TREE_TYPE (to))
+ else if (VOID_TYPE_P (to_pointee)
&& !TYPE_PTRDATAMEM_P (from)
- && TREE_CODE (TREE_TYPE (from)) != FUNCTION_TYPE)
+ && TREE_CODE (from_pointee) != FUNCTION_TYPE)
{
tree nfrom = TREE_TYPE (from);
/* Don't try to apply restrict to void. */
int quals = cp_type_quals (nfrom) & ~TYPE_QUAL_RESTRICT;
- from = build_pointer_type
- (cp_build_qualified_type (void_type_node, quals));
+ from_pointee = cp_build_qualified_type (void_type_node, quals);
+ from = build_pointer_type (from_pointee);
conv = build_conv (ck_ptr, from, conv);
}
else if (TYPE_PTRDATAMEM_P (from))
@@ -1226,18 +1256,16 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
if (DERIVED_FROM_P (fbase, tbase)
&& (same_type_ignoring_top_level_qualifiers_p
- (TYPE_PTRMEM_POINTED_TO_TYPE (from),
- TYPE_PTRMEM_POINTED_TO_TYPE (to))))
+ (from_pointee, to_pointee)))
{
- from = build_ptrmem_type (tbase,
- TYPE_PTRMEM_POINTED_TO_TYPE (from));
+ from = build_ptrmem_type (tbase, from_pointee);
conv = build_conv (ck_pmem, from, conv);
}
else if (!same_type_p (fbase, tbase))
return NULL;
}
- else if (CLASS_TYPE_P (TREE_TYPE (from))
- && CLASS_TYPE_P (TREE_TYPE (to))
+ else if (CLASS_TYPE_P (from_pointee)
+ && CLASS_TYPE_P (to_pointee)
/* [conv.ptr]
An rvalue of type "pointer to cv D," where D is a
@@ -1249,37 +1277,15 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
that necessitates this conversion is ill-formed.
Therefore, we use DERIVED_FROM_P, and do not check
access or uniqueness. */
- && DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
+ && DERIVED_FROM_P (to_pointee, from_pointee))
{
- from =
- cp_build_qualified_type (TREE_TYPE (to),
- cp_type_quals (TREE_TYPE (from)));
- from = build_pointer_type (from);
+ from_pointee
+ = cp_build_qualified_type (to_pointee,
+ cp_type_quals (from_pointee));
+ from = build_pointer_type (from_pointee);
conv = build_conv (ck_ptr, from, conv);
conv->base_p = true;
}
- else if (tx_safe_fn_type_p (TREE_TYPE (from)))
- {
- /* A prvalue of type "pointer to transaction_safe function" can be
- converted to a prvalue of type "pointer to function". */
- tree unsafe = tx_unsafe_fn_variant (TREE_TYPE (from));
- if (same_type_p (unsafe, TREE_TYPE (to)))
- {
- from = build_pointer_type (unsafe);
- conv = build_conv (ck_tsafe, from, conv);
- }
- }
-
- if (tcode == POINTER_TYPE)
- {
- to_pointee = TREE_TYPE (to);
- from_pointee = TREE_TYPE (from);
- }
- else
- {
- to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to);
- from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from);
- }
if (same_type_p (from, to))
/* OK */;
@@ -1293,6 +1299,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
else if (expr && string_conv_p (to, expr, 0))
/* converting from string constant to char *. */
conv = build_conv (ck_qual, to, conv);
+ else if (fnptr_conv_p (to, from))
+ conv = build_conv (ck_fnptr, to, conv);
/* Allow conversions among compatible ObjC pointer types (base
conversions have been already handled above). */
else if (c_dialect_objc ()
@@ -1315,18 +1323,29 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
tree fbase = class_of_this_parm (fromfn);
tree tbase = class_of_this_parm (tofn);
- if (!DERIVED_FROM_P (fbase, tbase)
- || !same_type_p (static_fn_type (fromfn),
- static_fn_type (tofn)))
+ if (!DERIVED_FROM_P (fbase, tbase))
return NULL;
- from = build_memfn_type (fromfn,
- tbase,
- cp_type_quals (tbase),
- type_memfn_rqual (tofn));
- from = build_ptrmemfunc_type (build_pointer_type (from));
- conv = build_conv (ck_pmem, from, conv);
- conv->base_p = true;
+ tree fstat = static_fn_type (fromfn);
+ tree tstat = static_fn_type (tofn);
+ if (same_type_p (tstat, fstat)
+ || fnptr_conv_p (tstat, fstat))
+ /* OK */;
+ else
+ return NULL;
+
+ if (!same_type_p (fbase, tbase))
+ {
+ from = build_memfn_type (fstat,
+ tbase,
+ cp_type_quals (tbase),
+ type_memfn_rqual (tofn));
+ from = build_ptrmemfunc_type (build_pointer_type (from));
+ conv = build_conv (ck_pmem, from, conv);
+ conv->base_p = true;
+ }
+ if (fnptr_conv_p (tstat, fstat))
+ conv = build_conv (ck_fnptr, to, conv);
}
else if (tcode == BOOLEAN_TYPE)
{
@@ -1424,10 +1443,14 @@ reference_compatible_p (tree t1, tree t2)
{
/* [dcl.init.ref]
- "cv1 T1" is reference compatible with "cv2 T2" if T1 is
- reference-related to T2 and cv1 is the same cv-qualification as,
- or greater cv-qualification than, cv2. */
- return (reference_related_p (t1, t2)
+ "cv1 T1" is reference compatible with "cv2 T2" if
+ * T1 is reference-related to T2 or
+ * T2 is "noexcept function" and T1 is "function", where the
+ function types are otherwise the same,
+ and cv1 is the same cv-qualification as, or greater cv-qualification
+ than, cv2. */
+ return ((reference_related_p (t1, t2)
+ || fnptr_conv_p (t1, t2))
&& at_least_as_qualified_p (t1, t2));
}
@@ -1461,7 +1484,7 @@ direct_reference_binding (tree type, conversion *conv)
either an identity conversion or, if the conversion function
returns an entity of a type that is a derived class of the
parameter type, a derived-to-base conversion. */
- if (!same_type_ignoring_top_level_qualifiers_p (t, conv->type))
+ if (is_properly_derived_from (conv->type, t))
{
/* Represent the derived-to-base conversion. */
conv = build_conv (ck_base, t, conv);
@@ -1574,7 +1597,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
[8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
const and rvalue references to rvalues of compatible class type.
We should also do direct bindings for non-class xvalues. */
- if (related_p && gl_kind)
+ if ((related_p || compatible_p) && gl_kind)
{
/* [dcl.init.ref]
@@ -2111,6 +2134,18 @@ add_function_candidate (struct z_candidate **candidates,
}
}
+ /* Don't consider inherited constructors for initialization from an
+ expression of the same or derived type. */
+ /* FIXME extend to operator=. */
+ if (i == 0 && len == 1
+ && DECL_INHERITED_CTOR (fn)
+ && reference_related_p (ctype, argtype))
+ {
+ viable = 0;
+ reason = inherited_ctor_rejection ();
+ goto out;
+ }
+
/* Core issue 899: When [copy-]initializing a temporary to be bound
to the first parameter of a copy constructor (12.8) called with
a single argument in the context of direct-initialization,
@@ -3393,32 +3428,40 @@ print_z_candidate (location_t loc, const char *msgstr,
const char *msg = (msgstr == NULL
? ""
: ACONCAT ((msgstr, " ", NULL)));
- location_t cloc = location_of (candidate->fn);
+ tree fn = candidate->fn;
+ if (flag_new_inheriting_ctors)
+ fn = strip_inheriting_ctors (fn);
+ location_t cloc = location_of (fn);
- if (identifier_p (candidate->fn))
+ if (identifier_p (fn))
{
cloc = loc;
if (candidate->num_convs == 3)
- inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T, %T, %T) <built-in>", msg, fn,
candidate->convs[0]->type,
candidate->convs[1]->type,
candidate->convs[2]->type);
else if (candidate->num_convs == 2)
- inform (cloc, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T, %T) <built-in>", msg, fn,
candidate->convs[0]->type,
candidate->convs[1]->type);
else
- inform (cloc, "%s%D(%T) <built-in>", msg, candidate->fn,
+ inform (cloc, "%s%D(%T) <built-in>", msg, fn,
candidate->convs[0]->type);
}
- else if (TYPE_P (candidate->fn))
- inform (cloc, "%s%T <conversion>", msg, candidate->fn);
+ else if (TYPE_P (fn))
+ inform (cloc, "%s%T <conversion>", msg, fn);
else if (candidate->viable == -1)
- inform (cloc, "%s%#D <near match>", msg, candidate->fn);
- else if (DECL_DELETED_FN (candidate->fn))
- inform (cloc, "%s%#D <deleted>", msg, candidate->fn);
+ inform (cloc, "%s%#D <near match>", msg, fn);
+ else if (DECL_DELETED_FN (fn))
+ inform (cloc, "%s%#D <deleted>", msg, fn);
else
- inform (cloc, "%s%#D", msg, candidate->fn);
+ inform (cloc, "%s%#D", msg, fn);
+ if (fn != candidate->fn)
+ {
+ cloc = location_of (candidate->fn);
+ inform (cloc, " inherited here");
+ }
/* Give the user some information about why this candidate failed. */
if (candidate->reason != NULL)
{
@@ -3483,6 +3526,11 @@ print_z_candidate (location_t loc, const char *msgstr,
diagnose_constraints (cloc, tmpl, args);
}
break;
+ case rr_inherited_ctor:
+ inform (cloc, " an inherited constructor is not a candidate for "
+ "initialization from an expression of the same or derived "
+ "type");
+ break;
case rr_none:
default:
/* This candidate didn't have any issues or we failed to
@@ -6338,10 +6386,22 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl,
{
gcc_assert (TREE_CODE (basetype_path) == TREE_BINFO);
+ if (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (decl))
+ {
+ /* 7.3.3/18: The additional constructors are accessible if they would be
+ accessible when used to construct an object of the corresponding base
+ class. */
+ decl = strip_inheriting_ctors (decl);
+ basetype_path = TYPE_BINFO (DECL_CONTEXT (decl));
+ }
+
if (!accessible_p (basetype_path, decl, true))
{
if (complain & tf_error)
{
+ if (flag_new_inheriting_ctors)
+ diag_decl = strip_inheriting_ctors (diag_decl);
if (TREE_PRIVATE (decl))
{
error ("%q#D is private within this context", diag_decl);
@@ -6773,6 +6833,15 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (! MAYBE_CLASS_TYPE_P (totype))
return expr;
+
+ /* Don't introduce copies when passing arguments along to the inherited
+ constructor. */
+ if (current_function_decl
+ && flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (current_function_decl)
+ && TREE_ADDRESSABLE (totype))
+ return expr;
+
/* Fall through. */
case ck_base:
if (convs->kind == ck_base && !convs->need_temporary_p)
@@ -6915,9 +6984,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
case ck_lvalue:
return decay_conversion (expr, complain);
- case ck_tsafe:
+ case ck_fnptr:
/* ??? Should the address of a transaction-safe pointer point to the TM
- clone, and this conversion look up the primary function? */
+ clone, and this conversion look up the primary function? */
return build_nop (totype, expr);
case ck_qual:
@@ -7139,6 +7208,9 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum,
/* See through clones. */
fn = DECL_ORIGIN (fn);
+ /* And inheriting ctors. */
+ if (flag_new_inheriting_ctors)
+ fn = strip_inheriting_ctors (fn);
/* Detect recursion. */
FOR_EACH_VEC_SAFE_ELT (default_arg_context, i, t)
@@ -7800,6 +7872,29 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
check_function_arguments (input_location, TREE_TYPE (fn), nargs, fargs);
}
+ if (DECL_INHERITED_CTOR (fn))
+ {
+ /* Check for passing ellipsis arguments to an inherited constructor. We
+ could handle this by open-coding the inherited constructor rather than
+ defining it, but let's not bother now. */
+ if (!cp_unevaluated_operand
+ && cand->convs[cand->num_convs-1]->ellipsis_p)
+ {
+ if (complain & tf_error)
+ {
+ sorry ("passing arguments to ellipsis of inherited constructor "
+ "%qD", cand->fn);
+ inform (DECL_SOURCE_LOCATION (cand->fn), "declared here");
+ }
+ return error_mark_node;
+ }
+
+ /* A base constructor inheriting from a virtual base doesn't get the
+ inherited arguments, just this and __vtt. */
+ if (ctor_omit_inherited_parms (fn))
+ nargs = 2;
+ }
+
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -7985,13 +8080,21 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
- if (call != error_mark_node
- && cand->flags & LOOKUP_LIST_INIT_CTOR)
+ if (call == error_mark_node)
+ return call;
+ if (cand->flags & LOOKUP_LIST_INIT_CTOR)
{
tree c = extract_call_expr (call);
/* build_new_op_1 will clear this when appropriate. */
CALL_EXPR_ORDERED_ARGS (c) = true;
}
+ if (current_function_decl
+ && flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (current_function_decl)
+ && cand->num_convs)
+ /* Don't introduce copies when passing arguments along to the inherited
+ constructor. */
+ CALL_FROM_THUNK_P (call) = true;
return call;
}
@@ -8766,10 +8869,15 @@ is_subseq (conversion *ics1, conversion *ics2)
ics2 = next_conversion (ics2);
+ while (ics2->kind == ck_rvalue
+ || ics2->kind == ck_lvalue)
+ ics2 = next_conversion (ics2);
+
if (ics2->kind == ics1->kind
&& same_type_p (ics2->type, ics1->type)
- && same_type_p (next_conversion (ics2)->type,
- next_conversion (ics1)->type))
+ && (ics1->kind == ck_identity
+ || same_type_p (next_conversion (ics2)->type,
+ next_conversion (ics1)->type)))
return true;
}
}
@@ -9539,6 +9647,34 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
+ /* or, if not that, F2 is from a using-declaration, F1 is not, and the
+ conversion sequences are equivalent.
+ (proposed in http://lists.isocpp.org/core/2016/10/1142.php) */
+ if (DECL_P (cand1->fn) && DECL_CLASS_SCOPE_P (cand1->fn)
+ && !DECL_CONV_FN_P (cand1->fn)
+ && DECL_P (cand2->fn) && DECL_CLASS_SCOPE_P (cand2->fn)
+ && !DECL_CONV_FN_P (cand2->fn))
+ {
+ bool used1 = (DECL_INHERITED_CTOR (cand1->fn)
+ || (BINFO_TYPE (cand1->access_path)
+ != DECL_CONTEXT (cand1->fn)));
+ bool used2 = (DECL_INHERITED_CTOR (cand2->fn)
+ || (BINFO_TYPE (cand2->access_path)
+ != DECL_CONTEXT (cand2->fn)));
+ if (int diff = used2 - used1)
+ {
+ for (i = 0; i < len; ++i)
+ {
+ conversion *t1 = cand1->convs[i + off1];
+ conversion *t2 = cand2->convs[i + off2];
+ if (!same_type_p (t1->type, t2->type))
+ break;
+ }
+ if (i == len)
+ return diff;
+ }
+ }
+
/* Check whether we can discard a builtin candidate, either because we
have two identical ones or matching builtin and non-builtin candidates.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a2a93469151..5460ae5d626 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1016,7 +1016,6 @@ add_method (tree type, tree method, tree using_decl)
bool complete_p;
bool insert_p = false;
tree current_fns;
- tree fns;
if (method == error_mark_node)
return false;
@@ -1083,8 +1082,9 @@ add_method (tree type, tree method, tree using_decl)
current_fns = insert_p ? NULL_TREE : (*method_vec)[slot];
/* Check to see if we've already got this method. */
- for (fns = current_fns; fns; fns = OVL_NEXT (fns))
+ for (tree *p = &current_fns; *p; )
{
+ tree fns = *p;
tree fn = OVL_CURRENT (fns);
tree fn_type;
tree method_type;
@@ -1092,12 +1092,14 @@ add_method (tree type, tree method, tree using_decl)
tree parms2;
if (TREE_CODE (fn) != TREE_CODE (method))
- continue;
+ goto cont;
/* Two using-declarations can coexist, we'll complain about ambiguity in
overload resolution. */
- if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns))
- continue;
+ if (using_decl && TREE_CODE (fns) == OVERLOAD && OVL_USED (fns)
+ /* Except handle inherited constructors specially. */
+ && ! DECL_CONSTRUCTOR_P (fn))
+ goto cont;
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
@@ -1131,7 +1133,7 @@ add_method (tree type, tree method, tree using_decl)
== FUNCTION_REF_QUALIFIED (method_type))
&& (type_memfn_quals (fn_type) != type_memfn_quals (method_type)
|| type_memfn_rqual (fn_type) != type_memfn_rqual (method_type)))
- continue;
+ goto cont;
/* For templates, the return type and template parameters
must be identical. */
@@ -1140,7 +1142,7 @@ add_method (tree type, tree method, tree using_decl)
TREE_TYPE (method_type))
|| !comp_template_parms (DECL_TEMPLATE_PARMS (fn),
DECL_TEMPLATE_PARMS (method))))
- continue;
+ goto cont;
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
@@ -1178,18 +1180,38 @@ add_method (tree type, tree method, tree using_decl)
mangle_decl (method);
}
cgraph_node::record_function_versions (fn, method);
- continue;
+ goto cont;
}
- if (DECL_INHERITED_CTOR_BASE (method))
+ if (DECL_INHERITED_CTOR (method))
{
- if (DECL_INHERITED_CTOR_BASE (fn))
+ if (DECL_INHERITED_CTOR (fn))
{
+ tree basem = DECL_INHERITED_CTOR_BASE (method);
+ tree basef = DECL_INHERITED_CTOR_BASE (fn);
+ if (flag_new_inheriting_ctors)
+ {
+ if (basem == basef)
+ {
+ /* Inheriting the same constructor along different
+ paths, combine them. */
+ SET_DECL_INHERITED_CTOR
+ (fn, ovl_cons (DECL_INHERITED_CTOR (method),
+ DECL_INHERITED_CTOR (fn)));
+ /* Adjust deletedness and such. */
+ deduce_inheriting_ctor (fn);
+ /* And discard the new one. */
+ return false;
+ }
+ else
+ /* Inherited ctors can coexist until overload
+ resolution. */
+ goto cont;
+ }
error_at (DECL_SOURCE_LOCATION (method),
- "%q#D inherited from %qT", method,
- DECL_INHERITED_CTOR_BASE (method));
+ "%q#D", method);
error_at (DECL_SOURCE_LOCATION (fn),
"conflicts with version inherited from %qT",
- DECL_INHERITED_CTOR_BASE (fn));
+ basef);
}
/* Otherwise defer to the other function. */
return false;
@@ -1200,6 +1222,13 @@ add_method (tree type, tree method, tree using_decl)
/* Defer to the local function. */
return false;
}
+ else if (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (fn))
+ {
+ /* Hide the inherited constructor. */
+ *p = OVL_NEXT (fns);
+ continue;
+ }
else
{
error ("%q+#D cannot be overloaded", method);
@@ -1212,6 +1241,12 @@ add_method (tree type, tree method, tree using_decl)
will crash while processing the definitions. */
return false;
}
+
+ cont:
+ if (TREE_CODE (fns) == OVERLOAD)
+ p = &OVL_CHAIN (fns);
+ else
+ break;
}
/* A class should never have more than one destructor. */
@@ -1299,6 +1334,16 @@ alter_access (tree t, tree fdecl, tree access)
return 0;
}
+/* Return the access node for DECL's access in its enclosing class. */
+
+tree
+declared_access (tree decl)
+{
+ return (TREE_PRIVATE (decl) ? access_private_node
+ : TREE_PROTECTED (decl) ? access_protected_node
+ : access_public_node);
+}
+
/* Process the USING_DECL, which is a member of T. */
static void
@@ -1306,10 +1351,7 @@ handle_using_decl (tree using_decl, tree t)
{
tree decl = USING_DECL_DECLS (using_decl);
tree name = DECL_NAME (using_decl);
- tree access
- = TREE_PRIVATE (using_decl) ? access_private_node
- : TREE_PROTECTED (using_decl) ? access_protected_node
- : access_public_node;
+ tree access = declared_access (using_decl);
tree flist = NULL_TREE;
tree old_value;
@@ -3301,10 +3343,19 @@ one_inheriting_sig (tree t, tree ctor, tree *parms, int nparms)
constructor CTOR. */
static void
-one_inherited_ctor (tree ctor, tree t)
+one_inherited_ctor (tree ctor, tree t, tree using_decl)
{
tree parms = FUNCTION_FIRST_USER_PARMTYPE (ctor);
+ if (flag_new_inheriting_ctors)
+ {
+ ctor = implicitly_declare_fn (sfk_inheriting_constructor,
+ t, /*const*/false, ctor, parms);
+ add_method (t, ctor, using_decl);
+ TYPE_HAS_USER_CONSTRUCTOR (t) = true;
+ return;
+ }
+
tree *new_parms = XALLOCAVEC (tree, list_length (parms));
int i = 0;
for (; parms && parms != void_list_node; parms = TREE_CHAIN (parms))
@@ -3405,7 +3456,7 @@ add_implicitly_declared_members (tree t, tree* access_decls,
input_location = DECL_SOURCE_LOCATION (using_decl);
if (ctor_list)
for (; ctor_list; ctor_list = OVL_NEXT (ctor_list))
- one_inherited_ctor (OVL_CURRENT (ctor_list), t);
+ one_inherited_ctor (OVL_CURRENT (ctor_list), t, using_decl);
*access_decls = TREE_CHAIN (*access_decls);
input_location = loc;
}
@@ -4765,6 +4816,11 @@ build_clone (tree fn, tree name)
}
}
+ /* A base constructor inheriting from a virtual base doesn't get the
+ arguments. */
+ if (ctor_omit_inherited_parms (fn))
+ DECL_CHAIN (DECL_CHAIN (DECL_ARGUMENTS (clone))) = NULL_TREE;
+
for (parms = DECL_ARGUMENTS (clone); parms; parms = DECL_CHAIN (parms))
{
DECL_CONTEXT (parms) = clone;
@@ -8121,10 +8177,14 @@ resolve_address_of_overloaded_function (tree target_type,
if (DECL_ANTICIPATED (fn))
continue;
+ /* In C++17 we need the noexcept-qualifier to compare types. */
+ if (flag_noexcept_type)
+ maybe_instantiate_noexcept (fn);
+
/* See if there's a match. */
tree fntype = static_fn_type (fn);
if (same_type_p (target_fn_type, fntype)
- || can_convert_tx_safety (target_fn_type, fntype))
+ || fnptr_conv_p (target_fn_type, fntype))
matches = tree_cons (fn, NULL_TREE, matches);
}
}
@@ -8201,10 +8261,14 @@ resolve_address_of_overloaded_function (tree target_type,
require_deduced_type (instantiation);
}
+ /* In C++17 we need the noexcept-qualifier to compare types. */
+ if (flag_noexcept_type)
+ maybe_instantiate_noexcept (instantiation);
+
/* See if there's a match. */
tree fntype = static_fn_type (instantiation);
if (same_type_p (target_fn_type, fntype)
- || can_convert_tx_safety (target_fn_type, fntype))
+ || fnptr_conv_p (target_fn_type, fntype))
matches = tree_cons (instantiation, fn, matches);
}
@@ -8368,6 +8432,8 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t complain)
tree fntype = non_reference (lhstype);
if (same_type_p (fntype, TREE_TYPE (rhs)))
return rhs;
+ if (fnptr_conv_p (fntype, TREE_TYPE (rhs)))
+ return rhs;
if (flag_ms_extensions
&& TYPE_PTRMEMFUNC_P (fntype)
&& !TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1ebd647e7d1..43457d2463f 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -171,13 +171,13 @@ is_valid_constexpr_fn (tree fun, bool complain)
{
bool ret = true;
- if (DECL_INHERITED_CTOR_BASE (fun)
+ if (DECL_INHERITED_CTOR (fun)
&& TREE_CODE (fun) == TEMPLATE_DECL)
{
ret = false;
if (complain)
error ("inherited constructor %qD is not constexpr",
- get_inherited_ctor (fun));
+ DECL_INHERITED_CTOR (fun));
}
else
{
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 070b64c5d82..633831ce4b3 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -131,6 +131,19 @@ cxx_types_compatible_p (tree x, tree y)
return same_type_ignoring_top_level_qualifiers_p (x, y);
}
+/* Return a type to use in the debug info instead of TYPE, or NULL_TREE to
+ keep TYPE. */
+
+tree
+cp_get_debug_type (const_tree type)
+{
+ if (TYPE_PTRMEMFUNC_P (type) && !typedef_variant_p (type))
+ return build_offset_type (TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
+ TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)));
+
+ return NULL_TREE;
+}
+
/* Return -1 if dwarf ATTR shouldn't be added for DECL, or the attribute
value otherwise. */
int
@@ -179,11 +192,6 @@ cp_decl_dwarf_attribute (const_tree decl, int attr)
&& FUNCTION_REF_QUALIFIED (TREE_TYPE (decl))
&& !FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl)))
return 1;
- if ((TREE_CODE (decl) == FUNCTION_TYPE
- || TREE_CODE (decl) == METHOD_TYPE)
- && FUNCTION_REF_QUALIFIED (decl)
- && !FUNCTION_RVALUE_QUALIFIED (decl))
- return 1;
break;
case DW_AT_rvalue_reference:
@@ -192,10 +200,48 @@ cp_decl_dwarf_attribute (const_tree decl, int attr)
&& FUNCTION_REF_QUALIFIED (TREE_TYPE (decl))
&& FUNCTION_RVALUE_QUALIFIED (TREE_TYPE (decl)))
return 1;
- if ((TREE_CODE (decl) == FUNCTION_TYPE
- || TREE_CODE (decl) == METHOD_TYPE)
- && FUNCTION_REF_QUALIFIED (decl)
- && FUNCTION_RVALUE_QUALIFIED (decl))
+ break;
+
+ case DW_AT_inline:
+ if (VAR_P (decl) && DECL_INLINE_VAR_P (decl))
+ {
+ if (DECL_VAR_DECLARED_INLINE_P (decl))
+ return DW_INL_declared_inlined;
+ else
+ return DW_INL_inlined;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+/* Return -1 if dwarf ATTR shouldn't be added for TYPE, or the attribute
+ value otherwise. */
+int
+cp_type_dwarf_attribute (const_tree type, int attr)
+{
+ if (type == NULL_TREE)
+ return -1;
+
+ switch (attr)
+ {
+ case DW_AT_reference:
+ if ((TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ && FUNCTION_REF_QUALIFIED (type)
+ && !FUNCTION_RVALUE_QUALIFIED (type))
+ return 1;
+ break;
+
+ case DW_AT_rvalue_reference:
+ if ((TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ && FUNCTION_REF_QUALIFIED (type)
+ && FUNCTION_RVALUE_QUALIFIED (type))
return 1;
break;
diff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h
index 9dd847e4220..65ac95c2ee1 100644
--- a/gcc/cp/cp-objcp-common.h
+++ b/gcc/cp/cp-objcp-common.h
@@ -21,12 +21,14 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_CP_OBJCP_COMMON
#define GCC_CP_OBJCP_COMMON
-/* In cp/cp-lang.c and objcp/objcp-lang.c. */
+/* In cp/objcp-common.c, cp/cp-lang.c and objcp/objcp-lang.c. */
+extern tree cp_get_debug_type (const_tree);
extern tree objcp_tsubst_copy_and_build (tree, tree, tsubst_flags_t,
tree, bool);
extern int cp_decl_dwarf_attribute (const_tree, int);
+extern int cp_type_dwarf_attribute (const_tree, int);
extern void cp_common_init_ts (void);
/* Lang hooks that are shared between C++ and ObjC++ are defined here. Hooks
@@ -125,12 +127,16 @@ extern void cp_common_init_ts (void);
#define LANG_HOOKS_REGISTER_BUILTIN_TYPE c_register_builtin_type
#undef LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE
#define LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE cp_reconstruct_complex_type
+#undef LANG_HOOKS_GET_DEBUG_TYPE
+#define LANG_HOOKS_GET_DEBUG_TYPE cp_get_debug_type
#undef LANG_HOOKS_TO_TARGET_CHARSET
#define LANG_HOOKS_TO_TARGET_CHARSET c_common_to_target_charset
#undef LANG_HOOKS_GIMPLIFY_EXPR
#define LANG_HOOKS_GIMPLIFY_EXPR cp_gimplify_expr
#undef LANG_HOOKS_DECL_DWARF_ATTRIBUTE
#define LANG_HOOKS_DECL_DWARF_ATTRIBUTE cp_decl_dwarf_attribute
+#undef LANG_HOOKS_TYPE_DWARF_ATTRIBUTE
+#define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE cp_type_dwarf_attribute
#undef LANG_HOOKS_OMP_PREDETERMINED_SHARING
#define LANG_HOOKS_OMP_PREDETERMINED_SHARING cxx_omp_predetermined_sharing
#undef LANG_HOOKS_OMP_CLAUSE_DEFAULT_CTOR
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c58996925c3..20b52ad675d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2730,12 +2730,21 @@ struct GTY(()) lang_decl {
(LANG_DECL_FN_CHECK (NODE)->context = (THUNKS))
/* If NODE, a FUNCTION_DECL, is a C++11 inheriting constructor, then this
- is the base it inherits from. */
-#define DECL_INHERITED_CTOR_BASE(NODE) \
- (DECL_CONSTRUCTOR_P (NODE) ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+ is the constructor it inherits from. */
+#define DECL_INHERITED_CTOR(NODE) \
+ (DECL_DECLARES_FUNCTION_P (NODE) && DECL_CONSTRUCTOR_P (NODE) \
+ ? LANG_DECL_FN_CHECK (NODE)->context : NULL_TREE)
+
+/* And this is the base that constructor comes from. */
+#define DECL_INHERITED_CTOR_BASE(NODE) \
+ (DECL_INHERITED_CTOR (NODE) \
+ ? DECL_CONTEXT (flag_new_inheriting_ctors \
+ ? strip_inheriting_ctors (NODE) \
+ : DECL_INHERITED_CTOR (NODE)) \
+ : NULL_TREE)
/* Set the inherited base. */
-#define SET_DECL_INHERITED_CTOR_BASE(NODE,INH) \
+#define SET_DECL_INHERITED_CTOR(NODE,INH) \
(LANG_DECL_FN_CHECK (NODE)->context = (INH))
/* Nonzero if NODE is a thunk, rather than an ordinary function. */
@@ -4735,6 +4744,8 @@ enum tsubst_flags {
for calls in decltype (5.2.2/11). */
tf_partial = 1 << 8, /* Doing initial explicit argument
substitution in fn_type_unification. */
+ tf_fndecl_type = 1 << 9, /* Substituting the type of a function
+ declaration. */
/* Convenient substitution flags combinations. */
tf_warning_or_error = tf_warning | tf_error
};
@@ -4940,6 +4951,10 @@ extern int at_eof;
extern bool defer_mangling_aliases;
+/* True if noexcept is part of the type (i.e. in C++17). */
+
+extern bool flag_noexcept_type;
+
/* A list of namespace-scope objects which have constructors or
destructors which reside in the global scope. The decl is stored
in the TREE_VALUE slot and the initializer is stored in the
@@ -5635,6 +5650,7 @@ extern tree get_vtable_decl (tree, int);
extern void resort_type_method_vec (void *, void *,
gt_pointer_operator, void *);
extern bool add_method (tree, tree, tree);
+extern tree declared_access (tree);
extern tree currently_open_class (tree);
extern tree currently_open_derived_class (tree);
extern tree outermost_open_class (void);
@@ -5727,7 +5743,8 @@ extern tree type_promotes_to (tree);
extern tree perform_qualification_conversions (tree, tree);
extern bool tx_safe_fn_type_p (tree);
extern tree tx_unsafe_fn_variant (tree);
-extern bool can_convert_tx_safety (tree, tree);
+extern bool fnptr_conv_p (tree, tree);
+extern tree strip_fnptr_conv (tree);
/* in name-lookup.c */
extern tree pushdecl (tree);
@@ -6035,7 +6052,9 @@ extern tree get_copy_ctor (tree, tsubst_flags_t);
extern tree get_copy_assign (tree);
extern tree get_default_ctor (tree);
extern tree get_dtor (tree, tsubst_flags_t);
-extern tree get_inherited_ctor (tree);
+extern tree strip_inheriting_ctors (tree);
+extern tree inherited_ctor_binfo (tree);
+extern bool ctor_omit_inherited_parms (tree);
extern tree locate_ctor (tree);
extern tree implicitly_declare_fn (special_function_kind, tree,
bool, tree, tree);
@@ -6565,6 +6584,7 @@ extern tree build_overload (tree, tree);
extern tree ovl_scope (tree);
extern const char *cxx_printable_name (tree, int);
extern const char *cxx_printable_name_translate (tree, int);
+extern tree canonical_eh_spec (tree);
extern tree build_exception_variant (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
@@ -6636,7 +6656,7 @@ extern tree complete_type (tree);
extern tree complete_type_or_else (tree, tree);
extern tree complete_type_or_maybe_complain (tree, tree, tsubst_flags_t);
extern int type_unknown_p (const_tree);
-enum { ce_derived, ce_normal, ce_exact };
+enum { ce_derived, ce_type, ce_normal, ce_exact };
extern bool comp_except_specs (const_tree, const_tree, int);
extern bool comptypes (tree, tree, int);
extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 2f5f15a2c82..400566f4e36 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1932,9 +1932,84 @@ tx_unsafe_fn_variant (tree t)
/* Return true iff FROM can convert to TO by a transaction-safety
conversion. */
-bool
+static bool
can_convert_tx_safety (tree to, tree from)
{
return (flag_tm && tx_safe_fn_type_p (from)
&& same_type_p (to, tx_unsafe_fn_variant (from)));
}
+
+/* Return true iff FROM can convert to TO by dropping noexcept. */
+
+static bool
+noexcept_conv_p (tree to, tree from)
+{
+ if (!flag_noexcept_type)
+ return false;
+
+ tree t = non_reference (to);
+ tree f = from;
+ if (TYPE_PTRMEMFUNC_P (t)
+ && TYPE_PTRMEMFUNC_P (f))
+ {
+ t = TYPE_PTRMEMFUNC_FN_TYPE (t);
+ f = TYPE_PTRMEMFUNC_FN_TYPE (f);
+ }
+ if (TREE_CODE (t) == POINTER_TYPE
+ && TREE_CODE (f) == POINTER_TYPE)
+ {
+ t = TREE_TYPE (t);
+ f = TREE_TYPE (f);
+ }
+ tree_code code = TREE_CODE (f);
+ if (TREE_CODE (t) != code)
+ return false;
+ if (code != FUNCTION_TYPE && code != METHOD_TYPE)
+ return false;
+ if (!type_throw_all_p (t)
+ || type_throw_all_p (f))
+ return false;
+ tree v = build_exception_variant (f, NULL_TREE);
+ return same_type_p (t, v);
+}
+
+/* Return true iff FROM can convert to TO by a function pointer conversion. */
+
+bool
+fnptr_conv_p (tree to, tree from)
+{
+ tree t = non_reference (to);
+ tree f = from;
+ if (TYPE_PTRMEMFUNC_P (t)
+ && TYPE_PTRMEMFUNC_P (f))
+ {
+ t = TYPE_PTRMEMFUNC_FN_TYPE (t);
+ f = TYPE_PTRMEMFUNC_FN_TYPE (f);
+ }
+ if (TREE_CODE (t) == POINTER_TYPE
+ && TREE_CODE (f) == POINTER_TYPE)
+ {
+ t = TREE_TYPE (t);
+ f = TREE_TYPE (f);
+ }
+
+ return (noexcept_conv_p (t, f)
+ || can_convert_tx_safety (t, f));
+}
+
+/* Return FN with any NOP_EXPRs that represent function pointer
+ conversions stripped. */
+
+tree
+strip_fnptr_conv (tree fn)
+{
+ while (TREE_CODE (fn) == NOP_EXPR)
+ {
+ tree op = TREE_OPERAND (fn, 0);
+ if (fnptr_conv_p (TREE_TYPE (fn), TREE_TYPE (op)))
+ fn = op;
+ else
+ break;
+ }
+ return fn;
+}
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ecf4d147d2a..c0321f9f959 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -73,8 +73,6 @@ static int check_static_variable_definition (tree, tree);
static void record_unknown_type (tree, const char *);
static tree builtin_function_1 (tree, tree, bool);
static int member_function_or_else (tree, tree, enum overload_flags);
-static void bad_specifiers (tree, enum bad_spec_place, int, int, int, int,
- int);
static void check_for_uninitialized_const_var (tree);
static tree local_variable_p_walkfn (tree *, int *, void *);
static const char *tag_name (enum tag_types);
@@ -227,6 +225,9 @@ struct GTY((for_user)) named_label_entry {
function, two inside the body of a function in a local class, etc.) */
int function_depth;
+/* Whether the exception-specifier is part of a function type (i.e. C++17). */
+bool flag_noexcept_type;
+
/* States indicating how grokdeclarator() should handle declspecs marked
with __attribute__((deprecated)). An object declared as
__attribute__((deprecated)) suppresses warnings of uses of other
@@ -4044,6 +4045,8 @@ cxx_init_decl_processing (void)
std_node = current_namespace;
pop_namespace ();
+ flag_noexcept_type = (cxx_dialect >= cxx1z);
+
c_common_nodes_and_builtins ();
integer_two_node = build_int_cst (NULL_TREE, 2);
@@ -7842,6 +7845,7 @@ bad_specifiers (tree object,
if (friendp)
error ("%q+D declared as a friend", object);
if (raises
+ && !flag_noexcept_type
&& (TREE_CODE (object) == TYPE_DECL
|| (!TYPE_PTRFN_P (TREE_TYPE (object))
&& !TYPE_REFFN_P (TREE_TYPE (object))
@@ -10477,6 +10481,9 @@ grokdeclarator (const cp_declarator *declarator,
The optional attribute-specifier-seq appertains to
the function type. */
decl_attributes (&type, attrs, 0);
+
+ if (raises)
+ type = build_exception_variant (type, raises);
}
break;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 917a448ad34..aa92a7e6a6b 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1617,6 +1617,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_requires_clause (pp, reqs);
dump_substitution (pp, t, template_parms, template_args, flags);
+
+ if (tree base = DECL_INHERITED_CTOR_BASE (t))
+ {
+ pp_cxx_ws_string (pp, "[inherited from");
+ dump_type (pp, base, TFF_PLAIN_IDENTIFIER);
+ pp_character (pp, ']');
+ }
}
else if (template_args)
{
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 2418a9d48c1..5eba4c3e18c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1117,7 +1117,7 @@ emit_mem_initializers (tree mem_inits)
}
if (DECL_DEFAULTED_FN (current_function_decl)
- && ! DECL_INHERITED_CTOR_BASE (current_function_decl))
+ && ! DECL_INHERITED_CTOR (current_function_decl))
flags |= LOOKUP_DEFAULTED;
/* Sort the mem-initializers into the order in which the
@@ -1138,6 +1138,13 @@ emit_mem_initializers (tree mem_inits)
if (arguments == error_mark_node)
continue;
+ /* Suppress access control when calling the inherited ctor. */
+ bool inherited_base = (DECL_INHERITED_CTOR (current_function_decl)
+ && flag_new_inheriting_ctors
+ && arguments);
+ if (inherited_base)
+ push_deferring_access_checks (dk_deferred);
+
if (arguments == NULL_TREE)
{
/* If these initializations are taking place in a copy constructor,
@@ -1172,6 +1179,9 @@ emit_mem_initializers (tree mem_inits)
/* C++14 DR1658 Means we do not have to construct vbases of
abstract classes. */
construct_virtual_base (subobject, arguments);
+
+ if (inherited_base)
+ pop_deferring_access_checks ();
}
in_base_initializer = 0;
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index d4284bfa48b..c48cd5201e0 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -1029,6 +1029,9 @@ maybe_add_lambda_conv_op (tree type)
tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop));
stattype = (cp_build_type_attribute_variant
(stattype, TYPE_ATTRIBUTES (optype)));
+ if (flag_noexcept_type
+ && TYPE_NOTHROW_P (TREE_TYPE (callop)))
+ stattype = build_exception_variant (stattype, noexcept_true_spec);
/* First build up the conversion op. */
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index cb2f260c2d1..a354ec5ead3 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -114,6 +114,9 @@ struct GTY(()) globals {
/* True if the mangling will be different in a future version of the
ABI. */
bool need_abi_warning;
+
+ /* True if the mangling will be different in C++17 mode. */
+ bool need_cxx1z_warning;
};
static GTY (()) globals G;
@@ -344,6 +347,43 @@ dump_substitution_candidates (void)
}
}
+/* <exception-spec> ::=
+ Do -- non-throwing exception specification
+ DO <expression> E -- computed (instantiation-dependent) noexcept
+ Dw <type>* E -- throw (types) */
+
+static void
+write_exception_spec (tree spec)
+{
+
+ if (!spec || spec == noexcept_false_spec)
+ /* Nothing. */
+ return;
+
+ if (!flag_noexcept_type)
+ {
+ G.need_cxx1z_warning = true;
+ return;
+ }
+
+ if (nothrow_spec_p (spec))
+ write_string ("Do");
+ else if (TREE_PURPOSE (spec))
+ {
+ gcc_assert (uses_template_parms (TREE_PURPOSE (spec)));
+ write_string ("DO");
+ write_expression (TREE_PURPOSE (spec));
+ write_char ('E');
+ }
+ else
+ {
+ write_string ("Dw");
+ for (tree t = spec; t; t = TREE_CHAIN (t))
+ write_type (TREE_VALUE (t));
+ write_char ('E');
+ }
+}
+
/* Both decls and types can be substitution candidates, but sometimes
they refer to the same thing. For instance, a TYPE_DECL and
RECORD_TYPE for the same class refer to the same thing, and should
@@ -375,7 +415,15 @@ canonicalize_for_substitution (tree node)
cp_type_quals (node));
if (TREE_CODE (node) == FUNCTION_TYPE
|| TREE_CODE (node) == METHOD_TYPE)
- node = build_ref_qualified_type (node, type_memfn_rqual (orig));
+ {
+ node = build_ref_qualified_type (node, type_memfn_rqual (orig));
+ tree r = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (orig));
+ if (flag_noexcept_type)
+ node = build_exception_variant (node, r);
+ else
+ /* Set the warning flag if appropriate. */
+ write_exception_spec (r);
+ }
}
return node;
}
@@ -777,9 +825,11 @@ write_encoding (const tree decl)
{
tree fn_type;
tree d;
+ bool tmpl = decl_is_template_id (decl, NULL);
- if (decl_is_template_id (decl, NULL))
+ if (tmpl)
{
+ ++processing_template_decl;
fn_type = get_mostly_instantiated_function_type (decl);
/* FN_TYPE will not have parameter types for in-charge or
VTT parameters. Therefore, we pass NULL_TREE to
@@ -796,6 +846,9 @@ write_encoding (const tree decl)
write_bare_function_type (fn_type,
mangle_return_type_p (decl),
d);
+
+ if (tmpl)
+ --processing_template_decl;
}
}
@@ -1786,18 +1839,25 @@ write_identifier (const char *identifier)
static void
write_special_name_constructor (const tree ctor)
{
+ write_char ('C');
+ bool new_inh = (flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (ctor));
+ if (new_inh)
+ write_char ('I');
if (DECL_BASE_CONSTRUCTOR_P (ctor))
- write_string ("C2");
+ write_char ('2');
/* This is the old-style "[unified]" constructor.
In some cases, we may emit this function and call
it from the clones in order to share code and save space. */
else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (ctor))
- write_string ("C4");
+ write_char ('4');
else
{
gcc_assert (DECL_COMPLETE_CONSTRUCTOR_P (ctor));
- write_string ("C1");
+ write_char ('1');
}
+ if (new_inh)
+ write_type (DECL_INHERITED_CTOR_BASE (ctor));
}
/* Handle destructor productions of non-terminal <special-name>.
@@ -2057,7 +2117,11 @@ write_type (tree type)
type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE)
- type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
+ {
+ type = build_ref_qualified_type (type, type_memfn_rqual (type_orig));
+ type = build_exception_variant (type,
+ TYPE_RAISES_EXCEPTIONS (type_orig));
+ }
/* According to the C++ ABI, some library classes are passed the
same as the scalar type of their single member and use the same
@@ -2582,6 +2646,8 @@ write_function_type (const tree type)
write_CV_qualifiers_for_type (this_type);
}
+ write_exception_spec (TYPE_RAISES_EXCEPTIONS (type));
+
if (tx_safe_fn_type_p (type))
write_string ("Dx");
@@ -3769,6 +3835,12 @@ mangle_decl (const tree decl)
}
SET_DECL_ASSEMBLER_NAME (decl, id);
+ if (G.need_cxx1z_warning)
+ warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc__1z_compat,
+ "mangled name for %qD will change in C++17 because the "
+ "exception specification is part of a function type",
+ decl);
+
if (id != DECL_NAME (decl)
/* Don't do this for a fake symbol we aren't going to emit anyway. */
&& TREE_CODE (decl) != TYPE_DECL
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 73a670b59c8..73d42b19d55 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -492,6 +492,118 @@ forward_parm (tree parm)
return exp;
}
+/* Strip all inheriting constructors, if any, to return the original
+ constructor from a (possibly indirect) base class. */
+
+tree
+strip_inheriting_ctors (tree fn)
+{
+ gcc_assert (flag_new_inheriting_ctors);
+ while (tree inh = DECL_INHERITED_CTOR (fn))
+ {
+ inh = OVL_CURRENT (inh);
+ fn = inh;
+ }
+ return fn;
+}
+
+/* Find the binfo for the base subobject of BINFO being initialized by
+ inherited constructor FNDECL (a member of a direct base of BINFO). */
+
+static tree inherited_ctor_binfo (tree, tree);
+static tree
+inherited_ctor_binfo_1 (tree binfo, tree fndecl)
+{
+ tree base = DECL_CONTEXT (fndecl);
+ tree base_binfo;
+ for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ if (BINFO_TYPE (base_binfo) == base)
+ return inherited_ctor_binfo (base_binfo, fndecl);
+
+ gcc_unreachable();
+}
+
+/* Find the binfo for the base subobject of BINFO being initialized by
+ inheriting constructor FNDECL (a member of BINFO), or BINFO if FNDECL is not
+ an inheriting constructor. */
+
+static tree
+inherited_ctor_binfo (tree binfo, tree fndecl)
+{
+ tree inh = DECL_INHERITED_CTOR (fndecl);
+ if (!inh)
+ return binfo;
+
+ tree results = NULL_TREE;
+ for (; inh; inh = OVL_NEXT (inh))
+ {
+ tree one = inherited_ctor_binfo_1 (binfo, OVL_CURRENT (inh));
+ if (!results)
+ results = one;
+ else if (one != results)
+ results = tree_cons (NULL_TREE, one, results);
+ }
+ return results;
+}
+
+/* Find the binfo for the base subobject being initialized by inheriting
+ constructor FNDECL, or NULL_TREE if FNDECL is not an inheriting
+ constructor. */
+
+tree
+inherited_ctor_binfo (tree fndecl)
+{
+ if (!DECL_INHERITED_CTOR (fndecl))
+ return NULL_TREE;
+ tree binfo = TYPE_BINFO (DECL_CONTEXT (fndecl));
+ return inherited_ctor_binfo (binfo, fndecl);
+}
+
+/* True if we should omit all user-declared parameters from constructor FN,
+ because it is a base clone of a ctor inherited from a virtual base. */
+
+bool
+ctor_omit_inherited_parms (tree fn)
+{
+ if (!flag_new_inheriting_ctors)
+ /* We only optimize away the parameters in the new model. */
+ return false;
+ if (!DECL_BASE_CONSTRUCTOR_P (fn)
+ || !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
+ return false;
+ tree binfo = inherited_ctor_binfo (fn);
+ for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+ if (BINFO_VIRTUAL_P (binfo))
+ return true;
+ return false;
+}
+
+/* True iff constructor(s) INH inherited into BINFO initializes INIT_BINFO.
+ This can be true for multiple virtual bases as well as one direct
+ non-virtual base. */
+
+static bool
+binfo_inherited_from (tree binfo, tree init_binfo, tree inh)
+{
+ /* inh is an OVERLOAD if we inherited the same constructor along
+ multiple paths, check all of them. */
+ for (; inh; inh = OVL_NEXT (inh))
+ {
+ tree fn = OVL_CURRENT (inh);
+ tree base = DECL_CONTEXT (fn);
+ tree base_binfo = NULL_TREE;
+ for (int i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ if (BINFO_TYPE (base_binfo) == base)
+ break;
+ if (base_binfo == init_binfo
+ || (flag_new_inheriting_ctors
+ && binfo_inherited_from (base_binfo, init_binfo,
+ DECL_INHERITED_CTOR (fn))))
+ return true;
+ }
+ return false;
+}
+
/* Subroutine of do_build_copy_constructor: Add a mem-initializer for BINFO
given the parameter or parameters PARM, possibly inherited constructor
base INH, or move flag MOVE_P. */
@@ -505,7 +617,7 @@ add_one_base_init (tree binfo, tree parm, bool move_p, tree inh,
{
/* An inheriting constructor only has a mem-initializer for
the base it inherits from. */
- if (BINFO_TYPE (binfo) != inh)
+ if (!binfo_inherited_from (TYPE_BINFO (current_class_type), binfo, inh))
return member_init_list;
tree *p = &init;
@@ -537,7 +649,7 @@ do_build_copy_constructor (tree fndecl)
tree parm = FUNCTION_FIRST_USER_PARM (fndecl);
bool move_p = DECL_MOVE_CONSTRUCTOR_P (fndecl);
bool trivial = trivial_fn_p (fndecl);
- tree inh = DECL_INHERITED_CTOR_BASE (fndecl);
+ tree inh = DECL_INHERITED_CTOR (fndecl);
if (!inh)
parm = convert_from_reference (parm);
@@ -901,7 +1013,7 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
{
if (TREE_CODE (argtype) == TREE_LIST)
{
- for (tree elt = argtype; elt != void_list_node;
+ for (tree elt = argtype; elt && elt != void_list_node;
elt = TREE_CHAIN (elt))
{
tree type = TREE_VALUE (elt);
@@ -996,25 +1108,6 @@ get_copy_assign (tree type)
return fn;
}
-/* Locate the inherited constructor of constructor CTOR. */
-
-tree
-get_inherited_ctor (tree ctor)
-{
- gcc_assert (DECL_INHERITED_CTOR_BASE (ctor));
-
- push_deferring_access_checks (dk_no_check);
- tree fn = locate_fn_flags (DECL_INHERITED_CTOR_BASE (ctor),
- complete_ctor_identifier,
- FUNCTION_FIRST_USER_PARMTYPE (ctor),
- LOOKUP_NORMAL|LOOKUP_SPECULATIVE,
- tf_none);
- pop_deferring_access_checks ();
- if (fn == error_mark_node)
- return NULL_TREE;
- return fn;
-}
-
/* walk_tree helper function for is_trivially_xible. If *TP is a call,
return it if it calls something other than a trivial special member
function. */
@@ -1330,7 +1423,7 @@ static void
synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
tree *spec_p, bool *trivial_p, bool *deleted_p,
bool *constexpr_p, bool diag,
- tree inherited_base, tree inherited_parms)
+ tree inheriting_ctor, tree inherited_parms)
{
tree binfo, base_binfo, scope, fnname, rval, argtype;
bool move_p, copy_arg_p, assign_p, expected_trivial, check_vdtor;
@@ -1389,7 +1482,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
}
gcc_assert ((sfk == sfk_inheriting_constructor)
- == (inherited_base != NULL_TREE));
+ == (inheriting_ctor != NULL_TREE));
/* If that user-written default constructor would satisfy the
requirements of a constexpr constructor (7.1.5), the
@@ -1465,7 +1558,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
scope = push_scope (ctype);
flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE;
- if (!inherited_base)
+ if (!inheriting_ctor)
flags |= LOOKUP_DEFAULTED;
complain = diag ? tf_warning_or_error : tf_none;
@@ -1485,13 +1578,25 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
/* We'll handle virtual bases below. */
continue;
+ bool inherited_binfo = false;
+
if (copy_arg_p)
argtype = build_stub_type (basetype, quals, move_p);
- else if (basetype == inherited_base)
- argtype = inherited_parms;
+ else if ((inherited_binfo
+ = binfo_inherited_from (binfo, base_binfo, inheriting_ctor)))
+ {
+ /* Don't check access on the inherited constructor. */
+ argtype = inherited_parms;
+ if (flag_new_inheriting_ctors)
+ push_deferring_access_checks (dk_deferred);
+ }
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
- if (inherited_base)
- argtype = NULL_TREE;
+ if (inherited_binfo)
+ {
+ if (flag_new_inheriting_ctors)
+ pop_deferring_access_checks ();
+ argtype = NULL_TREE;
+ }
process_subob_fn (rval, spec_p, trivial_p, deleted_p,
constexpr_p, diag, basetype);
@@ -1547,9 +1652,24 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
FOR_EACH_VEC_ELT (*vbases, i, base_binfo)
{
tree basetype = BINFO_TYPE (base_binfo);
+ bool inherited_binfo = false;
+
if (copy_arg_p)
argtype = build_stub_type (basetype, quals, move_p);
+ else if ((inherited_binfo
+ = binfo_inherited_from (binfo, base_binfo, inheriting_ctor)))
+ {
+ argtype = inherited_parms;
+ if (flag_new_inheriting_ctors)
+ push_deferring_access_checks (dk_deferred);
+ }
rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
+ if (inherited_binfo)
+ {
+ if (flag_new_inheriting_ctors)
+ pop_deferring_access_checks ();
+ argtype = NULL_TREE;
+ }
process_subob_fn (rval, spec_p, trivial_p, deleted_p,
constexpr_p, diag, basetype);
@@ -1598,7 +1718,7 @@ get_defaulted_eh_spec (tree decl)
bool const_p = CP_TYPE_CONST_P (non_reference (parm_type));
tree spec = empty_except_spec;
synthesized_method_walk (ctype, sfk, const_p, &spec, NULL, NULL,
- NULL, false, DECL_INHERITED_CTOR_BASE (decl),
+ NULL, false, DECL_INHERITED_CTOR (decl),
parms);
return spec;
}
@@ -1657,6 +1777,17 @@ maybe_explain_implicit_delete (tree decl)
decl, ctype);
informed = true;
}
+ else if (sfk == sfk_inheriting_constructor)
+ {
+ tree binfo = inherited_ctor_binfo (decl);
+ if (TREE_CODE (binfo) != TREE_BINFO)
+ {
+ inform (DECL_SOURCE_LOCATION (decl),
+ "%q#D inherits from multiple base subobjects",
+ decl);
+ informed = true;
+ }
+ }
if (!informed)
{
tree parms = FUNCTION_FIRST_USER_PARMTYPE (decl);
@@ -1668,7 +1799,7 @@ maybe_explain_implicit_delete (tree decl)
synthesized_method_walk (ctype, sfk, const_p,
&raises, NULL, &deleted_p, NULL, false,
- DECL_INHERITED_CTOR_BASE (decl), parms);
+ DECL_INHERITED_CTOR (decl), parms);
if (deleted_p)
{
inform (DECL_SOURCE_LOCATION (decl),
@@ -1676,7 +1807,7 @@ maybe_explain_implicit_delete (tree decl)
"definition would be ill-formed:", decl);
synthesized_method_walk (ctype, sfk, const_p,
NULL, NULL, NULL, NULL, true,
- DECL_INHERITED_CTOR_BASE (decl), parms);
+ DECL_INHERITED_CTOR (decl), parms);
}
else if (!comp_except_specs
(TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)),
@@ -1709,7 +1840,7 @@ explain_implicit_non_constexpr (tree decl)
synthesized_method_walk (DECL_CLASS_CONTEXT (decl),
special_function_p (decl), const_p,
NULL, NULL, NULL, &dummy, true,
- DECL_INHERITED_CTOR_BASE (decl),
+ DECL_INHERITED_CTOR (decl),
FUNCTION_FIRST_USER_PARMTYPE (decl));
}
@@ -1720,14 +1851,17 @@ explain_implicit_non_constexpr (tree decl)
void
deduce_inheriting_ctor (tree decl)
{
- gcc_assert (DECL_INHERITED_CTOR_BASE (decl));
+ gcc_assert (DECL_INHERITED_CTOR (decl));
tree spec;
bool trivial, constexpr_, deleted;
synthesized_method_walk (DECL_CONTEXT (decl), sfk_inheriting_constructor,
false, &spec, &trivial, &deleted, &constexpr_,
/*diag*/false,
- DECL_INHERITED_CTOR_BASE (decl),
+ DECL_INHERITED_CTOR (decl),
FUNCTION_FIRST_USER_PARMTYPE (decl));
+ if (TREE_CODE (inherited_ctor_binfo (decl)) != TREE_BINFO)
+ /* Inherited the same constructor from different base subobjects. */
+ deleted = true;
DECL_DELETED_FN (decl) = deleted;
TREE_TYPE (decl) = build_exception_variant (TREE_TYPE (decl), spec);
}
@@ -1828,9 +1962,6 @@ implicitly_declare_fn (special_function_kind kind, tree type,
gcc_unreachable ();
}
- tree inherited_base = (inherited_ctor
- ? DECL_CONTEXT (inherited_ctor)
- : NULL_TREE);
bool trivial_p = false;
if (inherited_ctor && TREE_CODE (inherited_ctor) == TEMPLATE_DECL)
@@ -1846,12 +1977,12 @@ implicitly_declare_fn (special_function_kind kind, tree type,
raises = unevaluated_noexcept_spec ();
synthesized_method_walk (type, kind, const_p, NULL, &trivial_p,
&deleted_p, &constexpr_p, false,
- inherited_base, inherited_parms);
+ inherited_ctor, inherited_parms);
}
else
synthesized_method_walk (type, kind, const_p, &raises, &trivial_p,
&deleted_p, &constexpr_p, false,
- inherited_base, inherited_parms);
+ inherited_ctor, inherited_parms);
/* Don't bother marking a deleted constructor as constexpr. */
if (deleted_p)
constexpr_p = false;
@@ -1902,7 +2033,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
{
tree *p = &DECL_ARGUMENTS (fn);
int index = 1;
- for (tree parm = inherited_parms; parm != void_list_node;
+ for (tree parm = inherited_parms; parm && parm != void_list_node;
parm = TREE_CHAIN (parm))
{
*p = cp_build_parm_decl (NULL_TREE, TREE_VALUE (parm));
@@ -1912,7 +2043,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
DECL_CONTEXT (*p) = fn;
p = &DECL_CHAIN (*p);
}
- SET_DECL_INHERITED_CTOR_BASE (fn, inherited_base);
+ SET_DECL_INHERITED_CTOR (fn, inherited_ctor);
DECL_NONCONVERTING_P (fn) = DECL_NONCONVERTING_P (inherited_ctor);
/* A constructor so declared has the same access as the corresponding
constructor in X. */
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 9e84a1b1f2e..e574c271194 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -1195,19 +1195,41 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
nowarn = true;
}
- if (warn_shadow && !nowarn)
+ if ((warn_shadow
+ || warn_shadow_local
+ || warn_shadow_compatible_local)
+ && !nowarn)
{
bool warned;
+ enum opt_code warning_code;
+ /* If '-Wshadow=compatible-local' is specified without other
+ -Wshadow= flags, we will warn only when the type of the
+ shadowing variable (i.e. x) can be converted to that of
+ the shadowed parameter (oldlocal). The reason why we only
+ check if x's type can be converted to oldlocal's type
+ (but not the other way around) is because when users
+ accidentally shadow a parameter, more than often they
+ would use the variable thinking (mistakenly) it's still
+ the parameter. It would be rare that users would use the
+ variable in the place that expects the parameter but
+ thinking it's a new decl. */
+ if (warn_shadow)
+ warning_code = OPT_Wshadow;
+ else if (can_convert (TREE_TYPE (oldlocal), TREE_TYPE (x),
+ tf_none))
+ warning_code = OPT_Wshadow_compatible_local;
+ else
+ warning_code = OPT_Wshadow_local;
if (TREE_CODE (oldlocal) == PARM_DECL)
- warned = warning_at (input_location, OPT_Wshadow,
+ warned = warning_at (input_location, warning_code,
"declaration of %q#D shadows a parameter", x);
else if (is_capture_proxy (oldlocal))
- warned = warning_at (input_location, OPT_Wshadow,
+ warned = warning_at (input_location, warning_code,
"declaration of %qD shadows a lambda capture",
x);
else
- warned = warning_at (input_location, OPT_Wshadow,
+ warned = warning_at (input_location, warning_code,
"declaration of %qD shadows a previous local",
x);
@@ -3399,6 +3421,12 @@ do_class_using_decl (tree scope, tree name)
return NULL_TREE;
}
}
+ else if (name == ctor_identifier
+ && BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo)))
+ {
+ error ("cannot inherit constructors from indirect base %qT", scope);
+ return NULL_TREE;
+ }
else if (!name_dependent_p)
{
decl = lookup_member (binfo, name, 0, false, tf_warning_or_error);
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index e2032c1d90e..b926ef7ad6c 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -166,7 +166,8 @@ cdtor_comdat_group (tree complete, tree base)
{
gcc_assert (!diff_seen
&& idx > 0
- && (p[idx - 1] == 'C' || p[idx - 1] == 'D')
+ && (p[idx - 1] == 'C' || p[idx - 1] == 'D'
+ || p[idx - 1] == 'I')
&& p[idx] == '1'
&& q[idx] == '2');
grp_name[idx] = '5';
@@ -259,6 +260,11 @@ maybe_thunk_body (tree fn, bool force)
(for non-vague linkage ctors) or the COMDAT group (otherwise). */
populate_clone_array (fn, fns);
+
+ /* Don't use thunks if the base clone omits inherited parameters. */
+ if (ctor_omit_inherited_parms (fns[0]))
+ return 0;
+
DECL_ABSTRACT_P (fn) = false;
if (!DECL_WEAK (fn))
{
@@ -490,7 +496,7 @@ maybe_clone_body (tree fn)
parm = DECL_CHAIN (parm);
if (DECL_HAS_VTT_PARM_P (clone))
clone_parm = DECL_CHAIN (clone_parm);
- for (; parm;
+ for (; parm && clone_parm;
parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm))
/* Update this parameter. */
update_cloned_parm (parm, clone_parm, first);
@@ -616,7 +622,8 @@ maybe_clone_body (tree fn)
else
{
decl_map->put (parm, clone_parm);
- clone_parm = DECL_CHAIN (clone_parm);
+ if (clone_parm)
+ clone_parm = DECL_CHAIN (clone_parm);
}
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 53eafa7beeb..e4436485053 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6441,7 +6441,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
can be used in constant-expressions. */
if (!cast_valid_in_integral_constant_expression_p (type)
&& cp_parser_non_integral_constant_expression (parser, NIC_CAST))
- return error_mark_node;
+ {
+ postfix_expression = error_mark_node;
+ break;
+ }
switch (keyword)
{
@@ -6521,7 +6524,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
parser->type_definition_forbidden_message = saved_message;
/* `typeid' may not appear in an integral constant expression. */
if (cp_parser_non_integral_constant_expression (parser, NIC_TYPEID))
- return error_mark_node;
+ postfix_expression = error_mark_node;
}
break;
@@ -6615,7 +6618,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
/*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL);
if (vec == NULL)
- return error_mark_node;
+ {
+ postfix_expression = error_mark_node;
+ break;
+ }
FOR_EACH_VEC_ELT (*vec, i, p)
mark_exp_read (p);
@@ -6624,10 +6630,15 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
{
case RID_ADDRESSOF:
if (vec->length () == 1)
- return cp_build_addressof (loc, (*vec)[0], tf_warning_or_error);
- error_at (loc, "wrong number of arguments to "
- "%<__builtin_addressof%>");
- return error_mark_node;
+ postfix_expression
+ = cp_build_addressof (loc, (*vec)[0], tf_warning_or_error);
+ else
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_addressof%>");
+ postfix_expression = error_mark_node;
+ }
+ break;
case RID_BUILTIN_LAUNDER:
if (vec->length () == 1)
@@ -6643,14 +6654,20 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
case RID_BUILTIN_SHUFFLE:
if (vec->length () == 2)
- return build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE,
- (*vec)[1], tf_warning_or_error);
+ postfix_expression
+ = build_x_vec_perm_expr (loc, (*vec)[0], NULL_TREE,
+ (*vec)[1], tf_warning_or_error);
else if (vec->length () == 3)
- return build_x_vec_perm_expr (loc, (*vec)[0], (*vec)[1],
- (*vec)[2], tf_warning_or_error);
- error_at (loc, "wrong number of arguments to "
- "%<__builtin_shuffle%>");
- return error_mark_node;
+ postfix_expression
+ = build_x_vec_perm_expr (loc, (*vec)[0], (*vec)[1],
+ (*vec)[2], tf_warning_or_error);
+ else
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_shuffle%>");
+ postfix_expression = error_mark_node;
+ }
+ break;
default:
gcc_unreachable ();
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c916e58482f..3df71dd97db 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2216,7 +2216,7 @@ determine_specialization (tree template_id,
continue;
// Then, try to form the new function type.
- insttype = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE);
+ insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE);
if (insttype == error_mark_node)
continue;
fn_arg_types
@@ -5876,7 +5876,7 @@ get_underlying_template (tree tmpl)
}
/* Subroutine of convert_nontype_argument. Converts EXPR to TYPE, which
- must be a function or a pointer-to-function type, as specified
+ must be a reference-to-function or a pointer-to-function type, as specified
in [temp.arg.nontype]: disambiguate EXPR if it is an overload set,
and check that the resulting function has external linkage. */
@@ -5892,7 +5892,7 @@ convert_nontype_argument_function (tree type, tree expr,
if (fn == error_mark_node)
return error_mark_node;
- fn_no_ptr = fn;
+ fn_no_ptr = strip_fnptr_conv (fn);
if (TREE_CODE (fn_no_ptr) == ADDR_EXPR)
fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
if (BASELINK_P (fn_no_ptr))
@@ -5913,11 +5913,11 @@ convert_nontype_argument_function (tree type, tree expr,
error ("%qE is not a valid template argument for type %qT",
expr, type);
if (TYPE_PTR_P (type))
- error ("it must be the address of a function with "
- "external linkage");
+ inform (input_location, "it must be the address of a function "
+ "with external linkage");
else
- error ("it must be the name of a function with "
- "external linkage");
+ inform (input_location, "it must be the name of a function with "
+ "external linkage");
}
return NULL_TREE;
}
@@ -5939,6 +5939,11 @@ convert_nontype_argument_function (tree type, tree expr,
return NULL_TREE;
}
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ fn = build_address (fn);
+ if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (fn)))
+ fn = build_nop (type, fn);
+
return fn;
}
@@ -6648,8 +6653,6 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
expr = convert_nontype_argument_function (type, expr, complain);
if (!expr || expr == error_mark_node)
return expr;
-
- expr = build_nop (type, build_address (expr));
}
/* [temp.arg.nontype]/5, bullet 6
@@ -6669,6 +6672,11 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
&& !check_valid_ptrmem_cst_expr (type, expr, complain))
return error_mark_node;
+ /* Repeated conversion can't deal with a conversion that turns PTRMEM_CST
+ into a CONSTRUCTOR, so build up a new PTRMEM_CST instead. */
+ if (fnptr_conv_p (type, TREE_TYPE (expr)))
+ expr = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr));
+
/* There is no way to disable standard conversions in
resolve_address_of_overloaded_function (called by
instantiate_type). It is possible that the call succeeded by
@@ -7325,7 +7333,8 @@ convert_template_argument (tree parm,
if (val == NULL_TREE)
val = error_mark_node;
else if (val == error_mark_node && (complain & tf_error))
- error ("could not convert template argument %qE to %qT", orig_arg, t);
+ error ("could not convert template argument %qE from %qT to %qT",
+ orig_arg, TREE_TYPE (orig_arg), t);
if (INDIRECT_REF_P (val))
{
@@ -8857,6 +8866,13 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
want walk_tree walking into them itself. */
*walk_subtrees = 0;
}
+
+ if (flag_noexcept_type)
+ {
+ tree spec = TYPE_RAISES_EXCEPTIONS (t);
+ if (spec)
+ WALK_SUBTREE (TREE_PURPOSE (spec));
+ }
break;
case TYPEOF_TYPE:
@@ -9170,6 +9186,13 @@ push_tinst_level_loc (tree d, location_t loc)
if (limit_bad_template_recursion (d))
return false;
+ /* When not -quiet, dump template instantiations other than functions, since
+ announce_function will take care of those. */
+ if (!quiet_flag
+ && TREE_CODE (d) != TREE_LIST
+ && TREE_CODE (d) != FUNCTION_DECL)
+ fprintf (stderr, " %s", decl_as_string (d, TFF_DECL_SPECIFIERS));
+
new_level = ggc_alloc<tinst_level> ();
new_level->decl = d;
new_level->locus = loc;
@@ -11921,7 +11944,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
member = 0;
ctx = DECL_CONTEXT (t);
}
- type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ type = tsubst (TREE_TYPE (t), args, complain|tf_fndecl_type, in_decl);
if (type == error_mark_node)
RETURN (error_mark_node);
@@ -12056,7 +12079,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
maybe_retrofit_in_chrg (r);
if (DECL_CONSTRUCTOR_P (r))
grok_ctor_properties (ctx, r);
- if (DECL_INHERITED_CTOR_BASE (r))
+ if (DECL_INHERITED_CTOR (r))
deduce_inheriting_ctor (r);
/* If this is an instantiation of a member template, clone it.
If it isn't, that'll be handled by
@@ -13004,6 +13027,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
}
+ bool fndecl_type = (complain & tf_fndecl_type);
+ complain &= ~tf_fndecl_type;
+
if (type
&& code != TYPENAME_TYPE
&& code != TEMPLATE_TYPE_PARM
@@ -13501,8 +13527,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return error_mark_node;
/* Substitute the exception specification. */
- specs = tsubst_exception_specification (t, args, complain,
- in_decl, /*defer_ok*/true);
+ specs = tsubst_exception_specification (t, args, complain, in_decl,
+ /*defer_ok*/fndecl_type);
if (specs == error_mark_node)
return error_mark_node;
if (specs)
@@ -15437,15 +15463,27 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
if (IF_STMT_CONSTEXPR_P (t) && integer_zerop (tmp))
/* Don't instantiate the THEN_CLAUSE. */;
else
- RECUR (THEN_CLAUSE (t));
+ {
+ bool inhibit = integer_zerop (fold_non_dependent_expr (tmp));
+ if (inhibit)
+ ++c_inhibit_evaluation_warnings;
+ RECUR (THEN_CLAUSE (t));
+ if (inhibit)
+ --c_inhibit_evaluation_warnings;
+ }
finish_then_clause (stmt);
if (IF_STMT_CONSTEXPR_P (t) && integer_nonzerop (tmp))
/* Don't instantiate the ELSE_CLAUSE. */;
else if (ELSE_CLAUSE (t))
{
+ bool inhibit = integer_nonzerop (fold_non_dependent_expr (tmp));
begin_else_clause (stmt);
+ if (inhibit)
+ ++c_inhibit_evaluation_warnings;
RECUR (ELSE_CLAUSE (t));
+ if (inhibit)
+ --c_inhibit_evaluation_warnings;
finish_else_clause (stmt);
}
@@ -15487,7 +15525,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
{
tree low = RECUR (CASE_LOW (t));
tree high = RECUR (CASE_HIGH (t));
- finish_case_label (EXPR_LOCATION (t), low, high);
+ tree l = finish_case_label (EXPR_LOCATION (t), low, high);
+ if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
+ FALLTHROUGH_LABEL_P (CASE_LABEL (l))
+ = FALLTHROUGH_LABEL_P (CASE_LABEL (t));
}
break;
@@ -15497,6 +15538,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
tree label;
label = finish_label_stmt (DECL_NAME (decl));
+ if (TREE_CODE (label) == LABEL_DECL)
+ FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
if (DECL_ATTRIBUTES (decl) != NULL_TREE)
cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
}
@@ -17658,11 +17701,16 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
DECL_TI_ARGS (fndecl) = targ_ptr;
/* Now we know the specialization, compute access previously
- deferred. */
- push_access_scope (fndecl);
- if (!perform_deferred_access_checks (complain))
- access_ok = false;
- pop_access_scope (fndecl);
+ deferred. Do no access control for inheriting constructors,
+ as we already checked access for the inherited constructor. */
+ if (!(flag_new_inheriting_ctors
+ && DECL_INHERITED_CTOR (fndecl)))
+ {
+ push_access_scope (fndecl);
+ if (!perform_deferred_access_checks (complain))
+ access_ok = false;
+ pop_access_scope (fndecl);
+ }
pop_deferring_access_checks ();
/* If we've just instantiated the main entry point for a function,
@@ -17820,6 +17868,11 @@ fn_type_unification (tree fn,
static int deduction_depth;
struct pending_template *old_last_pend = last_pending_template;
struct tinst_level *old_error_tinst = last_error_tinst_level;
+
+ tree orig_fn = fn;
+ if (flag_new_inheriting_ctors)
+ fn = strip_inheriting_ctors (fn);
+
tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
tree tinst;
tree r = error_mark_node;
@@ -17953,7 +18006,7 @@ fn_type_unification (tree fn,
access path at this point. */
push_deferring_access_checks (dk_deferred);
fntype = tsubst (TREE_TYPE (fn), explicit_targs,
- complain | tf_partial, NULL_TREE);
+ complain | tf_partial | tf_fndecl_type, NULL_TREE);
pop_deferring_access_checks ();
input_location = loc;
processing_template_decl -= incomplete;
@@ -18108,6 +18161,11 @@ fn_type_unification (tree fn,
}
}
+ /* After doing deduction with the inherited constructor, actually return an
+ instantiation of the inheriting constructor. */
+ if (orig_fn != fn)
+ decl = instantiate_template (orig_fn, targs, complain);
+
r = decl;
fail:
@@ -19315,7 +19373,7 @@ template_parm_level_and_index (tree parm, int* level, int* index)
do { \
if (unify (TP, TA, P, A, S, EP)) \
return 1; \
- } while (0);
+ } while (0)
/* Unifies the remaining arguments in PACKED_ARGS with the pack
expansion at the end of PACKED_PARMS. Returns 0 if the type
@@ -20273,6 +20331,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
class_of_this_parm (arg),
class_of_this_parm (parm))))
return unify_cv_qual_mismatch (explain_p, parm, arg);
+ if (TREE_CODE (arg) == FUNCTION_TYPE
+ && type_memfn_quals (parm) != type_memfn_quals (arg))
+ return unify_cv_qual_mismatch (explain_p, parm, arg);
+ if (type_memfn_rqual (parm) != type_memfn_rqual (arg))
+ return unify_type_mismatch (explain_p, parm, arg);
RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm),
TREE_TYPE (arg), UNIFY_ALLOW_NONE, explain_p);
@@ -20285,9 +20348,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
args[i] = TREE_VALUE (a);
nargs = i;
- return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
- args, nargs, 1, DEDUCE_EXACT,
- LOOKUP_NORMAL, NULL, explain_p);
+ if (type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
+ args, nargs, 1, DEDUCE_EXACT,
+ LOOKUP_NORMAL, NULL, explain_p))
+ return 1;
+
+ if (flag_noexcept_type)
+ {
+ tree pspec = TYPE_RAISES_EXCEPTIONS (parm);
+ tree aspec = canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (arg));
+ if (pspec == NULL_TREE) pspec = noexcept_false_spec;
+ if (aspec == NULL_TREE) aspec = noexcept_false_spec;
+ if (TREE_PURPOSE (pspec) && TREE_PURPOSE (aspec)
+ && uses_template_parms (TREE_PURPOSE (pspec)))
+ RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_PURPOSE (pspec),
+ TREE_PURPOSE (aspec),
+ UNIFY_ALLOW_NONE, explain_p);
+ else if (nothrow_spec_p (pspec) && !nothrow_spec_p (aspec))
+ return unify_type_mismatch (explain_p, parm, arg);
+ }
+
+ return 0;
}
case OFFSET_TYPE:
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index cfbc3d40680..247a98fc5e9 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -985,6 +985,14 @@ ptr_initializer (tinfo_s *ti, tree target)
flags |= 0x20;
to = tx_unsafe_fn_variant (to);
}
+ if (flag_noexcept_type
+ && (TREE_CODE (to) == FUNCTION_TYPE
+ || TREE_CODE (to) == METHOD_TYPE)
+ && TYPE_NOTHROW_P (to))
+ {
+ flags |= 0x40;
+ to = build_exception_variant (to, NULL_TREE);
+ }
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (NULL_TREE, flags));
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 03eef0030d0..7872dd29cf8 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1980,7 +1980,8 @@ static bool
cp_check_qualified_type (const_tree cand, const_tree base, int type_quals,
cp_ref_qualifier rqual, tree raises)
{
- return (check_qualified_type (cand, base, type_quals)
+ return (TYPE_QUALS (cand) == type_quals
+ && check_base_type (cand, base)
&& comp_except_specs (raises, TYPE_RAISES_EXCEPTIONS (cand),
ce_exact)
&& type_memfn_rqual (cand) == rqual);
@@ -2208,6 +2209,27 @@ cxx_printable_name_translate (tree decl, int v)
return cxx_printable_name_internal (decl, v, true);
}
+/* Return the canonical version of exception-specification RAISES for a C++17
+ function type, for use in type comparison and building TYPE_CANONICAL. */
+
+tree
+canonical_eh_spec (tree raises)
+{
+ if (raises == NULL_TREE)
+ return raises;
+ else if (DEFERRED_NOEXCEPT_SPEC_P (raises)
+ || uses_template_parms (raises)
+ || uses_template_parms (TREE_PURPOSE (raises)))
+ /* Keep a dependent or deferred exception specification. */
+ return raises;
+ else if (nothrow_spec_p (raises))
+ /* throw() -> noexcept. */
+ return noexcept_true_spec;
+ else
+ /* For C++17 type matching, anything else -> nothing. */
+ return NULL_TREE;
+}
+
/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
listed in RAISES. */
@@ -2229,6 +2251,25 @@ build_exception_variant (tree type, tree raises)
/* Need to build a new variant. */
v = build_variant_type_copy (type);
TYPE_RAISES_EXCEPTIONS (v) = raises;
+
+ if (!flag_noexcept_type)
+ /* The exception-specification is not part of the canonical type. */
+ return v;
+
+ /* Canonicalize the exception specification. */
+ tree cr = canonical_eh_spec (raises);
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (type))
+ /* Propagate structural equality. */
+ SET_TYPE_STRUCTURAL_EQUALITY (v);
+ else if (TYPE_CANONICAL (type) != type || cr != raises)
+ /* Build the underlying canonical type, since it is different
+ from TYPE. */
+ TYPE_CANONICAL (v) = build_exception_variant (TYPE_CANONICAL (type), cr);
+ else
+ /* T is its own canonical type. */
+ TYPE_CANONICAL (v) = v;
+
return v;
}
@@ -4080,9 +4121,7 @@ cp_build_type_attribute_variant (tree type, tree attributes)
}
/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
- Called only after doing all language independent checks. Only
- to check TYPE_RAISES_EXCEPTIONS for FUNCTION_TYPE, the rest is already
- compared in type_hash_eq. */
+ Called only after doing all language independent checks. */
bool
cxx_type_hash_eq (const_tree typea, const_tree typeb)
@@ -4090,6 +4129,8 @@ cxx_type_hash_eq (const_tree typea, const_tree typeb)
gcc_assert (TREE_CODE (typea) == FUNCTION_TYPE
|| TREE_CODE (typea) == METHOD_TYPE);
+ if (type_memfn_rqual (typea) != type_memfn_rqual (typeb))
+ return false;
return comp_except_specs (TYPE_RAISES_EXCEPTIONS (typea),
TYPE_RAISES_EXCEPTIONS (typeb), ce_exact);
}
@@ -4282,7 +4323,7 @@ special_function_p (const_tree decl)
/* Rather than doing all this stuff with magic names, we should
probably have a field of type `special_function_kind' in
DECL_LANG_SPECIFIC. */
- if (DECL_INHERITED_CTOR_BASE (decl))
+ if (DECL_INHERITED_CTOR (decl))
return sfk_inheriting_constructor;
if (DECL_COPY_CONSTRUCTOR_P (decl))
return sfk_copy_constructor;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 569442f38ac..211696cf029 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -647,6 +647,14 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
return objc_common_type (t1, t2);
}
+ /* if T1 or T2 is "pointer to noexcept function" and the other type is
+ "pointer to function", where the function types are otherwise the same,
+ "pointer to function" */
+ if (fnptr_conv_p (t1, t2))
+ return t1;
+ if (fnptr_conv_p (t2, t1))
+ return t2;
+
/* [expr.eq] permits the application of a pointer conversion to
bring the pointers to a common type. */
if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2)
@@ -710,22 +718,6 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
return error_mark_node;
}
}
- else if (TYPE_PTR_P (t1) && TYPE_PTR_P (t2)
- && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (t1))
- && TREE_CODE (TREE_TYPE (t2)) == TREE_CODE (TREE_TYPE (t1)))
- {
- /* ...if T1 is "pointer to transaction_safe function" and T2 is "pointer
- to function", where the function types are otherwise the same, T2, and
- vice versa.... */
- tree f1 = TREE_TYPE (t1);
- tree f2 = TREE_TYPE (t2);
- bool safe1 = tx_safe_fn_type_p (f1);
- bool safe2 = tx_safe_fn_type_p (f2);
- if (safe1 && !safe2)
- t1 = build_pointer_type (tx_unsafe_fn_variant (f1));
- else if (safe2 && !safe1)
- t2 = build_pointer_type (tx_unsafe_fn_variant (f2));
- }
return composite_pointer_type_r (t1, t2, operation, complain);
}
@@ -1020,6 +1012,7 @@ comp_except_types (tree a, tree b, bool exact)
/* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
+ If EXACT is ce_type, the C++17 type compatibility rules apply.
If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
If EXACT is ce_exact, the specs must be exactly the same. Exception lists
are unordered, but we've already filtered out duplicates. Most lists will
@@ -1038,8 +1031,13 @@ comp_except_specs (const_tree t1, const_tree t2, int exact)
/* First handle noexcept. */
if (exact < ce_exact)
{
+ if (exact == ce_type
+ && (canonical_eh_spec (CONST_CAST_TREE (t1))
+ == canonical_eh_spec (CONST_CAST_TREE (t2))))
+ return true;
+
/* noexcept(false) is compatible with no exception-specification,
- and stricter than any spec. */
+ and less strict than any spec. */
if (t1 == noexcept_false_spec)
return t2 == NULL_TREE || exact == ce_derived;
/* Even a derived noexcept(false) is compatible with no
@@ -1222,10 +1220,17 @@ structural_comptypes (tree t1, tree t2, int strict)
return false;
/* Need to check this before TYPE_MAIN_VARIANT.
FIXME function qualifiers should really change the main variant. */
- if ((TREE_CODE (t1) == FUNCTION_TYPE
- || TREE_CODE (t1) == METHOD_TYPE)
- && type_memfn_rqual (t1) != type_memfn_rqual (t2))
- return false;
+ if (TREE_CODE (t1) == FUNCTION_TYPE
+ || TREE_CODE (t1) == METHOD_TYPE)
+ {
+ if (type_memfn_rqual (t1) != type_memfn_rqual (t2))
+ return false;
+ if (flag_noexcept_type
+ && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2),
+ ce_type))
+ return false;
+ }
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
@@ -1457,7 +1462,9 @@ same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
if (type1 == error_mark_node || type2 == error_mark_node)
return false;
- return same_type_p (TYPE_MAIN_VARIANT (type1), TYPE_MAIN_VARIANT (type2));
+ type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED);
+ type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED);
+ return same_type_p (type1, type2);
}
/* Returns 1 if TYPE1 is at least as qualified as TYPE2. */
@@ -9227,13 +9234,6 @@ apply_memfn_quals (tree type, cp_cv_quals memfn_quals, cp_ref_qualifier rqual)
/* This should really have a different TYPE_MAIN_VARIANT, but that gets
complex. */
tree result = build_qualified_type (type, memfn_quals);
- if (tree canon = TYPE_CANONICAL (result))
- if (canon != result)
- /* check_qualified_type doesn't check the ref-qualifier, so make sure
- TYPE_CANONICAL is correct. */
- TYPE_CANONICAL (result)
- = build_ref_qualified_type (canon, type_memfn_rqual (result));
- result = build_exception_variant (result, TYPE_RAISES_EXCEPTIONS (type));
return build_ref_qualified_type (result, rqual);
}
diff --git a/gcc/cse.c b/gcc/cse.c
index 4b3cd2e1df4..11b8fbed06e 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -43,10 +43,6 @@ along with GCC; see the file COPYING3. If not see
#include "dbgcnt.h"
#include "rtl-iter.h"
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
/* The basic idea of common subexpression elimination is to go
through the code, keeping a record of expressions that would
have the same value at the current scan point, and replacing
diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def
index 78ddcc2be8b..0a45bac279e 100644
--- a/gcc/dbgcnt.def
+++ b/gcc/dbgcnt.def
@@ -141,6 +141,7 @@ echo ubound: $ub
*/
/* Debug counter definitions. */
+DEBUG_COUNTER (asan_use_after_scope)
DEBUG_COUNTER (auto_inc_dec)
DEBUG_COUNTER (ccp)
DEBUG_COUNTER (cfg_cleanup)
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 74d41e72e0f..9c4000252a2 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1259,6 +1259,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define WORD_REGISTER_OPERATIONS 0
#endif
+#ifndef LOAD_EXTEND_OP
+#define LOAD_EXTEND_OP(M) UNKNOWN
+#endif
+
#ifndef CONSTANT_ALIGNMENT
#define CONSTANT_ALIGNMENT(EXP, ALIGN) ALIGN
#endif
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 160bcb5177f..f06e2b8206d 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -199,6 +199,7 @@ in the following sections.
-fno-implicit-templates @gol
-fno-implicit-inline-templates @gol
-fno-implement-inlines -fms-extensions @gol
+-fnew-inheriting-ctors @gol
-fno-nonansi-builtins -fnothrow-opt -fno-operator-names @gol
-fno-optional-diags -fpermissive @gol
-fno-pretty-templates @gol
@@ -293,6 +294,7 @@ Objective-C and Objective-C++ Dialects}.
-Wpointer-arith -Wno-pointer-to-int-cast @gol
-Wno-pragmas -Wredundant-decls -Wno-return-local-addr @gol
-Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol
+-Wshadow=global, -Wshadow=local, -Wshadow=compatible-local @gol
-Wshift-overflow -Wshift-overflow=@var{n} @gol
-Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol
-Wsign-compare -Wsign-conversion -Wfloat-conversion @gol
@@ -2219,6 +2221,10 @@ Version 10, which first appeared in G++ 6.1, adds mangling of
attributes that affect type identity, such as ia32 calling convention
attributes (e.g. @samp{stdcall}).
+Version 11, which first appeared in G++ 7, corrects the mangling of
+sizeof... expressions. It also implies
+@option{-fnew-inheriting-ctors}.
+
See also @option{-Wabi}.
@item -fabi-compat-version=@var{n}
@@ -2412,6 +2418,13 @@ errors if these functions are not inlined everywhere they are called.
Disable Wpedantic warnings about constructs used in MFC, such as implicit
int and getting a pointer to member function via non-standard syntax.
+@item -fnew-inheriting-ctors
+@opindex fnew-inheriting-ctors
+Enable the P0136 adjustment to the semantics of C++11 constructor
+inheritance. This is part of C++17 but also considered to be a Defect
+Report against C++11 and C++14. This flag is enabled by default
+unless @option{-fabi-version=10} or lower is specified.
+
@item -fno-nonansi-builtins
@opindex fno-nonansi-builtins
Disable built-in declarations of functions that are not mandated by
@@ -4984,8 +4997,10 @@ This option warns on all uses of @code{alloca} in the source.
@item -Walloca-larger-than=@var{n}
This option warns on calls to @code{alloca} that are not bounded by a
-controlling predicate limiting its size to @var{n} bytes, or calls to
-@code{alloca} where the bound is unknown.
+controlling predicate limiting its argument of integer type to at most
+@var{n} bytes, or calls to @code{alloca} where the bound is unknown.
+Arguments of non-integer types are considered unbounded even if they
+appear to be constrained to the expected range.
For example, a bounded case of @code{alloca} could be:
@@ -5001,13 +5016,13 @@ void func (size_t n)
@}
@end smallexample
-In the above example, passing @code{-Walloca=1000} would not issue a
-warning because the call to @code{alloca} is known to be at most 1000
-bytes. However, if @code{-Walloca=500} was passed, the compiler would
-have emitted a warning.
+In the above example, passing @code{-Walloca-larger-than=1000} would not
+issue a warning because the call to @code{alloca} is known to be at most
+1000 bytes. However, if @code{-Walloca-larger-than=500} were passed,
+the compiler would emit a warning.
Unbounded uses, on the other hand, are uses of @code{alloca} with no
-controlling predicate verifying its size. For example:
+controlling predicate constraining its integer argument. For example:
@smallexample
void func ()
@@ -5017,8 +5032,8 @@ void func ()
@}
@end smallexample
-If @code{-Walloca=500} was passed, the above would trigger a warning,
-but this time because of the lack of bounds checking.
+If @code{-Walloca-larger-than=500} were passed, the above would trigger
+a warning, but this time because of the lack of bounds checking.
Note, that even seemingly correct code involving signed integers could
cause a warning:
@@ -5035,7 +5050,7 @@ void func (signed int n)
@end smallexample
In the above example, @var{n} could be negative, causing a larger than
-expected argument to be implicitly casted into the @code{alloca} call.
+expected argument to be implicitly cast into the @code{alloca} call.
This option also warns when @code{alloca} is used in a loop.
@@ -5321,6 +5336,7 @@ variable, parameter, type, class member (in C++), or instance variable
(in Objective-C) or whenever a built-in function is shadowed. Note
that in C++, the compiler warns if a local variable shadows an
explicit typedef, but not if it shadows a struct/class/enum.
+Same as @option{-Wshadow=global}.
@item -Wno-shadow-ivar @r{(Objective-C only)}
@opindex Wno-shadow-ivar
@@ -5328,6 +5344,48 @@ explicit typedef, but not if it shadows a struct/class/enum.
Do not warn whenever a local variable shadows an instance variable in an
Objective-C method.
+@item -Wshadow=global
+@opindex Wshadow=local
+The default for @option{-Wshadow}. Warns for any (global) shadowing.
+
+@item -Wshadow=local
+@opindex Wshadow=local
+Warn when a local variable shadows another local variable or parameter.
+This warning is enabled by @option{-Wshadow=global}.
+
+@item -Wshadow=compatible-local
+@opindex Wshadow=compatible-local
+Warn when a local variable shadows another local variable or parameter
+whose type is compatible with that of the shadowing variable. In C++,
+type compatibility here means the type of the shadowing variable can be
+converted to that of the shadowed variable. The creation of this flag
+(in addition to @option{-Wshadow=local}) is based on the idea that when
+a local variable shadows another one of incompatible type, it is most
+likely intentional, not a bug or typo, as shown in the following example:
+
+@smallexample
+@group
+for (SomeIterator i = SomeObj.begin(); i != SomeObj.end(); ++i)
+@{
+ for (int i = 0; i < N; ++i)
+ @{
+ ...
+ @}
+ ...
+@}
+@end group
+@end smallexample
+
+Since the two variable @code{i} in the example above have incompatible types,
+enabling only @option{-Wshadow=compatible-local} will not emit a warning.
+Because their types are incompatible, if a programmer accidentally uses one
+in place of the other, type checking will catch that and emit an error or
+warning. So not warning (about shadowing) in this case will not lead to
+undetected bugs. Use of this flag instead of @option{-Wshadow=local} can
+possibly reduce the number of warnings triggered by intentional shadowing.
+
+This warning is enabled by @option{-Wshadow=local}.
+
@item -Wlarger-than=@var{len}
@opindex Wlarger-than=@var{len}
@opindex Wlarger-than-@var{len}
@@ -5516,6 +5574,11 @@ enabled by @option{-Wall}.
Warn about C++ constructs whose meaning differs between ISO C++ 2011
and ISO C++ 2014. This warning is enabled by @option{-Wall}.
+@item -Wc++1z-compat @r{(C++ and Objective-C++ only)}
+@opindex Wc++1z-compat
+Warn about C++ constructs whose meaning differs between ISO C++ 2014
+and the forthoming ISO C++ 2017(?). This warning is enabled by @option{-Wall}.
+
@item -Wcast-qual
@opindex Wcast-qual
@opindex Wno-cast-qual
@@ -10232,6 +10295,10 @@ is greater or equal to this number, use callbacks instead of inline checks.
E.g. to disable inline code use
@option{--param asan-instrumentation-with-call-threshold=0}.
+@item use-after-scope-direct-emission-threshold
+If size of a local variables in bytes is smaller of equal to this number,
+direct instruction emission is utilized to poison and unpoison local variables.
+
@item chkp-max-ctor-size
Static constructors generated by Pointer Bounds Checker may become very
large and significantly increase compile time at optimization level
@@ -10442,6 +10509,7 @@ thread-safe code.
Enable AddressSanitizer, a fast memory error detector.
Memory access instructions are instrumented to detect
out-of-bounds and use-after-free bugs.
+The option enables @option{-fsanitize-address-use-after-scope}.
See @uref{https://github.com/google/sanitizers/wiki/AddressSanitizer} for
more details. The run-time behavior can be influenced using the
@env{ASAN_OPTIONS} environment variable. When set to @code{help=1},
@@ -10453,6 +10521,7 @@ The option can't be combined with @option{-fsanitize=thread}.
@item -fsanitize=kernel-address
@opindex fsanitize=kernel-address
Enable AddressSanitizer for Linux kernel.
+The option enables @option{-fsanitize-address-use-after-scope}.
See @uref{https://github.com/google/kasan/wiki} for more details.
@item -fsanitize=thread
@@ -10652,8 +10721,8 @@ except for @option{-fsanitize=unreachable} and @option{-fsanitize=return}),
@option{-fsanitize=float-cast-overflow}, @option{-fsanitize=float-divide-by-zero},
@option{-fsanitize=bounds-strict},
@option{-fsanitize=kernel-address} and @option{-fsanitize=address}.
-For these sanitizers error recovery is turned on by default, except @option{-fsanitize=address},
-for which this feature is experimental.
+For these sanitizers error recovery is turned on by default,
+except @option{-fsanitize=address}, for which this feature is experimental.
@option{-fsanitize-recover=all} and @option{-fno-sanitize-recover=all} is also
accepted, the former enables recovery for all sanitizers that support it,
the latter disables recovery for all sanitizers that support it.
@@ -10675,6 +10744,11 @@ Similarly @option{-fno-sanitize-recover} is equivalent to
-fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
@end smallexample
+@item -fsanitize-address-use-after-scope
+@opindex fsanitize-address-use-after-scope
+Enable sanitization of local variables to detect use-after-scope bugs.
+The option sets @option{-fstack-reuse} to @samp{none}.
+
@item -fsanitize-undefined-trap-on-error
@opindex fsanitize-undefined-trap-on-error
The @option{-fsanitize-undefined-trap-on-error} option instructs the compiler to
@@ -14869,6 +14943,8 @@ Permissible names are: @samp{arm2}, @samp{arm250},
@samp{cortex-a32}, @samp{cortex-a35}, @samp{cortex-a53}, @samp{cortex-a57},
@samp{cortex-a72}, @samp{cortex-a73}, @samp{cortex-r4},
@samp{cortex-r4f}, @samp{cortex-r5}, @samp{cortex-r7}, @samp{cortex-r8},
+@samp{cortex-m33},
+@samp{cortex-m23},
@samp{cortex-m7},
@samp{cortex-m4},
@samp{cortex-m3},
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 07c75e2847a..fb5dbb590c5 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1675,6 +1675,10 @@ and @code{MOVT} instructions available.
ARM target generates Thumb-1 code for @code{-mthumb} with
@code{CBZ} and @code{CBNZ} instructions available.
+@item arm_divmod_simode
+ARM target for which divmod transform is disabled, if it supports hardware
+div instruction.
+
@end table
@subsubsection AArch64-specific attributes
@@ -1848,6 +1852,13 @@ Target requires a command line argument to enable a SIMD instruction set.
@item pie_copyreloc
The x86-64 target linker supports PIE with copy reloc.
+
+@item divmod
+Target supporting hardware divmod insn or divmod libcall.
+
+@item divmod_simode
+Target supporting hardware divmod insn or divmod libcall for SImode.
+
@end table
@subsubsection Environment attributes
@@ -2479,10 +2490,6 @@ The tests are organized by directory, each directory corresponding to
a chapter of the Ada Reference Manual. So for example, @file{c9} corresponds
to chapter 9, which deals with tasking features of the language.
-There is also an extra chapter called @file{gcc} containing a template for
-creating new executable tests, although this is deprecated in favor of
-the @file{gnat.dg} testsuite.
-
The tests are run using two @command{sh} scripts: @file{run_acats} and
@file{run_all.sh}. To run the tests using a simulator or a cross
target, see the small
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 6d0cbc3c40e..10122439c30 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2903,6 +2903,10 @@ This hook defines a class of registers which could be used for spilling pseudos
This hook defines the machine mode to use for the boolean result of conditional store patterns. The ICODE argument is the instruction code for the cstore being performed. Not definiting this hook is the same as accepting the mode encoded into operand 0 of the cstore expander patterns.
@end deftypefn
+@deftypefn {Target Hook} int TARGET_COMPUTE_PRESSURE_CLASSES (enum reg_class *@var{pressure_classes})
+A target hook which lets a backend compute the set of pressure classes to be used by those optimization passes which take register pressure into account, as opposed to letting IRA compute them. It returns the number of register classes stored in the array @var{pressure_classes}.
+@end deftypefn
+
@node Stack and Calling
@section Stack Layout and Calling Conventions
@cindex calling conventions
@@ -7100,6 +7104,11 @@ This is firstly introduced on ARM/AArch64 targets, please refer to
the hook implementation for how different fusion types are supported.
@end deftypefn
+@deftypefn {Target Hook} void TARGET_EXPAND_DIVMOD_LIBFUNC (rtx @var{libfunc}, machine_mode @var{mode}, rtx @var{op0}, rtx @var{op1}, rtx *@var{quot}, rtx *@var{rem})
+Define this hook for enabling divmod transform if the port does not have
+hardware divmod insn but defines target-specific divmod libfuncs.
+@end deftypefn
+
@node Sections
@section Dividing the Output into Sections (Texts, Data, @dots{})
@c the above section title is WAY too long. maybe cut the part between
@@ -10622,6 +10631,23 @@ smaller than a word are always performed on the entire register.
Most RISC machines have this property and most CISC machines do not.
@end defmac
+@deftypefn {Target Hook} {unsigned int} TARGET_MIN_ARITHMETIC_PRECISION (void)
+On some RISC architectures with 64-bit registers, the processor also
+maintains 32-bit condition codes that make it possible to do real 32-bit
+arithmetic, although the operations are performed on the full registers.
+
+On such architectures, defining this hook to 32 tells the compiler to try
+using 32-bit arithmetical operations setting the condition codes instead
+of doing full 64-bit arithmetic.
+
+More generally, define this hook on RISC architectures if you want the
+compiler to try using arithmetical operations setting the condition codes
+with a precision lower than the word precision.
+
+You need not define this hook if @code{WORD_REGISTER_OPERATIONS} is not
+defined to 1.
+@end deftypefn
+
@defmac LOAD_EXTEND_OP (@var{mem_mode})
Define this macro to be a C expression indicating when insns that read
memory in @var{mem_mode}, an integral mode narrower than a word, set the
@@ -11532,7 +11558,7 @@ This target hook is required only when the target has several different
modes and they have different conditional execution capability, such as ARM.
@end deftypefn
-@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx *@var{prep_seq}, rtx *@var{gen_seq}, int @var{code}, tree @var{op0}, tree @var{op1})
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_FIRST (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, int @var{code}, tree @var{op0}, tree @var{op1})
This function prepares to emit a comparison insn for the first compare in a
sequence of conditional comparisions. It returns an appropriate comparison
with @code{CC} for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.
@@ -11542,7 +11568,7 @@ This function prepares to emit a comparison insn for the first compare in a
@var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}.
@end deftypefn
-@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx *@var{prep_seq}, rtx *@var{gen_seq}, rtx @var{prev}, int @var{cmp_code}, tree @var{op0}, tree @var{op1}, int @var{bit_code})
+@deftypefn {Target Hook} rtx TARGET_GEN_CCMP_NEXT (rtx_insn **@var{prep_seq}, rtx_insn **@var{gen_seq}, rtx @var{prev}, int @var{cmp_code}, tree @var{op0}, tree @var{op1}, int @var{bit_code})
This function prepares to emit a conditional comparison within a sequence
of conditional comparisons. It returns an appropriate comparison with
@code{CC} for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.
@@ -11821,3 +11847,7 @@ All and all it does not take long to convert ports that the
maintainer is familiar with.
@end defmac
+
+@deftypefn {Target Hook} void TARGET_RUN_TARGET_SELFTESTS (void)
+If selftests are enabled, run any selftests for this target.
+@end deftypefn
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index b1fd50097bc..0a7eca32639 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2509,6 +2509,8 @@ value that the middle-end intended.
@hook TARGET_CSTORE_MODE
+@hook TARGET_COMPUTE_PRESSURE_CLASSES
+
@node Stack and Calling
@section Stack Layout and Calling Conventions
@cindex calling conventions
@@ -4894,6 +4896,8 @@ them: try the first ones in this list first.
@hook TARGET_SCHED_FUSION_PRIORITY
+@hook TARGET_EXPAND_DIVMOD_LIBFUNC
+
@node Sections
@section Dividing the Output into Sections (Texts, Data, @dots{})
@c the above section title is WAY too long. maybe cut the part between
@@ -7577,6 +7581,8 @@ smaller than a word are always performed on the entire register.
Most RISC machines have this property and most CISC machines do not.
@end defmac
+@hook TARGET_MIN_ARITHMETIC_PRECISION
+
@defmac LOAD_EXTEND_OP (@var{mem_mode})
Define this macro to be a C expression indicating when insns that read
memory in @var{mem_mode}, an integral mode narrower than a word, set the
@@ -8307,3 +8313,5 @@ All and all it does not take long to convert ports that the
maintainer is familiar with.
@end defmac
+
+@hook TARGET_RUN_TARGET_SELFTESTS
diff --git a/gcc/dojump.c b/gcc/dojump.c
index 5a32c34aee6..e6ddf78898d 100644
--- a/gcc/dojump.c
+++ b/gcc/dojump.c
@@ -703,6 +703,7 @@ do_jump_by_parts_greater_rtx (machine_mode mode, int unsignedp, rtx op0,
if_false_label = drop_through_label;
drop_through_if_true = false;
drop_through_if_false = true;
+ prob = inv (prob);
}
/* Compare a word at a time, high order first. */
diff --git a/gcc/dse.c b/gcc/dse.c
index 95d5757140e..a7ae02200eb 100644
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -3298,12 +3298,19 @@ dse_step5 (void)
bitmap_clear (v);
}
else if (insn_info->read_rec
- || insn_info->non_frame_wild_read)
+ || insn_info->non_frame_wild_read
+ || insn_info->frame_read)
{
- if (dump_file && !insn_info->non_frame_wild_read)
- fprintf (dump_file, "regular read\n");
- else if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "non-frame wild read\n");
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (!insn_info->non_frame_wild_read
+ && !insn_info->frame_read)
+ fprintf (dump_file, "regular read\n");
+ if (insn_info->non_frame_wild_read)
+ fprintf (dump_file, "non-frame wild read\n");
+ if (insn_info->frame_read)
+ fprintf (dump_file, "frame read\n");
+ }
scan_reads (insn_info, v, NULL);
}
}
diff --git a/gcc/dwarf2asm.c b/gcc/dwarf2asm.c
index 47335388500..2e0aae40827 100644
--- a/gcc/dwarf2asm.c
+++ b/gcc/dwarf2asm.c
@@ -825,7 +825,7 @@ static GTY(()) hash_map<const char *, tree> *indirect_pool;
static GTY(()) int dw2_const_labelno;
#if defined(HAVE_GAS_HIDDEN)
-# define USE_LINKONCE_INDIRECT (SUPPORTS_ONE_ONLY)
+# define USE_LINKONCE_INDIRECT (SUPPORTS_ONE_ONLY && !XCOFF_DEBUGGING_INFO)
#else
# define USE_LINKONCE_INDIRECT 0
#endif
diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index da9da52353e..b6e8b4b6c61 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -1236,7 +1236,7 @@ dwarf2out_frame_debug_cfa_register (rtx set)
reg_save (sregno, dregno, 0);
}
-/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
+/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
static void
dwarf2out_frame_debug_cfa_expression (rtx set)
@@ -1268,6 +1268,29 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
update_row_reg_save (cur_row, regno, cfi);
}
+/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_VAL_EXPRESSION
+ note. */
+
+static void
+dwarf2out_frame_debug_cfa_val_expression (rtx set)
+{
+ rtx dest = SET_DEST (set);
+ gcc_assert (REG_P (dest));
+
+ rtx span = targetm.dwarf_register_span (dest);
+ gcc_assert (!span);
+
+ rtx src = SET_SRC (set);
+ dw_cfi_ref cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_val_expression;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = dwf_regno (dest);
+ cfi->dw_cfi_oprnd2.dw_cfi_loc
+ = mem_loc_descriptor (src, GET_MODE (src),
+ GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED);
+ add_cfi (cfi);
+ update_row_reg_save (cur_row, dwf_regno (dest), cfi);
+}
+
/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */
static void
@@ -2034,10 +2057,16 @@ dwarf2out_frame_debug (rtx_insn *insn)
break;
case REG_CFA_EXPRESSION:
+ case REG_CFA_VAL_EXPRESSION:
n = XEXP (note, 0);
if (n == NULL)
n = single_set (insn);
- dwarf2out_frame_debug_cfa_expression (n);
+
+ if (REG_NOTE_KIND (note) == REG_CFA_EXPRESSION)
+ dwarf2out_frame_debug_cfa_expression (n);
+ else
+ dwarf2out_frame_debug_cfa_val_expression (n);
+
handled_one = true;
break;
@@ -3016,7 +3045,8 @@ output_cfa_loc (dw_cfi_ref cfi, int for_eh)
dw_loc_descr_ref loc;
unsigned long size;
- if (cfi->dw_cfi_opc == DW_CFA_expression)
+ if (cfi->dw_cfi_opc == DW_CFA_expression
+ || cfi->dw_cfi_opc == DW_CFA_val_expression)
{
unsigned r =
DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
@@ -3042,7 +3072,8 @@ output_cfa_loc_raw (dw_cfi_ref cfi)
dw_loc_descr_ref loc;
unsigned long size;
- if (cfi->dw_cfi_opc == DW_CFA_expression)
+ if (cfi->dw_cfi_opc == DW_CFA_expression
+ || cfi->dw_cfi_opc == DW_CFA_val_expression)
{
unsigned r =
DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
@@ -3189,6 +3220,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
case DW_CFA_def_cfa_expression:
case DW_CFA_expression:
+ case DW_CFA_val_expression:
output_cfa_loc (cfi, for_eh);
break;
@@ -3303,16 +3335,13 @@ output_cfi_directive (FILE *f, dw_cfi_ref cfi)
break;
case DW_CFA_def_cfa_expression:
- if (f != asm_out_file)
- {
- fprintf (f, "\t.cfi_def_cfa_expression ...\n");
- break;
- }
- /* FALLTHRU */
case DW_CFA_expression:
+ case DW_CFA_val_expression:
if (f != asm_out_file)
{
- fprintf (f, "\t.cfi_cfa_expression ...\n");
+ fprintf (f, "\t.cfi_%scfa_%sexpression ...\n",
+ cfi->dw_cfi_opc == DW_CFA_def_cfa_expression ? "def_" : "",
+ cfi->dw_cfi_opc == DW_CFA_val_expression ? "val_" : "");
break;
}
fprintf (f, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 78a29799564..1dfff38a862 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -167,6 +167,7 @@ static GTY(()) section *debug_loc_section;
static GTY(()) section *debug_pubnames_section;
static GTY(()) section *debug_pubtypes_section;
static GTY(()) section *debug_str_section;
+static GTY(()) section *debug_line_str_section;
static GTY(()) section *debug_str_dwo_section;
static GTY(()) section *debug_str_offsets_section;
static GTY(()) section *debug_ranges_section;
@@ -225,6 +226,8 @@ struct indirect_string_hasher : ggc_ptr_hash<indirect_string_node>
static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
+static GTY (()) hash_table<indirect_string_hasher> *debug_line_str_hash;
+
/* With split_debug_info, both the comp_dir and dwo_name go in the
main object file, rather than the dwo, similar to the force_direct
parameter elsewhere but with additional complications:
@@ -232,8 +235,8 @@ static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
1) The string is needed in both the main object file and the dwo.
That is, the comp_dir and dwo_name will appear in both places.
- 2) Strings can use three forms: DW_FORM_string, DW_FORM_strp or
- DW_FORM_GNU_str_index.
+ 2) Strings can use four forms: DW_FORM_string, DW_FORM_strp,
+ DW_FORM_line_strp or DW_FORM_GNU_str_index.
3) GCC chooses the form to use late, depending on the size and
reference count.
@@ -274,6 +277,9 @@ static void dwarf2out_note_section_used (void);
personality CFI. */
static GTY(()) rtx current_unit_personality;
+/* .debug_rnglists next index. */
+static unsigned int rnglist_idx;
+
/* Data and reference forms for relocatable data. */
#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
@@ -519,6 +525,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi)
case DW_CFA_def_cfa_register:
case DW_CFA_register:
case DW_CFA_expression:
+ case DW_CFA_val_expression:
return dw_cfi_oprnd_reg_num;
case DW_CFA_def_cfa_offset:
@@ -552,6 +559,7 @@ dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
return dw_cfi_oprnd_reg_num;
case DW_CFA_expression:
+ case DW_CFA_val_expression:
return dw_cfi_oprnd_loc;
default:
@@ -1276,7 +1284,13 @@ typedef struct GTY(()) dw_loc_list_struct {
bool resolved_addr;
/* True if this list has been replaced by dw_loc_next. */
bool replaced;
- bool emitted;
+ /* True if it has been emitted into .debug_loc* / .debug_loclists*
+ section. */
+ unsigned char emitted : 1;
+ /* True if hash field is index rather than hash value. */
+ unsigned char num_assigned : 1;
+ /* True if .debug_loclists.dwo offset has been emitted for it already. */
+ unsigned char offset_emitted : 1;
/* True if the range should be emitted even if begin and end
are the same. */
bool force;
@@ -1363,9 +1377,9 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
case dw_val_class_offset:
case dw_val_class_unsigned_const:
case dw_val_class_const:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_const_implicit:
case dw_val_class_range_list:
- case dw_val_class_lineptr:
- case dw_val_class_macptr:
/* These are all HOST_WIDE_INT, signed or unsigned. */
return a->v.val_unsigned == b->v.val_unsigned;
@@ -1378,6 +1392,9 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
case dw_val_class_fde_ref:
return a->v.val_fde_index == b->v.val_fde_index;
case dw_val_class_lbl_id:
+ case dw_val_class_lineptr:
+ case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
case dw_val_class_high_pc:
return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
case dw_val_class_str:
@@ -1385,6 +1402,7 @@ dw_val_equal_p (dw_val_node *a, dw_val_node *b)
case dw_val_class_flag:
return a->v.val_flag == b->v.val_flag;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
return a->v.val_file == b->v.val_file;
case dw_val_class_decl_ref:
return a->v.val_decl_ref == b->v.val_decl_ref;
@@ -1514,6 +1532,149 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
#define DWARF_REF_SIZE \
(dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
+/* The number of bits that can be encoded by largest DW_FORM_dataN.
+ In DWARF4 and earlier it is DW_FORM_data8 with 64 bits, in DWARF5
+ DW_FORM_data16 with 128 bits. */
+#define DWARF_LARGEST_DATA_FORM_BITS \
+ (dwarf_version >= 5 ? 128 : 64)
+
+/* Utility inline function for construction of ops that were GNU extension
+ before DWARF 5. */
+static inline enum dwarf_location_atom
+dwarf_OP (enum dwarf_location_atom op)
+{
+ switch (op)
+ {
+ case DW_OP_implicit_pointer:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_implicit_pointer;
+ break;
+
+ case DW_OP_entry_value:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_entry_value;
+ break;
+
+ case DW_OP_const_type:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_const_type;
+ break;
+
+ case DW_OP_regval_type:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_regval_type;
+ break;
+
+ case DW_OP_deref_type:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_deref_type;
+ break;
+
+ case DW_OP_convert:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_convert;
+ break;
+
+ case DW_OP_reinterpret:
+ if (dwarf_version < 5)
+ return DW_OP_GNU_reinterpret;
+ break;
+
+ default:
+ break;
+ }
+ return op;
+}
+
+/* Similarly for attributes. */
+static inline enum dwarf_attribute
+dwarf_AT (enum dwarf_attribute at)
+{
+ switch (at)
+ {
+ case DW_AT_call_return_pc:
+ if (dwarf_version < 5)
+ return DW_AT_low_pc;
+ break;
+
+ case DW_AT_call_tail_call:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_tail_call;
+ break;
+
+ case DW_AT_call_origin:
+ if (dwarf_version < 5)
+ return DW_AT_abstract_origin;
+ break;
+
+ case DW_AT_call_target:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_call_site_target;
+ break;
+
+ case DW_AT_call_target_clobbered:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_call_site_target_clobbered;
+ break;
+
+ case DW_AT_call_parameter:
+ if (dwarf_version < 5)
+ return DW_AT_abstract_origin;
+ break;
+
+ case DW_AT_call_value:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_call_site_value;
+ break;
+
+ case DW_AT_call_data_value:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_call_site_data_value;
+ break;
+
+ case DW_AT_call_all_calls:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_all_call_sites;
+ break;
+
+ case DW_AT_call_all_tail_calls:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_all_tail_call_sites;
+ break;
+
+ case DW_AT_dwo_name:
+ if (dwarf_version < 5)
+ return DW_AT_GNU_dwo_name;
+ break;
+
+ default:
+ break;
+ }
+ return at;
+}
+
+/* And similarly for tags. */
+static inline enum dwarf_tag
+dwarf_TAG (enum dwarf_tag tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_call_site:
+ if (dwarf_version < 5)
+ return DW_TAG_GNU_call_site;
+ break;
+
+ case DW_TAG_call_site_parameter:
+ if (dwarf_version < 5)
+ return DW_TAG_GNU_call_site_parameter;
+ break;
+
+ default:
+ break;
+ }
+ return tag;
+}
+
static unsigned long int get_base_type_offset (dw_die_ref);
/* Return the size of a location descriptor. */
@@ -1633,15 +1794,18 @@ size_of_loc_descr (dw_loc_descr_ref loc)
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned)
+ loc->dw_loc_oprnd1.v.val_unsigned;
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
{
unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
size += size_of_uleb128 (op_size) + op_size;
break;
}
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
{
unsigned long o
@@ -1668,6 +1832,7 @@ size_of_loc_descr (dw_loc_descr_ref loc)
}
break;
}
+ case DW_OP_regval_type:
case DW_OP_GNU_regval_type:
{
unsigned long o
@@ -1676,6 +1841,7 @@ size_of_loc_descr (dw_loc_descr_ref loc)
+ size_of_uleb128 (o);
}
break;
+ case DW_OP_deref_type:
case DW_OP_GNU_deref_type:
{
unsigned long o
@@ -1683,6 +1849,8 @@ size_of_loc_descr (dw_loc_descr_ref loc)
size += 1 + size_of_uleb128 (o);
}
break;
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
@@ -2043,6 +2211,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
}
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
{
char label[MAX_ARTIFICIAL_LABEL_BYTES
@@ -2054,11 +2223,13 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
}
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
output_loc_sequence (val1->v.val_loc, for_eh_or_skip);
break;
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
{
unsigned long o = get_base_type_offset (val1->v.val_die_ref.die), l;
@@ -2132,6 +2303,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
}
}
break;
+ case DW_OP_regval_type:
case DW_OP_GNU_regval_type:
{
unsigned r = val1->v.val_unsigned;
@@ -2147,6 +2319,7 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
dw2_asm_output_data_uleb128 (o, NULL);
}
break;
+ case DW_OP_deref_type:
case DW_OP_GNU_deref_type:
{
unsigned long o = get_base_type_offset (val2->v.val_die_ref.die);
@@ -2155,6 +2328,8 @@ output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
dw2_asm_output_data_uleb128 (o, NULL);
}
break;
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
@@ -2353,6 +2528,13 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
}
break;
+ case DW_OP_implicit_pointer:
+ case DW_OP_entry_value:
+ case DW_OP_const_type:
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_implicit_pointer:
case DW_OP_GNU_entry_value:
case DW_OP_GNU_const_type:
@@ -2589,7 +2771,8 @@ const struct gcc_debug_hooks dwarf2_lineno_debug_hooks =
-fno-debug-types-section. It is more efficient to put them in a
separate comdat sections since the linker will then be able to
remove duplicates. But not all tools support .debug_types sections
- yet. */
+ yet. For Dwarf V5 or higher .debug_types doesn't exist any more,
+ it is DW_UT_type unit type in .debug_info section. */
#define use_debug_types (dwarf_version >= 4 && flag_debug_types_section)
@@ -2729,9 +2912,15 @@ pubname_entry;
struct GTY(()) dw_ranges {
+ const char *label;
/* If this is positive, it's a block number, otherwise it's a
bitwise-negated index into dw_ranges_by_label. */
int num;
+ /* Index for the range list for DW_FORM_rnglistx. */
+ unsigned int idx : 31;
+ /* True if this range might be possibly in a different section
+ from previous entry. */
+ unsigned int maybe_new_sec : 1;
};
/* A structure to hold a macinfo entry. */
@@ -2805,12 +2994,15 @@ skeleton_chain_node;
/* Fixed size portion of the DWARF compilation unit header. */
#define DWARF_COMPILE_UNIT_HEADER_SIZE \
- (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE + 3)
+ (DWARF_INITIAL_LENGTH_SIZE + DWARF_OFFSET_SIZE \
+ + (dwarf_version >= 5 \
+ ? 4 + DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE : 3))
/* Fixed size portion of the DWARF comdat type unit header. */
#define DWARF_COMDAT_TYPE_UNIT_HEADER_SIZE \
- (DWARF_COMPILE_UNIT_HEADER_SIZE + DWARF_TYPE_SIGNATURE_SIZE \
- + DWARF_OFFSET_SIZE)
+ (DWARF_COMPILE_UNIT_HEADER_SIZE \
+ + (dwarf_version >= 5 \
+ ? 0 : DWARF_TYPE_SIGNATURE_SIZE + DWARF_OFFSET_SIZE))
/* Fixed size portion of public names info. */
#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
@@ -3006,17 +3198,9 @@ struct dw_loc_list_hasher : ggc_ptr_hash<cached_dw_loc_list>
/* Table of cached location lists. */
static GTY (()) hash_table<dw_loc_list_hasher> *cached_dw_loc_list_table;
-/* A pointer to the base of a list of references to DIE's that
- are uniquely identified by their tag, presence/absence of
- children DIE's, and list of attribute/value pairs. */
-static GTY((length ("abbrev_die_table_allocated")))
- dw_die_ref *abbrev_die_table;
-
-/* Number of elements currently allocated for abbrev_die_table. */
-static GTY(()) unsigned abbrev_die_table_allocated;
-
-/* Number of elements in abbrev_die_table currently in use. */
-static GTY(()) unsigned abbrev_die_table_in_use;
+/* A vector of references to DIE's that are uniquely identified by their tag,
+ presence/absence of children DIE's, and list of attribute/value pairs. */
+static GTY(()) vec<dw_die_ref, va_gc> *abbrev_die_table;
/* A hash map to remember the stack usage for DWARF procedures. The value
stored is the stack size difference between before the DWARF procedure
@@ -3024,10 +3208,6 @@ static GTY(()) unsigned abbrev_die_table_in_use;
that consumes N stack slots and that pushes M ones, this stores M - N. */
static hash_map<dw_die_ref, int> *dwarf_proc_stack_usage_map;
-/* Size (in elements) of increments by which we may expand the
- abbrev_die_table. */
-#define ABBREV_DIE_TABLE_INCREMENT 256
-
/* A global counter for generating labels for line number data. */
static unsigned int line_info_label_num;
@@ -3160,6 +3340,8 @@ static inline rtx AT_addr (dw_attr_node *);
static void add_AT_lbl_id (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_lineptr (dw_die_ref, enum dwarf_attribute, const char *);
static void add_AT_macptr (dw_die_ref, enum dwarf_attribute, const char *);
+static void add_AT_loclistsptr (dw_die_ref, enum dwarf_attribute,
+ const char *);
static void add_AT_offset (dw_die_ref, enum dwarf_attribute,
unsigned HOST_WIDE_INT);
static void add_AT_range_list (dw_die_ref, enum dwarf_attribute,
@@ -3248,8 +3430,8 @@ static void output_abbrev_section (void);
static void output_die_abbrevs (unsigned long, dw_die_ref);
static void output_die_symbol (dw_die_ref);
static void output_die (dw_die_ref);
-static void output_compilation_unit_header (void);
-static void output_comp_unit (dw_die_ref, int);
+static void output_compilation_unit_header (enum dwarf_unit_type);
+static void output_comp_unit (dw_die_ref, int, const unsigned char *);
static void output_comdat_type_unit (comdat_type_node *);
static const char *dwarf2_name (tree, int);
static void add_pubname (tree, dw_die_ref);
@@ -3258,8 +3440,7 @@ static void add_pubname_string (const char *, dw_die_ref);
static void add_pubtype (tree, dw_die_ref);
static void output_pubnames (vec<pubname_entry, va_gc> *);
static void output_aranges (void);
-static unsigned int add_ranges_num (int);
-static unsigned int add_ranges (const_tree);
+static unsigned int add_ranges (const_tree, bool = false);
static void add_ranges_by_labels (dw_die_ref, const char *, const char *,
bool *, bool);
static void output_ranges (void);
@@ -3293,9 +3474,9 @@ struct loc_descr_context;
static void add_loc_descr_to_each (dw_loc_list_ref list, dw_loc_descr_ref ref);
static void add_loc_list (dw_loc_list_ref *ret, dw_loc_list_ref list);
static dw_loc_list_ref loc_list_from_tree (tree, int,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static tree field_type (const_tree);
static unsigned int simple_type_align_in_bits (const_tree);
@@ -3320,9 +3501,9 @@ static void add_name_attribute (dw_die_ref, const char *);
static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
static void add_comp_dir_attribute (dw_die_ref);
static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree,
- const struct loc_descr_context *);
+ struct loc_descr_context *);
static void add_subscript_info (dw_die_ref, tree, bool);
static void add_byte_size_attribute (dw_die_ref, tree);
static inline void add_bit_offset_attribute (dw_die_ref, tree,
@@ -3332,7 +3513,7 @@ static void add_prototyped_attribute (dw_die_ref, tree);
static dw_die_ref add_abstract_origin_attribute (dw_die_ref, tree);
static void add_pure_or_virtual_attribute (dw_die_ref, tree);
static void add_src_coords_attributes (dw_die_ref, tree);
-static void add_name_and_src_coords_attributes (dw_die_ref, tree);
+static void add_name_and_src_coords_attributes (dw_die_ref, tree, bool = false);
static void add_discr_value (dw_die_ref, dw_discr_value *);
static void add_discr_list (dw_die_ref, dw_discr_list_ref);
static inline dw_discr_list_ref AT_discr_list (dw_attr_node *);
@@ -3460,8 +3641,8 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
ref->dtprel = dtprel;
if (dwarf_split_debug_info)
ref->dw_loc_oprnd1.val_entry
- = add_addr_table_entry (addr,
- dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx);
+ = add_addr_table_entry (addr,
+ dtprel ? ate_kind_rtx_dtprel : ate_kind_rtx);
else
ref->dw_loc_oprnd1.val_entry = NULL;
@@ -3512,6 +3693,12 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_DWO_LOC_SECTION
#define DEBUG_DWO_LOC_SECTION ".debug_loc.dwo"
#endif
+#ifndef DEBUG_LOCLISTS_SECTION
+#define DEBUG_LOCLISTS_SECTION ".debug_loclists"
+#endif
+#ifndef DEBUG_DWO_LOCLISTS_SECTION
+#define DEBUG_DWO_LOCLISTS_SECTION ".debug_loclists.dwo"
+#endif
#ifndef DEBUG_PUBNAMES_SECTION
#define DEBUG_PUBNAMES_SECTION \
((debug_generate_pub_sections == 2) \
@@ -3537,6 +3724,12 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
+#ifndef DEBUG_RNGLISTS_SECTION
+#define DEBUG_RNGLISTS_SECTION ".debug_rnglists"
+#endif
+#ifndef DEBUG_LINE_STR_SECTION
+#define DEBUG_LINE_STR_SECTION ".debug_line_str"
+#endif
/* Standard ELF section names for compiled code and data. */
#ifndef TEXT_SECTION_NAME
@@ -3617,6 +3810,7 @@ static char debug_skeleton_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
+static char ranges_base_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
#ifndef TEXT_END_LABEL
#define TEXT_END_LABEL "Letext"
@@ -3905,7 +4099,8 @@ add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_va
static inline HOST_WIDE_INT
AT_int (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_const);
+ gcc_assert (a && (AT_class (a) == dw_val_class_const
+ || AT_class (a) == dw_val_class_const_implicit));
return a->dw_attr_val.v.val_int;
}
@@ -3927,7 +4122,8 @@ add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
static inline unsigned HOST_WIDE_INT
AT_unsigned (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
+ gcc_assert (a && (AT_class (a) == dw_val_class_unsigned_const
+ || AT_class (a) == dw_val_class_unsigned_const_implicit));
return a->dw_attr_val.v.val_unsigned;
}
@@ -4013,7 +4209,7 @@ add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
attr.dw_attr_val.v.val_lbl_id = lbl_id;
if (dwarf_split_debug_info && !force_direct)
attr.dw_attr_val.val_entry
- = add_addr_table_entry (lbl_id, ate_kind_label);
+ = add_addr_table_entry (lbl_id, ate_kind_label);
else
attr.dw_attr_val.val_entry = NULL;
add_dwarf_attr (die, &attr);
@@ -4028,7 +4224,7 @@ add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
if (attr.dw_attr_val.val_class == dw_val_class_lbl_id
&& dwarf_split_debug_info && !force_direct)
attr.dw_attr_val.val_entry
- = add_addr_table_entry (lbl_id, ate_kind_label);
+ = add_addr_table_entry (lbl_id, ate_kind_label);
else
attr.dw_attr_val.val_entry = NULL;
add_dwarf_attr (die, &attr);
@@ -4114,7 +4310,9 @@ set_indirect_string (struct indirect_string_node *node)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
/* Already indirect is a no op. */
- if (node->form == DW_FORM_strp || node->form == DW_FORM_GNU_str_index)
+ if (node->form == DW_FORM_strp
+ || node->form == DW_FORM_line_strp
+ || node->form == DW_FORM_GNU_str_index)
{
gcc_assert (node->label);
return;
@@ -4158,7 +4356,7 @@ find_string_form (struct indirect_string_node *node)
single module. */
if (DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
|| ((debug_str_section->common.flags & SECTION_MERGE) == 0
- && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
+ && (len - DWARF_OFFSET_SIZE) * node->refcount <= len))
return node->form = DW_FORM_string;
set_indirect_string (node);
@@ -4506,7 +4704,8 @@ add_AT_file (dw_die_ref die, enum dwarf_attribute attr_kind,
static inline struct dwarf_file_data *
AT_file (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_file);
+ gcc_assert (a && (AT_class (a) == dw_val_class_file
+ || AT_class (a) == dw_val_class_file_implicit));
return a->dw_attr_val.v.val_file;
}
@@ -4562,6 +4761,22 @@ add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
}
/* Add a section offset attribute value to a DIE, an offset into the
+ debug_loclists section. */
+
+static inline void
+add_AT_loclistsptr (dw_die_ref die, enum dwarf_attribute attr_kind,
+ const char *label)
+{
+ dw_attr_node attr;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loclistsptr;
+ attr.dw_attr_val.val_entry = NULL;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
+}
+
+/* Add a section offset attribute value to a DIE, an offset into the
debug_macinfo section. */
static inline void
@@ -4643,6 +4858,7 @@ AT_lbl (dw_attr_node *a)
gcc_assert (a && (AT_class (a) == dw_val_class_lbl_id
|| AT_class (a) == dw_val_class_lineptr
|| AT_class (a) == dw_val_class_macptr
+ || AT_class (a) == dw_val_class_loclistsptr
|| AT_class (a) == dw_val_class_high_pc));
return a->dw_attr_val.v.val_lbl_id;
}
@@ -5020,6 +5236,7 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
/* These are allowed because they're generated while
breaking out COMDAT units late. */
&& tag_value != DW_TAG_type_unit
+ && tag_value != DW_TAG_skeleton_unit
&& !early_dwarf
/* Allow nested functions to live in limbo because they will
only temporarily live there, as decls_for_scope will fix
@@ -5581,9 +5798,11 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
fprintf (outfile, "range list");
break;
case dw_val_class_const:
+ case dw_val_class_const_implicit:
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, val->v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, val->v.val_unsigned);
break;
case dw_val_class_const_double:
@@ -5640,6 +5859,7 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
case dw_val_class_high_pc:
fprintf (outfile, "label: %s", val->v.val_lbl_id);
break;
@@ -5650,6 +5870,7 @@ print_dw_val (dw_val_node *val, bool recurse, FILE *outfile)
fprintf (outfile, "<null>");
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
fprintf (outfile, "\"%s\" (%d)", val->v.val_file->filename,
val->v.val_file->emitted_number);
break;
@@ -5912,6 +6133,7 @@ check_die (dw_die_ref die)
&& a->dw_attr != DW_AT_high_pc
&& a->dw_attr != DW_AT_location
&& a->dw_attr != DW_AT_frame_base
+ && a->dw_attr != DW_AT_call_all_calls
&& a->dw_attr != DW_AT_GNU_all_call_sites);
}
}
@@ -5979,9 +6201,11 @@ attr_checksum (dw_attr_node *at, struct md5_ctx *ctx, int *mark)
switch (AT_class (at))
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
CHECKSUM (at->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
CHECKSUM (at->dw_attr_val.v.val_unsigned);
break;
case dw_val_class_const_double:
@@ -6028,10 +6252,12 @@ attr_checksum (dw_attr_node *at, struct md5_ctx *ctx, int *mark)
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
case dw_val_class_high_pc:
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
CHECKSUM_STRING (AT_file (at)->filename);
break;
@@ -6256,11 +6482,13 @@ attr_checksum_ordered (enum dwarf_tag tag, dw_attr_node *at,
switch (AT_class (at))
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
CHECKSUM_ULEB128 (DW_FORM_sdata);
CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
CHECKSUM_ULEB128 (DW_FORM_sdata);
CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
break;
@@ -6320,10 +6548,12 @@ attr_checksum_ordered (enum dwarf_tag tag, dw_attr_node *at,
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
case dw_val_class_high_pc:
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
CHECKSUM_ULEB128 (DW_FORM_string);
CHECKSUM_STRING (AT_file (at)->filename);
break;
@@ -6766,8 +6996,10 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
switch (v1->val_class)
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
return v1->v.val_int == v2->v.val_int;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
return v1->v.val_unsigned == v2->v.val_unsigned;
case dw_val_class_const_double:
return v1->v.val_double.high == v2->v.val_double.high
@@ -6813,10 +7045,12 @@ same_dw_val_p (const dw_val_node *v1, const dw_val_node *v2, int *mark)
case dw_val_class_lbl_id:
case dw_val_class_lineptr:
case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
case dw_val_class_high_pc:
return 1;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
return v1->v.val_file == v2->v.val_file;
case dw_val_class_data8:
@@ -7031,7 +7265,8 @@ is_symbol_die (dw_die_ref c)
static inline bool
is_cu_die (dw_die_ref c)
{
- return c && c->die_tag == DW_TAG_compile_unit;
+ return c && (c->die_tag == DW_TAG_compile_unit
+ || c->die_tag == DW_TAG_skeleton_unit);
}
/* Returns true iff C is a unit DIE of some sort. */
@@ -7041,7 +7276,8 @@ is_unit_die (dw_die_ref c)
{
return c && (c->die_tag == DW_TAG_compile_unit
|| c->die_tag == DW_TAG_partial_unit
- || c->die_tag == DW_TAG_type_unit);
+ || c->die_tag == DW_TAG_type_unit
+ || c->die_tag == DW_TAG_skeleton_unit);
}
/* Returns true iff C is a namespace DIE. */
@@ -7326,7 +7562,8 @@ contains_subprogram_definition (dw_die_ref die)
}
/* Return non-zero if this is a type DIE that should be moved to a
- COMDAT .debug_types section. */
+ COMDAT .debug_types section or .debug_info section with DW_UT_*type
+ unit type. */
static int
should_move_die_to_comdat (dw_die_ref die)
@@ -7843,8 +8080,9 @@ copy_dwarf_procs_ref_in_dies (dw_die_ref die,
copied_dwarf_procs));
}
-/* Traverse the DIE and set up additional .debug_types sections for each
- type worthy of being placed in a COMDAT section. */
+/* Traverse the DIE and set up additional .debug_types or .debug_info
+ DW_UT_*type sections for each type worthy of being placed in a COMDAT
+ section. */
static void
break_out_comdat_types (dw_die_ref die)
@@ -8093,6 +8331,59 @@ output_location_lists (dw_die_ref die)
FOR_EACH_CHILD (die, c, output_location_lists (c));
}
+/* During assign_location_list_indexes and output_loclists_offset the
+ current index, after it the number of assigned indexes (i.e. how
+ large the .debug_loclists* offset table should be). */
+static unsigned int loc_list_idx;
+
+/* Output all location list offsets for the DIE and its children. */
+
+static void
+output_loclists_offsets (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_node *a;
+ unsigned ix;
+
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (AT_class (a) == dw_val_class_loc_list)
+ {
+ dw_loc_list_ref l = AT_loc_list (a);
+ if (l->offset_emitted)
+ continue;
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, l->ll_symbol,
+ loc_section_label, NULL);
+ gcc_assert (l->hash == loc_list_idx);
+ loc_list_idx++;
+ l->offset_emitted = true;
+ }
+
+ FOR_EACH_CHILD (die, c, output_loclists_offsets (c));
+}
+
+/* Recursively set indexes of location lists. */
+
+static void
+assign_location_list_indexes (dw_die_ref die)
+{
+ dw_die_ref c;
+ dw_attr_node *a;
+ unsigned ix;
+
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (AT_class (a) == dw_val_class_loc_list)
+ {
+ dw_loc_list_ref list = AT_loc_list (a);
+ if (!list->num_assigned)
+ {
+ list->num_assigned = true;
+ list->hash = loc_list_idx++;
+ }
+ }
+
+ FOR_EACH_CHILD (die, c, assign_location_list_indexes (c));
+}
+
/* We want to limit the number of external references, because they are
larger than local references: a relocation takes multiple words, and
even a sig8 reference is always eight bytes, whereas a local reference
@@ -8252,6 +8543,20 @@ optimize_external_refs (dw_die_ref die)
return map;
}
+/* The following 3 variables are temporaries that are computed only during the
+ build_abbrev_table call and used and released during the following
+ optimize_abbrev_table call. */
+
+/* First abbrev_id that can be optimized based on usage. */
+static unsigned int abbrev_opt_start;
+
+/* Vector of usage counts during build_abbrev_table. Indexed by
+ abbrev_id - abbrev_opt_start. */
+static vec<unsigned int> abbrev_usage_count;
+
+/* Vector of all DIEs added with die_abbrev >= abbrev_opt_start. */
+static vec<dw_die_ref> sorted_abbrev_dies;
+
/* The format of each DIE (and its attribute value pairs) is encoded in an
abbreviation table. This routine builds the abbreviation table and assigns
a unique abbreviation id for each abbreviation entry. The children of each
@@ -8260,11 +8565,11 @@ optimize_external_refs (dw_die_ref die)
static void
build_abbrev_table (dw_die_ref die, external_ref_hash_type *extern_map)
{
- unsigned long abbrev_id;
- unsigned int n_alloc;
+ unsigned int abbrev_id = 0;
dw_die_ref c;
dw_attr_node *a;
unsigned ix;
+ dw_die_ref abbrev;
/* Scan the DIE references, and replace any that refer to
DIEs from other CUs (i.e. those which are not marked) with
@@ -8284,13 +8589,14 @@ build_abbrev_table (dw_die_ref die, external_ref_hash_type *extern_map)
set_AT_ref_external (a, 1);
}
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ FOR_EACH_VEC_SAFE_ELT (abbrev_die_table, abbrev_id, abbrev)
{
- dw_die_ref abbrev = abbrev_die_table[abbrev_id];
dw_attr_node *die_a, *abbrev_a;
unsigned ix;
bool ok = true;
+ if (abbrev_id == 0)
+ continue;
if (abbrev->die_tag != die->die_tag)
continue;
if ((abbrev->die_child != NULL) != (die->die_child != NULL))
@@ -8313,25 +8619,179 @@ build_abbrev_table (dw_die_ref die, external_ref_hash_type *extern_map)
break;
}
- if (abbrev_id >= abbrev_die_table_in_use)
+ if (abbrev_id >= vec_safe_length (abbrev_die_table))
+ {
+ vec_safe_push (abbrev_die_table, die);
+ if (abbrev_opt_start)
+ abbrev_usage_count.safe_push (0);
+ }
+ if (abbrev_opt_start && abbrev_id >= abbrev_opt_start)
+ {
+ abbrev_usage_count[abbrev_id - abbrev_opt_start]++;
+ sorted_abbrev_dies.safe_push (die);
+ }
+
+ die->die_abbrev = abbrev_id;
+ FOR_EACH_CHILD (die, c, build_abbrev_table (c, extern_map));
+}
+
+/* Callback function for sorted_abbrev_dies vector sorting. We sort
+ by die_abbrev's usage count, from the most commonly used
+ abbreviation to the least. */
+
+static int
+die_abbrev_cmp (const void *p1, const void *p2)
+{
+ dw_die_ref die1 = *(const dw_die_ref *) p1;
+ dw_die_ref die2 = *(const dw_die_ref *) p2;
+
+ gcc_checking_assert (die1->die_abbrev >= abbrev_opt_start);
+ gcc_checking_assert (die2->die_abbrev >= abbrev_opt_start);
+
+ if (abbrev_usage_count[die1->die_abbrev - abbrev_opt_start]
+ > abbrev_usage_count[die2->die_abbrev - abbrev_opt_start])
+ return -1;
+ if (abbrev_usage_count[die1->die_abbrev - abbrev_opt_start]
+ < abbrev_usage_count[die2->die_abbrev - abbrev_opt_start])
+ return 1;
+
+ /* Stabilize the sort. */
+ if (die1->die_abbrev < die2->die_abbrev)
+ return -1;
+ if (die1->die_abbrev > die2->die_abbrev)
+ return 1;
+
+ return 0;
+}
+
+/* Convert dw_val_class_const and dw_val_class_unsigned_const class attributes
+ of DIEs in between sorted_abbrev_dies[first_id] and abbrev_dies[end_id - 1]
+ into dw_val_class_const_implicit or
+ dw_val_class_unsigned_const_implicit. */
+
+static void
+optimize_implicit_const (unsigned int first_id, unsigned int end,
+ vec<bool> &implicit_consts)
+{
+ /* It never makes sense if there is just one DIE using the abbreviation. */
+ if (end < first_id + 2)
+ return;
+
+ dw_attr_node *a;
+ unsigned ix, i;
+ dw_die_ref die = sorted_abbrev_dies[first_id];
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (implicit_consts[ix])
+ {
+ enum dw_val_class new_class = dw_val_class_none;
+ switch (AT_class (a))
+ {
+ case dw_val_class_unsigned_const:
+ if ((HOST_WIDE_INT) AT_unsigned (a) < 0)
+ continue;
+
+ /* The .debug_abbrev section will grow by
+ size_of_sleb128 (AT_unsigned (a)) and we avoid the constants
+ in all the DIEs using that abbreviation. */
+ if (constant_size (AT_unsigned (a)) * (end - first_id)
+ <= (unsigned) size_of_sleb128 (AT_unsigned (a)))
+ continue;
+
+ new_class = dw_val_class_unsigned_const_implicit;
+ break;
+
+ case dw_val_class_const:
+ new_class = dw_val_class_const_implicit;
+ break;
+
+ case dw_val_class_file:
+ new_class = dw_val_class_file_implicit;
+ break;
+
+ default:
+ continue;
+ }
+ for (i = first_id; i < end; i++)
+ (*sorted_abbrev_dies[i]->die_attr)[ix].dw_attr_val.val_class
+ = new_class;
+ }
+}
+
+/* Attempt to optimize abbreviation table from abbrev_opt_start
+ abbreviation above. */
+
+static void
+optimize_abbrev_table (void)
+{
+ if (abbrev_opt_start
+ && vec_safe_length (abbrev_die_table) > abbrev_opt_start
+ && (dwarf_version >= 5 || vec_safe_length (abbrev_die_table) > 127))
{
- if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+ auto_vec<bool, 32> implicit_consts;
+ sorted_abbrev_dies.qsort (die_abbrev_cmp);
+
+ unsigned int abbrev_id = abbrev_opt_start - 1;
+ unsigned int first_id = 0;
+ unsigned int last_abbrev_id = 0;
+ unsigned int i;
+ dw_die_ref die;
+ /* Reassign abbreviation ids from abbrev_opt_start above, so that
+ most commonly used abbreviations come first. */
+ FOR_EACH_VEC_ELT (sorted_abbrev_dies, i, die)
{
- n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
- abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
- n_alloc);
+ dw_attr_node *a;
+ unsigned ix;
- memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
- (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
- abbrev_die_table_allocated = n_alloc;
- }
+ if (die->die_abbrev != last_abbrev_id)
+ {
+ last_abbrev_id = die->die_abbrev;
+ if (dwarf_version >= 5 && i)
+ optimize_implicit_const (first_id, i, implicit_consts);
+ abbrev_id++;
+ (*abbrev_die_table)[abbrev_id] = die;
+ if (dwarf_version >= 5)
+ {
+ first_id = i;
+ implicit_consts.truncate (0);
- ++abbrev_die_table_in_use;
- abbrev_die_table[abbrev_id] = die;
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ switch (AT_class (a))
+ {
+ case dw_val_class_const:
+ case dw_val_class_unsigned_const:
+ case dw_val_class_file:
+ implicit_consts.safe_push (true);
+ break;
+ default:
+ implicit_consts.safe_push (false);
+ break;
+ }
+ }
+ }
+ else if (dwarf_version >= 5)
+ {
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (!implicit_consts[ix])
+ continue;
+ else
+ {
+ dw_attr_node *other_a
+ = &(*(*abbrev_die_table)[abbrev_id]->die_attr)[ix];
+ if (!dw_val_equal_p (&a->dw_attr_val,
+ &other_a->dw_attr_val))
+ implicit_consts[ix] = false;
+ }
+ }
+ die->die_abbrev = abbrev_id;
+ }
+ gcc_assert (abbrev_id == vec_safe_length (abbrev_die_table) - 1);
+ if (dwarf_version >= 5)
+ optimize_implicit_const (first_id, i, implicit_consts);
}
- die->die_abbrev = abbrev_id;
- FOR_EACH_CHILD (die, c, build_abbrev_table (c, extern_map));
+ abbrev_opt_start = 0;
+ abbrev_usage_count.release ();
+ sorted_abbrev_dies.release ();
}
/* Return the power-of-two number of bytes necessary to represent VALUE. */
@@ -8393,16 +8853,23 @@ size_of_die (dw_die_ref die)
}
break;
case dw_val_class_loc_list:
- if (dwarf_split_debug_info && AT_index (a) != NOT_INDEXED)
- {
- gcc_assert (AT_index (a) != NO_INDEX_ASSIGNED);
- size += size_of_uleb128 (AT_index (a));
- }
+ if (dwarf_split_debug_info && dwarf_version >= 5)
+ {
+ gcc_assert (AT_loc_list (a)->num_assigned);
+ size += size_of_uleb128 (AT_loc_list (a)->hash);
+ }
else
size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_range_list:
- size += DWARF_OFFSET_SIZE;
+ if (value_format (a) == DW_FORM_rnglistx)
+ {
+ gcc_assert (rnglist_idx);
+ dw_ranges *r = &(*ranges_table)[a->dw_attr_val.v.val_offset];
+ size += size_of_uleb128 (r->idx);
+ }
+ else
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_const:
size += size_of_sleb128 (AT_int (a));
@@ -8418,16 +8885,22 @@ size_of_die (dw_die_ref die)
size += csize;
}
break;
+ case dw_val_class_const_implicit:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_file_implicit:
+ /* These occupy no size in the DIE, just an extra sleb128 in
+ .debug_abbrev. */
+ break;
case dw_val_class_const_double:
size += HOST_BITS_PER_DOUBLE_INT / HOST_BITS_PER_CHAR;
- if (HOST_BITS_PER_WIDE_INT >= 64)
+ if (HOST_BITS_PER_WIDE_INT >= DWARF_LARGEST_DATA_FORM_BITS)
size++; /* block */
break;
case dw_val_class_wide_int:
size += (get_full_len (*a->dw_attr_val.v.val_wide)
* HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR);
- if (get_full_len (*a->dw_attr_val.v.val_wide) * HOST_BITS_PER_WIDE_INT
- > 64)
+ if (get_full_len (*a->dw_attr_val.v.val_wide)
+ * HOST_BITS_PER_WIDE_INT > DWARF_LARGEST_DATA_FORM_BITS)
size++; /* block */
break;
case dw_val_class_vec:
@@ -8479,14 +8952,15 @@ size_of_die (dw_die_ref die)
break;
case dw_val_class_lineptr:
case dw_val_class_macptr:
- size += DWARF_OFFSET_SIZE;
+ case dw_val_class_loclistsptr:
+ size += DWARF_OFFSET_SIZE;
break;
case dw_val_class_str:
form = AT_string_form (a);
- if (form == DW_FORM_strp)
+ if (form == DW_FORM_strp || form == DW_FORM_line_strp)
size += DWARF_OFFSET_SIZE;
- else if (form == DW_FORM_GNU_str_index)
- size += size_of_uleb128 (AT_index (a));
+ else if (form == DW_FORM_GNU_str_index)
+ size += size_of_uleb128 (AT_index (a));
else
size += strlen (a->dw_attr_val.v.val_str->str) + 1;
break;
@@ -8744,8 +9218,25 @@ value_format (dw_attr_node *a)
default:
gcc_unreachable ();
}
- case dw_val_class_range_list:
case dw_val_class_loc_list:
+ if (dwarf_split_debug_info
+ && dwarf_version >= 5
+ && AT_loc_list (a)->num_assigned)
+ return DW_FORM_loclistx;
+ /* FALLTHRU */
+ case dw_val_class_range_list:
+ /* For range lists in DWARF 5, use DW_FORM_rnglistx from .debug_info.dwo
+ but in .debug_info use DW_FORM_sec_offset, which is shorter if we
+ care about sizes of .debug* sections in shared libraries and
+ executables and don't take into account relocations that affect just
+ relocatable objects - for DW_FORM_rnglistx we'd have to emit offset
+ table in the .debug_rnglists section. */
+ if (dwarf_split_debug_info
+ && dwarf_version >= 5
+ && AT_class (a) == dw_val_class_range_list
+ && rnglist_idx
+ && a->dw_attr_val.val_entry != RELOCATED_OFFSET)
+ return DW_FORM_rnglistx;
if (dwarf_version >= 4)
return DW_FORM_sec_offset;
/* FALLTHRU */
@@ -8798,6 +9289,10 @@ value_format (dw_attr_node *a)
default:
gcc_unreachable ();
}
+ case dw_val_class_const_implicit:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_file_implicit:
+ return DW_FORM_implicit_const;
case dw_val_class_const_double:
switch (HOST_BITS_PER_WIDE_INT)
{
@@ -8808,6 +9303,9 @@ value_format (dw_attr_node *a)
case 32:
return DW_FORM_data8;
case 64:
+ if (dwarf_version >= 5)
+ return DW_FORM_data16;
+ /* FALLTHRU */
default:
return DW_FORM_block1;
}
@@ -8822,6 +9320,10 @@ value_format (dw_attr_node *a)
return DW_FORM_data4;
case 64:
return DW_FORM_data8;
+ case 128:
+ if (dwarf_version >= 5)
+ return DW_FORM_data16;
+ /* FALLTHRU */
default:
return DW_FORM_block1;
}
@@ -8863,6 +9365,7 @@ value_format (dw_attr_node *a)
? DW_FORM_addr : DW_FORM_GNU_addr_index);
case dw_val_class_lineptr:
case dw_val_class_macptr:
+ case dw_val_class_loclistsptr:
return dwarf_version >= 4 ? DW_FORM_sec_offset : DW_FORM_data;
case dw_val_class_str:
return AT_string_form (a);
@@ -8951,6 +9454,17 @@ output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
dwarf_attr_name (a_attr->dw_attr));
output_value_format (a_attr);
+ if (value_format (a_attr) == DW_FORM_implicit_const)
+ {
+ if (AT_class (a_attr) == dw_val_class_file_implicit)
+ {
+ int f = maybe_emit_file (a_attr->dw_attr_val.v.val_file);
+ const char *filename = a_attr->dw_attr_val.v.val_file->filename;
+ dw2_asm_output_data_sleb128 (f, "(%s)", filename);
+ }
+ else
+ dw2_asm_output_data_sleb128 (a_attr->dw_attr_val.v.val_int, NULL);
+ }
}
dw2_asm_output_data (1, 0, NULL);
@@ -8964,10 +9478,12 @@ output_die_abbrevs (unsigned long abbrev_id, dw_die_ref abbrev)
static void
output_abbrev_section (void)
{
- unsigned long abbrev_id;
+ unsigned int abbrev_id;
+ dw_die_ref abbrev;
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
- output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
+ FOR_EACH_VEC_SAFE_ELT (abbrev_die_table, abbrev_id, abbrev)
+ if (abbrev_id != 0)
+ output_die_abbrevs (abbrev_id, abbrev);
/* Terminate the table. */
dw2_asm_output_data (1, 0, NULL);
@@ -9027,14 +9543,18 @@ gen_llsym (dw_loc_list_ref list)
static void
output_loc_list (dw_loc_list_ref list_head)
{
- dw_loc_list_ref curr = list_head;
-
if (list_head->emitted)
return;
list_head->emitted = true;
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+ dw_loc_list_ref curr = list_head;
+#ifdef HAVE_AS_LEB128
+ const char *last_section = NULL;
+ const char *base_label = NULL;
+#endif
+
/* Walk the location list, and output each range + expression. */
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
@@ -9049,23 +9569,142 @@ output_loc_list (dw_loc_list_ref list_head)
in a single range are unlikely very useful. */
if (size > 0xffff)
continue;
- if (dwarf_split_debug_info)
- {
- dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
- "Location list start/length entry (%s)",
- list_head->ll_symbol);
- dw2_asm_output_data_uleb128 (curr->begin_entry->index,
- "Location list range start index (%s)",
- curr->begin);
- /* The length field is 4 bytes. If we ever need to support
- an 8-byte length, we can add a new DW_LLE code or fall back
- to DW_LLE_GNU_start_end_entry. */
- dw2_asm_output_delta (4, curr->end, curr->begin,
- "Location list range length (%s)",
- list_head->ll_symbol);
- }
+ if (dwarf_version >= 5)
+ {
+ if (dwarf_split_debug_info)
+ {
+ /* For -gsplit-dwarf, emit DW_LLE_starx_length, which has
+ uleb128 index into .debug_addr and uleb128 length. */
+ dw2_asm_output_data (1, DW_LLE_startx_length,
+ "DW_LLE_startx_length (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data_uleb128 (curr->begin_entry->index,
+ "Location list range start index "
+ "(%s)", curr->begin);
+ /* FIXME: This will ICE ifndef HAVE_AS_LEB128.
+ For that case we probably need to emit DW_LLE_startx_endx,
+ but we'd need 2 .debug_addr entries rather than just one. */
+ dw2_asm_output_delta_uleb128 (curr->end, curr->begin,
+ "Location list length (%s)",
+ list_head->ll_symbol);
+ }
+#ifdef HAVE_AS_LEB128
+ else if (!have_multiple_function_sections)
+ {
+ /* If all code is in .text section, the base address is
+ already provided by the CU attributes. Use
+ DW_LLE_offset_pair where both addresses are uleb128 encoded
+ offsets against that base. */
+ dw2_asm_output_data (1, DW_LLE_offset_pair,
+ "DW_LLE_offset_pair (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta_uleb128 (curr->begin, curr->section,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta_uleb128 (curr->end, curr->section,
+ "Location list end address (%s)",
+ list_head->ll_symbol);
+ }
+ else
+ {
+ /* Otherwise, find out how many consecutive entries could share
+ the same base entry. If just one, emit DW_LLE_start_length,
+ otherwise emit DW_LLE_base_address for the base address
+ followed by a series of DW_LLE_offset_pair. */
+ if (last_section == NULL || curr->section != last_section)
+ {
+ dw_loc_list_ref curr2;
+ for (curr2 = curr->dw_loc_next; curr2 != NULL;
+ curr2 = curr2->dw_loc_next)
+ {
+ if (strcmp (curr2->begin, curr2->end) == 0
+ && !curr2->force)
+ continue;
+ if ((unsigned long) size_of_locs (curr2->expr) > 0xffff)
+ continue;
+ break;
+ }
+ if (curr2 == NULL || curr->section != curr2->section)
+ last_section = NULL;
+ else
+ {
+ last_section = curr->section;
+ base_label = curr->begin;
+ dw2_asm_output_data (1, DW_LLE_base_address,
+ "DW_LLE_base_address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, base_label,
+ "Base address (%s)",
+ list_head->ll_symbol);
+ }
+ }
+ /* Only one entry with the same base address. Use
+ DW_LLE_start_length with absolute address and uleb128
+ length. */
+ if (last_section == NULL)
+ {
+ dw2_asm_output_data (1, DW_LLE_start_length,
+ "DW_LLE_start_length (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta_uleb128 (curr->end, curr->begin,
+ "Location list length "
+ "(%s)", list_head->ll_symbol);
+ }
+ /* Otherwise emit DW_LLE_offset_pair, relative to above emitted
+ DW_LLE_base_address. */
+ else
+ {
+ dw2_asm_output_data (1, DW_LLE_offset_pair,
+ "DW_LLE_offset_pair (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_delta_uleb128 (curr->begin, base_label,
+ "Location list begin address "
+ "(%s)", list_head->ll_symbol);
+ dw2_asm_output_delta_uleb128 (curr->end, base_label,
+ "Location list end address "
+ "(%s)", list_head->ll_symbol);
+ }
+ }
+#else
+ /* The assembler does not support .uleb128 directive. Emit
+ DW_LLE_start_end with a pair of absolute addresses. */
+ else
+ {
+ dw2_asm_output_data (1, DW_LLE_start_end,
+ "DW_LLE_start_end (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
+ "Location list begin address (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
+ "Location list end address (%s)",
+ list_head->ll_symbol);
+ }
+#endif
+ }
+ else if (dwarf_split_debug_info)
+ {
+ /* For -gsplit-dwarf -gdwarf-{2,3,4} emit index into .debug_addr
+ and 4 byte length. */
+ dw2_asm_output_data (1, DW_LLE_GNU_start_length_entry,
+ "Location list start/length entry (%s)",
+ list_head->ll_symbol);
+ dw2_asm_output_data_uleb128 (curr->begin_entry->index,
+ "Location list range start index (%s)",
+ curr->begin);
+ /* The length field is 4 bytes. If we ever need to support
+ an 8-byte length, we can add a new DW_LLE code or fall back
+ to DW_LLE_GNU_start_end_entry. */
+ dw2_asm_output_delta (4, curr->end, curr->begin,
+ "Location list range length (%s)",
+ list_head->ll_symbol);
+ }
else if (!have_multiple_function_sections)
{
+ /* Pair of relative addresses against start of text section. */
dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
"Location list begin address (%s)",
list_head->ll_symbol);
@@ -9075,6 +9714,7 @@ output_loc_list (dw_loc_list_ref list_head)
}
else
{
+ /* Pair of absolute addresses. */
dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
"Location list begin address (%s)",
list_head->ll_symbol);
@@ -9090,24 +9730,28 @@ output_loc_list (dw_loc_list_ref list_head)
output_loc_sequence (curr->expr, -1);
}
- if (dwarf_split_debug_info)
+ /* And finally list termination. */
+ if (dwarf_version >= 5)
+ dw2_asm_output_data (1, DW_LLE_end_of_list,
+ "DW_LLE_end_of_list (%s)", list_head->ll_symbol);
+ else if (dwarf_split_debug_info)
dw2_asm_output_data (1, DW_LLE_GNU_end_of_list_entry,
- "Location list terminator (%s)",
- list_head->ll_symbol);
+ "Location list terminator (%s)",
+ list_head->ll_symbol);
else
{
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator begin (%s)",
- list_head->ll_symbol);
+ "Location list terminator begin (%s)",
+ list_head->ll_symbol);
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
- "Location list terminator end (%s)",
- list_head->ll_symbol);
+ "Location list terminator end (%s)",
+ list_head->ll_symbol);
}
}
-/* Output a range_list offset into the debug_range section. Emit a
- relocated reference if val_entry is NULL, otherwise, emit an
- indirect reference. */
+/* Output a range_list offset into the .debug_ranges or .debug_rnglists
+ section. Emit a relocated reference if val_entry is NULL, otherwise,
+ emit an indirect reference. */
static void
output_range_list_offset (dw_attr_node *a)
@@ -9116,14 +9760,31 @@ output_range_list_offset (dw_attr_node *a)
if (a->dw_attr_val.val_entry == RELOCATED_OFFSET)
{
- char *p = strchr (ranges_section_label, '\0');
- sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX, a->dw_attr_val.v.val_offset);
- dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
- debug_ranges_section, "%s", name);
- *p = '\0';
+ if (dwarf_version >= 5)
+ {
+ dw_ranges *r = &(*ranges_table)[a->dw_attr_val.v.val_offset];
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, r->label,
+ debug_ranges_section, "%s", name);
+ }
+ else
+ {
+ char *p = strchr (ranges_section_label, '\0');
+ sprintf (p, "+" HOST_WIDE_INT_PRINT_HEX,
+ a->dw_attr_val.v.val_offset * 2 * DWARF2_ADDR_SIZE);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, ranges_section_label,
+ debug_ranges_section, "%s", name);
+ *p = '\0';
+ }
+ }
+ else if (dwarf_version >= 5)
+ {
+ dw_ranges *r = &(*ranges_table)[a->dw_attr_val.v.val_offset];
+ gcc_assert (rnglist_idx);
+ dw2_asm_output_data_uleb128 (r->idx, "%s", name);
}
else
- dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
+ dw2_asm_output_data (DWARF_OFFSET_SIZE,
+ a->dw_attr_val.v.val_offset * 2 * DWARF2_ADDR_SIZE,
"%s (offset from %s)", name, ranges_section_label);
}
@@ -9135,12 +9796,19 @@ output_loc_list_offset (dw_attr_node *a)
char *sym = AT_loc_list (a)->ll_symbol;
gcc_assert (sym);
- if (dwarf_split_debug_info)
- dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
- "%s", dwarf_attr_name (a->dw_attr));
- else
+ if (!dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
"%s", dwarf_attr_name (a->dw_attr));
+ else if (dwarf_version >= 5)
+ {
+ gcc_assert (AT_loc_list (a)->num_assigned);
+ dw2_asm_output_data_uleb128 (AT_loc_list (a)->hash, "%s (%s)",
+ dwarf_attr_name (a->dw_attr),
+ sym);
+ }
+ else
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
+ "%s", dwarf_attr_name (a->dw_attr));
}
/* Output an attribute's index or value appropriately. */
@@ -9157,18 +9825,15 @@ output_attr_index_or_value (dw_attr_node *a)
}
switch (AT_class (a))
{
- case dw_val_class_addr:
- dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
- break;
- case dw_val_class_high_pc:
- case dw_val_class_lbl_id:
- dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
- break;
- case dw_val_class_loc_list:
- output_loc_list_offset (a);
- break;
- default:
- gcc_unreachable ();
+ case dw_val_class_addr:
+ dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
+ break;
+ case dw_val_class_high_pc:
+ case dw_val_class_lbl_id:
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
+ break;
+ default:
+ gcc_unreachable ();
}
}
@@ -9264,11 +9929,25 @@ output_die (dw_die_ref die)
}
break;
+ case dw_val_class_const_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s ("
+ HOST_WIDE_INT_PRINT_DEC ")\n",
+ ASM_COMMENT_START, name, AT_int (a));
+ break;
+
+ case dw_val_class_unsigned_const_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s ("
+ HOST_WIDE_INT_PRINT_HEX ")\n",
+ ASM_COMMENT_START, name, AT_unsigned (a));
+ break;
+
case dw_val_class_const_double:
{
unsigned HOST_WIDE_INT first, second;
- if (HOST_BITS_PER_WIDE_INT >= 64)
+ if (HOST_BITS_PER_WIDE_INT >= DWARF_LARGEST_DATA_FORM_BITS)
dw2_asm_output_data (1,
HOST_BITS_PER_DOUBLE_INT
/ HOST_BITS_PER_CHAR,
@@ -9297,9 +9976,9 @@ output_die (dw_die_ref die)
int i;
int len = get_full_len (*a->dw_attr_val.v.val_wide);
int l = HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR;
- if (len * HOST_BITS_PER_WIDE_INT > 64)
- dw2_asm_output_data (1, get_full_len (*a->dw_attr_val.v.val_wide) * l,
- NULL);
+ if (len * HOST_BITS_PER_WIDE_INT > DWARF_LARGEST_DATA_FORM_BITS)
+ dw2_asm_output_data (1, get_full_len (*a->dw_attr_val.v.val_wide)
+ * l, NULL);
if (WORDS_BIG_ENDIAN)
for (i = len - 1; i >= 0; --i)
@@ -9359,7 +10038,7 @@ output_die (dw_die_ref die)
break;
case dw_val_class_loc_list:
- output_attr_index_or_value (a);
+ output_loc_list_offset (a);
break;
case dw_val_class_die_ref:
@@ -9367,8 +10046,8 @@ output_die (dw_die_ref die)
{
if (AT_ref (a)->comdat_type_p)
{
- comdat_type_node *type_node =
- AT_ref (a)->die_id.die_type_node;
+ comdat_type_node *type_node
+ = AT_ref (a)->die_id.die_type_node;
gcc_assert (type_node);
output_signature (type_node->signature, name);
@@ -9422,7 +10101,7 @@ output_die (dw_die_ref die)
break;
case dw_val_class_lbl_id:
- output_attr_index_or_value (a);
+ output_attr_index_or_value (a);
break;
case dw_val_class_lineptr:
@@ -9435,12 +10114,22 @@ output_die (dw_die_ref die)
debug_macinfo_section, "%s", name);
break;
+ case dw_val_class_loclistsptr:
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a),
+ debug_loc_section, "%s", name);
+ break;
+
case dw_val_class_str:
if (a->dw_attr_val.v.val_str->form == DW_FORM_strp)
dw2_asm_output_offset (DWARF_OFFSET_SIZE,
a->dw_attr_val.v.val_str->label,
debug_str_section,
"%s: \"%s\"", name, AT_string (a));
+ else if (a->dw_attr_val.v.val_str->form == DW_FORM_line_strp)
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+ a->dw_attr_val.v.val_str->label,
+ debug_line_str_section,
+ "%s: \"%s\"", name, AT_string (a));
else if (a->dw_attr_val.v.val_str->form == DW_FORM_GNU_str_index)
dw2_asm_output_data_uleb128 (AT_index (a),
"%s: \"%s\"", name, AT_string (a));
@@ -9457,6 +10146,14 @@ output_die (dw_die_ref die)
break;
}
+ case dw_val_class_file_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s (%d, %s)\n",
+ ASM_COMMENT_START, name,
+ maybe_emit_file (a->dw_attr_val.v.val_file),
+ a->dw_attr_val.v.val_file->filename);
+ break;
+
case dw_val_class_data8:
{
int i;
@@ -9520,12 +10217,8 @@ output_die (dw_die_ref die)
.debug_info section, and precedes the DIE descriptions. */
static void
-output_compilation_unit_header (void)
+output_compilation_unit_header (enum dwarf_unit_type ut)
{
- /* We don't support actual DWARFv5 units yet, we just use some
- DWARFv5 draft DIE tags in DWARFv4 format. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
-
if (!XCOFF_DEBUGGING_INFO)
{
if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
@@ -9536,17 +10229,33 @@ output_compilation_unit_header (void)
"Length of Compilation Unit Info");
}
- dw2_asm_output_data (2, ver, "DWARF version number");
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ if (dwarf_version >= 5)
+ {
+ const char *name;
+ switch (ut)
+ {
+ case DW_UT_compile: name = "DW_UT_compile"; break;
+ case DW_UT_type: name = "DW_UT_type"; break;
+ case DW_UT_split_compile: name = "DW_UT_split_compile"; break;
+ case DW_UT_split_type: name = "DW_UT_split_type"; break;
+ default: gcc_unreachable ();
+ }
+ dw2_asm_output_data (1, ut, name);
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ }
dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
debug_abbrev_section,
"Offset Into Abbrev. Section");
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ if (dwarf_version < 5)
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
}
/* Output the compilation unit DIE and its children. */
static void
-output_comp_unit (dw_die_ref die, int output_if_empty)
+output_comp_unit (dw_die_ref die, int output_if_empty,
+ const unsigned char *dwo_id)
{
const char *secname, *oldsym;
char *tmp;
@@ -9564,8 +10273,16 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
external_ref_hash_type *extern_map = optimize_external_refs (die);
+ /* For now, optimize only the main CU, in order to optimize the rest
+ we'd need to see all of them earlier. Leave the rest for post-linking
+ tools like DWZ. */
+ if (die == comp_unit_die ())
+ abbrev_opt_start = vec_safe_length (abbrev_die_table);
+
build_abbrev_table (die, extern_map);
+ optimize_abbrev_table ();
+
delete extern_map;
/* Initialize the beginning DIE offset - and calculate sizes/offsets. */
@@ -9590,7 +10307,20 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
}
/* Output debugging information. */
- output_compilation_unit_header ();
+ output_compilation_unit_header (dwo_id
+ ? DW_UT_split_compile : DW_UT_compile);
+ if (dwarf_version >= 5)
+ {
+ if (dwo_id != NULL)
+ for (int i = 0; i < 8; i++)
+ dw2_asm_output_data (1, dwo_id[i], i == 0 ? "DWO id" : NULL);
+ else
+ /* Hope all the padding will be removed for DWARF 5 final for
+ DW_AT_compile and DW_AT_partial. */
+ dw2_asm_output_data (8, 0, "Padding 1");
+
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Padding 2");
+ }
output_die (die);
/* Leave the marks on the main CU, so we can check them in
@@ -9659,7 +10389,7 @@ add_top_level_skeleton_die_attrs (dw_die_ref die)
const char *dwo_file_name = concat (aux_base_name, ".dwo", NULL);
const char *comp_dir = comp_dir_string ();
- add_skeleton_AT_string (die, DW_AT_GNU_dwo_name, dwo_file_name);
+ add_skeleton_AT_string (die, dwarf_AT (DW_AT_dwo_name), dwo_file_name);
if (comp_dir != NULL)
add_skeleton_AT_string (die, DW_AT_comp_dir, comp_dir);
add_AT_pubnames (die);
@@ -9669,12 +10399,9 @@ add_top_level_skeleton_die_attrs (dw_die_ref die)
/* Output skeleton debug sections that point to the dwo file. */
static void
-output_skeleton_debug_sections (dw_die_ref comp_unit)
+output_skeleton_debug_sections (dw_die_ref comp_unit,
+ const unsigned char *dwo_id)
{
- /* We don't support actual DWARFv5 units yet, we just use some
- DWARFv5 draft DIE tags in DWARFv4 format. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
-
/* These attributes will be found in the full debug_info section. */
remove_AT (comp_unit, DW_AT_producer);
remove_AT (comp_unit, DW_AT_language);
@@ -9694,11 +10421,24 @@ output_skeleton_debug_sections (dw_die_ref comp_unit)
- DWARF_INITIAL_LENGTH_SIZE
+ size_of_die (comp_unit),
"Length of Compilation Unit Info");
- dw2_asm_output_data (2, ver, "DWARF version number");
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ if (dwarf_version >= 5)
+ {
+ dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ }
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_abbrev_section_label,
- debug_abbrev_section,
+ debug_skeleton_abbrev_section,
"Offset Into Abbrev. Section");
- dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ if (dwarf_version < 5)
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ dw2_asm_output_data (1, dwo_id[i], i == 0 ? "DWO id" : NULL);
+
+ dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "Padding 2");
+ }
comp_unit->die_abbrev = SKELETON_COMP_DIE_ABBREV;
output_die (comp_unit);
@@ -9739,13 +10479,20 @@ output_comdat_type_unit (comdat_type_node *node)
calc_die_sizes (node->root_die);
#if defined (OBJECT_FORMAT_ELF)
- if (!dwarf_split_debug_info)
+ if (dwarf_version >= 5)
+ {
+ if (!dwarf_split_debug_info)
+ secname = ".debug_info";
+ else
+ secname = ".debug_info.dwo";
+ }
+ else if (!dwarf_split_debug_info)
secname = ".debug_types";
else
secname = ".debug_types.dwo";
tmp = XALLOCAVEC (char, 4 + DWARF_TYPE_SIGNATURE_SIZE * 2);
- sprintf (tmp, "wt.");
+ sprintf (tmp, dwarf_version >= 5 ? "wi." : "wt.");
for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
sprintf (tmp + 3 + i * 2, "%02x", node->signature[i] & 0xff);
comdat_key = get_identifier (tmp);
@@ -9754,7 +10501,8 @@ output_comdat_type_unit (comdat_type_node *node)
comdat_key);
#else
tmp = XALLOCAVEC (char, 18 + DWARF_TYPE_SIGNATURE_SIZE * 2);
- sprintf (tmp, ".gnu.linkonce.wt.");
+ sprintf (tmp, (dwarf_version >= 5
+ ? ".gnu.linkonce.wi." : ".gnu.linkonce.wt."));
for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++)
sprintf (tmp + 17 + i * 2, "%02x", node->signature[i] & 0xff);
secname = tmp;
@@ -9762,7 +10510,8 @@ output_comdat_type_unit (comdat_type_node *node)
#endif
/* Output debugging information. */
- output_compilation_unit_header ();
+ output_compilation_unit_header (dwarf_split_debug_info
+ ? DW_UT_split_type : DW_UT_type);
output_signature (node->signature, "Type Signature");
dw2_asm_output_data (DWARF_OFFSET_SIZE, node->type_die->die_offset,
"Offset to Type DIE");
@@ -10130,24 +10879,36 @@ output_aranges (void)
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
}
-/* Add a new entry to .debug_ranges. Return the offset at which it
- was placed. */
+/* Add a new entry to .debug_ranges. Return its index into
+ ranges_table vector. */
static unsigned int
-add_ranges_num (int num)
+add_ranges_num (int num, bool maybe_new_sec)
{
- dw_ranges r = { num };
+ dw_ranges r = { NULL, num, 0, maybe_new_sec };
vec_safe_push (ranges_table, r);
- return (vec_safe_length (ranges_table) - 1) * 2 * DWARF2_ADDR_SIZE;
+ return vec_safe_length (ranges_table) - 1;
}
/* Add a new entry to .debug_ranges corresponding to a block, or a
- range terminator if BLOCK is NULL. */
+ range terminator if BLOCK is NULL. MAYBE_NEW_SEC is true if
+ this entry might be in a different section from previous range. */
static unsigned int
-add_ranges (const_tree block)
+add_ranges (const_tree block, bool maybe_new_sec)
+{
+ return add_ranges_num (block ? BLOCK_NUMBER (block) : 0, maybe_new_sec);
+}
+
+/* Note that (*rnglist_table)[offset] is either a head of a rnglist
+ chain, or middle entry of a chain that will be directly referred to. */
+
+static void
+note_rnglist_head (unsigned int offset)
{
- return add_ranges_num (block ? BLOCK_NUMBER (block) : 0);
+ if (dwarf_version < 5 || (*ranges_table)[offset].label)
+ return;
+ (*ranges_table)[offset].label = gen_internal_sym ("LLRL");
}
/* Add a new entry to .debug_ranges corresponding to a pair of labels.
@@ -10163,14 +10924,17 @@ add_ranges_by_labels (dw_die_ref die, const char *begin, const char *end,
unsigned int offset;
dw_ranges_by_label rbl = { begin, end };
vec_safe_push (ranges_by_label, rbl);
- offset = add_ranges_num (-(int)in_use - 1);
+ offset = add_ranges_num (-(int)in_use - 1, true);
if (!*added)
{
add_AT_range_list (die, DW_AT_ranges, offset, force_direct);
*added = true;
+ note_rnglist_head (offset);
}
}
+/* Emit .debug_ranges section. */
+
static void
output_ranges (void)
{
@@ -10179,6 +10943,8 @@ output_ranges (void)
const char *fmt = start_fmt;
dw_ranges *r;
+ switch_to_section (debug_ranges_section);
+ ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r)
{
int block_num = r->num;
@@ -10257,6 +11023,188 @@ output_ranges (void)
}
}
+/* Non-zero if .debug_line_str should be used for .debug_line section
+ strings or strings that are likely shareable with those. */
+#define DWARF5_USE_DEBUG_LINE_STR \
+ (!DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET \
+ && (DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) != 0 \
+ /* FIXME: there is no .debug_line_str.dwo section, \
+ for -gsplit-dwarf we should use DW_FORM_strx instead. */ \
+ && !dwarf_split_debug_info)
+
+/* Assign .debug_rnglists indexes. */
+
+static void
+index_rnglists (void)
+{
+ unsigned i;
+ dw_ranges *r;
+
+ FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r)
+ if (r->label)
+ r->idx = rnglist_idx++;
+}
+
+/* Emit .debug_rnglists section. */
+
+static void
+output_rnglists (void)
+{
+ unsigned i;
+ dw_ranges *r;
+ char l1[MAX_ARTIFICIAL_LABEL_BYTES];
+ char l2[MAX_ARTIFICIAL_LABEL_BYTES];
+#ifdef HAVE_AS_LEB128
+ char basebuf[MAX_ARTIFICIAL_LABEL_BYTES];
+#endif
+
+ switch_to_section (debug_ranges_section);
+ ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
+ ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_RANGES_SECTION_LABEL, 2);
+ ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_RANGES_SECTION_LABEL, 3);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating "
+ "64-bit DWARF extension");
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+ "Length of Range Lists");
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+ dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
+ dw2_asm_output_data (1, 0, "Segment Size");
+ /* Emit the offset table only for -gsplit-dwarf. If we don't care
+ about relocation sizes and primarily care about the size of .debug*
+ sections in linked shared libraries and executables, then
+ the offset table plus corresponding DW_FORM_rnglistx uleb128 indexes
+ into it are usually larger than just DW_FORM_sec_offset offsets
+ into the .debug_rnglists section. */
+ dw2_asm_output_data (4, dwarf_split_debug_info ? rnglist_idx : 0,
+ "Offset Entry Count");
+ if (dwarf_split_debug_info)
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, ranges_base_label);
+ FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r)
+ if (r->label)
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, r->label,
+ ranges_base_label, NULL);
+ }
+
+ const char *lab = "";
+#ifdef HAVE_AS_LEB128
+ unsigned int len = vec_safe_length (ranges_table);
+ const char *base = NULL;
+#endif
+ FOR_EACH_VEC_SAFE_ELT (ranges_table, i, r)
+ {
+ int block_num = r->num;
+
+ if (r->label)
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, r->label);
+ lab = r->label;
+ }
+#ifdef HAVE_AS_LEB128
+ if (r->label || r->maybe_new_sec)
+ base = NULL;
+#endif
+ if (block_num > 0)
+ {
+ char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
+ char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
+ ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
+
+#ifdef HAVE_AS_LEB128
+ /* If all code is in the text section, then the compilation
+ unit base address defaults to DW_AT_low_pc, which is the
+ base of the text section. */
+ if (!have_multiple_function_sections)
+ {
+ dw2_asm_output_data (1, DW_RLE_offset_pair,
+ "DW_RLE_offset_pair (%s)", lab);
+ dw2_asm_output_delta_uleb128 (blabel, text_section_label,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_delta_uleb128 (elabel, text_section_label,
+ "Range end address (%s)", lab);
+ continue;
+ }
+ if (base == NULL)
+ {
+ dw_ranges *r2 = NULL;
+ if (i < len - 1)
+ r2 = &(*ranges_table)[i + 1];
+ if (r2
+ && r2->num != 0
+ && r2->label == NULL
+ && !r2->maybe_new_sec)
+ {
+ dw2_asm_output_data (1, DW_RLE_base_address,
+ "DW_RLE_base_address (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ "Base address (%s)", lab);
+ strcpy (basebuf, blabel);
+ base = basebuf;
+ }
+ }
+ if (base)
+ {
+ dw2_asm_output_data (1, DW_RLE_offset_pair,
+ "DW_RLE_offset_pair (%s)", lab);
+ dw2_asm_output_delta_uleb128 (blabel, base,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_delta_uleb128 (elabel, base,
+ "Range end address (%s)", lab);
+ continue;
+ }
+ dw2_asm_output_data (1, DW_RLE_start_length,
+ "DW_RLE_start_length (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_delta_uleb128 (elabel, blabel,
+ "Range length (%s)", lab);
+#else
+ dw2_asm_output_data (1, DW_RLE_start_end,
+ "DW_RLE_start_end (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel,
+ "Range end address (%s)", lab);
+#endif
+ }
+
+ /* Negative block_num stands for an index into ranges_by_label. */
+ else if (block_num < 0)
+ {
+ int lab_idx = - block_num - 1;
+ const char *blabel = (*ranges_by_label)[lab_idx].begin;
+ const char *elabel = (*ranges_by_label)[lab_idx].end;
+
+ if (!have_multiple_function_sections)
+ gcc_unreachable ();
+#ifdef HAVE_AS_LEB128
+ dw2_asm_output_data (1, DW_RLE_start_length,
+ "DW_RLE_start_length (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_delta_uleb128 (elabel, blabel,
+ "Range length (%s)", lab);
+#else
+ dw2_asm_output_data (1, DW_RLE_start_end,
+ "DW_RLE_start_end (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
+ "Range begin address (%s)", lab);
+ dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel,
+ "Range end address (%s)", lab);
+#endif
+ }
+ else
+ dw2_asm_output_data (1, DW_RLE_end_of_list,
+ "DW_RLE_end_of_list (%s)", lab);
+ }
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+}
+
/* Data structure containing information about input files. */
struct file_info
{
@@ -10369,6 +11317,37 @@ file_name_acquire (dwarf_file_data **slot, file_name_acquire_data *fnad)
return 1;
}
+/* Helper function for output_file_names. Emit a FORM encoded
+ string STR, with assembly comment start ENTRY_KIND and
+ index IDX */
+
+static void
+output_line_string (enum dwarf_form form, const char *str,
+ const char *entry_kind, unsigned int idx)
+{
+ switch (form)
+ {
+ case DW_FORM_string:
+ dw2_asm_output_nstring (str, -1, "%s: %#x", entry_kind, idx);
+ break;
+ case DW_FORM_line_strp:
+ if (!debug_line_str_hash)
+ debug_line_str_hash
+ = hash_table<indirect_string_hasher>::create_ggc (10);
+
+ struct indirect_string_node *node;
+ node = find_AT_string_in_table (str, debug_line_str_hash);
+ set_indirect_string (node);
+ node->form = form;
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+ debug_line_str_section, "%s: %#x: \"%s\"",
+ entry_kind, 0, node->str);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Output the directory table and the file name table. We try to minimize
the total amount of memory needed. A heuristic is used to avoid large
slowdowns with many input files. */
@@ -10389,8 +11368,18 @@ output_file_names (void)
if (!last_emitted_file)
{
- dw2_asm_output_data (1, 0, "End directory table");
- dw2_asm_output_data (1, 0, "End file name table");
+ if (dwarf_version >= 5)
+ {
+ dw2_asm_output_data (1, 0, "Directory entry format count");
+ dw2_asm_output_data_uleb128 (0, "Directories count");
+ dw2_asm_output_data (1, 0, "File name entry format count");
+ dw2_asm_output_data_uleb128 (0, "File names count");
+ }
+ else
+ {
+ dw2_asm_output_data (1, 0, "End directory table");
+ dw2_asm_output_data (1, 0, "End file name table");
+ }
return;
}
@@ -10513,13 +11502,52 @@ output_file_names (void)
/* Emit the directory name table. */
idx_offset = dirs[0].length > 0 ? 1 : 0;
- for (i = 1 - idx_offset; i < ndirs; i++)
- dw2_asm_output_nstring (dirs[i].path,
- dirs[i].length
- - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
- "Directory Entry: %#x", i + idx_offset);
+ enum dwarf_form str_form = DW_FORM_string;
+ enum dwarf_form idx_form = DW_FORM_udata;
+ if (dwarf_version >= 5)
+ {
+ const char *comp_dir = comp_dir_string ();
+ if (comp_dir == NULL)
+ comp_dir = "";
+ dw2_asm_output_data (1, 1, "Directory entry format count");
+ if (DWARF5_USE_DEBUG_LINE_STR)
+ str_form = DW_FORM_line_strp;
+ dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path");
+ dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form));
+ dw2_asm_output_data_uleb128 (ndirs + idx_offset, "Directories count");
+ if (str_form == DW_FORM_string)
+ {
+ dw2_asm_output_nstring (comp_dir, -1, "Directory Entry: %#x", 0);
+ for (i = 1 - idx_offset; i < ndirs; i++)
+ dw2_asm_output_nstring (dirs[i].path,
+ dirs[i].length
+ - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+ "Directory Entry: %#x", i + idx_offset);
+ }
+ else
+ {
+ output_line_string (str_form, comp_dir, "Directory Entry", 0);
+ for (i = 1 - idx_offset; i < ndirs; i++)
+ {
+ const char *str
+ = ggc_alloc_string (dirs[i].path,
+ dirs[i].length
+ - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR);
+ output_line_string (str_form, str, "Directory Entry",
+ (unsigned) i + idx_offset);
+ }
+ }
+ }
+ else
+ {
+ for (i = 1 - idx_offset; i < ndirs; i++)
+ dw2_asm_output_nstring (dirs[i].path,
+ dirs[i].length
+ - !DWARF2_DIR_SHOULD_END_WITH_SEPARATOR,
+ "Directory Entry: %#x", i + idx_offset);
- dw2_asm_output_data (1, 0, "End directory table");
+ dw2_asm_output_data (1, 0, "End directory table");
+ }
/* We have to emit them in the order of emitted_number since that's
used in the debug info generation. To do this efficiently we
@@ -10528,6 +11556,70 @@ output_file_names (void)
for (i = 0; i < numfiles; i++)
backmap[files[i].file_idx->emitted_number - 1] = i;
+ if (dwarf_version >= 5)
+ {
+ const char *filename0 = get_AT_string (comp_unit_die (), DW_AT_name);
+ if (filename0 == NULL)
+ filename0 = "";
+ /* DW_LNCT_directory_index can use DW_FORM_udata, DW_FORM_data1 and
+ DW_FORM_data2. Choose one based on the number of directories
+ and how much space would they occupy in each encoding.
+ If we have at most 256 directories, all indexes fit into
+ a single byte, so DW_FORM_data1 is most compact (if there
+ are at most 128 directories, DW_FORM_udata would be as
+ compact as that, but not shorter and slower to decode). */
+ if (ndirs + idx_offset <= 256)
+ idx_form = DW_FORM_data1;
+ /* If there are more than 65536 directories, we have to use
+ DW_FORM_udata, DW_FORM_data2 can't refer to them.
+ Otherwise, compute what space would occupy if all the indexes
+ used DW_FORM_udata - sum - and compare that to how large would
+ be DW_FORM_data2 encoding, and pick the more efficient one. */
+ else if (ndirs + idx_offset <= 65536)
+ {
+ unsigned HOST_WIDE_INT sum = 1;
+ for (i = 0; i < numfiles; i++)
+ {
+ int file_idx = backmap[i];
+ int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+ sum += size_of_uleb128 (dir_idx);
+ }
+ if (sum >= HOST_WIDE_INT_UC (2) * (numfiles + 1))
+ idx_form = DW_FORM_data2;
+ }
+#ifdef VMS_DEBUGGING_INFO
+ dw2_asm_output_data (1, 4, "File name entry format count");
+#else
+ dw2_asm_output_data (1, 2, "File name entry format count");
+#endif
+ dw2_asm_output_data_uleb128 (DW_LNCT_path, "DW_LNCT_path");
+ dw2_asm_output_data_uleb128 (str_form, get_DW_FORM_name (str_form));
+ dw2_asm_output_data_uleb128 (DW_LNCT_directory_index,
+ "DW_LNCT_directory_index");
+ dw2_asm_output_data_uleb128 (idx_form, get_DW_FORM_name (idx_form));
+#ifdef VMS_DEBUGGING_INFO
+ dw2_asm_output_data_uleb128 (DW_LNCT_timestamp, "DW_LNCT_timestamp");
+ dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata");
+ dw2_asm_output_data_uleb128 (DW_LNCT_size, "DW_LNCT_size");
+ dw2_asm_output_data_uleb128 (DW_FORM_udata, "DW_FORM_udata");
+#endif
+ dw2_asm_output_data_uleb128 (numfiles + 1, "File names count");
+
+ output_line_string (str_form, filename0, "File Entry", 0);
+
+ /* Include directory index. */
+ if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+ dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+ 0, NULL);
+ else
+ dw2_asm_output_data_uleb128 (0, NULL);
+
+#ifdef VMS_DEBUGGING_INFO
+ dw2_asm_output_data_uleb128 (0, NULL);
+ dw2_asm_output_data_uleb128 (0, NULL);
+#endif
+ }
+
/* Now write all the file names. */
for (i = 0; i < numfiles; i++)
{
@@ -10543,38 +11635,47 @@ output_file_names (void)
int ver;
long long cdt;
long siz;
- int maxfilelen = strlen (files[file_idx].path)
- + dirs[dir_idx].length
- + MAX_VMS_VERSION_LEN + 1;
+ int maxfilelen = (strlen (files[file_idx].path)
+ + dirs[dir_idx].length
+ + MAX_VMS_VERSION_LEN + 1);
char *filebuf = XALLOCAVEC (char, maxfilelen);
vms_file_stats_name (files[file_idx].path, 0, 0, 0, &ver);
snprintf (filebuf, maxfilelen, "%s;%d",
files[file_idx].path + dirs[dir_idx].length, ver);
- dw2_asm_output_nstring
- (filebuf, -1, "File Entry: %#x", (unsigned) i + 1);
+ output_line_string (str_form, filebuf, "File Entry", (unsigned) i + 1);
/* Include directory index. */
- dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+ if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+ dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+ dir_idx + idx_offset, NULL);
+ else
+ dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
/* Modification time. */
- dw2_asm_output_data_uleb128
- ((vms_file_stats_name (files[file_idx].path, &cdt, 0, 0, 0) == 0)
- ? cdt : 0,
- NULL);
+ dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path,
+ &cdt, 0, 0, 0) == 0)
+ ? cdt : 0, NULL);
/* File length in bytes. */
- dw2_asm_output_data_uleb128
- ((vms_file_stats_name (files[file_idx].path, 0, &siz, 0, 0) == 0)
- ? siz : 0,
- NULL);
+ dw2_asm_output_data_uleb128 ((vms_file_stats_name (files[file_idx].path,
+ 0, &siz, 0, 0) == 0)
+ ? siz : 0, NULL);
#else
- dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
- "File Entry: %#x", (unsigned) i + 1);
+ output_line_string (str_form,
+ files[file_idx].path + dirs[dir_idx].length,
+ "File Entry", (unsigned) i + 1);
/* Include directory index. */
- dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+ if (dwarf_version >= 5 && idx_form != DW_FORM_udata)
+ dw2_asm_output_data (idx_form == DW_FORM_data1 ? 1 : 2,
+ dir_idx + idx_offset, NULL);
+ else
+ dw2_asm_output_data_uleb128 (dir_idx + idx_offset, NULL);
+
+ if (dwarf_version >= 5)
+ continue;
/* Modification time. */
dw2_asm_output_data_uleb128 (0, NULL);
@@ -10584,7 +11685,8 @@ output_file_names (void)
#endif /* VMS_DEBUGGING_INFO */
}
- dw2_asm_output_data (1, 0, "End file name table");
+ if (dwarf_version < 5)
+ dw2_asm_output_data (1, 0, "End file name table");
}
@@ -10708,8 +11810,6 @@ output_line_info (bool prologue_only)
static unsigned int generation;
char l1[MAX_ARTIFICIAL_LABEL_BYTES], l2[MAX_ARTIFICIAL_LABEL_BYTES];
char p1[MAX_ARTIFICIAL_LABEL_BYTES], p2[MAX_ARTIFICIAL_LABEL_BYTES];
- /* We don't support DWARFv5 line tables yet. */
- int ver = dwarf_version < 5 ? dwarf_version : 4;
bool saw_one = false;
int opc;
@@ -10729,7 +11829,12 @@ output_line_info (bool prologue_only)
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, ver, "DWARF Version");
+ dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ if (dwarf_version >= 5)
+ {
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
+ dw2_asm_output_data (1, 0, "Segment Size");
+ }
dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
ASM_OUTPUT_LABEL (asm_out_file, p1);
@@ -10743,7 +11848,7 @@ output_line_info (bool prologue_only)
and don't let the target override. */
dw2_asm_output_data (1, 1, "Minimum Instruction Length");
- if (ver >= 4)
+ if (dwarf_version >= 4)
dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN,
"Maximum Operations Per Instruction");
dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
@@ -11468,8 +12573,20 @@ modified_type_die (tree type, int cv_quals, bool reverse,
copy was created to help us keep track of typedef names) and
that copy might have a different TYPE_UID from the original
..._TYPE node. */
- if (TREE_CODE (type) != VECTOR_TYPE
- && TREE_CODE (type) != ARRAY_TYPE)
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ /* For function/method types, can't just use type_main_variant here,
+ because that can have different ref-qualifiers for C++,
+ but try to canonicalize. */
+ tree main = TYPE_MAIN_VARIANT (type);
+ for (tree t = main; t; t = TYPE_NEXT_VARIANT (t))
+ if (check_base_type (t, main) && check_lang_type (t, type))
+ return lookup_type_die (t);
+ return lookup_type_die (type);
+ }
+ else if (TREE_CODE (type) != VECTOR_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE)
return lookup_type_die (type_main_variant (type));
else
/* Vectors have the debugging information in the type,
@@ -12587,13 +13704,13 @@ convert_descriptor_to_mode (machine_mode mode, dw_loc_descr_ref op)
if (GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
{
- add_loc_descr (&op, new_loc_descr (DW_OP_GNU_convert, 0, 0));
+ add_loc_descr (&op, new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0));
return op;
}
type_die = base_type_for_mode (outer_mode, 1);
if (type_die == NULL)
return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -12634,6 +13751,7 @@ scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
return NULL;
if (dwarf_strict
+ && dwarf_version < 5
&& (!SCALAR_INT_MODE_P (op_mode)
|| GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE))
return NULL;
@@ -12657,12 +13775,12 @@ scompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
if (type_die == NULL)
return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -12744,7 +13862,9 @@ ucompare_loc_descriptor (enum dwarf_location_atom op, rtx rtl,
if (!SCALAR_INT_MODE_P (op_mode))
return NULL;
- if (dwarf_strict && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
+ if (dwarf_strict
+ && dwarf_version < 5
+ && GET_MODE_SIZE (op_mode) > DWARF2_ADDR_SIZE)
return NULL;
op0 = mem_loc_descriptor (XEXP (rtl, 0), op_mode, mem_mode,
@@ -12808,6 +13928,7 @@ minmax_loc_descriptor (rtx rtl, machine_mode mode,
dw_loc_descr_ref bra_node, drop_node;
if (dwarf_strict
+ && dwarf_version < 5
&& (!SCALAR_INT_MODE_P (mode)
|| GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE))
return NULL;
@@ -12857,12 +13978,12 @@ minmax_loc_descriptor (rtx rtl, machine_mode mode,
dw_loc_descr_ref cvt;
if (type_die == NULL)
return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -12908,12 +14029,12 @@ typed_binop (enum dwarf_location_atom op, rtx rtl, dw_die_ref type_die,
VAR_INIT_STATUS_INITIALIZED);
if (op0 == NULL || op1 == NULL)
return NULL;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
add_loc_descr (&op0, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -13381,7 +14502,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
mem_mode, initialized);
break;
}
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
break;
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (inner)))
break;
@@ -13407,9 +14528,9 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
}
if (GET_MODE_SIZE (mode)
!= GET_MODE_SIZE (GET_MODE (inner)))
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
else
- cvt = new_loc_descr (DW_OP_GNU_reinterpret, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_reinterpret), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -13418,7 +14539,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
&& GET_MODE_SIZE (mode) <= DWARF2_ADDR_SIZE)
{
/* Convert it to untyped afterwards. */
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
add_loc_descr (&mem_loc_result, cvt);
}
}
@@ -13437,7 +14558,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
dw_die_ref type_die;
unsigned int dbx_regnum;
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
break;
if (REGNO (rtl) > FIRST_PSEUDO_REGISTER)
break;
@@ -13448,7 +14569,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
dbx_regnum = dbx_reg_number (rtl);
if (dbx_regnum == IGNORED_DWARF_REGNUM)
break;
- mem_loc_result = new_loc_descr (DW_OP_GNU_regval_type,
+ mem_loc_result = new_loc_descr (dwarf_OP (DW_OP_regval_type),
dbx_regnum, 0);
mem_loc_result->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
mem_loc_result->dw_loc_oprnd2.v.val_die_ref.die = type_die;
@@ -13520,7 +14641,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
add_loc_descr (&mem_loc_result, int_loc_descriptor (shift));
add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
}
- else if (!dwarf_strict)
+ else if (!dwarf_strict || dwarf_version >= 5)
{
dw_die_ref type_die1, type_die2;
dw_loc_descr_ref cvt;
@@ -13533,12 +14654,12 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
if (type_die2 == NULL)
break;
mem_loc_result = op0;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die1;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
add_loc_descr (&mem_loc_result, cvt);
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die2;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -13570,13 +14691,13 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
dw_die_ref type_die;
dw_loc_descr_ref deref;
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
return NULL;
type_die
= base_type_for_mode (mode, SCALAR_INT_MODE_P (mode));
if (type_die == NULL)
return NULL;
- deref = new_loc_descr (DW_OP_GNU_deref_type,
+ deref = new_loc_descr (dwarf_OP (DW_OP_deref_type),
GET_MODE_SIZE (mode), 0);
deref->dw_loc_oprnd2.val_class = dw_val_class_die_ref;
deref->dw_loc_oprnd2.v.val_die_ref.die = type_die;
@@ -13619,7 +14740,12 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
temp = new_addr_loc_descr (rtl, dtprel_true);
- mem_loc_result = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
+ /* We check for DWARF 5 here because gdb did not implement
+ DW_OP_form_tls_address until after 7.12. */
+ mem_loc_result = new_loc_descr ((dwarf_version >= 5
+ ? DW_OP_form_tls_address
+ : DW_OP_GNU_push_tls_address),
+ 0, 0);
add_loc_descr (&mem_loc_result, temp);
break;
@@ -13647,7 +14773,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
return 0;
case ENTRY_VALUE:
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
return NULL;
if (REG_P (ENTRY_VALUE_EXP (rtl)))
{
@@ -13676,7 +14802,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
gcc_unreachable ();
if (op0 == NULL)
return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
+ mem_loc_result = new_loc_descr (dwarf_OP (DW_OP_entry_value), 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
mem_loc_result->dw_loc_oprnd1.v.val_loc = op0;
break;
@@ -13747,7 +14873,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
goto do_binop;
case DIV:
- if (!dwarf_strict
+ if ((!dwarf_strict || dwarf_version >= 5)
&& SCALAR_INT_MODE_P (mode)
&& GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
{
@@ -13825,7 +14951,8 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
break;
case MOD:
- if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE && !dwarf_strict)
+ if (GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE
+ && (!dwarf_strict || dwarf_version >= 5))
{
mem_loc_result = typed_binop (DW_OP_mod, rtl,
base_type_for_mode (mode, 0),
@@ -13851,7 +14978,8 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
break;
case UDIV:
- if (!dwarf_strict && SCALAR_INT_MODE_P (mode))
+ if ((!dwarf_strict || dwarf_version >= 5)
+ && SCALAR_INT_MODE_P (mode))
{
if (GET_MODE_CLASS (mode) > DWARF2_ADDR_SIZE)
{
@@ -13899,7 +15027,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
break;
}
- if (!dwarf_strict
+ if ((!dwarf_strict || dwarf_version >= 5)
&& (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT
|| GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT))
{
@@ -13912,20 +15040,20 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
if (INTVAL (rtl) >= 0
&& amode != BLKmode
&& trunc_int_for_mode (INTVAL (rtl), amode) == INTVAL (rtl)
- /* const DW_OP_GNU_convert <XXX> vs.
- DW_OP_GNU_const_type <XXX, 1, const>. */
+ /* const DW_OP_convert <XXX> vs.
+ DW_OP_const_type <XXX, 1, const>. */
&& size_of_int_loc_descriptor (INTVAL (rtl)) + 1 + 1
< (unsigned long) 1 + 1 + 1 + GET_MODE_SIZE (mode))
{
mem_loc_result = int_loc_descriptor (INTVAL (rtl));
- op0 = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ op0 = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
op0->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
op0->dw_loc_oprnd1.v.val_die_ref.die = type_die;
op0->dw_loc_oprnd1.v.val_die_ref.external = 0;
add_loc_descr (&mem_loc_result, op0);
return mem_loc_result;
}
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0,
+ mem_loc_result = new_loc_descr (dwarf_OP (DW_OP_const_type), 0,
INTVAL (rtl));
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
@@ -13943,7 +15071,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
break;
case CONST_DOUBLE:
- if (!dwarf_strict)
+ if (!dwarf_strict || dwarf_version >= 5)
{
dw_die_ref type_die;
@@ -13962,7 +15090,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
type_die = base_type_for_mode (mode, SCALAR_INT_MODE_P (mode));
if (type_die == NULL)
return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
+ mem_loc_result = new_loc_descr (dwarf_OP (DW_OP_const_type), 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -13990,14 +15118,14 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
break;
case CONST_WIDE_INT:
- if (!dwarf_strict)
+ if (!dwarf_strict || dwarf_version >= 5)
{
dw_die_ref type_die;
type_die = base_type_for_mode (mode, SCALAR_INT_MODE_P (mode));
if (type_die == NULL)
return NULL;
- mem_loc_result = new_loc_descr (DW_OP_GNU_const_type, 0, 0);
+ mem_loc_result = new_loc_descr (dwarf_OP (DW_OP_const_type), 0, 0);
mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.die = type_die;
mem_loc_result->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -14133,7 +15261,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
case UNSIGNED_FLOAT:
case FIX:
case UNSIGNED_FIX:
- if (!dwarf_strict)
+ if (!dwarf_strict || dwarf_version >= 5)
{
dw_die_ref type_die;
dw_loc_descr_ref cvt;
@@ -14151,7 +15279,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
GET_CODE (rtl) == UNSIGNED_FLOAT);
if (type_die == NULL)
break;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -14160,7 +15288,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
type_die = base_type_for_mode (mode, GET_CODE (rtl) == UNSIGNED_FIX);
if (type_die == NULL)
break;
- cvt = new_loc_descr (DW_OP_GNU_convert, 0, 0);
+ cvt = new_loc_descr (dwarf_OP (DW_OP_convert), 0, 0);
cvt->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
cvt->dw_loc_oprnd1.v.val_die_ref.die = type_die;
cvt->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -14251,6 +15379,46 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
resolve_one_addr (&rtl);
goto symref;
+ /* RTL sequences inside PARALLEL record a series of DWARF operations for
+ the expression. An UNSPEC rtx represents a raw DWARF operation,
+ new_loc_descr is called for it to build the operation directly.
+ Otherwise mem_loc_descriptor is called recursively. */
+ case PARALLEL:
+ {
+ int index = 0;
+ dw_loc_descr_ref exp_result = NULL;
+
+ for (; index < XVECLEN (rtl, 0); index++)
+ {
+ rtx elem = XVECEXP (rtl, 0, index);
+ if (GET_CODE (elem) == UNSPEC)
+ {
+ /* Each DWARF operation UNSPEC contain two operands, if
+ one operand is not used for the operation, const0_rtx is
+ passed. */
+ gcc_assert (XVECLEN (elem, 0) == 2);
+
+ HOST_WIDE_INT dw_op = XINT (elem, 1);
+ HOST_WIDE_INT oprnd1 = INTVAL (XVECEXP (elem, 0, 0));
+ HOST_WIDE_INT oprnd2 = INTVAL (XVECEXP (elem, 0, 1));
+ exp_result
+ = new_loc_descr ((enum dwarf_location_atom) dw_op, oprnd1,
+ oprnd2);
+ }
+ else
+ exp_result
+ = mem_loc_descriptor (elem, mode, mem_mode,
+ VAR_INIT_STATUS_INITIALIZED);
+
+ if (!mem_loc_result)
+ mem_loc_result = exp_result;
+ else
+ add_loc_descr (&mem_loc_result, exp_result);
+ }
+
+ break;
+ }
+
default:
if (flag_checking)
{
@@ -14322,7 +15490,7 @@ concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
return cc_loc_result;
}
-/* Helper function for loc_descriptor. Return DW_OP_GNU_implicit_pointer
+/* Helper function for loc_descriptor. Return DW_OP_implicit_pointer
for DEBUG_IMPLICIT_PTR RTL. */
static dw_loc_descr_ref
@@ -14331,13 +15499,13 @@ implicit_ptr_descriptor (rtx rtl, HOST_WIDE_INT offset)
dw_loc_descr_ref ret;
dw_die_ref ref;
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
return NULL;
gcc_assert (TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == VAR_DECL
|| TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == PARM_DECL
|| TREE_CODE (DEBUG_IMPLICIT_PTR_DECL (rtl)) == RESULT_DECL);
ref = lookup_decl_die (DEBUG_IMPLICIT_PTR_DECL (rtl));
- ret = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
+ ret = new_loc_descr (dwarf_OP (DW_OP_implicit_pointer), 0, offset);
ret->dw_loc_oprnd2.val_class = dw_val_class_const;
if (ref)
{
@@ -15157,7 +16325,7 @@ cst_pool_loc_descr (tree loc)
static dw_loc_list_ref
loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev,
- const loc_descr_context *context)
+ loc_descr_context *context)
{
tree obj, offset;
HOST_WIDE_INT bitsize, bitpos, bytepos;
@@ -15291,6 +16459,11 @@ struct loc_descr_context
/* Information about the DWARF procedure we are currently generating. NULL if
we are not generating a DWARF procedure. */
struct dwarf_procedure_info *dpi;
+ /* True if integral PLACEHOLDER_EXPR stands for the first argument passed
+ by consumer. Used for DW_TAG_generic_subrange attributes. */
+ bool placeholder_arg;
+ /* True if PLACEHOLDER_EXPR has been seen. */
+ bool placeholder_seen;
};
/* DWARF procedures generation
@@ -15400,8 +16573,23 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset,
/* If needed, relocate the picking offset with respect to the frame
offset. */
- if (l->dw_loc_opc == DW_OP_pick && l->frame_offset_rel)
+ if (l->frame_offset_rel)
{
+ unsigned HOST_WIDE_INT off;
+ switch (l->dw_loc_opc)
+ {
+ case DW_OP_pick:
+ off = l->dw_loc_oprnd1.v.val_unsigned;
+ break;
+ case DW_OP_dup:
+ off = 0;
+ break;
+ case DW_OP_over:
+ off = 1;
+ break;
+ default:
+ gcc_unreachable ();
+ }
/* frame_offset_ is the size of the current stack frame, including
incoming arguments. Besides, the arguments are pushed
right-to-left. Thus, in order to access the Nth argument from
@@ -15412,11 +16600,27 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset,
The targetted argument number (N) is already set as the operand,
and the number of temporaries can be computed with:
frame_offsets_ - dpi->args_count */
- l->dw_loc_oprnd1.v.val_unsigned += frame_offset_ - dpi->args_count;
+ off += frame_offset_ - dpi->args_count;
/* DW_OP_pick handles only offsets from 0 to 255 (inclusive)... */
- if (l->dw_loc_oprnd1.v.val_unsigned > 255)
+ if (off > 255)
return false;
+
+ if (off == 0)
+ {
+ l->dw_loc_opc = DW_OP_dup;
+ l->dw_loc_oprnd1.v.val_unsigned = 0;
+ }
+ else if (off == 1)
+ {
+ l->dw_loc_opc = DW_OP_over;
+ l->dw_loc_oprnd1.v.val_unsigned = 0;
+ }
+ else
+ {
+ l->dw_loc_opc = DW_OP_pick;
+ l->dw_loc_oprnd1.v.val_unsigned = off;
+ }
}
/* Update frame_offset according to the effect the current operation has
@@ -15467,7 +16671,6 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset,
case DW_OP_piece:
case DW_OP_deref_size:
case DW_OP_nop:
- case DW_OP_form_tls_address:
case DW_OP_bit_piece:
case DW_OP_implicit_value:
case DW_OP_stack_value:
@@ -15595,6 +16798,14 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset,
break;
}
+ case DW_OP_implicit_pointer:
+ case DW_OP_entry_value:
+ case DW_OP_const_type:
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
+ case DW_OP_form_tls_address:
case DW_OP_GNU_push_tls_address:
case DW_OP_GNU_uninit:
case DW_OP_GNU_encoded_addr:
@@ -15712,6 +16923,8 @@ function_to_dwarf_procedure (tree fndecl)
ctx.context_type = NULL_TREE;
ctx.base_decl = NULL_TREE;
ctx.dpi = &dpi;
+ ctx.placeholder_arg = false;
+ ctx.placeholder_seen = false;
dpi.fndecl = fndecl;
dpi.args_count = list_length (DECL_ARGUMENTS (fndecl));
loc_body = loc_descriptor_from_tree (tree_body, 0, &ctx);
@@ -15774,7 +16987,7 @@ function_to_dwarf_procedure (tree fndecl)
static dw_loc_list_ref
loc_list_from_tree_1 (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_descr_ref ret = NULL, ret1 = NULL;
dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
@@ -15820,6 +17033,18 @@ loc_list_from_tree_1 (tree loc, int want_address,
else
return NULL;
}
+ /* For DW_TAG_generic_subrange attributes, PLACEHOLDER_EXPR stands for
+ the single argument passed by consumer. */
+ else if (context != NULL
+ && context->placeholder_arg
+ && INTEGRAL_TYPE_P (TREE_TYPE (loc))
+ && want_address == 0)
+ {
+ ret = new_loc_descr (DW_OP_pick, 0, 0);
+ ret->frame_offset_rel = 1;
+ context->placeholder_seen = true;
+ break;
+ }
else
expansion_failed (loc, NULL_RTX,
"PLACEHOLDER_EXPR for an unexpected type");
@@ -15924,8 +17149,11 @@ loc_list_from_tree_1 (tree loc, int want_address,
operand shouldn't be. */
if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
return 0;
- dtprel = dtprel_true;
- tls_op = DW_OP_GNU_push_tls_address;
+ dtprel = dtprel_true;
+ /* We check for DWARF 5 here because gdb did not implement
+ DW_OP_form_tls_address until after 7.12. */
+ tls_op = (dwarf_version >= 5 ? DW_OP_form_tls_address
+ : DW_OP_GNU_push_tls_address);
}
else
{
@@ -16573,7 +17801,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
static dw_loc_list_ref
loc_list_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_list_ref result = loc_list_from_tree_1 (loc, want_address, context);
@@ -16587,7 +17815,7 @@ loc_list_from_tree (tree loc, int want_address,
/* Same as above but return only single location expression. */
static dw_loc_descr_ref
loc_descriptor_from_tree (tree loc, int want_address,
- const struct loc_descr_context *context)
+ struct loc_descr_context *context)
{
dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context);
if (!ret)
@@ -16673,6 +17901,8 @@ type_byte_size (const_tree type, HOST_WIDE_INT *cst_size)
ctx.context_type = const_cast<tree> (type);
ctx.base_decl = NULL_TREE;
ctx.dpi = NULL;
+ ctx.placeholder_arg = false;
+ ctx.placeholder_seen = false;
type = TYPE_MAIN_VARIANT (type);
tree_size = TYPE_SIZE_UNIT (type);
@@ -16852,7 +18082,9 @@ field_byte_offset (const_tree decl, struct vlr_context *ctx,
struct loc_descr_context loc_ctx = {
ctx->struct_type, /* context_type */
NULL_TREE, /* base_decl */
- NULL /* dpi */
+ NULL, /* dpi */
+ false, /* placeholder_arg */
+ false /* placeholder_seen */
};
loc_result = loc_list_from_tree (tree_result, 0, &loc_ctx);
@@ -18245,12 +19477,12 @@ add_comp_dir_attribute (dw_die_ref die)
static void
add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
- int forms, const struct loc_descr_context *context)
+ int forms, struct loc_descr_context *context)
{
dw_die_ref context_die, decl_die;
dw_loc_list_ref list;
-
bool strip_conversions = true;
+ bool placeholder_seen = false;
while (strip_conversions)
switch (TREE_CODE (value))
@@ -18345,6 +19577,11 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
return;
list = loc_list_from_tree (value, 2, context);
+ if (context && context->placeholder_arg)
+ {
+ placeholder_seen = context->placeholder_seen;
+ context->placeholder_seen = false;
+ }
if (list == NULL || single_element_loc_list_p (list))
{
/* If this attribute is not a reference nor constant, it is
@@ -18353,6 +19590,14 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context);
if (list2 && single_element_loc_list_p (list2))
{
+ if (placeholder_seen)
+ {
+ struct dwarf_procedure_info dpi;
+ dpi.fndecl = NULL_TREE;
+ dpi.args_count = 1;
+ if (!resolve_args_picking (list2->expr, 1, &dpi))
+ return;
+ }
add_AT_loc (die, attr, list2->expr);
return;
}
@@ -18360,7 +19605,9 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
/* If that failed to give a single element location list, fall back to
outputting this as a reference... still if permitted. */
- if (list == NULL || (forms & dw_scalar_form_reference) == 0)
+ if (list == NULL
+ || (forms & dw_scalar_form_reference) == 0
+ || placeholder_seen)
return;
if (current_function_decl == 0)
@@ -18423,7 +19670,7 @@ lower_bound_default (void)
static void
add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
- tree bound, const struct loc_descr_context *context)
+ tree bound, struct loc_descr_context *context)
{
int dflt;
@@ -18454,7 +19701,8 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
encodings, GDB isn't ready yet to handle proper DWARF description
for self-referencial subrange bounds: let GNAT encodings do the
magic in such a case. */
- if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL
+ if (is_ada ()
+ && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL
&& contains_placeholder_p (bound))
return;
@@ -18864,7 +20112,8 @@ add_linkage_name (dw_die_ref die, tree decl)
given decl, but only if it actually has a name. */
static void
-add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
+add_name_and_src_coords_attributes (dw_die_ref die, tree decl,
+ bool no_linkage_name)
{
tree decl_name;
@@ -18877,7 +20126,8 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl)
if (! DECL_ARTIFICIAL (decl))
add_src_coords_attributes (die, decl);
- add_linkage_name (die, decl);
+ if (!no_linkage_name)
+ add_linkage_name (die, decl);
}
#ifdef VMS_DEBUGGING_INFO
@@ -19480,7 +20730,9 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info,
{
const dw_die_ref scope_die = scope_die_for (type, context_die);
const dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die, type);
- const struct loc_descr_context context = { type, info->base_decl, NULL };
+ struct loc_descr_context context = { type, info->base_decl, NULL,
+ false, false };
+ enum dwarf_tag subrange_tag = DW_TAG_subrange_type;
int dim;
add_name_attribute (array_die, type_tag (type));
@@ -19528,13 +20780,23 @@ gen_descr_array_type_die (tree type, struct array_descr_info *info,
add_scalar_info (array_die, attr, info->stride, forms, &context);
}
}
+ if (dwarf_version >= 5)
+ {
+ if (info->rank)
+ {
+ add_scalar_info (array_die, DW_AT_rank, info->rank,
+ dw_scalar_form_constant
+ | dw_scalar_form_exprloc, &context);
+ subrange_tag = DW_TAG_generic_subrange;
+ context.placeholder_arg = true;
+ }
+ }
add_gnat_descriptive_type_attribute (array_die, type, context_die);
for (dim = 0; dim < info->ndimensions; dim++)
{
- dw_die_ref subrange_die
- = new_die (DW_TAG_subrange_type, array_die, NULL);
+ dw_die_ref subrange_die = new_die (subrange_tag, array_die, NULL);
if (info->dimen[dim].bounds_type)
add_type_attribute (subrange_die,
@@ -20325,7 +21587,7 @@ premark_types_used_by_global_vars (void)
->traverse<void *, premark_types_used_by_global_vars_helper> (NULL);
}
-/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
+/* Generate a DW_TAG_call_site DIE in function DECL under SUBR_DIE
for CA_LOC call arg loc node. */
static dw_die_ref
@@ -20346,17 +21608,18 @@ gen_call_site_die (tree decl, dw_die_ref subr_die,
}
if (stmt_die == NULL)
stmt_die = subr_die;
- die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
- add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+ die = new_die (dwarf_TAG (DW_TAG_call_site), stmt_die, NULL_TREE);
+ add_AT_lbl_id (die, dwarf_AT (DW_AT_call_return_pc), ca_loc->label);
if (ca_loc->tail_call_p)
- add_AT_flag (die, DW_AT_GNU_tail_call, 1);
+ add_AT_flag (die, dwarf_AT (DW_AT_call_tail_call), 1);
if (ca_loc->symbol_ref)
{
dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref));
if (tdie)
- add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
+ add_AT_die_ref (die, dwarf_AT (DW_AT_call_origin), tdie);
else
- add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref, false);
+ add_AT_addr (die, dwarf_AT (DW_AT_call_origin), ca_loc->symbol_ref,
+ false);
}
return die;
}
@@ -20653,7 +21916,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
add_AT_flag (subr_die, DW_AT_deleted, 1);
/* If this is a C++11 defaulted special function member then
- generate a DW_AT_GNU_defaulted attribute. */
+ generate a DW_AT_defaulted attribute. */
if (dwarf_version >= 5 || !dwarf_strict)
{
int defaulted
@@ -20771,11 +22034,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
alignment offset. */
bool range_list_added = false;
add_ranges_by_labels (subr_die, fde->dw_fde_begin,
- fde->dw_fde_end, &range_list_added,
- false);
+ fde->dw_fde_end, &range_list_added,
+ false);
add_ranges_by_labels (subr_die, fde->dw_fde_second_begin,
fde->dw_fde_second_end,
- &range_list_added, false);
+ &range_list_added, false);
if (range_list_added)
add_ranges (NULL);
}
@@ -21022,7 +22285,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
location info. */
decls_for_scope (outer_scope, subr_die);
- if (call_arg_locations && !dwarf_strict)
+ if (call_arg_locations && (!dwarf_strict || dwarf_version >= 5))
{
struct call_arg_loc_node *ca_loc;
for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
@@ -21058,7 +22321,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
continue;
/* Get dynamic information about call target only if we
have no static information: we cannot generate both
- DW_AT_abstract_origin and DW_AT_GNU_call_site_target
+ DW_AT_call_origin and DW_AT_call_target
attributes. */
if (ca_loc->symbol_ref == NULL_RTX)
{
@@ -21108,13 +22371,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
continue;
if (die == NULL)
die = gen_call_site_die (decl, subr_die, ca_loc);
- cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
+ cdie = new_die (dwarf_TAG (DW_TAG_call_site_parameter), die,
NULL_TREE);
if (reg != NULL)
add_AT_loc (cdie, DW_AT_location, reg);
else if (tdie != NULL)
- add_AT_die_ref (cdie, DW_AT_abstract_origin, tdie);
- add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
+ add_AT_die_ref (cdie, dwarf_AT (DW_AT_call_parameter),
+ tdie);
+ add_AT_loc (cdie, dwarf_AT (DW_AT_call_value), val);
if (next_arg != XEXP (arg, 1))
{
mode = GET_MODE (XEXP (XEXP (XEXP (arg, 1), 0), 1));
@@ -21125,7 +22389,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
mode, VOIDmode,
VAR_INIT_STATUS_INITIALIZED);
if (val != NULL)
- add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
+ add_AT_loc (cdie, dwarf_AT (DW_AT_call_data_value),
+ val);
}
}
if (die == NULL
@@ -21142,7 +22407,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
VOIDmode,
VAR_INIT_STATUS_INITIALIZED);
if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
+ add_AT_loc (die, dwarf_AT (DW_AT_call_target), tval);
else if (tlocc != NULL_RTX)
{
tval = mem_loc_descriptor (tlocc,
@@ -21151,7 +22416,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
VOIDmode,
VAR_INIT_STATUS_INITIALIZED);
if (tval)
- add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered,
+ add_AT_loc (die,
+ dwarf_AT (DW_AT_call_target_clobbered),
tval);
}
}
@@ -21167,13 +22433,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
call_arg_loc_last = NULL;
if (tail_call_site_count >= 0
&& tail_call_site_count == tail_call_site_note_count
- && !dwarf_strict)
+ && (!dwarf_strict || dwarf_version >= 5))
{
if (call_site_count >= 0
&& call_site_count == call_site_note_count)
- add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
+ add_AT_flag (subr_die, dwarf_AT (DW_AT_call_all_calls), 1);
else
- add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
+ add_AT_flag (subr_die, dwarf_AT (DW_AT_call_all_tail_calls), 1);
}
call_site_count = -1;
tail_call_site_count = -1;
@@ -21239,10 +22505,25 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
tree ultimate_origin;
dw_die_ref var_die;
dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
- dw_die_ref origin_die = NULL;
bool declaration = (DECL_EXTERNAL (decl_or_origin)
|| class_or_namespace_scope_p (context_die));
bool specialization_p = false;
+ bool no_linkage_name = false;
+
+ /* While C++ inline static data members have definitions inside of the
+ class, force the first DIE to be a declaration, then let gen_member_die
+ reparent it to the class context and call gen_variable_die again
+ to create the outside of the class DIE for the definition. */
+ if (!declaration
+ && old_die == NULL
+ && decl
+ && DECL_CONTEXT (decl)
+ && TYPE_P (DECL_CONTEXT (decl))
+ && lang_hooks.decls.decl_dwarf_attribute (decl, DW_AT_inline) != -1)
+ {
+ declaration = true;
+ no_linkage_name = true;
+ }
ultimate_origin = decl_ultimate_origin (decl_or_origin);
if (decl || ultimate_origin)
@@ -21399,7 +22680,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
var_die = new_die (DW_TAG_variable, context_die, decl);
if (origin != NULL)
- origin_die = add_abstract_origin_attribute (var_die, origin);
+ add_abstract_origin_attribute (var_die, origin);
/* Loop unrolling can create multiple blocks that refer to the same
static variable, so we must test for the DW_AT_declaration flag.
@@ -21430,7 +22711,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
}
}
else
- add_name_and_src_coords_attributes (var_die, decl);
+ add_name_and_src_coords_attributes (var_die, decl, no_linkage_name);
if ((origin == NULL && !specialization_p)
|| (origin != NULL
@@ -21490,9 +22771,18 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
&& lang_hooks.decls.decl_dwarf_attribute (decl_or_origin,
DW_AT_const_expr) == 1
&& !get_AT (var_die, DW_AT_const_expr)
- && (origin_die == NULL || get_AT (origin_die, DW_AT_const_expr) == NULL)
&& !specialization_p)
add_AT_flag (var_die, DW_AT_const_expr, 1);
+
+ if (!dwarf_strict)
+ {
+ int inl = lang_hooks.decls.decl_dwarf_attribute (decl_or_origin,
+ DW_AT_inline);
+ if (inl != -1
+ && !get_AT (var_die, DW_AT_inline)
+ && !specialization_p)
+ add_AT_unsigned (var_die, DW_AT_inline, inl);
+ }
}
/* Generate a DIE to represent a named constant. */
@@ -21637,13 +22927,11 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
superblock = BLOCK_SUPERCONTEXT (chain);
}
if (attr != NULL
- && ((*ranges_table)[attr->dw_attr_val.v.val_offset
- / 2 / DWARF2_ADDR_SIZE].num
+ && ((*ranges_table)[attr->dw_attr_val.v.val_offset].num
== BLOCK_NUMBER (superblock))
&& BLOCK_FRAGMENT_CHAIN (superblock))
{
- unsigned long off = attr->dw_attr_val.v.val_offset
- / 2 / DWARF2_ADDR_SIZE;
+ unsigned long off = attr->dw_attr_val.v.val_offset;
unsigned long supercnt = 0, thiscnt = 0;
for (chain = BLOCK_FRAGMENT_CHAIN (superblock);
chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
@@ -21657,19 +22945,22 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
++thiscnt;
gcc_assert (supercnt >= thiscnt);
- add_AT_range_list (die, DW_AT_ranges,
- ((off + supercnt - thiscnt)
- * 2 * DWARF2_ADDR_SIZE),
- false);
+ add_AT_range_list (die, DW_AT_ranges, off + supercnt - thiscnt,
+ false);
+ note_rnglist_head (off + supercnt - thiscnt);
return;
}
- add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt), false);
+ unsigned int offset = add_ranges (stmt, true);
+ add_AT_range_list (die, DW_AT_ranges, offset, false);
+ note_rnglist_head (offset);
+ bool prev_in_cold = BLOCK_IN_COLD_SECTION_P (stmt);
chain = BLOCK_FRAGMENT_CHAIN (stmt);
do
{
- add_ranges (chain);
+ add_ranges (chain, prev_in_cold != BLOCK_IN_COLD_SECTION_P (chain));
+ prev_in_cold = BLOCK_IN_COLD_SECTION_P (chain);
chain = BLOCK_FRAGMENT_CHAIN (chain);
}
while (chain);
@@ -21868,20 +23159,31 @@ gen_reference_type_die (tree type, dw_die_ref context_die)
}
#endif
-/* Generate a DIE for a pointer to a member type. */
+/* Generate a DIE for a pointer to a member type. TYPE can be an
+ OFFSET_TYPE, for a pointer to data member, or a RECORD_TYPE, for a
+ pointer to member function. */
static void
gen_ptr_to_mbr_type_die (tree type, dw_die_ref context_die)
{
- dw_die_ref ptr_die
- = new_die (DW_TAG_ptr_to_member_type,
- scope_die_for (type, context_die), type);
+ if (lookup_type_die (type))
+ return;
+
+ dw_die_ref ptr_die = new_die (DW_TAG_ptr_to_member_type,
+ scope_die_for (type, context_die), type);
equate_type_number_to_die (type, ptr_die);
add_AT_die_ref (ptr_die, DW_AT_containing_type,
lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
add_type_attribute (ptr_die, TREE_TYPE (type), TYPE_UNQUALIFIED, false,
context_die);
+
+ if (TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (type)) != METHOD_TYPE)
+ {
+ dw_loc_descr_ref op = new_loc_descr (DW_OP_plus, 0, 0);
+ add_AT_loc (ptr_die, DW_AT_use_location, op);
+ }
}
static char *producer_string;
@@ -22459,7 +23761,9 @@ gen_variant_part (tree variant_part_decl, struct vlr_context *vlr_ctx,
struct loc_descr_context ctx = {
vlr_ctx->struct_type, /* context_type */
NULL_TREE, /* base_decl */
- NULL /* dpi */
+ NULL, /* dpi */
+ false, /* placeholder_arg */
+ false /* placeholder_seen */
};
/* The FIELD_DECL node in STRUCT_TYPE that acts as the discriminant, or
@@ -22648,6 +23952,19 @@ gen_member_die (tree type, dw_die_ref context_die)
vlr_ctx.variant_part_offset = NULL_TREE;
gen_decl_die (member, NULL, &vlr_ctx, context_die);
}
+
+ /* For C++ inline static data members emit immediately a DW_TAG_variable
+ DIE that will refer to that DW_TAG_member through
+ DW_AT_specification. */
+ if (TREE_STATIC (member)
+ && (lang_hooks.decls.decl_dwarf_attribute (member, DW_AT_inline)
+ != -1))
+ {
+ int old_extern = DECL_EXTERNAL (member);
+ DECL_EXTERNAL (member) = 0;
+ gen_decl_die (member, NULL, NULL, comp_unit_die ());
+ DECL_EXTERNAL (member) = old_extern;
+ }
}
/* We do not keep type methods in type variants. */
@@ -22801,6 +24118,13 @@ gen_subroutine_type_die (tree type, dw_die_ref context_die)
if (get_AT (subr_die, DW_AT_name))
add_pubtype (type, subr_die);
+ if ((dwarf_version >= 5 || !dwarf_strict)
+ && lang_hooks.types.type_dwarf_attribute (type, DW_AT_reference) != -1)
+ add_AT_flag (subr_die, DW_AT_reference, 1);
+ if ((dwarf_version >= 5 || !dwarf_strict)
+ && lang_hooks.types.type_dwarf_attribute (type,
+ DW_AT_rvalue_reference) != -1)
+ add_AT_flag (subr_die, DW_AT_rvalue_reference, 1);
}
/* Generate a DIE for a type definition. */
@@ -23022,13 +24346,36 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
return;
}
+ if (lang_hooks.types.get_debug_type)
+ {
+ tree debug_type = lang_hooks.types.get_debug_type (type);
+
+ if (debug_type != NULL_TREE && debug_type != type)
+ {
+ gen_type_die_with_usage (debug_type, context_die, usage);
+ return;
+ }
+ }
+
/* We are going to output a DIE to represent the unqualified version
of this type (i.e. without any const or volatile qualifiers) so
get the main variant (i.e. the unqualified version) of this type
now. (Vectors and arrays are special because the debugging info is in the
- cloned type itself). */
- if (TREE_CODE (type) != VECTOR_TYPE
- && TREE_CODE (type) != ARRAY_TYPE)
+ cloned type itself. Similarly function/method types can contain extra
+ ref-qualification). */
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ /* For function/method types, can't use type_main_variant here,
+ because that can have different ref-qualifiers for C++,
+ but try to canonicalize. */
+ tree main = TYPE_MAIN_VARIANT (type);
+ for (tree t = main; t; t = TYPE_NEXT_VARIANT (t))
+ if (check_base_type (t, main) && check_lang_type (t, type))
+ type = t;
+ }
+ else if (TREE_CODE (type) != VECTOR_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE)
type = type_main_variant (type);
/* If this is an array type with hidden descriptor, handle it first. */
@@ -23079,18 +24426,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
/* For these types, all that is required is that we output a DIE (or a
set of DIEs) to represent the "basis" type. */
gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_IND_USE);
+ DINFO_USAGE_IND_USE);
break;
case OFFSET_TYPE:
/* This code is used for C++ pointer-to-data-member types.
Output a description of the relevant class type. */
gen_type_die_with_usage (TYPE_OFFSET_BASETYPE (type), context_die,
- DINFO_USAGE_IND_USE);
+ DINFO_USAGE_IND_USE);
/* Output a description of the type of the object pointed to. */
gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_IND_USE);
+ DINFO_USAGE_IND_USE);
/* Now output a DIE to represent this pointer-to-data-member type
itself. */
@@ -23100,14 +24447,14 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
case FUNCTION_TYPE:
/* Force out return type (in case it wasn't forced out already). */
gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_DIR_USE);
+ DINFO_USAGE_DIR_USE);
gen_subroutine_type_die (type, context_die);
break;
case METHOD_TYPE:
/* Force out return type (in case it wasn't forced out already). */
gen_type_die_with_usage (TREE_TYPE (type), context_die,
- DINFO_USAGE_DIR_USE);
+ DINFO_USAGE_DIR_USE);
gen_subroutine_type_die (type, context_die);
break;
@@ -25165,7 +26512,7 @@ dwarf2out_define (unsigned int lineno ATTRIBUTE_UNUSED,
{
macinfo_entry e;
/* Insert a dummy first entry to be able to optimize the whole
- predefined macro block using DW_MACRO_GNU_transparent_include. */
+ predefined macro block using DW_MACRO_import. */
if (macinfo_table->is_empty () && lineno <= 1)
{
e.code = 0;
@@ -25192,7 +26539,7 @@ dwarf2out_undef (unsigned int lineno ATTRIBUTE_UNUSED,
{
macinfo_entry e;
/* Insert a dummy first entry to be able to optimize the whole
- predefined macro block using DW_MACRO_GNU_transparent_include. */
+ predefined macro block using DW_MACRO_import. */
if (macinfo_table->is_empty () && lineno <= 1)
{
e.code = 0;
@@ -25264,8 +26611,7 @@ output_macinfo_op (macinfo_entry *ref)
&& (debug_str_section->common.flags & SECTION_MERGE) != 0)
{
ref->code = ref->code == DW_MACINFO_define
- ? DW_MACRO_GNU_define_indirect
- : DW_MACRO_GNU_undef_indirect;
+ ? DW_MACRO_define_strp : DW_MACRO_undef_strp;
output_macinfo_op (ref);
return;
}
@@ -25276,16 +26622,16 @@ output_macinfo_op (macinfo_entry *ref)
(unsigned long) ref->lineno);
dw2_asm_output_nstring (ref->info, -1, "The macro");
break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
node = find_AT_string (ref->info);
gcc_assert (node
- && ((node->form == DW_FORM_strp)
- || (node->form == DW_FORM_GNU_str_index)));
+ && (node->form == DW_FORM_strp
+ || node->form == DW_FORM_GNU_str_index));
dw2_asm_output_data (1, ref->code,
- ref->code == DW_MACRO_GNU_define_indirect
- ? "Define macro indirect"
- : "Undefine macro indirect");
+ ref->code == DW_MACRO_define_strp
+ ? "Define macro strp"
+ : "Undefine macro strp");
dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
(unsigned long) ref->lineno);
if (node->form == DW_FORM_strp)
@@ -25296,8 +26642,8 @@ output_macinfo_op (macinfo_entry *ref)
dw2_asm_output_data_uleb128 (node->index, "The macro: \"%s\"",
ref->info);
break;
- case DW_MACRO_GNU_transparent_include:
- dw2_asm_output_data (1, ref->code, "Transparent include");
+ case DW_MACRO_import:
+ dw2_asm_output_data (1, ref->code, "Import");
ASM_GENERATE_INTERNAL_LABEL (label,
DEBUG_MACRO_SECTION_LABEL, ref->lineno);
dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
@@ -25313,7 +26659,7 @@ output_macinfo_op (macinfo_entry *ref)
other compilation unit .debug_macinfo sections. IDX is the first
index of a define/undef, return the number of ops that should be
emitted in a comdat .debug_macinfo section and emit
- a DW_MACRO_GNU_transparent_include entry referencing it.
+ a DW_MACRO_import entry referencing it.
If the define/undef entry should be emitted normally, return 0. */
static unsigned
@@ -25399,10 +26745,10 @@ optimize_macinfo_range (unsigned int idx, vec<macinfo_entry, va_gc> *files,
for (i = 0; i < 16; i++)
sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
- /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+ /* Construct a macinfo_entry for DW_MACRO_import
in the empty vector entry before the first define/undef. */
inc = &(*macinfo_table)[idx - 1];
- inc->code = DW_MACRO_GNU_transparent_include;
+ inc->code = DW_MACRO_import;
inc->lineno = 0;
inc->info = ggc_strdup (grp_name);
if (!*macinfo_htab)
@@ -25414,7 +26760,7 @@ optimize_macinfo_range (unsigned int idx, vec<macinfo_entry, va_gc> *files,
inc->code = 0;
inc->info = NULL;
/* If such an entry has been used before, just emit
- a DW_MACRO_GNU_transparent_include op. */
+ a DW_MACRO_import op. */
inc = *slot;
output_macinfo_op (inc);
/* And clear all macinfo_entry in the range to avoid emitting them
@@ -25460,8 +26806,8 @@ save_macinfo_strings (void)
&& (debug_str_section->common.flags & SECTION_MERGE) != 0)
set_indirect_string (find_AT_string (ref->info));
break;
- case DW_MACRO_GNU_define_indirect:
- case DW_MACRO_GNU_undef_indirect:
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
set_indirect_string (find_AT_string (ref->info));
break;
default:
@@ -25485,15 +26831,16 @@ output_macinfo (void)
return;
/* output_macinfo* uses these interchangeably. */
- gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_GNU_define
- && (int) DW_MACINFO_undef == (int) DW_MACRO_GNU_undef
- && (int) DW_MACINFO_start_file == (int) DW_MACRO_GNU_start_file
- && (int) DW_MACINFO_end_file == (int) DW_MACRO_GNU_end_file);
+ gcc_assert ((int) DW_MACINFO_define == (int) DW_MACRO_define
+ && (int) DW_MACINFO_undef == (int) DW_MACRO_undef
+ && (int) DW_MACINFO_start_file == (int) DW_MACRO_start_file
+ && (int) DW_MACINFO_end_file == (int) DW_MACRO_end_file);
/* For .debug_macro emit the section header. */
- if (!dwarf_strict)
+ if (!dwarf_strict || dwarf_version >= 5)
{
- dw2_asm_output_data (2, 4, "DWARF macro version number");
+ dw2_asm_output_data (2, dwarf_version >= 5 ? 5 : 4,
+ "DWARF macro version number");
if (DWARF_OFFSET_SIZE == 8)
dw2_asm_output_data (1, 3, "Flags: 64-bit, lineptr present");
else
@@ -25507,8 +26854,7 @@ output_macinfo (void)
/* In the first loop, it emits the primary .debug_macinfo section
and after each emitted op the macinfo_entry is cleared.
If a longer range of define/undef ops can be optimized using
- DW_MACRO_GNU_transparent_include, the
- DW_MACRO_GNU_transparent_include op is emitted and kept in
+ DW_MACRO_import, the DW_MACRO_import op is emitted and kept in
the vector before the first define/undef in the range and the
whole range of define/undef ops is not emitted and kept. */
for (i = 0; macinfo_table->iterate (i, &ref); i++)
@@ -25524,7 +26870,7 @@ output_macinfo (void)
break;
case DW_MACINFO_define:
case DW_MACINFO_undef:
- if (!dwarf_strict
+ if ((!dwarf_strict || dwarf_version >= 5)
&& HAVE_COMDAT_GROUP
&& vec_safe_length (files) != 1
&& i > 0
@@ -25558,16 +26904,15 @@ output_macinfo (void)
delete macinfo_htab;
macinfo_htab = NULL;
- /* If any DW_MACRO_GNU_transparent_include were used, on those
- DW_MACRO_GNU_transparent_include entries terminate the
- current chain and switch to a new comdat .debug_macinfo
+ /* If any DW_MACRO_import were used, on those DW_MACRO_import entries
+ terminate the current chain and switch to a new comdat .debug_macinfo
section and emit the define/undef entries within it. */
for (i = 0; macinfo_table->iterate (i, &ref); i++)
switch (ref->code)
{
case 0:
continue;
- case DW_MACRO_GNU_transparent_include:
+ case DW_MACRO_import:
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
tree comdat_key = get_identifier (ref->info);
@@ -25583,7 +26928,8 @@ output_macinfo (void)
ASM_OUTPUT_LABEL (asm_out_file, label);
ref->code = 0;
ref->info = NULL;
- dw2_asm_output_data (2, 4, "DWARF macro version number");
+ dw2_asm_output_data (2, dwarf_version >= 5 ? 5 : 4,
+ "DWARF macro version number");
if (DWARF_OFFSET_SIZE == 8)
dw2_asm_output_data (1, 1, "Flags: 64-bit");
else
@@ -25612,10 +26958,13 @@ init_sections_and_labels (void)
SECTION_DEBUG, NULL);
debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
SECTION_DEBUG, NULL);
- debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ debug_loc_section = get_section (dwarf_version >= 5
+ ? DEBUG_LOCLISTS_SECTION
+ : DEBUG_LOC_SECTION,
SECTION_DEBUG, NULL);
debug_macinfo_section_name
- = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+ = (dwarf_strict && dwarf_version < 5)
+ ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG, NULL);
}
@@ -25647,12 +26996,15 @@ init_sections_and_labels (void)
NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
DEBUG_SKELETON_INFO_SECTION_LABEL, 0);
- debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
+ debug_loc_section = get_section (dwarf_version >= 5
+ ? DEBUG_DWO_LOCLISTS_SECTION
+ : DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
DEBUG_STR_DWO_SECTION_FLAGS, NULL);
debug_macinfo_section_name
- = dwarf_strict ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+ = (dwarf_strict && dwarf_version < 5)
+ ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
@@ -25667,7 +27019,13 @@ init_sections_and_labels (void)
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
- debug_ranges_section = get_section (DEBUG_RANGES_SECTION,
+ if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
+
+ debug_ranges_section = get_section (dwarf_version >= 5
+ ? DEBUG_RNGLISTS_SECTION
+ : DEBUG_RANGES_SECTION,
SECTION_DEBUG, NULL);
debug_frame_section = get_section (DEBUG_FRAME_SECTION,
SECTION_DEBUG, NULL);
@@ -25680,10 +27038,13 @@ init_sections_and_labels (void)
DEBUG_LINE_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (ranges_section_label,
DEBUG_RANGES_SECTION_LABEL, 0);
+ if (dwarf_version >= 5 && dwarf_split_debug_info)
+ ASM_GENERATE_INTERNAL_LABEL (ranges_base_label,
+ DEBUG_RANGES_SECTION_LABEL, 1);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
DEBUG_ADDR_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
- dwarf_strict
+ (dwarf_strict && dwarf_version < 5)
? DEBUG_MACINFO_SECTION_LABEL
: DEBUG_MACRO_SECTION_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
@@ -25719,11 +27080,9 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
vec_alloc (decl_scope_table, 256);
/* Allocate the initial hunk of the abbrev_die_table. */
- abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
- (ABBREV_DIE_TABLE_INCREMENT);
- abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
+ vec_alloc (abbrev_die_table, 256);
/* Zero-th entry is allocated, but unused. */
- abbrev_die_table_in_use = 1;
+ abbrev_die_table->quick_push (NULL);
/* Allocate the dwarf_proc_stack_usage_map. */
dwarf_proc_stack_usage_map = new hash_map<dw_die_ref, int>;
@@ -25843,12 +27202,12 @@ output_index_string (indirect_string_node **h, unsigned int *cur_idx)
htab_traverse. Emit one queued .debug_str string. */
int
-output_indirect_string (indirect_string_node **h, void *)
+output_indirect_string (indirect_string_node **h, enum dwarf_form form)
{
struct indirect_string_node *node = *h;
node->form = find_string_form (node);
- if (node->form == DW_FORM_strp && node->refcount > 0)
+ if (node->form == form && node->refcount > 0)
{
ASM_OUTPUT_LABEL (asm_out_file, node->label);
assemble_string (node->str, strlen (node->str) + 1);
@@ -25864,13 +27223,15 @@ output_indirect_strings (void)
{
switch_to_section (debug_str_section);
if (!dwarf_split_debug_info)
- debug_str_hash->traverse<void *, output_indirect_string> (NULL);
+ debug_str_hash->traverse<enum dwarf_form,
+ output_indirect_string> (DW_FORM_strp);
else
{
unsigned int offset = 0;
unsigned int cur_idx = 0;
- skeleton_debug_str_hash->traverse<void *, output_indirect_string> (NULL);
+ skeleton_debug_str_hash->traverse<enum dwarf_form,
+ output_indirect_string> (DW_FORM_strp);
switch_to_section (debug_str_offsets_section);
debug_str_hash->traverse_noresize
@@ -25971,6 +27332,9 @@ prune_unused_types_walk_loc_descr (dw_loc_descr_ref loc)
for (; loc != NULL; loc = loc->dw_loc_next)
switch (loc->dw_loc_opc)
{
+ case DW_OP_implicit_pointer:
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_implicit_pointer:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
@@ -25980,16 +27344,20 @@ prune_unused_types_walk_loc_descr (dw_loc_descr_ref loc)
case DW_OP_call2:
case DW_OP_call4:
case DW_OP_call_ref:
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
case DW_OP_GNU_parameter_ref:
gcc_assert (loc->dw_loc_oprnd1.val_class == dw_val_class_die_ref);
prune_unused_types_mark (loc->dw_loc_oprnd1.v.val_die_ref.die, 1);
break;
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
gcc_assert (loc->dw_loc_oprnd2.val_class == dw_val_class_die_ref);
prune_unused_types_mark (loc->dw_loc_oprnd2.v.val_die_ref.die, 1);
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
gcc_assert (loc->dw_loc_oprnd1.val_class == dw_val_class_loc);
prune_unused_types_walk_loc_descr (loc->dw_loc_oprnd1.v.val_loc);
@@ -26451,18 +27819,24 @@ mark_base_types (dw_loc_descr_ref loc)
{
switch (loc->dw_loc_opc)
{
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
base_type = loc->dw_loc_oprnd2.v.val_die_ref.die;
break;
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_unsigned_const)
continue;
/* FALLTHRU */
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
base_type = loc->dw_loc_oprnd1.v.val_die_ref.die;
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
mark_base_types (loc->dw_loc_oprnd1.v.val_loc);
continue;
@@ -26607,7 +27981,7 @@ resolve_one_addr (rtx *addr)
/* For STRING_CST, return SYMBOL_REF of its constant pool entry,
if possible, and create DW_TAG_dwarf_procedure that can be referenced
- from DW_OP_GNU_implicit_pointer if the string hasn't been seen yet. */
+ from DW_OP_implicit_pointer if the string hasn't been seen yet. */
static rtx
string_cst_pool_decl (tree t)
@@ -26649,7 +28023,7 @@ string_cst_pool_decl (tree t)
a DW_OP_addr followed by DW_OP_stack_value, either at the start
of exprloc or after DW_OP_{,bit_}piece, and val_addr can't be
resolved. Replace it (both DW_OP_addr and DW_OP_stack_value)
- with DW_OP_GNU_implicit_pointer if possible
+ with DW_OP_implicit_pointer if possible
and return true, if unsuccessful, return false. */
static bool
@@ -26688,7 +28062,7 @@ optimize_one_addr_into_implicit_ptr (dw_loc_descr_ref loc)
if (ref && (get_AT (ref, DW_AT_location)
|| get_AT (ref, DW_AT_const_value)))
{
- loc->dw_loc_opc = DW_OP_GNU_implicit_pointer;
+ loc->dw_loc_opc = dwarf_OP (DW_OP_implicit_pointer);
loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
loc->dw_loc_oprnd1.val_entry = NULL;
loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
@@ -26721,7 +28095,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
|| prev->dw_loc_opc == DW_OP_bit_piece)
&& loc->dw_loc_next
&& loc->dw_loc_next->dw_loc_opc == DW_OP_stack_value
- && !dwarf_strict
+ && (!dwarf_strict || dwarf_version >= 5)
&& optimize_one_addr_into_implicit_ptr (loc))
break;
return false;
@@ -26736,8 +28110,8 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
if (!resolve_one_addr (&rtl))
return false;
remove_addr_table_entry (loc->dw_loc_oprnd1.val_entry);
- loc->dw_loc_oprnd1.val_entry =
- add_addr_table_entry (rtl, ate_kind_rtx);
+ loc->dw_loc_oprnd1.val_entry
+ = add_addr_table_entry (rtl, ate_kind_rtx);
}
break;
case DW_OP_const4u:
@@ -26764,6 +28138,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
&& !resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr))
return false;
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
case DW_OP_GNU_parameter_ref:
if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
@@ -26777,17 +28152,25 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
}
break;
+ case DW_OP_const_type:
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_const_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
while (loc->dw_loc_next
- && loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_convert)
+ && (loc->dw_loc_next->dw_loc_opc == DW_OP_convert
+ || loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_convert))
{
dw_die_ref base1, base2;
unsigned enc1, enc2, size1, size2;
- if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+ if (loc->dw_loc_opc == DW_OP_regval_type
+ || loc->dw_loc_opc == DW_OP_deref_type
+ || loc->dw_loc_opc == DW_OP_GNU_regval_type
|| loc->dw_loc_opc == DW_OP_GNU_deref_type)
base1 = loc->dw_loc_oprnd2.v.val_die_ref.die;
else if (loc->dw_loc_oprnd1.val_class
@@ -26811,9 +28194,11 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
&& loc != keep)
|| enc1 == enc2))
{
- /* Optimize away next DW_OP_GNU_convert after
+ /* Optimize away next DW_OP_convert after
adjusting LOC's base type die reference. */
- if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+ if (loc->dw_loc_opc == DW_OP_regval_type
+ || loc->dw_loc_opc == DW_OP_deref_type
+ || loc->dw_loc_opc == DW_OP_GNU_regval_type
|| loc->dw_loc_opc == DW_OP_GNU_deref_type)
loc->dw_loc_oprnd2.v.val_die_ref.die = base2;
else
@@ -26821,7 +28206,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
continue;
}
- /* Don't change integer DW_OP_GNU_convert after e.g. floating
+ /* Don't change integer DW_OP_convert after e.g. floating
point typed stack entry. */
else if (enc1 != DW_ATE_unsigned && enc1 != DW_ATE_signed)
keep = loc->dw_loc_next;
@@ -26838,7 +28223,7 @@ resolve_addr_in_expr (dw_loc_descr_ref loc)
DW_OP_addr alone, which referred to DECL in DW_OP_addr's operand
and DW_OP_addr couldn't be resolved. resolve_addr has already
removed the DW_AT_location attribute. This function attempts to
- add a new DW_AT_location attribute with DW_OP_GNU_implicit_pointer
+ add a new DW_AT_location attribute with DW_OP_implicit_pointer
to it or DW_AT_const_value attribute, if possible. */
static void
@@ -26860,13 +28245,13 @@ optimize_location_into_implicit_ptr (dw_die_ref die, tree decl)
DW_AT_const_value instead. */
if (tree_add_const_value_attribute (die, init))
return;
- if (dwarf_strict)
+ if (dwarf_strict && dwarf_version < 5)
return;
/* If init is ADDR_EXPR or POINTER_PLUS_EXPR of ADDR_EXPR,
and ADDR_EXPR refers to a decl that has DW_AT_location or
DW_AT_const_value (but isn't addressable, otherwise
resolving the original DW_OP_addr wouldn't fail), see if
- we can add DW_OP_GNU_implicit_pointer. */
+ we can add DW_OP_implicit_pointer. */
STRIP_NOPS (init);
if (TREE_CODE (init) == POINTER_PLUS_EXPR
&& tree_fits_shwi_p (TREE_OPERAND (init, 1)))
@@ -26900,7 +28285,7 @@ optimize_location_into_implicit_ptr (dw_die_ref die, tree decl)
|| (!get_AT (ref, DW_AT_location)
&& !get_AT (ref, DW_AT_const_value)))
return;
- l = new_loc_descr (DW_OP_GNU_implicit_pointer, 0, offset);
+ l = new_loc_descr (dwarf_OP (DW_OP_implicit_pointer), 0, offset);
l->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
l->dw_loc_oprnd1.v.val_die_ref.die = ref;
l->dw_loc_oprnd1.v.val_die_ref.external = 0;
@@ -26923,6 +28308,7 @@ non_dwarf_expression (dw_loc_descr_ref l)
case DW_OP_regx:
case DW_OP_implicit_value:
case DW_OP_stack_value:
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
case DW_OP_GNU_parameter_ref:
case DW_OP_piece:
@@ -27227,8 +28613,10 @@ resolve_addr (dw_die_ref die)
remove_AT (die, a->dw_attr);
ix--;
}
- if (die->die_tag == DW_TAG_GNU_call_site
- && a->dw_attr == DW_AT_abstract_origin)
+ if ((die->die_tag == DW_TAG_call_site
+ && a->dw_attr == DW_AT_call_origin)
+ || (die->die_tag == DW_TAG_GNU_call_site
+ && a->dw_attr == DW_AT_abstract_origin))
{
tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
dw_die_ref tdie = lookup_decl_die (tdecl);
@@ -27412,12 +28800,16 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate)
inchash::add_rtx (val1->val_entry->addr.rtl, hstate);
}
break;
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
hstate.add_int (val2->v.val_int);
break;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
hstate.add_object (val1->v.val_loc);
break;
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
{
@@ -27430,6 +28822,8 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate)
hstate.add_object (encoding);
}
break;
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (val1->val_class == dw_val_class_unsigned_const)
@@ -27438,6 +28832,7 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate)
break;
}
/* FALLTHRU */
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
{
unsigned int byte_size
@@ -27446,7 +28841,8 @@ hash_loc_operands (dw_loc_descr_ref loc, inchash::hash &hstate)
= get_AT_unsigned (val1->v.val_die_ref.die, DW_AT_encoding);
hstate.add_object (byte_size);
hstate.add_object (encoding);
- if (loc->dw_loc_opc != DW_OP_GNU_const_type)
+ if (loc->dw_loc_opc != DW_OP_const_type
+ && loc->dw_loc_opc != DW_OP_GNU_const_type)
break;
hstate.add_object (val2->val_class);
switch (val2->val_class)
@@ -27639,13 +29035,16 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
rtx ay1 = valy1->val_entry->addr.rtl;
return rtx_equal_p (ax1, ay1);
}
+ case DW_OP_implicit_pointer:
case DW_OP_GNU_implicit_pointer:
return valx1->val_class == dw_val_class_die_ref
&& valx1->val_class == valy1->val_class
&& valx1->v.val_die_ref.die == valy1->v.val_die_ref.die
&& valx2->v.val_int == valy2->v.val_int;
+ case DW_OP_entry_value:
case DW_OP_GNU_entry_value:
return compare_loc_operands (valx1->v.val_loc, valy1->v.val_loc);
+ case DW_OP_const_type:
case DW_OP_GNU_const_type:
if (valx1->v.val_die_ref.die != valy1->v.val_die_ref.die
|| valx2->val_class != valy2->val_class)
@@ -27668,10 +29067,14 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y)
default:
gcc_unreachable ();
}
+ case DW_OP_regval_type:
+ case DW_OP_deref_type:
case DW_OP_GNU_regval_type:
case DW_OP_GNU_deref_type:
return valx1->v.val_int == valy1->v.val_int
&& valx2->v.val_die_ref.die == valy2->v.val_die_ref.die;
+ case DW_OP_convert:
+ case DW_OP_reinterpret:
case DW_OP_GNU_convert:
case DW_OP_GNU_reinterpret:
if (valx1->val_class != valy1->val_class)
@@ -27795,8 +29198,7 @@ index_location_lists (dw_die_ref die)
continue;
curr->begin_entry
- = add_addr_table_entry (xstrdup (curr->begin),
- ate_kind_label);
+ = add_addr_table_entry (xstrdup (curr->begin), ate_kind_label);
}
}
@@ -27878,6 +29280,7 @@ dwarf2out_finish (const char *)
{
comdat_type_node *ctnode;
dw_die_ref main_comp_unit_die;
+ unsigned char checksum[16];
/* Flush out any latecomers to the limbo party. */
flush_limbo_die_list ();
@@ -27923,6 +29326,8 @@ dwarf2out_finish (const char *)
{
limbo_die_node *cu;
main_comp_unit_die = gen_compile_unit_die (NULL);
+ if (dwarf_version >= 5)
+ main_comp_unit_die->die_tag = DW_TAG_skeleton_unit;
cu = limbo_die_list;
gcc_assert (cu->die == main_comp_unit_die);
limbo_die_list = limbo_die_list->next;
@@ -27999,17 +29404,24 @@ dwarf2out_finish (const char *)
if (have_macinfo)
add_AT_macptr (comp_unit_die (),
- dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
+ dwarf_version >= 5 ? DW_AT_macros
+ : dwarf_strict ? DW_AT_macro_info : DW_AT_GNU_macros,
macinfo_section_label);
if (dwarf_split_debug_info)
{
- /* optimize_location_lists calculates the size of the lists,
- so index them first, and assign indices to the entries.
- Although optimize_location_lists will remove entries from
- the table, it only does so for duplicates, and therefore
- only reduces ref_counts to 1. */
- index_location_lists (comp_unit_die ());
+ if (have_location_lists)
+ {
+ if (dwarf_version >= 5)
+ add_AT_loclistsptr (comp_unit_die (), DW_AT_loclists_base,
+ loc_section_label);
+ /* optimize_location_lists calculates the size of the lists,
+ so index them first, and assign indices to the entries.
+ Although optimize_location_lists will remove entries from
+ the table, it only does so for duplicates, and therefore
+ only reduces ref_counts to 1. */
+ index_location_lists (comp_unit_die ());
+ }
if (addr_index_table != NULL)
{
@@ -28020,8 +29432,14 @@ dwarf2out_finish (const char *)
}
}
+ loc_list_idx = 0;
if (have_location_lists)
- optimize_location_lists (comp_unit_die ());
+ {
+ optimize_location_lists (comp_unit_die ());
+ /* And finally assign indexes to the entries for -gsplit-dwarf. */
+ if (dwarf_version >= 5 && dwarf_split_debug_info)
+ assign_location_list_indexes (comp_unit_die ());
+ }
save_macinfo_strings ();
@@ -28041,7 +29459,7 @@ dwarf2out_finish (const char *)
/* Output all of the compilation units. We put the main one last so that
the offsets are available to output_pubnames. */
for (node = cu_die_list; node; node = node->next)
- output_comp_unit (node->die, 0);
+ output_comp_unit (node->die, 0, NULL);
hash_table<comdat_type_hasher> comdat_type_table (100);
for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -28075,9 +29493,11 @@ dwarf2out_finish (const char *)
if (dwarf_split_debug_info)
{
int mark;
- unsigned char checksum[16];
struct md5_ctx ctx;
+ if (dwarf_version >= 5 && !vec_safe_is_empty (ranges_table))
+ index_rnglists ();
+
/* Compute a checksum of the comp_unit to use as the dwo_id. */
md5_init_ctx (&ctx);
mark = 0;
@@ -28085,16 +29505,25 @@ dwarf2out_finish (const char *)
unmark_all_dies (comp_unit_die ());
md5_finish_ctx (&ctx, checksum);
- /* Use the first 8 bytes of the checksum as the dwo_id,
- and add it to both comp-unit DIEs. */
- add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
- add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
+ if (dwarf_version < 5)
+ {
+ /* Use the first 8 bytes of the checksum as the dwo_id,
+ and add it to both comp-unit DIEs. */
+ add_AT_data8 (main_comp_unit_die, DW_AT_GNU_dwo_id, checksum);
+ add_AT_data8 (comp_unit_die (), DW_AT_GNU_dwo_id, checksum);
+ }
/* Add the base offset of the ranges table to the skeleton
comp-unit DIE. */
if (!vec_safe_is_empty (ranges_table))
- add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
- ranges_section_label);
+ {
+ if (dwarf_version >= 5)
+ add_AT_lineptr (main_comp_unit_die, DW_AT_rnglists_base,
+ ranges_base_label);
+ else
+ add_AT_lineptr (main_comp_unit_die, DW_AT_GNU_ranges_base,
+ ranges_section_label);
+ }
switch_to_section (debug_addr_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_addr_section_label);
@@ -28103,13 +29532,14 @@ dwarf2out_finish (const char *)
/* Output the main compilation unit if non-empty or if .debug_macinfo
or .debug_macro will be emitted. */
- output_comp_unit (comp_unit_die (), have_macinfo);
+ output_comp_unit (comp_unit_die (), have_macinfo,
+ dwarf_split_debug_info ? checksum : NULL);
if (dwarf_split_debug_info && info_section_emitted)
- output_skeleton_debug_sections (main_comp_unit_die);
+ output_skeleton_debug_sections (main_comp_unit_die, checksum);
/* Output the abbreviation table. */
- if (abbrev_die_table_in_use != 1)
+ if (vec_safe_length (abbrev_die_table) != 1)
{
switch_to_section (debug_abbrev_section);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
@@ -28119,10 +29549,38 @@ dwarf2out_finish (const char *)
/* Output location list section if necessary. */
if (have_location_lists)
{
+ char l1[MAX_ARTIFICIAL_LABEL_BYTES];
+ char l2[MAX_ARTIFICIAL_LABEL_BYTES];
/* Output the location lists info. */
switch_to_section (debug_loc_section);
+ if (dwarf_version >= 5)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (l1, DEBUG_LOC_SECTION_LABEL, 1);
+ ASM_GENERATE_INTERNAL_LABEL (l2, DEBUG_LOC_SECTION_LABEL, 2);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating "
+ "64-bit DWARF extension");
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+ "Length of Location Lists");
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+ dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
+ dw2_asm_output_data (1, 0, "Segment Size");
+ dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0,
+ "Offset Entry Count");
+ }
ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+ if (dwarf_version >= 5 && dwarf_split_debug_info)
+ {
+ unsigned int save_loc_list_idx = loc_list_idx;
+ loc_list_idx = 0;
+ output_loclists_offsets (comp_unit_die ());
+ gcc_assert (save_loc_list_idx == loc_list_idx);
+ }
output_location_lists (comp_unit_die ());
+ if (dwarf_version >= 5)
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
}
output_pubtables ();
@@ -28141,9 +29599,10 @@ dwarf2out_finish (const char *)
/* Output ranges section if necessary. */
if (!vec_safe_is_empty (ranges_table))
{
- switch_to_section (debug_ranges_section);
- ASM_OUTPUT_LABEL (asm_out_file, ranges_section_label);
- output_ranges ();
+ if (dwarf_version >= 5)
+ output_rnglists ();
+ else
+ output_ranges ();
}
/* Have to end the macro section. */
@@ -28176,6 +29635,13 @@ dwarf2out_finish (const char *)
/* If we emitted any indirect strings, output the string table too. */
if (debug_str_hash || skeleton_debug_str_hash)
output_indirect_strings ();
+ if (debug_line_str_hash)
+ {
+ switch_to_section (debug_line_str_section);
+ const enum dwarf_form form = DW_FORM_line_strp;
+ debug_line_str_hash->traverse<enum dwarf_form,
+ output_indirect_string> (form);
+ }
}
/* Perform any cleanups needed after the early debug generation pass
@@ -28199,6 +29665,34 @@ dwarf2out_early_finish (const char *filename)
add_name_attribute (comp_unit_die (), remap_debug_filename (filename));
add_comp_dir_attribute (comp_unit_die ());
+ /* When emitting DWARF5 .debug_line_str, move DW_AT_name and
+ DW_AT_comp_dir into .debug_line_str section. */
+ if (!DWARF2_ASM_LINE_DEBUG_INFO
+ && dwarf_version >= 5
+ && DWARF5_USE_DEBUG_LINE_STR)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ dw_attr_node *a = get_AT (comp_unit_die (),
+ i ? DW_AT_comp_dir : DW_AT_name);
+ if (a == NULL
+ || AT_class (a) != dw_val_class_str
+ || strlen (AT_string (a)) + 1 <= DWARF_OFFSET_SIZE)
+ continue;
+
+ if (! debug_line_str_hash)
+ debug_line_str_hash
+ = hash_table<indirect_string_hasher>::create_ggc (10);
+
+ struct indirect_string_node *node
+ = find_AT_string_in_table (AT_string (a), debug_line_str_hash);
+ set_indirect_string (node);
+ node->form = DW_FORM_line_strp;
+ a->dw_attr_val.v.val_str->refcount--;
+ a->dw_attr_val.v.val_str = node;
+ }
+ }
+
/* With LTO early dwarf was really finished at compile-time, so make
sure to adjust the phase after annotating the LTRANS CU DIE. */
if (in_lto_p)
@@ -28304,12 +29798,14 @@ dwarf2out_c_finalize (void)
debug_pubnames_section = NULL;
debug_pubtypes_section = NULL;
debug_str_section = NULL;
+ debug_line_str_section = NULL;
debug_str_dwo_section = NULL;
debug_str_offsets_section = NULL;
debug_ranges_section = NULL;
debug_frame_section = NULL;
fde_vec = NULL;
debug_str_hash = NULL;
+ debug_line_str_hash = NULL;
skeleton_debug_str_hash = NULL;
dw2_string_counter = 0;
have_multiple_function_sections = false;
@@ -28332,8 +29828,6 @@ dwarf2out_c_finalize (void)
tail_call_site_count = -1;
cached_dw_loc_list_table = NULL;
abbrev_die_table = NULL;
- abbrev_die_table_allocated = 0;
- abbrev_die_table_in_use = 0;
delete dwarf_proc_stack_usage_map;
dwarf_proc_stack_usage_map = NULL;
line_info_label_num = 0;
@@ -28347,6 +29841,7 @@ dwarf2out_c_finalize (void)
macinfo_table = NULL;
ranges_table = NULL;
ranges_by_label = NULL;
+ rnglist_idx = 0;
have_location_lists = false;
loclabel_num = 0;
poc_label_num = 0;
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index abf05505900..ae1af572f5d 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -147,13 +147,17 @@ enum dw_val_class
dw_val_class_lineptr,
dw_val_class_str,
dw_val_class_macptr,
+ dw_val_class_loclistsptr,
dw_val_class_file,
dw_val_class_data8,
dw_val_class_decl_ref,
dw_val_class_vms_delta,
dw_val_class_high_pc,
dw_val_class_discr_value,
- dw_val_class_discr_list
+ dw_val_class_discr_list,
+ dw_val_class_const_implicit,
+ dw_val_class_unsigned_const_implicit,
+ dw_val_class_file_implicit
};
/* Describe a floating point constant value, or a vector constant value. */
@@ -198,7 +202,8 @@ struct GTY(()) dw_val_node {
dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
HOST_WIDE_INT GTY ((default)) val_int;
- unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
+ unsigned HOST_WIDE_INT
+ GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
wide_int_ptr GTY ((tag ("dw_val_class_wide_int"))) val_wide;
dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
@@ -212,6 +217,8 @@ struct GTY(()) dw_val_node {
char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
+ struct dwarf_file_data *
+ GTY ((tag ("dw_val_class_file_implicit"))) val_file_implicit;
unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
tree GTY ((tag ("dw_val_class_decl_ref"))) val_decl_ref;
struct dw_val_vms_delta_union
@@ -234,9 +241,9 @@ struct GTY((chain_next ("%h.dw_loc_next"))) dw_loc_descr_node {
/* Used to distinguish DW_OP_addr with a direct symbol relocation
from DW_OP_addr with a dtp-relative symbol relocation. */
unsigned int dtprel : 1;
- /* For DW_OP_pick operations: true iff. it targets a DWARF prodecure
- argument. In this case, it needs to be relocated according to the current
- frame offset. */
+ /* For DW_OP_pick, DW_OP_dup and DW_OP_over operations: true iff.
+ it targets a DWARF prodecure argument. In this case, it needs to be
+ relocated according to the current frame offset. */
unsigned int frame_offset_rel : 1;
int dw_loc_addr;
dw_val_node dw_loc_oprnd1;
@@ -322,6 +329,7 @@ struct array_descr_info
tree allocated;
tree associated;
tree stride;
+ tree rank;
bool stride_in_bits;
struct array_descr_dimen
{
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 8afcfbec98a..9ea0c8fb888 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3354,9 +3354,8 @@ prev_nonnote_insn (rtx_insn *insn)
not look inside SEQUENCEs. */
rtx_insn *
-prev_nonnote_insn_bb (rtx uncast_insn)
+prev_nonnote_insn_bb (rtx_insn *insn)
{
- rtx_insn *insn = safe_as_a <rtx_insn *> (uncast_insn);
while (insn)
{
@@ -4813,7 +4812,7 @@ emit_pattern_before (rtx pattern, rtx uncast_before, bool skip_debug_insns,
insnp, make_raw);
else
return emit_pattern_before_noloc (pattern, before,
- insnp ? before : NULL_RTX,
+ insnp ? before : NULL_RTX,
NULL, make_raw);
}
@@ -6169,17 +6168,19 @@ emit_copy_of_insn_after (rtx_insn *insn, rtx_insn *after)
which may be duplicated by the basic block reordering code. */
RTX_FRAME_RELATED_P (new_rtx) = RTX_FRAME_RELATED_P (insn);
+ /* Locate the end of existing REG_NOTES in NEW_RTX. */
+ rtx *ptail = &REG_NOTES (new_rtx);
+ while (*ptail != NULL_RTX)
+ ptail = &XEXP (*ptail, 1);
+
/* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
will make them. REG_LABEL_TARGETs are created there too, but are
supposed to be sticky, so we copy them. */
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
{
- if (GET_CODE (link) == EXPR_LIST)
- add_reg_note (new_rtx, REG_NOTE_KIND (link),
- copy_insn_1 (XEXP (link, 0)));
- else
- add_shallow_copy_of_reg_note (new_rtx, link);
+ *ptail = duplicate_reg_note (link);
+ ptail = &XEXP (*ptail, 1);
}
INSN_CODE (new_rtx) = INSN_CODE (insn);
diff --git a/gcc/except.c b/gcc/except.c
index f0a1be0099f..e811b56074d 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -909,7 +909,7 @@ assign_filter_values (void)
first instruction of some existing BB and return the newly
produced block. */
static basic_block
-emit_to_new_bb_before (rtx_insn *seq, rtx insn)
+emit_to_new_bb_before (rtx_insn *seq, rtx_insn *insn)
{
rtx_insn *last;
basic_block bb;
diff --git a/gcc/expr.c b/gcc/expr.c
index 6420e278f3d..0b0946de345 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -2591,7 +2591,7 @@ maybe_emit_group_store (rtx x, tree type)
This is used on targets that return BLKmode values in registers. */
-void
+static void
copy_blkmode_from_reg (rtx target, rtx srcreg, tree type)
{
unsigned HOST_WIDE_INT bytes = int_size_in_bytes (type);
@@ -7681,10 +7681,6 @@ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
}
else
{
- /* If we need to preserve evaluation order, copy exp0 into its own
- temporary variable so that it can't be clobbered by exp1. */
- if (flag_evaluation_order && TREE_SIDE_EFFECTS (exp1))
- exp0 = save_expr (exp0);
*op0 = expand_expr (exp0, target, VOIDmode, modifier);
*op1 = expand_expr (exp1, NULL_RTX, VOIDmode, modifier);
}
@@ -10422,10 +10418,35 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
{
if (bitpos == 0
&& bitsize == GET_MODE_BITSIZE (GET_MODE (op0))
- && COMPLEX_MODE_P (mode1))
+ && COMPLEX_MODE_P (mode1)
+ && COMPLEX_MODE_P (GET_MODE (op0))
+ && (GET_MODE_PRECISION (GET_MODE_INNER (mode1))
+ == GET_MODE_PRECISION (GET_MODE_INNER (GET_MODE (op0)))))
{
if (reversep)
op0 = flip_storage_order (GET_MODE (op0), op0);
+ if (mode1 != GET_MODE (op0))
+ {
+ rtx parts[2];
+ for (int i = 0; i < 2; i++)
+ {
+ rtx op = read_complex_part (op0, i != 0);
+ if (GET_CODE (op) == SUBREG)
+ op = force_reg (GET_MODE (op), op);
+ rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1),
+ op);
+ if (temp)
+ op = temp;
+ else
+ {
+ if (!REG_P (op) && !MEM_P (op))
+ op = force_reg (GET_MODE (op), op);
+ op = gen_lowpart (GET_MODE_INNER (mode1), op);
+ }
+ parts[i] = op;
+ }
+ op0 = gen_rtx_CONCAT (mode1, parts[0], parts[1]);
+ }
return op0;
}
if (bitpos == 0
diff --git a/gcc/expr.h b/gcc/expr.h
index a77f6e53cd3..558721d7d8a 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -146,9 +146,6 @@ extern void emit_group_store (rtx, rtx, tree, int);
extern rtx maybe_emit_group_store (rtx, tree);
-/* Copy BLKmode object from a set of registers. */
-extern void copy_blkmode_from_reg (rtx, rtx, tree);
-
/* Mark REG as holding a parameter for the next CALL_INSN.
Mode is TYPE_MODE of the non-promoted parameter, or VOIDmode. */
extern void use_reg_mode (rtx *, rtx, machine_mode);
diff --git a/gcc/final.c b/gcc/final.c
index 36ef755aec8..5709d0e2406 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -214,7 +214,7 @@ static void leaf_renumber_regs (rtx_insn *);
static int alter_cond (rtx);
#endif
#ifndef ADDR_VEC_ALIGN
-static int final_addr_vec_align (rtx);
+static int final_addr_vec_align (rtx_insn *);
#endif
static int align_fuzz (rtx, rtx, int, unsigned);
static void collect_fn_hard_reg_usage (void);
@@ -513,7 +513,7 @@ default_jump_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
#ifndef ADDR_VEC_ALIGN
static int
-final_addr_vec_align (rtx addr_vec)
+final_addr_vec_align (rtx_insn *addr_vec)
{
int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
@@ -2323,6 +2323,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
/* Mark this block as output. */
TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
+ BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
}
if (write_symbols == DBX_DEBUG
|| write_symbols == SDB_DEBUG)
@@ -2355,6 +2356,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
if (!DECL_IGNORED_P (current_function_decl))
debug_hooks->end_block (high_block_linenum, n);
+ gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
+ == in_cold_section_p);
}
if (write_symbols == DBX_DEBUG
|| write_symbols == SDB_DEBUG)
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index 05a15f974e9..1b3a755df34 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "case-cfn-macros.h"
#include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */
#include "builtins.h"
+#include "gimple-expr.h"
/* Functions that test for certain constant types, abstracting away the
decision about whether to check for overflow. */
@@ -57,7 +58,8 @@ complex_cst_p (tree t)
static inline bool
host_size_t_cst_p (tree t, size_t *size_out)
{
- if (integer_cst_p (t)
+ if (types_compatible_p (size_type_node, TREE_TYPE (t))
+ && integer_cst_p (t)
&& wi::min_precision (t, UNSIGNED) <= sizeof (size_t) * CHAR_BIT)
{
*size_out = tree_to_uhwi (t);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index fb6e45dd393..b78b6d855a1 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -80,10 +80,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssanames.h"
#include "selftest.h"
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
/* Nonzero if we are folding constants inside an initializer; zero
otherwise. */
int folding_initializer = 0;
@@ -137,7 +133,6 @@ static tree fold_binary_op_with_conditional_arg (location_t,
tree, tree,
tree, tree, int);
static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree);
-static bool reorder_operands_p (const_tree, const_tree);
static tree fold_negate_const (tree, tree);
static tree fold_not_const (const_tree, tree);
static tree fold_relational_const (enum tree_code, tree, tree, tree);
@@ -439,9 +434,7 @@ negate_expr_p (tree t)
&& ! TYPE_OVERFLOW_WRAPS (type)))
return false;
/* -(A + B) -> (-B) - A. */
- if (negate_expr_p (TREE_OPERAND (t, 1))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)))
+ if (negate_expr_p (TREE_OPERAND (t, 1)))
return true;
/* -(A + B) -> (-A) - B. */
return negate_expr_p (TREE_OPERAND (t, 0));
@@ -451,9 +444,7 @@ negate_expr_p (tree t)
return !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type))
&& !HONOR_SIGNED_ZEROS (element_mode (type))
&& (! INTEGRAL_TYPE_P (type)
- || TYPE_OVERFLOW_WRAPS (type))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
+ || TYPE_OVERFLOW_WRAPS (type));
case MULT_EXPR:
if (TYPE_UNSIGNED (type))
@@ -610,9 +601,7 @@ fold_negate_expr (location_t loc, tree t)
&& !HONOR_SIGNED_ZEROS (element_mode (type)))
{
/* -(A + B) -> (-B) - A. */
- if (negate_expr_p (TREE_OPERAND (t, 1))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)))
+ if (negate_expr_p (TREE_OPERAND (t, 1)))
{
tem = negate_expr (TREE_OPERAND (t, 1));
return fold_build2_loc (loc, MINUS_EXPR, type,
@@ -632,8 +621,7 @@ fold_negate_expr (location_t loc, tree t)
case MINUS_EXPR:
/* - (A - B) -> B - A */
if (!HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type))
- && !HONOR_SIGNED_ZEROS (element_mode (type))
- && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
+ && !HONOR_SIGNED_ZEROS (element_mode (type)))
return fold_build2_loc (loc, MINUS_EXPR, type,
TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
break;
@@ -5082,12 +5070,10 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
case EQ_EXPR:
case UNEQ_EXPR:
tem = fold_convert_loc (loc, arg1_type, arg1);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type,
- negate_expr (tem)));
+ return fold_convert_loc (loc, type, negate_expr (tem));
case NE_EXPR:
case LTGT_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
case UNGE_EXPR:
case UNGT_EXPR:
if (flag_trapping_math)
@@ -5098,7 +5084,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
break;
tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1);
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
case UNLE_EXPR:
case UNLT_EXPR:
if (flag_trapping_math)
@@ -5124,7 +5110,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
&& integer_zerop (arg01) && integer_zerop (arg2))
{
if (comp_code == NE_EXPR)
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
else if (comp_code == EQ_EXPR)
return build_zero_cst (type);
}
@@ -5170,20 +5156,12 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
tree comp_op1 = arg01;
tree comp_type = TREE_TYPE (comp_op0);
- /* Avoid adding NOP_EXPRs in case this is an lvalue. */
- if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
- {
- comp_type = type;
- comp_op0 = arg1;
- comp_op1 = arg2;
- }
-
switch (comp_code)
{
case EQ_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg2));
+ return fold_convert_loc (loc, type, arg2);
case NE_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
case LE_EXPR:
case LT_EXPR:
case UNLE_EXPR:
@@ -5200,8 +5178,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
? fold_build2_loc (loc, MIN_EXPR, comp_type, comp_op0, comp_op1)
: fold_build2_loc (loc, MIN_EXPR, comp_type,
comp_op1, comp_op0);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
case GE_EXPR:
@@ -5216,19 +5193,16 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
? fold_build2_loc (loc, MAX_EXPR, comp_type, comp_op0, comp_op1)
: fold_build2_loc (loc, MAX_EXPR, comp_type,
comp_op1, comp_op0);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
case UNEQ_EXPR:
if (!HONOR_NANS (arg1))
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, arg2));
+ return fold_convert_loc (loc, type, arg2);
break;
case LTGT_EXPR:
if (!HONOR_NANS (arg1))
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
break;
default:
gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison);
@@ -5267,8 +5241,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
fold_convert_loc (loc, TREE_TYPE (arg00),
arg2));
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
@@ -5285,8 +5258,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
fold_convert_loc (loc, TREE_TYPE (arg00),
arg2));
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
@@ -5303,7 +5275,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
fold_convert_loc (loc, TREE_TYPE (arg00),
arg2));
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
@@ -5319,7 +5291,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type,
tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
fold_convert_loc (loc, TREE_TYPE (arg00),
arg2));
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
case NE_EXPR:
@@ -6781,27 +6753,12 @@ fold_single_bit_test (location_t loc, enum tree_code code,
return NULL_TREE;
}
-/* Check whether we are allowed to reorder operands arg0 and arg1,
- such that the evaluation of arg1 occurs before arg0. */
-
-static bool
-reorder_operands_p (const_tree arg0, const_tree arg1)
-{
- if (! flag_evaluation_order)
- return true;
- if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1))
- return true;
- return ! TREE_SIDE_EFFECTS (arg0)
- && ! TREE_SIDE_EFFECTS (arg1);
-}
-
/* Test whether it is preferable two swap two operands, ARG0 and
ARG1, for example because ARG0 is an integer constant and ARG1
- isn't. If REORDER is true, only recommend swapping if we can
- evaluate the operands in reverse order. */
+ isn't. */
bool
-tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder)
+tree_swap_operands_p (const_tree arg0, const_tree arg1, bool)
{
if (CONSTANT_CLASS_P (arg1))
return 0;
@@ -6816,10 +6773,6 @@ tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder)
if (TREE_CONSTANT (arg0))
return 1;
- if (reorder && flag_evaluation_order
- && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
- return 0;
-
/* It is preferable to swap two SSA_NAME to ensure a canonical form
for commutative and comparison operators. Ensuring a canonical
form allows the optimizers to find additional redundancies without
@@ -9244,8 +9197,7 @@ fold_binary_loc (location_t loc,
return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
tem);
}
- if (TREE_CODE (arg1) == COMPOUND_EXPR
- && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+ if (TREE_CODE (arg1) == COMPOUND_EXPR)
{
tem = fold_build2_loc (loc, code, type, op0,
fold_convert_loc (loc, TREE_TYPE (op1),
@@ -9734,8 +9686,7 @@ fold_binary_loc (location_t loc,
case MINUS_EXPR:
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
- && negate_expr_p (op1)
- && reorder_operands_p (arg0, arg1))
+ && negate_expr_p (op1))
return fold_build2_loc (loc, MINUS_EXPR, type,
negate_expr (op1),
fold_convert_loc (loc, type,
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 625189fd8e8..bb0beb713e9 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,177 @@
+2016-11-09 Paul Thomas <pault@gcc.gnu.org>
+
+ * check.c (gfc_check_move_alloc): Prevent error that avoids
+ aliasing between to and from arguments from rejecting valid
+ code.
+
+2016-11-09 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/71894
+ * class.c (gfc_add_component_ref): Add safety checks to avoid ICE.
+
+2016-11-08 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/68440
+ * expr.c (check_alloc_comp_init): Loosen an assert.
+ * resolve.c (resolve_fl_parameter): Reject class parameters.
+
+2016-11-08 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/77596
+ * expr.c (gfc_check_pointer_assign): Add special check for procedure-
+ pointer component with absent interface.
+
+2016-11-07 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78226
+ * expr.c (gfc_generate_initializer): Add where to EXPR_NULL
+ statement.
+ * iresolve.c (gfc_resolve_extends_type_of): Add where to
+ both arguments of the function.
+ * resolve.c (resolve_select_type): Add where to the
+ second argument of the new statement.
+
+2016-11-07 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78226
+ * match.c (gfc_match_select_type): Add where for expr1.
+ * resolve.c (resolev_select_type): Add where for expr1 of new
+ statement.
+
+2016-11-06 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78226
+ resolve.c (build_loc_call): Add location to return value.
+
+2016-11-06 Andre Vehreschild <vehre@gcc.gnu.org>
+
+ * expr.c (is_non_empty_structure_constructor): New function to detect
+ non-empty structure constructor.
+ (gfc_has_default_initializer): Analyse initializers.
+ * resolve.c (cond_init): Removed.
+ (resolve_allocate_expr): Removed dead code. Moved invariant code out
+ of the loop over all objects to allocate.
+ (resolve_allocate_deallocate): Added the invariant code remove from
+ resolve_allocate_expr.
+ * trans-array.c (gfc_array_allocate): Removed nullify of structure
+ components in favour of doing this in gfc_trans_allocate for both
+ scalars and arrays in the same place.
+ * trans-expr.c (gfc_trans_init_assign): Always using _vptr->copy for
+ class objects.
+ * trans-stmt.c (allocate_get_initializer): Get the initializer
+ expression for object allocated.
+ (gfc_trans_allocate): Nullify a derived type only, when no SOURCE=
+ or MOLD= is present preventing duplicate work. Moved the creation
+ of the init-expression here to prevent code for conditions that
+ can not occur on freshly allocated object, like checking for the need
+ to free allocatable components.
+
+2016-11-06 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78221
+ * arith.c (gfc_complex2real): Change gfc_warning_now to
+ gfc_warning.
+
+2016-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ * check.c (gfc_check_move_alloc): Introduce error to prevent
+ aliasing between to and from arguments.
+
+2016-11-05 Janus Weil <janus@gcc.gnu.org>
+ Manuel Lopez-Ibanez <manu@gcc.gnu.org>
+
+ PR fortran/69495
+ * invoke.texi: Mention -Wpedantic as an alias of -pedantic.
+ * check.c (gfc_check_transfer): Mention responsible flag in warning
+ message.
+ * frontend-passes.c (do_warn_function_elimination): Ditto.
+ * resolve.c (resolve_elemental_actual): Ditto.
+ (resolve_operator): Ditto.
+ (warn_unused_fortran_label): Ditto.
+ * trans-common.c (translate_common): Ditto.
+
+2016-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/67564
+ * trans-expr.c (gfc_conv_class_to_class): Return _len component
+ of unlimited polymorphic entities.
+
+2016-11-04 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/64933
+ * primary.c (gfc_match_varspec): If selector expression is
+ unambiguously an array, make sure that the associate name
+ is an array and has an array spec. Modify the original
+ condition for doing this to exclude character types.
+
+2016-11-03 Fritz Reese <fritzoreese@gmail.com>
+
+ * gfortran.texi: Document.
+ * gfortran.h (gfc_dt): New field default_exp.
+ * primary.c (match_real_constant): Default exponent with -fdec.
+ * io.c (match_io): Set dt.default_exp with -fdec.
+ * ioparm.def (IOPARM_dt_default_exp): New.
+ * trans-io.c (build_dt): Set IOPARM_dt_default_exp with -fdec.
+
+2016-11-03 Fritz O. Reese <fritzoreese@gmail.com>
+
+ * decl.c (gfc_match_parameter): Allow omitted '()' with -std=legacy.
+ * parse.c (decode_statement): Match "parameter" before assignments.
+ * gfortran.texi: Document.
+
+2016-11-02 Fritz O. Reese <fritzoreese@gmail.com>
+
+ * lang.opt, invoke.texi: New argument -Wargument-mismatch.
+ * interface.c (compare_parameter, compare_actual_formal,
+ gfc_check_typebound_override, argument_rank_mismatch): Control argument
+ mismatch warnings with -Wargument-mismatch.
+ * resolve.c (resolve_structure_cons, resolve_global_procedure): Ditto.
+
+2016-11-02 Fritz Reese <fritzoreese@gmail.com>
+
+ * gfortran.h (gfc_error): New declaration for gfc_error with 'opt'.
+ * error.c (gfc_error): Add optional 'opt' argument.
+ * error.c (gfc_notify_std): Call fully-qualified gfc_error.
+
+2016-11-01 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78178
+ * match.c (match_simple_where): Fill in locus for assigment
+ in simple WHERE statement.
+
+2016-11-01 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/69544
+ * match.c (gfc_match_where): Fill in locus for assigment
+ in simple WHERE statement.
+
+2016-10-31 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/54679
+ * io.c (check_format): Adjust checks for FMT_L to treat a zero
+ width as an extension, giving warnings or error as appropriate.
+ Improve messages.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ * trans-types.c (gfc_get_array_descr_info): For -gdwarf-5 or
+ -gno-strict-dwarf, handle assumed rank arrays the way dwarf2out
+ expects.
+
+2016-10-30 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/67219
+ * arith.c (gfc_int2real): Change gfc_warning_now
+ to gfc_warning.
+ * primary.c (match_complex_constant): If there
+ is no comma, throw away any warning which might have
+ been issued by gfc_int2real.
+
+2016-10-28 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/71891
+ * symbol.c (gfc_type_compatible): Fix typo.
+
2016-10-27 Jakub Jelinek <jakub@redhat.com>
PR fortran/78026
diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c
index 8af75400d80..2781f103841 100644
--- a/gcc/fortran/arith.c
+++ b/gcc/fortran/arith.c
@@ -2072,11 +2072,11 @@ gfc_int2real (gfc_expr *src, int kind)
if (warn_conversion
&& wprecision_int_real (src->value.integer, result->value.real))
- gfc_warning_now (OPT_Wconversion, "Change of value in conversion "
- "from %qs to %qs at %L",
- gfc_typename (&src->ts),
- gfc_typename (&result->ts),
- &src->where);
+ gfc_warning (OPT_Wconversion, "Change of value in conversion "
+ "from %qs to %qs at %L",
+ gfc_typename (&src->ts),
+ gfc_typename (&result->ts),
+ &src->where);
return result;
}
@@ -2369,10 +2369,10 @@ gfc_complex2real (gfc_expr *src, int kind)
/* See if we discarded an imaginary part. */
if (mpfr_cmp_si (mpc_imagref (src->value.complex), 0) != 0)
{
- gfc_warning_now (w, "Non-zero imaginary part discarded "
- "in conversion from %qs to %qs at %L",
- gfc_typename(&src->ts), gfc_typename (&result->ts),
- &src->where);
+ gfc_warning (w, "Non-zero imaginary part discarded "
+ "in conversion from %qs to %qs at %L",
+ gfc_typename(&src->ts), gfc_typename (&result->ts),
+ &src->where);
did_warn = true;
}
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index ff5e80b9df5..265fe22594f 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -880,7 +880,7 @@ gfc_check_a_p (gfc_expr *a, gfc_expr *p)
if (a->ts.kind != p->ts.kind)
{
- if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
+ if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
&p->where))
return false;
}
@@ -1797,7 +1797,7 @@ gfc_check_count (gfc_expr *mask, gfc_expr *dim, gfc_expr *kind)
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -2127,11 +2127,11 @@ gfc_check_eoshift (gfc_expr *array, gfc_expr *shift, gfc_expr *boundary,
}
else if (boundary->rank == array->rank - 1)
{
- if (!gfc_check_conformance (shift, boundary,
+ if (!gfc_check_conformance (shift, boundary,
"arguments '%s' and '%s' for "
- "intrinsic %s",
- gfc_current_intrinsic_arg[1]->name,
- gfc_current_intrinsic_arg[2]->name,
+ "intrinsic %s",
+ gfc_current_intrinsic_arg[1]->name,
+ gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic))
return false;
}
@@ -2156,7 +2156,7 @@ gfc_check_float (gfc_expr *a)
if ((a->ts.kind != gfc_default_integer_kind)
&& !gfc_notify_std (GFC_STD_GNU, "non-default INTEGER "
- "kind argument to %s intrinsic at %L",
+ "kind argument to %s intrinsic at %L",
gfc_current_intrinsic, &a->where))
return false;
@@ -2283,7 +2283,7 @@ gfc_check_iand (gfc_expr *i, gfc_expr *j)
if (i->ts.kind != j->ts.kind)
{
- if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
+ if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
&i->where))
return false;
}
@@ -2329,7 +2329,7 @@ gfc_check_ichar_iachar (gfc_expr *c, gfc_expr *kind)
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -2409,7 +2409,7 @@ gfc_check_ieor (gfc_expr *i, gfc_expr *j)
if (i->ts.kind != j->ts.kind)
{
- if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
+ if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
&i->where))
return false;
}
@@ -2432,7 +2432,7 @@ gfc_check_index (gfc_expr *string, gfc_expr *substring, gfc_expr *back,
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -2483,7 +2483,7 @@ gfc_check_ior (gfc_expr *i, gfc_expr *j)
if (i->ts.kind != j->ts.kind)
{
- if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
+ if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
&i->where))
return false;
}
@@ -2633,7 +2633,7 @@ gfc_check_lbound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -2678,7 +2678,7 @@ gfc_check_len_lentrim (gfc_expr *s, gfc_expr *kind)
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -2948,7 +2948,7 @@ gfc_check_min_max (gfc_actual_arglist *arg)
if (x->ts.type == BT_CHARACTER)
{
if (!gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with CHARACTER argument at %L",
+ "with CHARACTER argument at %L",
gfc_current_intrinsic, &x->where))
return false;
}
@@ -3118,10 +3118,10 @@ gfc_check_minloc_maxloc (gfc_actual_arglist *ap)
return false;
if (m != NULL
- && !gfc_check_conformance (a, m,
- "arguments '%s' and '%s' for intrinsic %s",
- gfc_current_intrinsic_arg[0]->name,
- gfc_current_intrinsic_arg[2]->name,
+ && !gfc_check_conformance (a, m,
+ "arguments '%s' and '%s' for intrinsic %s",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic))
return false;
@@ -3172,10 +3172,10 @@ check_reduction (gfc_actual_arglist *ap)
return false;
if (m != NULL
- && !gfc_check_conformance (a, m,
- "arguments '%s' and '%s' for intrinsic %s",
- gfc_current_intrinsic_arg[0]->name,
- gfc_current_intrinsic_arg[2]->name,
+ && !gfc_check_conformance (a, m,
+ "arguments '%s' and '%s' for intrinsic %s",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic))
return false;
@@ -3342,6 +3342,46 @@ gfc_check_move_alloc (gfc_expr *from, gfc_expr *to)
return false;
}
+ /* This is based losely on F2003 12.4.1.7. It is intended to prevent
+ the likes of to = sym->cmp1->cmp2 and from = sym->cmp1, where cmp1
+ and cmp2 are allocatable. After the allocation is transferred,
+ the 'to' chain is broken by the nullification of the 'from'. A bit
+ of reflection reveals that this can only occur for derived types
+ with recursive allocatable components. */
+ if (to->expr_type == EXPR_VARIABLE && from->expr_type == EXPR_VARIABLE
+ && !strcmp (to->symtree->n.sym->name, from->symtree->n.sym->name))
+ {
+ gfc_ref *to_ref, *from_ref;
+ to_ref = to->ref;
+ from_ref = from->ref;
+ bool aliasing = true;
+
+ for (; from_ref && to_ref;
+ from_ref = from_ref->next, to_ref = to_ref->next)
+ {
+ if (to_ref->type != from->ref->type)
+ aliasing = false;
+ else if (to_ref->type == REF_ARRAY
+ && to_ref->u.ar.type != AR_FULL
+ && from_ref->u.ar.type != AR_FULL)
+ /* Play safe; assume sections and elements are different. */
+ aliasing = false;
+ else if (to_ref->type == REF_COMPONENT
+ && to_ref->u.c.component != from_ref->u.c.component)
+ aliasing = false;
+
+ if (!aliasing)
+ break;
+ }
+
+ if (aliasing)
+ {
+ gfc_error ("The FROM and TO arguments at %L violate aliasing "
+ "restrictions (F2003 12.4.1.7)", &to->where);
+ return false;
+ }
+ }
+
/* CLASS arguments: Make sure the vtab of from is present. */
if (to->ts.type == BT_CLASS && !UNLIMITED_POLY (from))
gfc_find_vtab (&from->ts);
@@ -3447,10 +3487,10 @@ gfc_check_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector)
if (!type_check (mask, 1, BT_LOGICAL))
return false;
- if (!gfc_check_conformance (array, mask,
- "arguments '%s' and '%s' for intrinsic '%s'",
- gfc_current_intrinsic_arg[0]->name,
- gfc_current_intrinsic_arg[1]->name,
+ if (!gfc_check_conformance (array, mask,
+ "arguments '%s' and '%s' for intrinsic '%s'",
+ gfc_current_intrinsic_arg[0]->name,
+ gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic))
return false;
@@ -3989,7 +4029,7 @@ gfc_check_scan (gfc_expr *x, gfc_expr *y, gfc_expr *z, gfc_expr *kind)
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -4050,7 +4090,7 @@ gfc_check_selected_real_kind (gfc_expr *p, gfc_expr *r, gfc_expr *radix)
{
if (p == NULL && r == NULL
&& !gfc_notify_std (GFC_STD_F2008, "SELECTED_REAL_KIND with"
- " neither %<P%> nor %<R%> argument at %L",
+ " neither %<P%> nor %<R%> argument at %L",
gfc_current_intrinsic_where))
return false;
@@ -4081,7 +4121,7 @@ gfc_check_selected_real_kind (gfc_expr *p, gfc_expr *r, gfc_expr *radix)
return false;
if (!gfc_notify_std (GFC_STD_F2008, "%qs intrinsic with "
- "RADIX argument at %L", gfc_current_intrinsic,
+ "RADIX argument at %L", gfc_current_intrinsic,
&radix->where))
return false;
}
@@ -4123,7 +4163,7 @@ gfc_check_shape (gfc_expr *source, gfc_expr *kind)
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -4178,7 +4218,7 @@ gfc_check_size (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -4621,9 +4661,9 @@ gfc_check_c_loc (gfc_expr *x)
&x->where);
return false;
}
-
+
if (x->rank
- && !gfc_notify_std (GFC_STD_F2008_TS,
+ && !gfc_notify_std (GFC_STD_F2008_TS,
"Noninteroperable array at %L as"
" argument to C_LOC: %s", &x->where, msg))
return false;
@@ -4634,7 +4674,7 @@ gfc_check_c_loc (gfc_expr *x)
if (ar->as->type != AS_EXPLICIT && ar->as->type != AS_ASSUMED_SIZE
&& !attr.allocatable
- && !gfc_notify_std (GFC_STD_F2008,
+ && !gfc_notify_std (GFC_STD_F2008,
"Array of interoperable type at %L "
"to C_LOC which is nonallocatable and neither "
"assumed size nor explicit size", &x->where))
@@ -4669,7 +4709,7 @@ gfc_check_sngl (gfc_expr *a)
if ((a->ts.kind != gfc_default_double_kind)
&& !gfc_notify_std (GFC_STD_GNU, "non double precision "
- "REAL argument to %s intrinsic at %L",
+ "REAL argument to %s intrinsic at %L",
gfc_current_intrinsic, &a->where))
return false;
@@ -5182,12 +5222,13 @@ gfc_check_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size)
/* If we can't calculate the sizes, we cannot check any more.
Return true for that case. */
- if (!gfc_calculate_transfer_sizes (source, mold, size, &source_size,
+ if (!gfc_calculate_transfer_sizes (source, mold, size, &source_size,
&result_size, NULL))
return true;
if (source_size < result_size)
- gfc_warning (0, "Intrinsic TRANSFER at %L has partly undefined result: "
+ gfc_warning (OPT_Wsurprising,
+ "Intrinsic TRANSFER at %L has partly undefined result: "
"source size %ld < result size %ld", &source->where,
(long) source_size, (long) result_size);
@@ -5220,7 +5261,7 @@ gfc_check_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
@@ -5349,7 +5390,7 @@ gfc_check_verify (gfc_expr *x, gfc_expr *y, gfc_expr *z, gfc_expr *kind)
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
- "with KIND argument at %L",
+ "with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index 400c22abaf5..b7f68d2f19a 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -224,7 +224,8 @@ gfc_add_component_ref (gfc_expr *e, const char *name)
break;
tail = &((*tail)->next);
}
- if (derived->components->next->ts.type == BT_DERIVED &&
+ if (derived->components && derived->components->next &&
+ derived->components->next->ts.type == BT_DERIVED &&
derived->components->next->ts.u.derived == NULL)
{
/* Fix up missing vtype. */
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index f18eb41bc50..0120cebb322 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -7821,10 +7821,16 @@ cleanup:
match
gfc_match_parameter (void)
{
+ const char *term = " )%t";
match m;
if (gfc_match_char ('(') == MATCH_NO)
- return MATCH_NO;
+ {
+ /* With legacy PARAMETER statements, don't expect a terminating ')'. */
+ if (!gfc_notify_std (GFC_STD_LEGACY, "PARAMETER without '()' at %C"))
+ return MATCH_NO;
+ term = " %t";
+ }
for (;;)
{
@@ -7832,7 +7838,7 @@ gfc_match_parameter (void)
if (m != MATCH_YES)
break;
- if (gfc_match (" )%t") == MATCH_YES)
+ if (gfc_match (term) == MATCH_YES)
break;
if (gfc_match_char (',') != MATCH_YES)
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index fe91419ce44..0fd8a4e74e3 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -67,7 +67,7 @@ gfc_push_suppress_errors (void)
}
static void
-gfc_error (const char *gmsgid, va_list ap) ATTRIBUTE_GCC_GFC(1,0);
+gfc_error (int opt, const char *gmsgid, va_list ap) ATTRIBUTE_GCC_GFC(2,0);
static bool
gfc_warning (int opt, const char *gmsgid, va_list ap) ATTRIBUTE_GCC_GFC(2,0);
@@ -902,7 +902,7 @@ gfc_notify_std (int std, const char *gmsgid, ...)
if (warning)
gfc_warning (0, buffer, argp);
else
- gfc_error (buffer, argp);
+ gfc_error (0, buffer, argp);
va_end (argp);
return (warning && !warnings_are_errors) ? true : false;
@@ -1233,7 +1233,7 @@ gfc_warning_check (void)
/* Issue an error. */
static void
-gfc_error (const char *gmsgid, va_list ap)
+gfc_error (int opt, const char *gmsgid, va_list ap)
{
va_list argp;
va_copy (argp, ap);
@@ -1241,7 +1241,7 @@ gfc_error (const char *gmsgid, va_list ap)
if (warnings_not_errors)
{
- gfc_warning (/*opt=*/0, gmsgid, argp);
+ gfc_warning (opt, gmsgid, argp);
va_end (argp);
return;
}
@@ -1289,11 +1289,21 @@ gfc_error (const char *gmsgid, va_list ap)
void
+gfc_error (int opt, const char *gmsgid, ...)
+{
+ va_list argp;
+ va_start (argp, gmsgid);
+ gfc_error (opt, gmsgid, argp);
+ va_end (argp);
+}
+
+
+void
gfc_error (const char *gmsgid, ...)
{
va_list argp;
va_start (argp, gmsgid);
- gfc_error (gmsgid, argp);
+ gfc_error (0, gmsgid, argp);
va_end (argp);
}
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index bb183d411e6..b2ffaae246a 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -2206,7 +2206,7 @@ check_alloc_comp_init (gfc_expr *e)
gfc_constructor *ctor;
gcc_assert (e->expr_type == EXPR_STRUCTURE);
- gcc_assert (e->ts.type == BT_DERIVED);
+ gcc_assert (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS);
for (comp = e->ts.u.derived->components,
ctor = gfc_constructor_first (e->value.constructor);
@@ -3445,7 +3445,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
{
char err[200];
gfc_symbol *s1,*s2;
- gfc_component *comp;
+ gfc_component *comp1, *comp2;
const char *name;
attr = gfc_expr_attr (rvalue);
@@ -3549,9 +3549,9 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
}
}
- comp = gfc_get_proc_ptr_comp (lvalue);
- if (comp)
- s1 = comp->ts.interface;
+ comp1 = gfc_get_proc_ptr_comp (lvalue);
+ if (comp1)
+ s1 = comp1->ts.interface;
else
{
s1 = lvalue->symtree->n.sym;
@@ -3559,18 +3559,18 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
s1 = s1->ts.interface;
}
- comp = gfc_get_proc_ptr_comp (rvalue);
- if (comp)
+ comp2 = gfc_get_proc_ptr_comp (rvalue);
+ if (comp2)
{
if (rvalue->expr_type == EXPR_FUNCTION)
{
- s2 = comp->ts.interface->result;
+ s2 = comp2->ts.interface->result;
name = s2->name;
}
else
{
- s2 = comp->ts.interface;
- name = comp->name;
+ s2 = comp2->ts.interface;
+ name = comp2->name;
}
}
else if (rvalue->expr_type == EXPR_FUNCTION)
@@ -3591,6 +3591,15 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
if (s2 && s2->attr.proc_pointer && s2->ts.interface)
s2 = s2->ts.interface;
+ /* Special check for the case of absent interface on the lvalue.
+ * All other interface checks are done below. */
+ if (!s1 && comp1 && comp1->attr.subroutine && s2 && s2->attr.function)
+ {
+ gfc_error ("Interface mismatch in procedure pointer assignment "
+ "at %L: '%s' is not a subroutine", &rvalue->where, name);
+ return false;
+ }
+
if (s1 == s2 || !s1 || !s2)
return true;
@@ -4131,6 +4140,26 @@ gfc_apply_init (gfc_typespec *ts, symbol_attribute *attr, gfc_expr *init)
}
+/* Check whether an expression is a structure constructor and whether it has
+ other values than NULL. */
+
+bool
+is_non_empty_structure_constructor (gfc_expr * e)
+{
+ if (e->expr_type != EXPR_STRUCTURE)
+ return false;
+
+ gfc_constructor *cons = gfc_constructor_first (e->value.constructor);
+ while (cons)
+ {
+ if (!cons->expr || cons->expr->expr_type != EXPR_NULL)
+ return true;
+ cons = gfc_constructor_next (cons);
+ }
+ return false;
+}
+
+
/* Check for default initializer; sym->value is not enough
as it is also set for EXPR_NULL of allocatables. */
@@ -4145,7 +4174,9 @@ gfc_has_default_initializer (gfc_symbol *der)
{
if (!c->attr.pointer && !c->attr.proc_pointer
&& !(c->attr.allocatable && der == c->ts.u.derived)
- && gfc_has_default_initializer (c->ts.u.derived))
+ && ((c->initializer
+ && is_non_empty_structure_constructor (c->initializer))
+ || gfc_has_default_initializer (c->ts.u.derived)))
return true;
if (c->attr.pointer && c->initializer)
return true;
@@ -4345,6 +4376,7 @@ gfc_generate_initializer (gfc_typespec *ts, bool generate)
{
ctor->expr = gfc_get_expr ();
ctor->expr->expr_type = EXPR_NULL;
+ ctor->expr->where = init->where;
ctor->expr->ts = comp->ts;
}
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index e61673fc6e4..1ad797b579c 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -747,10 +747,12 @@ do_warn_function_elimination (gfc_expr *e)
if (e->expr_type != EXPR_FUNCTION)
return;
if (e->value.function.esym)
- gfc_warning (0, "Removing call to function %qs at %L",
+ gfc_warning (OPT_Wfunction_elimination,
+ "Removing call to function %qs at %L",
e->value.function.esym->name, &(e->where));
else if (e->value.function.isym)
- gfc_warning (0, "Removing call to function %qs at %L",
+ gfc_warning (OPT_Wfunction_elimination,
+ "Removing call to function %qs at %L",
e->value.function.isym->name, &(e->where));
}
/* Callback function for the code walker for doing common function
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index ea4437c5d83..3fb6f4152ce 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2336,6 +2336,7 @@ typedef struct
gfc_expr *io_unit, *format_expr, *rec, *advance, *iostat, *size, *iomsg,
*id, *pos, *asynchronous, *blank, *decimal, *delim, *pad, *round,
*sign, *extra_comma, *dt_io_kind, *udtio;
+ char default_exp;
gfc_symbol *namelist;
/* A format_label of `format_asterisk' indicates the "*" format */
@@ -2730,6 +2731,7 @@ bool gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
void gfc_clear_warning (void);
void gfc_warning_check (void);
+void gfc_error (int opt, const char *, ...) ATTRIBUTE_GCC_GFC(2,3);
void gfc_error (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
void gfc_error_now (const char *, ...) ATTRIBUTE_GCC_GFC(1,2);
void gfc_fatal_error (const char *, ...) ATTRIBUTE_NORETURN ATTRIBUTE_GCC_GFC(1,2);
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index e65c2decad2..6de6c9bfeeb 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -1471,6 +1471,8 @@ compatibility extensions along with those enabled by @option{-std=legacy}.
* .XOR. operator::
* Bitwise logical operators::
* Extended I/O specifiers::
+* Legacy PARAMETER statements::
+* Default exponents::
@end menu
@node Old-style kind specifications
@@ -2696,6 +2698,31 @@ supported on other systems.
@end table
+@node Legacy PARAMETER statements
+@subsection Legacy PARAMETER statements
+@cindex PARAMETER
+
+For compatibility, GNU Fortran supports legacy PARAMETER statements without
+parentheses with @option{-std=legacy}. A warning is emitted if used with
+@option{-std=gnu}, and an error is acknowledged with a real Fortran standard
+flag (@option{-std=f95}, etc...). These statements take the following form:
+
+@smallexample
+implicit real (E)
+parameter e = 2.718282
+real c
+parameter c = 3.0e8
+@end smallexample
+
+@node Default exponents
+@subsection Default exponents
+@cindex exponent
+
+For compatibility, GNU Fortran supports a default exponent of zero in real
+constants with @option{-fdec}. For example, @code{9e} would be
+interpreted as @code{9e0}, rather than an error.
+
+
@node Extensions not implemented in GNU Fortran
@section Extensions not implemented in GNU Fortran
@cindex extensions, not implemented
diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
index b851d5a425b..4dd432ef23d 100644
--- a/gcc/fortran/interface.c
+++ b/gcc/fortran/interface.c
@@ -2139,17 +2139,17 @@ argument_rank_mismatch (const char *name, locus *where,
}
else if (rank1 == 0)
{
- gfc_error ("Rank mismatch in argument %qs at %L "
+ gfc_error (OPT_Wargument_mismatch, "Rank mismatch in argument %qs at %L "
"(scalar and rank-%d)", name, where, rank2);
}
else if (rank2 == 0)
{
- gfc_error ("Rank mismatch in argument %qs at %L "
+ gfc_error (OPT_Wargument_mismatch, "Rank mismatch in argument %qs at %L "
"(rank-%d and scalar)", name, where, rank1);
}
else
{
- gfc_error ("Rank mismatch in argument %qs at %L "
+ gfc_error (OPT_Wargument_mismatch, "Rank mismatch in argument %qs at %L "
"(rank-%d and rank-%d)", name, where, rank1, rank2);
}
}
@@ -2200,7 +2200,8 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
sizeof(err), NULL, NULL))
{
if (where)
- gfc_error ("Interface mismatch in dummy procedure %qs at %L: %s",
+ gfc_error (OPT_Wargument_mismatch,
+ "Interface mismatch in dummy procedure %qs at %L: %s",
formal->name, &actual->where, err);
return 0;
}
@@ -2227,7 +2228,8 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
err, sizeof(err), NULL, NULL))
{
if (where)
- gfc_error ("Interface mismatch in dummy procedure %qs at %L: %s",
+ gfc_error (OPT_Wargument_mismatch,
+ "Interface mismatch in dummy procedure %qs at %L: %s",
formal->name, &actual->where, err);
return 0;
}
@@ -2253,7 +2255,8 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
CLASS_DATA (actual)->ts.u.derived)))
{
if (where)
- gfc_error ("Type mismatch in argument %qs at %L; passed %s to %s",
+ gfc_error (OPT_Wargument_mismatch,
+ "Type mismatch in argument %qs at %L; passed %s to %s",
formal->name, where, gfc_typename (&actual->ts),
gfc_typename (&formal->ts));
return 0;
@@ -2957,7 +2960,7 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
f->sym->ts.u.cl->length->value.integer) != 0))
{
if (where && (f->sym->attr.pointer || f->sym->attr.allocatable))
- gfc_warning (0,
+ gfc_warning (OPT_Wargument_mismatch,
"Character length mismatch (%ld/%ld) between actual "
"argument and pointer or allocatable dummy argument "
"%qs at %L",
@@ -2965,7 +2968,7 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
mpz_get_si (f->sym->ts.u.cl->length->value.integer),
f->sym->name, &a->expr->where);
else if (where)
- gfc_warning (0,
+ gfc_warning (OPT_Wargument_mismatch,
"Character length mismatch (%ld/%ld) between actual "
"argument and assumed-shape dummy argument %qs "
"at %L",
@@ -2997,12 +3000,14 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
&& f->sym->attr.flavor != FL_PROCEDURE)
{
if (a->expr->ts.type == BT_CHARACTER && !f->sym->as && where)
- gfc_warning (0, "Character length of actual argument shorter "
+ gfc_warning (OPT_Wargument_mismatch,
+ "Character length of actual argument shorter "
"than of dummy argument %qs (%lu/%lu) at %L",
f->sym->name, actual_size, formal_size,
&a->expr->where);
else if (where)
- gfc_warning (0, "Actual argument contains too few "
+ gfc_warning (OPT_Wargument_mismatch,
+ "Actual argument contains too few "
"elements for dummy argument %qs (%lu/%lu) at %L",
f->sym->name, actual_size, formal_size,
&a->expr->where);
@@ -4547,7 +4552,8 @@ gfc_check_typebound_override (gfc_symtree* proc, gfc_symtree* old)
if (!gfc_check_dummy_characteristics (proc_formal->sym, old_formal->sym,
check_type, err, sizeof(err)))
{
- gfc_error ("Argument mismatch for the overriding procedure "
+ gfc_error (OPT_Wargument_mismatch,
+ "Argument mismatch for the overriding procedure "
"%qs at %L: %s", proc->name, &where, err);
return false;
}
diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi
index ebf3aba8d4a..39a0232f71a 100644
--- a/gcc/fortran/invoke.texi
+++ b/gcc/fortran/invoke.texi
@@ -141,7 +141,7 @@ by type. Explanations are in the following sections.
@item Error and Warning Options
@xref{Error and Warning Options,,Options to request or suppress errors
and warnings}.
-@gccoptlist{-Waliasing -Wall -Wampersand -Warray-bounds
+@gccoptlist{-Waliasing -Wall -Wampersand -Wargument-mismatch -Warray-bounds
-Wc-binding-type -Wcharacter-truncation @gol
-Wconversion -Wfunction-elimination -Wimplicit-interface @gol
-Wimplicit-procedure -Wintrinsic-shadow -Wuse-without-only -Wintrinsics-std @gol
@@ -749,8 +749,10 @@ Check the code for syntax errors, but do not actually compile it. This
will generate module files for each module present in the code, but no
other output file.
-@item -pedantic
+@item -Wpedantic
+@itemx -pedantic
@opindex @code{pedantic}
+@opindex @code{Wpedantic}
Issue warnings for uses of extensions to Fortran 95.
@option{-pedantic} also applies to C-language constructs where they
occur in GNU Fortran source files, such as use of @samp{\e} in a
@@ -821,6 +823,15 @@ given in a continued character constant, GNU Fortran assumes continuation
at the first non-comment, non-whitespace character after the ampersand
that initiated the continuation.
+@item -Wargument-mismatch
+@opindex @code{Wargument-mismatch}
+@cindex warnings, argument mismatch
+@cindex warnings, parameter mismatch
+@cindex warnings, interface mismatch
+Warn about type, rank, and other mismatches between formal parameters and actual
+arguments to functions and subroutines. These warnings are recommended and
+thus enabled by default.
+
@item -Warray-temporaries
@opindex @code{Warray-temporaries}
@cindex warnings, array temporaries
diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c
index dce0f7cd970..04cc1a25358 100644
--- a/gcc/fortran/io.c
+++ b/gcc/fortran/io.c
@@ -601,7 +601,7 @@ check_format (bool is_input)
const char *unexpected_end = _("Unexpected end of format string");
const char *zero_width = _("Zero width in format descriptor");
- const char *error;
+ const char *error = NULL;
format_token t, u;
int level;
int repeat;
@@ -867,27 +867,31 @@ data_desc:
goto fail;
if (t == FMT_POSINT)
break;
-
- switch (gfc_notification_std (GFC_STD_GNU))
+ if (mode != MODE_FORMAT)
+ format_locus.nextc += format_string_pos;
+ if (t == FMT_ZERO)
{
- case WARNING:
- if (mode != MODE_FORMAT)
- format_locus.nextc += format_string_pos;
- gfc_warning (0, "Extension: Missing positive width after L "
- "descriptor at %L", &format_locus);
- saved_token = t;
- break;
-
- case ERROR:
- error = posint_required;
- goto syntax;
-
- case SILENT:
- saved_token = t;
- break;
-
- default:
- gcc_unreachable ();
+ switch (gfc_notification_std (GFC_STD_GNU))
+ {
+ case WARNING:
+ gfc_warning (0, "Extension: Zero width after L "
+ "descriptor at %L", &format_locus);
+ break;
+ case ERROR:
+ gfc_error ("Extension: Zero width after L "
+ "descriptor at %L", &format_locus);
+ goto fail;
+ case SILENT:
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ saved_token = t;
+ gfc_notify_std (GFC_STD_GNU, "Missing positive width after "
+ "L descriptor at %L", &format_locus);
}
break;
@@ -4163,6 +4167,10 @@ get_io_list:
goto syntax;
}
+ /* See if we want to use defaults for missing exponents in real transfers. */
+ if (flag_dec)
+ dt->default_exp = 1;
+
/* A full IO statement has been matched. Check the constraints. spec_end is
supplied for cases where no locus is supplied. */
m = check_io_constraints (k, dt, io_code, &spec_end);
diff --git a/gcc/fortran/ioparm.def b/gcc/fortran/ioparm.def
index f1bf7330fd0..46691874e10 100644
--- a/gcc/fortran/ioparm.def
+++ b/gcc/fortran/ioparm.def
@@ -118,4 +118,5 @@ IOPARM (dt, round, 1 << 23, char2)
IOPARM (dt, sign, 1 << 24, char1)
#define IOPARM_dt_f2003 (1 << 25)
#define IOPARM_dt_dtio (1 << 26)
+#define IOPARM_dt_default_exp (1 << 27)
IOPARM (dt, u, 0, pad)
diff --git a/gcc/fortran/iresolve.c b/gcc/fortran/iresolve.c
index 078e47dbaa0..b289c9f6840 100644
--- a/gcc/fortran/iresolve.c
+++ b/gcc/fortran/iresolve.c
@@ -1044,15 +1044,19 @@ gfc_resolve_extends_type_of (gfc_expr *f, gfc_expr *a, gfc_expr *mo)
gfc_add_vptr_component (a);
else if (a->ts.type == BT_DERIVED)
{
+ locus where;
+
vtab = gfc_find_derived_vtab (a->ts.u.derived);
/* Clear the old expr. */
gfc_free_ref_list (a->ref);
+ where = a->where;
memset (a, '\0', sizeof (gfc_expr));
/* Construct a new one. */
a->expr_type = EXPR_VARIABLE;
st = gfc_find_symtree (vtab->ns->sym_root, vtab->name);
a->symtree = st;
a->ts = vtab->ts;
+ a->where = where;
}
/* Replace the second argument with the corresponding vtab. */
@@ -1060,8 +1064,11 @@ gfc_resolve_extends_type_of (gfc_expr *f, gfc_expr *a, gfc_expr *mo)
gfc_add_vptr_component (mo);
else if (mo->ts.type == BT_DERIVED)
{
+ locus where;
+
vtab = gfc_find_derived_vtab (mo->ts.u.derived);
/* Clear the old expr. */
+ where = mo->where;
gfc_free_ref_list (mo->ref);
memset (mo, '\0', sizeof (gfc_expr));
/* Construct a new one. */
@@ -1069,6 +1076,7 @@ gfc_resolve_extends_type_of (gfc_expr *f, gfc_expr *a, gfc_expr *mo)
st = gfc_find_symtree (vtab->ns->sym_root, vtab->name);
mo->symtree = st;
mo->ts = vtab->ts;
+ mo->where = where;
}
f->ts.type = BT_LOGICAL;
diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt
index 2e7640302ee..e39e555792f 100644
--- a/gcc/fortran/lang.opt
+++ b/gcc/fortran/lang.opt
@@ -209,6 +209,10 @@ Warray-temporaries
Fortran Warning Var(warn_array_temporaries)
Warn about creation of array temporaries.
+Wargument-mismatch
+Fortran Warning Var(warn_argument_mismatch) Init(1)
+Warn about type and rank mismatches between arguments and parameters.
+
Wc-binding-type
Fortran Var(warn_c_binding_type) Warning LangEnabledBy(Fortran,Wall)
Warn if the type of a variable might be not interoperable with C.
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c
index 0996a9efae6..5a7451ec9c4 100644
--- a/gcc/fortran/match.c
+++ b/gcc/fortran/match.c
@@ -5898,6 +5898,7 @@ gfc_match_select_type (void)
{
expr1 = gfc_get_expr ();
expr1->expr_type = EXPR_VARIABLE;
+ expr1->where = expr2->where;
if (gfc_get_sym_tree (name, NULL, &expr1->symtree, false))
{
m = MATCH_ERROR;
@@ -6219,6 +6220,7 @@ match_simple_where (void)
c->next = XCNEW (gfc_code);
*c->next = new_st;
+ c->next->loc = gfc_current_locus;
gfc_clear_new_st ();
new_st.op = EXEC_WHERE;
@@ -6275,8 +6277,12 @@ gfc_match_where (gfc_statement *st)
c = gfc_get_code (EXEC_WHERE);
c->expr1 = expr;
+ /* Put in the assignment. It will not be processed by add_statement, so we
+ need to copy the location here. */
+
c->next = XCNEW (gfc_code);
*c->next = new_st;
+ c->next->loc = gfc_current_locus;
gfc_clear_new_st ();
new_st.op = EXEC_WHERE;
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 2aa2afc24e8..0ee054a014c 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -352,6 +352,9 @@ decode_statement (void)
}
gfc_matching_function = false;
+ /* Legacy parameter statements are ambiguous with assignments so try parameter
+ first. */
+ match ("parameter", gfc_match_parameter, ST_PARAMETER);
/* Match statements whose error messages are meant to be overwritten
by something better. */
@@ -528,7 +531,6 @@ decode_statement (void)
case 'p':
match ("print", gfc_match_print, ST_WRITE);
- match ("parameter", gfc_match_parameter, ST_PARAMETER);
match ("pause", gfc_match_pause, ST_PAUSE);
match ("pointer", gfc_match_pointer, ST_ATTR_DECL);
if (gfc_match_private (&st) == MATCH_YES)
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index bcbaeaa6369..50d7072b670 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -483,7 +483,7 @@ backup:
static match
match_real_constant (gfc_expr **result, int signflag)
{
- int kind, count, seen_dp, seen_digits, is_iso_c;
+ int kind, count, seen_dp, seen_digits, is_iso_c, default_exponent;
locus old_loc, temp_loc;
char *p, *buffer, c, exp_char;
gfc_expr *e;
@@ -494,6 +494,7 @@ match_real_constant (gfc_expr **result, int signflag)
e = NULL;
+ default_exponent = 0;
count = 0;
seen_dp = 0;
seen_digits = 0;
@@ -575,8 +576,14 @@ match_real_constant (gfc_expr **result, int signflag)
if (!ISDIGIT (c))
{
- gfc_error ("Missing exponent in real number at %C");
- return MATCH_ERROR;
+ /* With -fdec, default exponent to 0 instead of complaining. */
+ if (flag_dec)
+ default_exponent = 1;
+ else
+ {
+ gfc_error ("Missing exponent in real number at %C");
+ return MATCH_ERROR;
+ }
}
while (ISDIGIT (c))
@@ -597,8 +604,8 @@ done:
gfc_current_locus = old_loc;
gfc_gobble_whitespace ();
- buffer = (char *) alloca (count + 1);
- memset (buffer, '\0', count + 1);
+ buffer = (char *) alloca (count + default_exponent + 1);
+ memset (buffer, '\0', count + default_exponent + 1);
p = buffer;
c = gfc_next_ascii_char ();
@@ -621,6 +628,8 @@ done:
c = gfc_next_ascii_char ();
}
+ if (default_exponent)
+ *p++ = '0';
kind = get_kind (&is_iso_c);
if (kind == -1)
@@ -1353,6 +1362,10 @@ match_complex_constant (gfc_expr **result)
if (gfc_match_char (',') == MATCH_NO)
{
+ /* It is possible that gfc_int2real issued a warning when
+ converting an integer to real. Throw this away here. */
+
+ gfc_clear_warning ();
gfc_pop_error (&old_error);
m = MATCH_NO;
goto cleanup;
@@ -1918,15 +1931,36 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
}
/* For associate names, we may not yet know whether they are arrays or not.
- Thus if we have one and parentheses follow, we have to assume that it
- actually is one for now. The final decision will be made at
- resolution time, of course. */
- if (sym->assoc && gfc_peek_ascii_char () == '('
- && !(sym->assoc->dangling && sym->assoc->st
+ If the selector expression is unambiguously an array; eg. a full array
+ or an array section, then the associate name must be an array and we can
+ fix it now. Otherwise, if parentheses follow and it is not a character
+ type, we have to assume that it actually is one for now. The final
+ decision will be made at resolution, of course. */
+ if (sym->assoc
+ && gfc_peek_ascii_char () == '('
+ && sym->ts.type != BT_CLASS
+ && !sym->attr.dimension)
+ {
+ if ((!sym->assoc->dangling
+ && sym->assoc->target
+ && sym->assoc->target->ref
+ && sym->assoc->target->ref->type == REF_ARRAY
+ && (sym->assoc->target->ref->u.ar.type == AR_FULL
+ || sym->assoc->target->ref->u.ar.type == AR_SECTION))
+ ||
+ (!(sym->assoc->dangling || sym->ts.type == BT_CHARACTER)
+ && sym->assoc->st
&& sym->assoc->st->n.sym
- && sym->assoc->st->n.sym->attr.dimension == 0)
- && sym->ts.type != BT_CLASS)
+ && sym->assoc->st->n.sym->attr.dimension == 0))
+ {
sym->attr.dimension = 1;
+ if (sym->as == NULL && sym->assoc
+ && sym->assoc->st
+ && sym->assoc->st->n.sym
+ && sym->assoc->st->n.sym->as)
+ sym->as = gfc_copy_array_spec (sym->assoc->st->n.sym->as);
+ }
+ }
if ((equiv_flag && gfc_peek_ascii_char () == '(')
|| gfc_peek_ascii_char () == '[' || sym->attr.codimension
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index f9d11be5997..f4d346ed0f3 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -1317,7 +1317,8 @@ resolve_structure_cons (gfc_expr *expr, int init)
if (s2 && !gfc_compare_interfaces (comp->ts.interface, s2, name, 0, 1,
err, sizeof (err), NULL, NULL))
{
- gfc_error ("Interface mismatch for procedure-pointer component "
+ gfc_error (OPT_Wargument_mismatch,
+ "Interface mismatch for procedure-pointer component "
"%qs in structure constructor at %L: %s",
comp->name, &cons->expr->where, err);
return false;
@@ -2139,7 +2140,8 @@ resolve_elemental_actual (gfc_expr *expr, gfc_code *c)
&& (set_by_optional || arg->expr->rank != rank)
&& !(isym && isym->id == GFC_ISYM_CONVERSION))
{
- gfc_warning (0, "%qs at %L is an array and OPTIONAL; IF IT IS "
+ gfc_warning (OPT_Wpedantic,
+ "%qs at %L is an array and OPTIONAL; IF IT IS "
"MISSING, it cannot be the actual argument of an "
"ELEMENTAL procedure unless there is a non-optional "
"argument with the same rank (12.4.1.5)",
@@ -2469,7 +2471,8 @@ resolve_global_procedure (gfc_symbol *sym, locus *where,
if (!gfc_compare_interfaces (sym, def_sym, sym->name, 0, 1,
reason, sizeof(reason), NULL, NULL))
{
- gfc_error ("Interface mismatch in global procedure %qs at %L: %s ",
+ gfc_error (OPT_Wargument_mismatch,
+ "Interface mismatch in global procedure %qs at %L: %s ",
sym->name, &sym->declared_at, reason);
goto done;
}
@@ -3809,7 +3812,8 @@ resolve_operator (gfc_expr *e)
else
msg = "Inequality comparison for %s at %L";
- gfc_warning (0, msg, gfc_typename (&op1->ts), &op1->where);
+ gfc_warning (OPT_Wcompare_reals, msg,
+ gfc_typename (&op1->ts), &op1->where);
}
}
@@ -7044,35 +7048,6 @@ conformable_arrays (gfc_expr *e1, gfc_expr *e2)
return true;
}
-static void
-cond_init (gfc_code *code, gfc_expr *e, int pointer, gfc_expr *init_e)
-{
- gfc_code *block;
- gfc_expr *cond;
- gfc_code *init_st;
- gfc_expr *e_to_init = gfc_expr_to_initialize (e);
-
- cond = pointer
- ? gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_ASSOCIATED,
- "associated", code->loc, 2, gfc_copy_expr (e_to_init), NULL)
- : gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_ALLOCATED,
- "allocated", code->loc, 1, gfc_copy_expr (e_to_init));
-
- init_st = gfc_get_code (EXEC_INIT_ASSIGN);
- init_st->loc = code->loc;
- init_st->expr1 = e_to_init;
- init_st->expr2 = init_e;
-
- block = gfc_get_code (EXEC_IF);
- block->loc = code->loc;
- block->block = gfc_get_code (EXEC_IF);
- block->block->loc = code->loc;
- block->block->expr1 = cond;
- block->block->next = init_st;
- block->next = code->next;
-
- code->next = block;
-}
/* Resolve the expression in an ALLOCATE statement, doing the additional
checks to see whether the expression is OK or not. The expression must
@@ -7323,34 +7298,6 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec)
/* We have to zero initialize the integer variable. */
code->expr3 = gfc_get_int_expr (gfc_default_integer_kind, &e->where, 0);
}
- else if (!code->expr3)
- {
- /* Set up default initializer if needed. */
- gfc_typespec ts;
- gfc_expr *init_e;
-
- if (gfc_bt_struct (code->ext.alloc.ts.type))
- ts = code->ext.alloc.ts;
- else
- ts = e->ts;
-
- if (ts.type == BT_CLASS)
- ts = ts.u.derived->components->ts;
-
- if (gfc_bt_struct (ts.type) && (init_e = gfc_default_initializer (&ts)))
- cond_init (code, e, pointer, init_e);
- }
- else if (code->expr3->mold && code->expr3->ts.type == BT_DERIVED)
- {
- /* Default initialization via MOLD (non-polymorphic). */
- gfc_expr *rhs = gfc_default_initializer (&code->expr3->ts);
- if (rhs != NULL)
- {
- gfc_resolve_expr (rhs);
- gfc_free_expr (code->expr3);
- code->expr3 = rhs;
- }
- }
if (e->ts.type == BT_CLASS && !unlimited && !UNLIMITED_POLY (code->expr3))
{
@@ -7362,10 +7309,9 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec)
else if (code->ext.alloc.ts.type == BT_DERIVED)
ts = code->ext.alloc.ts;
+ /* Finding the vtab also publishes the type's symbol. Therefore this
+ statement is necessary. */
gfc_find_derived_vtab (ts.u.derived);
-
- if (dimension)
- e = gfc_expr_to_initialize (e);
}
else if (unlimited && !UNLIMITED_POLY (code->expr3))
{
@@ -7379,10 +7325,9 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec)
gcc_assert (ts);
+ /* Finding the vtab also publishes the type's symbol. Therefore this
+ statement is necessary. */
gfc_find_vtab (ts);
-
- if (dimension)
- e = gfc_expr_to_initialize (e);
}
if (dimension == 0 && codimension == 0)
@@ -7686,6 +7631,22 @@ resolve_allocate_deallocate (gfc_code *code, const char *fcn)
if (strcmp (fcn, "ALLOCATE") == 0)
{
bool arr_alloc_wo_spec = false;
+
+ /* Resolving the expr3 in the loop over all objects to allocate would
+ execute loop invariant code for each loop item. Therefore do it just
+ once here. */
+ if (code->expr3 && code->expr3->mold
+ && code->expr3->ts.type == BT_DERIVED)
+ {
+ /* Default initialization via MOLD (non-polymorphic). */
+ gfc_expr *rhs = gfc_default_initializer (&code->expr3->ts);
+ if (rhs != NULL)
+ {
+ gfc_resolve_expr (rhs);
+ gfc_free_expr (code->expr3);
+ code->expr3 = rhs;
+ }
+ }
for (a = code->ext.alloc.list; a; a = a->next)
resolve_allocate_expr (a->expr, code, &arr_alloc_wo_spec);
@@ -8496,6 +8457,7 @@ build_loc_call (gfc_expr *sym_expr)
loc_call->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LOC);
loc_call->value.function.actual = gfc_get_actual_arglist ();
loc_call->value.function.actual->expr = sym_expr;
+ loc_call->where = sym_expr->where;
return loc_call;
}
@@ -8895,11 +8857,13 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
new_st->expr1->value.function.actual = gfc_get_actual_arglist ();
new_st->expr1->value.function.actual->expr = gfc_get_variable_expr (selector_expr->symtree);
new_st->expr1->value.function.actual->expr->where = code->loc;
+ new_st->expr1->where = code->loc;
gfc_add_vptr_component (new_st->expr1->value.function.actual->expr);
vtab = gfc_find_derived_vtab (body->ext.block.case_list->ts.u.derived);
st = gfc_find_symtree (vtab->ns->sym_root, vtab->name);
new_st->expr1->value.function.actual->next = gfc_get_actual_arglist ();
new_st->expr1->value.function.actual->next->expr = gfc_get_variable_expr (st);
+ new_st->expr1->value.function.actual->next->expr->where = code->loc;
new_st->next = body->next;
}
if (default_case->next)
@@ -14037,6 +14001,15 @@ resolve_fl_parameter (gfc_symbol *sym)
&sym->value->where);
return false;
}
+
+ /* F03:C509,C514. */
+ if (sym->ts.type == BT_CLASS)
+ {
+ gfc_error ("CLASS variable %qs at %L cannot have the PARAMETER attribute",
+ sym->name, &sym->declared_at);
+ return false;
+ }
+
return true;
}
@@ -15391,12 +15364,13 @@ warn_unused_fortran_label (gfc_st_label *label)
switch (label->referenced)
{
case ST_LABEL_UNKNOWN:
- gfc_warning (0, "Label %d at %L defined but not used", label->value,
- &label->where);
+ gfc_warning (OPT_Wunused_label, "Label %d at %L defined but not used",
+ label->value, &label->where);
break;
case ST_LABEL_BAD_TARGET:
- gfc_warning (0, "Label %d at %L defined but cannot be used",
+ gfc_warning (OPT_Wunused_label,
+ "Label %d at %L defined but cannot be used",
label->value, &label->where);
break;
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index cbe4347351f..85ed375e297 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -4901,7 +4901,7 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2)
&& !is_union1 && !is_union2)
return (ts1->type == ts2->type);
- if ((is_derived1 && is_derived2) || (is_union1 && is_union1))
+ if ((is_derived1 && is_derived2) || (is_union1 && is_union2))
return gfc_compare_derived_types (ts1->u.derived, ts2->u.derived);
if (is_derived1 && is_class2)
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 74935b181f6..1708f7c8e44 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -5623,14 +5623,6 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
else
gfc_add_expr_to_block (&se->pre, set_descriptor);
- if (expr->ts.type == BT_DERIVED && expr->ts.u.derived->attr.alloc_comp
- && !coarray)
- {
- tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, se->expr,
- ref->u.ar.as->rank);
- gfc_add_expr_to_block (&se->pre, tmp);
- }
-
return true;
}
diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c
index ee12fa22dc0..0c030584b68 100644
--- a/gcc/fortran/trans-common.c
+++ b/gcc/fortran/trans-common.c
@@ -1149,13 +1149,13 @@ translate_common (gfc_common_head *common, gfc_symbol *var_list)
if (warn_align_commons)
{
if (strcmp (common->name, BLANK_COMMON_NAME))
- gfc_warning (0,
+ gfc_warning (OPT_Walign_commons,
"Padding of %d bytes required before %qs in "
"COMMON %qs at %L; reorder elements or use "
"-fno-align-commons", (int)offset,
s->sym->name, common->name, &common->where);
else
- gfc_warning (0,
+ gfc_warning (OPT_Walign_commons,
"Padding of %d bytes required before %qs in "
"COMMON at %L; reorder elements or use "
"-fno-align-commons", (int)offset,
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 7159b172eea..61214295f66 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -1091,6 +1091,12 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
tmp = integer_zero_node;
gfc_add_modify (&parmse->pre, ctree,
fold_convert (TREE_TYPE (ctree), tmp));
+
+ /* Return the len component, except in the case of scalarized array
+ references, where the dynamic type cannot change. */
+ if (!elemental && full_array && copyback)
+ gfc_add_modify (&parmse->post, tmp,
+ fold_convert (TREE_TYPE (tmp), ctree));
}
if (optional)
@@ -10036,7 +10042,7 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
tree
gfc_trans_init_assign (gfc_code * code)
{
- return gfc_trans_assignment (code->expr1, code->expr2, true, false);
+ return gfc_trans_assignment (code->expr1, code->expr2, true, false, true);
}
tree
diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c
index 285e551585c..253a5ac70a9 100644
--- a/gcc/fortran/trans-io.c
+++ b/gcc/fortran/trans-io.c
@@ -1911,6 +1911,9 @@ build_dt (tree function, gfc_code * code)
if (dt->udtio)
mask |= IOPARM_dt_dtio;
+ if (dt->default_exp)
+ mask |= IOPARM_dt_default_exp;
+
if (dt->namelist)
{
if (dt->format_expr || dt->format_label)
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index c52066ffd20..490b18dae31 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -5450,13 +5450,41 @@ gfc_trans_exit (gfc_code * code)
}
+/* Get the initializer expression for the code and expr of an allocate.
+ When no initializer is needed return NULL. */
+
+static gfc_expr *
+allocate_get_initializer (gfc_code * code, gfc_expr * expr)
+{
+ if (!gfc_bt_struct (expr->ts.type) && expr->ts.type != BT_CLASS)
+ return NULL;
+
+ /* An explicit type was given in allocate ( T:: object). */
+ if (code->ext.alloc.ts.type == BT_DERIVED
+ && (code->ext.alloc.ts.u.derived->attr.alloc_comp
+ || gfc_has_default_initializer (code->ext.alloc.ts.u.derived)))
+ return gfc_default_initializer (&code->ext.alloc.ts);
+
+ if (gfc_bt_struct (expr->ts.type)
+ && (expr->ts.u.derived->attr.alloc_comp
+ || gfc_has_default_initializer (expr->ts.u.derived)))
+ return gfc_default_initializer (&expr->ts);
+
+ if (expr->ts.type == BT_CLASS
+ && (CLASS_DATA (expr)->ts.u.derived->attr.alloc_comp
+ || gfc_has_default_initializer (CLASS_DATA (expr)->ts.u.derived)))
+ return gfc_default_initializer (&CLASS_DATA (expr)->ts);
+
+ return NULL;
+}
+
/* Translate the ALLOCATE statement. */
tree
gfc_trans_allocate (gfc_code * code)
{
gfc_alloc *al;
- gfc_expr *expr, *e3rhs = NULL;
+ gfc_expr *expr, *e3rhs = NULL, *init_expr;
gfc_se se, se_sz;
tree tmp;
tree parm;
@@ -6080,14 +6108,6 @@ gfc_trans_allocate (gfc_code * code)
label_finish, expr, 0);
else
gfc_allocate_using_malloc (&se.pre, se.expr, memsz, stat);
-
- if (al->expr->ts.type == BT_DERIVED
- && expr->ts.u.derived->attr.alloc_comp)
- {
- tmp = build_fold_indirect_ref_loc (input_location, se.expr);
- tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, tmp, 0);
- gfc_add_expr_to_block (&se.pre, tmp);
- }
}
else
{
@@ -6217,6 +6237,8 @@ gfc_trans_allocate (gfc_code * code)
fold_convert (TREE_TYPE (al_len),
integer_zero_node));
}
+
+ init_expr = NULL;
if (code->expr3 && !code->expr3->mold && e3_is != E3_MOLD)
{
/* Initialization via SOURCE block (or static default initializer).
@@ -6246,6 +6268,23 @@ gfc_trans_allocate (gfc_code * code)
gfc_free_statements (ini);
gfc_add_expr_to_block (&block, tmp);
}
+ else if ((init_expr = allocate_get_initializer (code, expr)))
+ {
+ /* Use class_init_assign to initialize expr. */
+ gfc_code *ini;
+ int realloc_lhs = flag_realloc_lhs;
+ ini = gfc_get_code (EXEC_INIT_ASSIGN);
+ ini->expr1 = gfc_expr_to_initialize (expr);
+ ini->expr2 = init_expr;
+ flag_realloc_lhs = 0;
+ tmp= gfc_trans_init_assign (ini);
+ flag_realloc_lhs = realloc_lhs;
+ gfc_free_statements (ini);
+ /* Init_expr is freeed by above free_statements, just need to null
+ it here. */
+ init_expr = NULL;
+ gfc_add_expr_to_block (&block, tmp);
+ }
gfc_free_expr (expr);
} // for-loop
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index eda0351119a..6f9bc381df6 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -3139,7 +3139,7 @@ gfc_get_array_descr_info (const_tree type, struct array_descr_info *info)
int rank, dim;
bool indirect = false;
tree etype, ptype, field, t, base_decl;
- tree data_off, dim_off, dim_size, elem_size;
+ tree data_off, dim_off, dtype_off, dim_size, elem_size;
tree lower_suboff, upper_suboff, stride_suboff;
if (! GFC_DESCRIPTOR_TYPE_P (type))
@@ -3203,6 +3203,7 @@ gfc_get_array_descr_info (const_tree type, struct array_descr_info *info)
data_off = byte_position (field);
field = DECL_CHAIN (field);
field = DECL_CHAIN (field);
+ dtype_off = byte_position (field);
field = DECL_CHAIN (field);
dim_off = byte_position (field);
dim_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (field)));
@@ -3225,6 +3226,24 @@ gfc_get_array_descr_info (const_tree type, struct array_descr_info *info)
|| GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_POINTER_CONT)
info->associated = build2 (NE_EXPR, boolean_type_node,
info->data_location, null_pointer_node);
+ if ((GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK
+ || GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ASSUMED_RANK_CONT)
+ && dwarf_version >= 5)
+ {
+ rank = 1;
+ info->ndimensions = 1;
+ t = base_decl;
+ if (!integer_zerop (dtype_off))
+ t = fold_build_pointer_plus (t, dtype_off);
+ t = build1 (NOP_EXPR, build_pointer_type (gfc_array_index_type), t);
+ t = build1 (INDIRECT_REF, gfc_array_index_type, t);
+ info->rank = build2 (BIT_AND_EXPR, gfc_array_index_type, t,
+ build_int_cst (gfc_array_index_type,
+ GFC_DTYPE_RANK_MASK));
+ t = build0 (PLACEHOLDER_EXPR, TREE_TYPE (dim_off));
+ t = size_binop (MULT_EXPR, t, dim_size);
+ dim_off = build2 (PLUS_EXPR, TREE_TYPE (dim_off), t, dim_off);
+ }
for (dim = 0; dim < rank; dim++)
{
@@ -3260,7 +3279,8 @@ gfc_get_array_descr_info (const_tree type, struct array_descr_info *info)
t = build1 (INDIRECT_REF, gfc_array_index_type, t);
t = build2 (MULT_EXPR, gfc_array_index_type, t, elem_size);
info->dimen[dim].stride = t;
- dim_off = size_binop (PLUS_EXPR, dim_off, dim_size);
+ if (dim + 1 < rank)
+ dim_off = size_binop (PLUS_EXPR, dim_off, dim_size);
}
return true;
diff --git a/gcc/fwprop.c b/gcc/fwprop.c
index 4365ff0db90..b2d670061be 100644
--- a/gcc/fwprop.c
+++ b/gcc/fwprop.c
@@ -1051,9 +1051,7 @@ free_load_extend (rtx src, rtx_insn *insn)
df_ref def, use;
reg = XEXP (src, 0);
-#ifdef LOAD_EXTEND_OP
if (LOAD_EXTEND_OP (GET_MODE (reg)) != GET_CODE (src))
-#endif
return false;
FOR_EACH_INSN_USE (use, insn)
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 10bf80139b6..f588f5e445e 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -728,6 +728,12 @@ pp_points_to_solution (pretty_printer *buffer, struct pt_solution *pt)
{
pp_string (buffer, comma);
pp_string (buffer, "restrict");
+ comma = ", ";
+ }
+ if (pt->vars_contains_interposable)
+ {
+ pp_string (buffer, comma);
+ pp_string (buffer, "interposable");
}
pp_string (buffer, ")");
}
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 5a293d7f307..bd9ba28ee51 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -125,6 +125,8 @@
#include "tree-cfg.h"
#include "tree-eh.h"
#include "target.h"
+#include "gimplify-me.h"
+#include "selftest.h"
/* The maximum size (in bits) of the stores this pass should generate. */
#define MAX_STORE_BITSIZE (BITS_PER_WORD)
@@ -140,19 +142,17 @@ struct store_immediate_info
{
unsigned HOST_WIDE_INT bitsize;
unsigned HOST_WIDE_INT bitpos;
- tree val;
- tree dest;
gimple *stmt;
unsigned int order;
- store_immediate_info (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, tree,
- tree, gimple *, unsigned int);
+ store_immediate_info (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+ gimple *, unsigned int);
};
store_immediate_info::store_immediate_info (unsigned HOST_WIDE_INT bs,
- unsigned HOST_WIDE_INT bp, tree v,
- tree d, gimple *st,
+ unsigned HOST_WIDE_INT bp,
+ gimple *st,
unsigned int ord)
- : bitsize (bs), bitpos (bp), val (v), dest (d), stmt (st), order (ord)
+ : bitsize (bs), bitpos (bp), stmt (st), order (ord)
{
}
@@ -338,7 +338,7 @@ clear_bit_region (unsigned char *ptr, unsigned int start,
else if (start != 0)
{
clear_bit_region (ptr, start, BITS_PER_UNIT - start);
- clear_bit_region (ptr + 1, 0, len - (BITS_PER_UNIT - start) + 1);
+ clear_bit_region (ptr + 1, 0, len - (BITS_PER_UNIT - start));
}
/* Whole bytes need to be cleared. */
else if (start == 0 && len > BITS_PER_UNIT)
@@ -432,13 +432,24 @@ encode_tree_to_bitpos (tree expr, unsigned char *ptr, int bitlen, int bitpos,
contain a sign bit due to sign-extension). */
unsigned int padding
= byte_size - ROUND_UP (bitlen, BITS_PER_UNIT) / BITS_PER_UNIT - 1;
- if (BYTES_BIG_ENDIAN)
+ if (padding != 0
+ || bitlen % BITS_PER_UNIT != 0)
{
- tmpbuf += padding;
+ /* On big-endian the padding is at the 'front' so just skip the initial
+ bytes. */
+ if (BYTES_BIG_ENDIAN)
+ tmpbuf += padding;
+
byte_size -= padding;
if (bitlen % BITS_PER_UNIT != 0)
- clear_bit_region_be (tmpbuf, BITS_PER_UNIT - 1,
- BITS_PER_UNIT - (bitlen % BITS_PER_UNIT));
+ {
+ if (BYTES_BIG_ENDIAN)
+ clear_bit_region_be (tmpbuf, BITS_PER_UNIT - 1,
+ BITS_PER_UNIT - (bitlen % BITS_PER_UNIT));
+ else
+ clear_bit_region (tmpbuf, bitlen,
+ byte_size * BITS_PER_UNIT - bitlen);
+ }
}
/* Clear the bit region in PTR where the bits from TMPBUF will be
@@ -547,7 +558,7 @@ merged_store_group::merged_store_group (store_immediate_info *info)
/* VAL has memory allocated for it in apply_stores once the group
width has been finalized. */
val = NULL;
- align = get_object_alignment (info->dest);
+ align = get_object_alignment (gimple_assign_lhs (info->stmt));
stores.create (1);
stores.safe_push (info);
last_stmt = info->stmt;
@@ -644,14 +655,16 @@ merged_store_group::apply_stores ()
FOR_EACH_VEC_ELT (stores, i, info)
{
unsigned int pos_in_buffer = info->bitpos - start;
- bool ret = encode_tree_to_bitpos (info->val, val, info->bitsize,
- pos_in_buffer, buf_size);
+ bool ret = encode_tree_to_bitpos (gimple_assign_rhs1 (info->stmt),
+ val, info->bitsize,
+ pos_in_buffer, buf_size);
if (dump_file && (dump_flags & TDF_DETAILS))
{
if (ret)
{
fprintf (dump_file, "After writing ");
- print_generic_expr (dump_file, info->val, 0);
+ print_generic_expr (dump_file,
+ gimple_assign_rhs1 (info->stmt), 0);
fprintf (dump_file, " of size " HOST_WIDE_INT_PRINT_DEC
" at position %d the merged region contains:\n",
info->bitsize, pos_in_buffer);
@@ -670,13 +683,15 @@ merged_store_group::apply_stores ()
struct imm_store_chain_info
{
+ tree base_addr;
auto_vec<struct store_immediate_info *> m_store_info;
auto_vec<merged_store_group *> m_merged_store_groups;
- bool terminate_and_process_chain (tree);
+ imm_store_chain_info (tree b_a) : base_addr (b_a) {}
+ bool terminate_and_process_chain ();
bool coalesce_immediate_stores ();
- bool output_merged_store (tree, merged_store_group *);
- bool output_merged_stores (tree);
+ bool output_merged_store (merged_store_group *);
+ bool output_merged_stores ();
};
const pass_data pass_data_tree_store_merging = {
@@ -712,8 +727,9 @@ private:
hash_map<tree_operand_hash, struct imm_store_chain_info *> m_stores;
bool terminate_and_process_all_chains ();
- bool terminate_all_aliasing_chains (tree, tree, bool, gimple *);
- bool terminate_and_release_chain (tree);
+ bool terminate_all_aliasing_chains (imm_store_chain_info **,
+ bool, gimple *);
+ bool terminate_and_release_chain (imm_store_chain_info *);
}; // class pass_store_merging
/* Terminate and process all recorded chains. Return true if any changes
@@ -726,7 +742,7 @@ pass_store_merging::terminate_and_process_all_chains ()
= m_stores.begin ();
bool ret = false;
for (; iter != m_stores.end (); ++iter)
- ret |= terminate_and_release_chain ((*iter).first);
+ ret |= terminate_and_release_chain ((*iter).second);
return ret;
}
@@ -740,7 +756,8 @@ pass_store_merging::terminate_and_process_all_chains ()
If that is the case we have to terminate any chain anchored at BASE. */
bool
-pass_store_merging::terminate_all_aliasing_chains (tree dest, tree base,
+pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info
+ **chain_info,
bool var_offset_p,
gimple *stmt)
{
@@ -750,44 +767,41 @@ pass_store_merging::terminate_all_aliasing_chains (tree dest, tree base,
if (!gimple_vuse (stmt))
return false;
- struct imm_store_chain_info **chain_info = NULL;
-
/* Check if the assignment destination (BASE) is part of a store chain.
This is to catch non-constant stores to destinations that may be part
of a chain. */
- if (base)
+ if (chain_info)
{
- chain_info = m_stores.get (base);
- if (chain_info)
+ /* We have a chain at BASE and we're writing to [BASE + <variable>].
+ This can interfere with any of the stores so terminate
+ the chain. */
+ if (var_offset_p)
{
- /* We have a chain at BASE and we're writing to [BASE + <variable>].
- This can interfere with any of the stores so terminate
- the chain. */
- if (var_offset_p)
- {
- terminate_and_release_chain (base);
- ret = true;
- }
- /* Otherwise go through every store in the chain to see if it
- aliases with any of them. */
- else
+ terminate_and_release_chain (*chain_info);
+ ret = true;
+ }
+ /* Otherwise go through every store in the chain to see if it
+ aliases with any of them. */
+ else
+ {
+ struct store_immediate_info *info;
+ unsigned int i;
+ FOR_EACH_VEC_ELT ((*chain_info)->m_store_info, i, info)
{
- struct store_immediate_info *info;
- unsigned int i;
- FOR_EACH_VEC_ELT ((*chain_info)->m_store_info, i, info)
+ if (ref_maybe_used_by_stmt_p (stmt,
+ gimple_assign_lhs (info->stmt))
+ || stmt_may_clobber_ref_p (stmt,
+ gimple_assign_lhs (info->stmt)))
{
- if (refs_may_alias_p (info->dest, dest))
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file,
- "stmt causes chain termination:\n");
- print_gimple_stmt (dump_file, stmt, 0, 0);
- }
- terminate_and_release_chain (base);
- ret = true;
- break;
+ fprintf (dump_file,
+ "stmt causes chain termination:\n");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
}
+ terminate_and_release_chain (*chain_info);
+ ret = true;
+ break;
}
}
}
@@ -804,11 +818,16 @@ pass_store_merging::terminate_all_aliasing_chains (tree dest, tree base,
if (chain_info && (*chain_info) == (*iter).second)
continue;
- tree key = (*iter).first;
- if (ref_maybe_used_by_stmt_p (stmt, key)
- || stmt_may_clobber_ref_p (stmt, key))
+ /* We can't use the base object here as that does not reliably exist.
+ Build a ao_ref from the base object address (if we know the
+ minimum and maximum offset and the maximum size we could improve
+ things here). */
+ ao_ref chain_ref;
+ ao_ref_init_from_ptr_and_size (&chain_ref, (*iter).first, NULL_TREE);
+ if (ref_maybe_used_by_stmt_p (stmt, &chain_ref)
+ || stmt_may_clobber_ref_p_1 (stmt, &chain_ref))
{
- terminate_and_release_chain (key);
+ terminate_and_release_chain ((*iter).second);
ret = true;
}
}
@@ -821,19 +840,11 @@ pass_store_merging::terminate_all_aliasing_chains (tree dest, tree base,
entry is removed after the processing in any case. */
bool
-pass_store_merging::terminate_and_release_chain (tree base)
+pass_store_merging::terminate_and_release_chain (imm_store_chain_info *chain_info)
{
- struct imm_store_chain_info **chain_info = m_stores.get (base);
-
- if (!chain_info)
- return false;
-
- gcc_assert (*chain_info);
-
- bool ret = (*chain_info)->terminate_and_process_chain (base);
- delete *chain_info;
- m_stores.remove (base);
-
+ bool ret = chain_info->terminate_and_process_chain ();
+ m_stores.remove (chain_info->base_addr);
+ delete chain_info;
return ret;
}
@@ -870,7 +881,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
fprintf (dump_file, "Store %u:\nbitsize:" HOST_WIDE_INT_PRINT_DEC
" bitpos:" HOST_WIDE_INT_PRINT_DEC " val:\n",
i, info->bitsize, info->bitpos);
- print_generic_expr (dump_file, info->val, 0);
+ print_generic_expr (dump_file, gimple_assign_rhs1 (info->stmt), 0);
fprintf (dump_file, "\n------------\n");
}
@@ -1093,7 +1104,7 @@ split_group (merged_store_group *group,
return true. */
bool
-imm_store_chain_info::output_merged_store (tree base, merged_store_group *group)
+imm_store_chain_info::output_merged_store (merged_store_group *group)
{
unsigned HOST_WIDE_INT start_byte_pos = group->start / BITS_PER_UNIT;
@@ -1121,6 +1132,8 @@ imm_store_chain_info::output_merged_store (tree base, merged_store_group *group)
unsigned int i;
bool fail = false;
+ tree addr = force_gimple_operand_1 (unshare_expr (base_addr), &seq,
+ is_gimple_mem_ref_addr, NULL_TREE);
FOR_EACH_VEC_ELT (split_stores, i, split_store)
{
unsigned HOST_WIDE_INT try_size = split_store->size;
@@ -1130,8 +1143,7 @@ imm_store_chain_info::output_merged_store (tree base, merged_store_group *group)
location_t loc = get_location_for_stmts (split_store->orig_stmts);
tree int_type = build_nonstandard_integer_type (try_size, UNSIGNED);
- SET_TYPE_ALIGN (int_type, align);
- tree addr = build_fold_addr_expr (base);
+ int_type = build_aligned_type (int_type, align);
tree dest = fold_build2 (MEM_REF, int_type, addr,
build_int_cst (offset_type, try_pos));
@@ -1203,14 +1215,14 @@ imm_store_chain_info::output_merged_store (tree base, merged_store_group *group)
successful. Return true iff any changes were made. */
bool
-imm_store_chain_info::output_merged_stores (tree base)
+imm_store_chain_info::output_merged_stores ()
{
unsigned int i;
merged_store_group *merged_store;
bool ret = false;
FOR_EACH_VEC_ELT (m_merged_store_groups, i, merged_store)
{
- if (output_merged_store (base, merged_store))
+ if (output_merged_store (merged_store))
{
unsigned int j;
store_immediate_info *store;
@@ -1240,7 +1252,7 @@ imm_store_chain_info::output_merged_stores (tree base)
Return true if any changes were made. */
bool
-imm_store_chain_info::terminate_and_process_chain (tree base)
+imm_store_chain_info::terminate_and_process_chain ()
{
/* Process store chain. */
bool ret = false;
@@ -1248,7 +1260,7 @@ imm_store_chain_info::terminate_and_process_chain (tree base)
{
ret = coalesce_immediate_stores ();
if (ret)
- ret = output_merged_stores (base);
+ ret = output_merged_stores ();
}
/* Delete all the entries we allocated ourselves. */
@@ -1361,37 +1373,58 @@ pass_store_merging::execute (function *fun)
&unsignedp, &reversep, &volatilep);
/* As a future enhancement we could handle stores with the same
base and offset. */
- bool invalid = offset || reversep
+ bool invalid = reversep
|| ((bitsize > MAX_BITSIZE_MODE_ANY_INT)
&& (TREE_CODE (rhs) != INTEGER_CST))
- || !rhs_valid_for_store_merging_p (rhs)
- /* An access may not be volatile itself but base_addr may be
- a volatile decl i.e. MEM[&volatile-decl]. The hashing for
- tree_operand_hash won't consider such stores equal to each
- other so we can't track chains on them. */
- || TREE_THIS_VOLATILE (base_addr);
+ || !rhs_valid_for_store_merging_p (rhs);
+ /* We do not want to rewrite TARGET_MEM_REFs. */
+ if (TREE_CODE (base_addr) == TARGET_MEM_REF)
+ invalid = true;
/* In some cases get_inner_reference may return a
MEM_REF [ptr + byteoffset]. For the purposes of this pass
canonicalize the base_addr to MEM_REF [ptr] and take
byteoffset into account in the bitpos. This occurs in
PR 23684 and this way we can catch more chains. */
- if (TREE_CODE (base_addr) == MEM_REF
- && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (base_addr, 0))))
+ else if (TREE_CODE (base_addr) == MEM_REF)
{
offset_int bit_off, byte_off = mem_ref_offset (base_addr);
bit_off = byte_off << LOG2_BITS_PER_UNIT;
bit_off += bitpos;
if (!wi::neg_p (bit_off) && wi::fits_shwi_p (bit_off))
- {
- bitpos = bit_off.to_shwi ();
- base_addr = build2 (MEM_REF, TREE_TYPE (base_addr),
- TREE_OPERAND (base_addr, 0),
- build_zero_cst (TREE_TYPE (
- TREE_OPERAND (base_addr, 1))));
- }
+ bitpos = bit_off.to_shwi ();
else
invalid = true;
+ base_addr = TREE_OPERAND (base_addr, 0);
+ }
+ /* get_inner_reference returns the base object, get at its
+ address now. */
+ else
+ {
+ if (bitpos < 0)
+ invalid = true;
+ base_addr = build_fold_addr_expr (base_addr);
+ }
+
+ if (! invalid
+ && offset != NULL_TREE)
+ {
+ /* If the access is variable offset then a base
+ decl has to be address-taken to be able to
+ emit pointer-based stores to it.
+ ??? We might be able to get away with
+ re-using the original base up to the first
+ variable part and then wrapping that inside
+ a BIT_FIELD_REF. */
+ tree base = get_base_address (base_addr);
+ if (! base
+ || (DECL_P (base)
+ && ! TREE_ADDRESSABLE (base)))
+ invalid = true;
+ else
+ base_addr = build2 (POINTER_PLUS_EXPR,
+ TREE_TYPE (base_addr),
+ base_addr, offset);
}
struct imm_store_chain_info **chain_info
@@ -1403,7 +1436,7 @@ pass_store_merging::execute (function *fun)
if (chain_info)
{
info = new store_immediate_info (
- bitsize, bitpos, rhs, lhs, stmt,
+ bitsize, bitpos, stmt,
(*chain_info)->m_store_info.length ());
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -1422,17 +1455,17 @@ pass_store_merging::execute (function *fun)
fprintf (dump_file,
"Reached maximum number of statements"
" to merge:\n");
- terminate_and_release_chain (base_addr);
+ terminate_and_release_chain (*chain_info);
}
continue;
}
/* Store aliases any existing chain? */
- terminate_all_aliasing_chains (lhs, base_addr, false, stmt);
+ terminate_all_aliasing_chains (chain_info, false, stmt);
/* Start a new chain. */
struct imm_store_chain_info *new_chain
- = new imm_store_chain_info;
- info = new store_immediate_info (bitsize, bitpos, rhs, lhs,
+ = new imm_store_chain_info (base_addr);
+ info = new store_immediate_info (bitsize, bitpos,
stmt, 0);
new_chain->m_store_info.safe_push (info);
m_stores.put (base_addr, new_chain);
@@ -1447,13 +1480,13 @@ pass_store_merging::execute (function *fun)
}
}
else
- terminate_all_aliasing_chains (lhs, base_addr,
+ terminate_all_aliasing_chains (chain_info,
offset != NULL_TREE, stmt);
continue;
}
- terminate_all_aliasing_chains (NULL_TREE, NULL_TREE, false, stmt);
+ terminate_all_aliasing_chains (NULL, false, stmt);
}
terminate_and_process_all_chains ();
}
@@ -1469,3 +1502,141 @@ make_pass_store_merging (gcc::context *ctxt)
{
return new pass_store_merging (ctxt);
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for store merging helpers. */
+
+/* Assert that all elements of the byte arrays X and Y, both of length N
+ are equal. */
+
+static void
+verify_array_eq (unsigned char *x, unsigned char *y, unsigned int n)
+{
+ for (unsigned int i = 0; i < n; i++)
+ {
+ if (x[i] != y[i])
+ {
+ fprintf (stderr, "Arrays do not match. X:\n");
+ dump_char_array (stderr, x, n);
+ fprintf (stderr, "Y:\n");
+ dump_char_array (stderr, y, n);
+ }
+ ASSERT_EQ (x[i], y[i]);
+ }
+}
+
+/* Test shift_bytes_in_array and that it carries bits across between
+ bytes correctly. */
+
+static void
+verify_shift_bytes_in_array (void)
+{
+ /* byte 1 | byte 0
+ 00011111 | 11100000. */
+ unsigned char orig[2] = { 0xe0, 0x1f };
+ unsigned char in[2];
+ memcpy (in, orig, sizeof orig);
+
+ unsigned char expected[2] = { 0x80, 0x7f };
+ shift_bytes_in_array (in, sizeof (in), 2);
+ verify_array_eq (in, expected, sizeof (in));
+
+ memcpy (in, orig, sizeof orig);
+ memcpy (expected, orig, sizeof orig);
+ /* Check that shifting by zero doesn't change anything. */
+ shift_bytes_in_array (in, sizeof (in), 0);
+ verify_array_eq (in, expected, sizeof (in));
+
+}
+
+/* Test shift_bytes_in_array_right and that it carries bits across between
+ bytes correctly. */
+
+static void
+verify_shift_bytes_in_array_right (void)
+{
+ /* byte 1 | byte 0
+ 00011111 | 11100000. */
+ unsigned char orig[2] = { 0x1f, 0xe0};
+ unsigned char in[2];
+ memcpy (in, orig, sizeof orig);
+ unsigned char expected[2] = { 0x07, 0xf8};
+ shift_bytes_in_array_right (in, sizeof (in), 2);
+ verify_array_eq (in, expected, sizeof (in));
+
+ memcpy (in, orig, sizeof orig);
+ memcpy (expected, orig, sizeof orig);
+ /* Check that shifting by zero doesn't change anything. */
+ shift_bytes_in_array_right (in, sizeof (in), 0);
+ verify_array_eq (in, expected, sizeof (in));
+}
+
+/* Test clear_bit_region that it clears exactly the bits asked and
+ nothing more. */
+
+static void
+verify_clear_bit_region (void)
+{
+ /* Start with all bits set and test clearing various patterns in them. */
+ unsigned char orig[3] = { 0xff, 0xff, 0xff};
+ unsigned char in[3];
+ unsigned char expected[3];
+ memcpy (in, orig, sizeof in);
+
+ /* Check zeroing out all the bits. */
+ clear_bit_region (in, 0, 3 * BITS_PER_UNIT);
+ expected[0] = expected[1] = expected[2] = 0;
+ verify_array_eq (in, expected, sizeof in);
+
+ memcpy (in, orig, sizeof in);
+ /* Leave the first and last bits intact. */
+ clear_bit_region (in, 1, 3 * BITS_PER_UNIT - 2);
+ expected[0] = 0x1;
+ expected[1] = 0;
+ expected[2] = 0x80;
+ verify_array_eq (in, expected, sizeof in);
+}
+
+/* Test verify_clear_bit_region_be that it clears exactly the bits asked and
+ nothing more. */
+
+static void
+verify_clear_bit_region_be (void)
+{
+ /* Start with all bits set and test clearing various patterns in them. */
+ unsigned char orig[3] = { 0xff, 0xff, 0xff};
+ unsigned char in[3];
+ unsigned char expected[3];
+ memcpy (in, orig, sizeof in);
+
+ /* Check zeroing out all the bits. */
+ clear_bit_region_be (in, BITS_PER_UNIT - 1, 3 * BITS_PER_UNIT);
+ expected[0] = expected[1] = expected[2] = 0;
+ verify_array_eq (in, expected, sizeof in);
+
+ memcpy (in, orig, sizeof in);
+ /* Leave the first and last bits intact. */
+ clear_bit_region_be (in, BITS_PER_UNIT - 2, 3 * BITS_PER_UNIT - 2);
+ expected[0] = 0x80;
+ expected[1] = 0;
+ expected[2] = 0x1;
+ verify_array_eq (in, expected, sizeof in);
+}
+
+
+/* Run all of the selftests within this file. */
+
+void
+store_merging_c_tests (void)
+{
+ verify_shift_bytes_in_array ();
+ verify_shift_bytes_in_array_right ();
+ verify_clear_bit_region ();
+ verify_clear_bit_region_be ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P. */
diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c
index 5dad1193c27..bdfdb9a82b1 100644
--- a/gcc/gimple-ssa-strength-reduction.c
+++ b/gcc/gimple-ssa-strength-reduction.c
@@ -246,6 +246,13 @@ struct slsr_cand_d
replacement MEM_REF.) */
tree cand_type;
+ /* The type to be used to interpret the stride field when the stride
+ is not a constant. Normally the same as the type of the recorded
+ stride, but when the stride has been cast we need to maintain that
+ knowledge in order to make legal substitutions without losing
+ precision. When the stride is a constant, this will be sizetype. */
+ tree stride_type;
+
/* The kind of candidate (CAND_MULT, etc.). */
enum cand_kind kind;
@@ -502,6 +509,7 @@ find_basis_for_base_expr (slsr_cand_t c, tree base_expr)
|| one_basis->cand_stmt == c->cand_stmt
|| !operand_equal_p (one_basis->stride, c->stride, 0)
|| !types_compatible_p (one_basis->cand_type, c->cand_type)
+ || !types_compatible_p (one_basis->stride_type, c->stride_type)
|| !dominated_by_p (CDI_DOMINATORS,
gimple_bb (c->cand_stmt),
gimple_bb (one_basis->cand_stmt)))
@@ -615,7 +623,7 @@ record_potential_basis (slsr_cand_t c, tree base)
static slsr_cand_t
alloc_cand_and_find_basis (enum cand_kind kind, gimple *gs, tree base,
const widest_int &index, tree stride, tree ctype,
- unsigned savings)
+ tree stype, unsigned savings)
{
slsr_cand_t c = (slsr_cand_t) obstack_alloc (&cand_obstack,
sizeof (slsr_cand));
@@ -624,6 +632,7 @@ alloc_cand_and_find_basis (enum cand_kind kind, gimple *gs, tree base,
c->stride = stride;
c->index = index;
c->cand_type = ctype;
+ c->stride_type = stype;
c->kind = kind;
c->cand_num = cand_vec.length () + 1;
c->next_interp = 0;
@@ -809,7 +818,8 @@ slsr_process_phi (gphi *phi, bool speed)
base_type = TREE_TYPE (arg0_base);
c = alloc_cand_and_find_basis (CAND_PHI, phi, arg0_base,
- 0, integer_one_node, base_type, savings);
+ 0, integer_one_node, base_type,
+ sizetype, savings);
/* Add the candidate to the statement-candidate mapping. */
add_cand_for_stmt (phi, c);
@@ -838,7 +848,8 @@ backtrace_base_for_ref (tree *pbase)
e.g. 'B' is widened from an 'int' in order to calculate
a 64-bit address. */
if (CONVERT_EXPR_P (base_in)
- && legal_cast_p_1 (base_in, TREE_OPERAND (base_in, 0)))
+ && legal_cast_p_1 (TREE_TYPE (base_in),
+ TREE_TYPE (TREE_OPERAND (base_in, 0))))
base_in = get_unwidened (base_in, NULL_TREE);
if (TREE_CODE (base_in) != SSA_NAME)
@@ -995,7 +1006,7 @@ slsr_process_ref (gimple *gs)
return;
c = alloc_cand_and_find_basis (CAND_REF, gs, base, index, offset,
- type, 0);
+ type, sizetype, 0);
/* Add the candidate to the statement-candidate mapping. */
add_cand_for_stmt (gs, c);
@@ -1010,6 +1021,7 @@ static slsr_cand_t
create_mul_ssa_cand (gimple *gs, tree base_in, tree stride_in, bool speed)
{
tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE;
+ tree stype = NULL_TREE;
widest_int index;
unsigned savings = 0;
slsr_cand_t c;
@@ -1030,6 +1042,7 @@ create_mul_ssa_cand (gimple *gs, tree base_in, tree stride_in, bool speed)
index = base_cand->index;
stride = stride_in;
ctype = base_cand->cand_type;
+ stype = TREE_TYPE (stride_in);
if (has_single_use (base_in))
savings = (base_cand->dead_savings
+ stmt_cost (base_cand->cand_stmt, speed));
@@ -1045,6 +1058,7 @@ create_mul_ssa_cand (gimple *gs, tree base_in, tree stride_in, bool speed)
index = base_cand->index * wi::to_widest (base_cand->stride);
stride = stride_in;
ctype = base_cand->cand_type;
+ stype = TREE_TYPE (stride_in);
if (has_single_use (base_in))
savings = (base_cand->dead_savings
+ stmt_cost (base_cand->cand_stmt, speed));
@@ -1064,10 +1078,11 @@ create_mul_ssa_cand (gimple *gs, tree base_in, tree stride_in, bool speed)
index = 0;
stride = stride_in;
ctype = TREE_TYPE (base_in);
+ stype = TREE_TYPE (stride_in);
}
c = alloc_cand_and_find_basis (CAND_MULT, gs, base, index, stride,
- ctype, savings);
+ ctype, stype, savings);
return c;
}
@@ -1156,7 +1171,7 @@ create_mul_imm_cand (gimple *gs, tree base_in, tree stride_in, bool speed)
}
c = alloc_cand_and_find_basis (CAND_MULT, gs, base, index, stride,
- ctype, savings);
+ ctype, sizetype, savings);
return c;
}
@@ -1212,7 +1227,8 @@ static slsr_cand_t
create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in,
bool subtract_p, bool speed)
{
- tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL;
+ tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE;
+ tree stype = NULL_TREE;
widest_int index;
unsigned savings = 0;
slsr_cand_t c;
@@ -1237,6 +1253,7 @@ create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in,
index = -index;
stride = addend_cand->base_expr;
ctype = TREE_TYPE (base_in);
+ stype = addend_cand->cand_type;
if (has_single_use (addend_in))
savings = (addend_cand->dead_savings
+ stmt_cost (addend_cand->cand_stmt, speed));
@@ -1263,6 +1280,8 @@ create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in,
index = subtract_p ? -1 : 1;
stride = addend_in;
ctype = base_cand->cand_type;
+ stype = (TREE_CODE (addend_in) == INTEGER_CST ? sizetype
+ : TREE_TYPE (addend_in));
if (has_single_use (base_in))
savings = (base_cand->dead_savings
+ stmt_cost (base_cand->cand_stmt, speed));
@@ -1286,6 +1305,7 @@ create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in,
index = -index;
stride = subtrahend_cand->base_expr;
ctype = TREE_TYPE (base_in);
+ stype = subtrahend_cand->cand_type;
if (has_single_use (addend_in))
savings = (subtrahend_cand->dead_savings
+ stmt_cost (subtrahend_cand->cand_stmt, speed));
@@ -1312,10 +1332,12 @@ create_add_ssa_cand (gimple *gs, tree base_in, tree addend_in,
index = subtract_p ? -1 : 1;
stride = addend_in;
ctype = TREE_TYPE (base_in);
+ stype = (TREE_CODE (addend_in) == INTEGER_CST ? sizetype
+ : TREE_TYPE (addend_in));
}
c = alloc_cand_and_find_basis (CAND_ADD, gs, base, index, stride,
- ctype, savings);
+ ctype, stype, savings);
return c;
}
@@ -1329,6 +1351,7 @@ create_add_imm_cand (gimple *gs, tree base_in, const widest_int &index_in,
{
enum cand_kind kind = CAND_ADD;
tree base = NULL_TREE, stride = NULL_TREE, ctype = NULL_TREE;
+ tree stype = NULL_TREE;
widest_int index, multiple;
unsigned savings = 0;
slsr_cand_t c;
@@ -1356,6 +1379,7 @@ create_add_imm_cand (gimple *gs, tree base_in, const widest_int &index_in,
index = base_cand->index + multiple;
stride = base_cand->stride;
ctype = base_cand->cand_type;
+ stype = base_cand->stride_type;
if (has_single_use (base_in))
savings = (base_cand->dead_savings
+ stmt_cost (base_cand->cand_stmt, speed));
@@ -1376,10 +1400,11 @@ create_add_imm_cand (gimple *gs, tree base_in, const widest_int &index_in,
index = index_in;
stride = integer_one_node;
ctype = TREE_TYPE (base_in);
+ stype = sizetype;
}
c = alloc_cand_and_find_basis (kind, gs, base, index, stride,
- ctype, savings);
+ ctype, stype, savings);
return c;
}
@@ -1456,14 +1481,11 @@ slsr_process_neg (gimple *gs, tree rhs1, bool speed)
for more details. */
static bool
-legal_cast_p_1 (tree lhs, tree rhs)
+legal_cast_p_1 (tree lhs_type, tree rhs_type)
{
- tree lhs_type, rhs_type;
unsigned lhs_size, rhs_size;
bool lhs_wraps, rhs_wraps;
- lhs_type = TREE_TYPE (lhs);
- rhs_type = TREE_TYPE (rhs);
lhs_size = TYPE_PRECISION (lhs_type);
rhs_size = TYPE_PRECISION (rhs_type);
lhs_wraps = ANY_INTEGRAL_TYPE_P (lhs_type) && TYPE_OVERFLOW_WRAPS (lhs_type);
@@ -1521,7 +1543,7 @@ legal_cast_p (gimple *gs, tree rhs)
|| !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs)))
return false;
- return legal_cast_p_1 (gimple_assign_lhs (gs), rhs);
+ return legal_cast_p_1 (TREE_TYPE (gimple_assign_lhs (gs)), TREE_TYPE (rhs));
}
/* Given GS which is a cast to a scalar integer type, determine whether
@@ -1556,7 +1578,8 @@ slsr_process_cast (gimple *gs, tree rhs1, bool speed)
c = alloc_cand_and_find_basis (base_cand->kind, gs,
base_cand->base_expr,
base_cand->index, base_cand->stride,
- ctype, savings);
+ ctype, base_cand->stride_type,
+ savings);
if (base_cand->next_interp)
base_cand = lookup_cand (base_cand->next_interp);
else
@@ -1574,10 +1597,10 @@ slsr_process_cast (gimple *gs, tree rhs1, bool speed)
The first of these is somewhat arbitrary, but the choice of
1 for the stride simplifies the logic for propagating casts
into their uses. */
- c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1,
- 0, integer_one_node, ctype, 0);
- c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1,
- 0, integer_one_node, ctype, 0);
+ c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1, 0,
+ integer_one_node, ctype, sizetype, 0);
+ c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1, 0,
+ integer_one_node, ctype, sizetype, 0);
c->next_interp = c2->cand_num;
}
@@ -1613,7 +1636,8 @@ slsr_process_copy (gimple *gs, tree rhs1, bool speed)
c = alloc_cand_and_find_basis (base_cand->kind, gs,
base_cand->base_expr,
base_cand->index, base_cand->stride,
- base_cand->cand_type, savings);
+ base_cand->cand_type,
+ base_cand->stride_type, savings);
if (base_cand->next_interp)
base_cand = lookup_cand (base_cand->next_interp);
else
@@ -1631,10 +1655,12 @@ slsr_process_copy (gimple *gs, tree rhs1, bool speed)
The first of these is somewhat arbitrary, but the choice of
1 for the stride simplifies the logic for propagating casts
into their uses. */
- c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1,
- 0, integer_one_node, TREE_TYPE (rhs1), 0);
- c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1,
- 0, integer_one_node, TREE_TYPE (rhs1), 0);
+ c = alloc_cand_and_find_basis (CAND_ADD, gs, rhs1, 0,
+ integer_one_node, TREE_TYPE (rhs1),
+ sizetype, 0);
+ c2 = alloc_cand_and_find_basis (CAND_MULT, gs, rhs1, 0,
+ integer_one_node, TREE_TYPE (rhs1),
+ sizetype, 0);
c->next_interp = c2->cand_num;
}
@@ -1755,6 +1781,13 @@ dump_candidate (slsr_cand_t c)
fputs (" + ", dump_file);
print_decs (c->index, dump_file);
fputs (") * ", dump_file);
+ if (TREE_CODE (c->stride) != INTEGER_CST
+ && c->stride_type != TREE_TYPE (c->stride))
+ {
+ fputs ("(", dump_file);
+ print_generic_expr (dump_file, c->stride_type, 0);
+ fputs (")", dump_file);
+ }
print_generic_expr (dump_file, c->stride, 0);
fputs (" : ", dump_file);
break;
@@ -1764,6 +1797,13 @@ dump_candidate (slsr_cand_t c)
fputs (" + (", dump_file);
print_decs (c->index, dump_file);
fputs (" * ", dump_file);
+ if (TREE_CODE (c->stride) != INTEGER_CST
+ && c->stride_type != TREE_TYPE (c->stride))
+ {
+ fputs ("(", dump_file);
+ print_generic_expr (dump_file, c->stride_type, 0);
+ fputs (")", dump_file);
+ }
print_generic_expr (dump_file, c->stride, 0);
fputs (") : ", dump_file);
break;
@@ -2143,7 +2183,7 @@ create_add_on_incoming_edge (slsr_cand_t c, tree basis_name,
basic_block insert_bb;
gimple_stmt_iterator gsi;
tree lhs, basis_type;
- gassign *new_stmt;
+ gassign *new_stmt, *cast_stmt = NULL;
/* If the add candidate along this incoming edge has the same
index as C's hidden basis, the hidden basis represents this
@@ -2187,27 +2227,61 @@ create_add_on_incoming_edge (slsr_cand_t c, tree basis_name,
new_stmt = gimple_build_assign (lhs, code, basis_name,
incr_vec[i].initializer);
}
- else if (increment == 1)
- new_stmt = gimple_build_assign (lhs, plus_code, basis_name, c->stride);
- else if (increment == -1)
- new_stmt = gimple_build_assign (lhs, MINUS_EXPR, basis_name,
- c->stride);
- else
- gcc_unreachable ();
+ else {
+ tree stride;
+
+ if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type))
+ {
+ tree cast_stride = make_temp_ssa_name (c->stride_type, NULL,
+ "slsr");
+ cast_stmt = gimple_build_assign (cast_stride, NOP_EXPR,
+ c->stride);
+ stride = cast_stride;
+ }
+ else
+ stride = c->stride;
+
+ if (increment == 1)
+ new_stmt = gimple_build_assign (lhs, plus_code, basis_name, stride);
+ else if (increment == -1)
+ new_stmt = gimple_build_assign (lhs, MINUS_EXPR, basis_name, stride);
+ else
+ gcc_unreachable ();
+ }
}
insert_bb = single_succ_p (e->src) ? e->src : split_edge (e);
gsi = gsi_last_bb (insert_bb);
if (!gsi_end_p (gsi) && is_ctrl_stmt (gsi_stmt (gsi)))
- gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
+ {
+ gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
+ if (cast_stmt)
+ {
+ gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT);
+ gimple_set_location (cast_stmt, loc);
+ }
+ }
else
- gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
+ {
+ if (cast_stmt)
+ {
+ gsi_insert_after (&gsi, cast_stmt, GSI_NEW_STMT);
+ gimple_set_location (cast_stmt, loc);
+ }
+ gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
+ }
gimple_set_location (new_stmt, loc);
if (dump_file && (dump_flags & TDF_DETAILS))
{
+ if (cast_stmt)
+ {
+ fprintf (dump_file, "Inserting cast in block %d: ",
+ insert_bb->index);
+ print_gimple_stmt (dump_file, cast_stmt, 0, 0);
+ }
fprintf (dump_file, "Inserting in block %d: ", insert_bb->index);
print_gimple_stmt (dump_file, new_stmt, 0, 0);
}
@@ -2825,40 +2899,35 @@ analyze_increments (slsr_cand_t first_dep, machine_mode mode, bool speed)
&& !POINTER_TYPE_P (first_dep->cand_type)))
incr_vec[i].cost = COST_NEUTRAL;
- /* FORNOW: If we need to add an initializer, give up if a cast from
- the candidate's type to its stride's type can lose precision.
- This could eventually be handled better by expressly retaining the
- result of a cast to a wider type in the stride. Example:
+ /* If we need to add an initializer, give up if a cast from the
+ candidate's type to its stride's type can lose precision.
+ Note that this already takes into account that the stride may
+ have been cast to a wider type, in which case this test won't
+ fire. Example:
short int _1;
_2 = (int) _1;
_3 = _2 * 10;
- _4 = x + _3; ADD: x + (10 * _1) : int
+ _4 = x + _3; ADD: x + (10 * (int)_1) : int
_5 = _2 * 15;
- _6 = x + _3; ADD: x + (15 * _1) : int
-
- Right now replacing _6 would cause insertion of an initializer
- of the form "short int T = _1 * 5;" followed by a cast to
- int, which could overflow incorrectly. Had we recorded _2 or
- (int)_1 as the stride, this wouldn't happen. However, doing
- this breaks other opportunities, so this will require some
- care. */
+ _6 = x + _5; ADD: x + (15 * (int)_1) : int
+
+ Although the stride was a short int initially, the stride
+ used in the analysis has been widened to an int, and such
+ widening will be done in the initializer as well. */
else if (!incr_vec[i].initializer
&& TREE_CODE (first_dep->stride) != INTEGER_CST
- && !legal_cast_p_1 (first_dep->stride,
- gimple_assign_lhs (first_dep->cand_stmt)))
-
+ && !legal_cast_p_1 (first_dep->stride_type,
+ TREE_TYPE (gimple_assign_lhs
+ (first_dep->cand_stmt))))
incr_vec[i].cost = COST_INFINITE;
/* If we need to add an initializer, make sure we don't introduce
a multiply by a pointer type, which can happen in certain cast
- scenarios. FIXME: When cleaning up these cast issues, we can
- afford to introduce the multiply provided we cast out to an
- unsigned int of appropriate size. */
+ scenarios. */
else if (!incr_vec[i].initializer
&& TREE_CODE (first_dep->stride) != INTEGER_CST
- && POINTER_TYPE_P (TREE_TYPE (first_dep->stride)))
-
+ && POINTER_TYPE_P (first_dep->stride_type))
incr_vec[i].cost = COST_INFINITE;
/* For any other increment, if this is a multiply candidate, we
@@ -3105,7 +3174,8 @@ insert_initializers (slsr_cand_t c)
basic_block bb;
slsr_cand_t where = NULL;
gassign *init_stmt;
- tree stride_type, new_name, incr_tree;
+ gassign *cast_stmt = NULL;
+ tree new_name, incr_tree, init_stride;
widest_int incr = incr_vec[i].incr;
if (!profitable_increment_p (i)
@@ -3134,37 +3204,74 @@ insert_initializers (slsr_cand_t c)
that block, the earliest one will be returned in WHERE. */
bb = nearest_common_dominator_for_cands (c, incr, &where);
+ /* If the nominal stride has a different type than the recorded
+ stride type, build a cast from the nominal stride to that type. */
+ if (!types_compatible_p (TREE_TYPE (c->stride), c->stride_type))
+ {
+ init_stride = make_temp_ssa_name (c->stride_type, NULL, "slsr");
+ cast_stmt = gimple_build_assign (init_stride, NOP_EXPR, c->stride);
+ }
+ else
+ init_stride = c->stride;
+
/* Create a new SSA name to hold the initializer's value. */
- stride_type = TREE_TYPE (c->stride);
- new_name = make_temp_ssa_name (stride_type, NULL, "slsr");
+ new_name = make_temp_ssa_name (c->stride_type, NULL, "slsr");
incr_vec[i].initializer = new_name;
/* Create the initializer and insert it in the latest possible
dominating position. */
- incr_tree = wide_int_to_tree (stride_type, incr);
+ incr_tree = wide_int_to_tree (c->stride_type, incr);
init_stmt = gimple_build_assign (new_name, MULT_EXPR,
- c->stride, incr_tree);
+ init_stride, incr_tree);
if (where)
{
gimple_stmt_iterator gsi = gsi_for_stmt (where->cand_stmt);
+ location_t loc = gimple_location (where->cand_stmt);
+
+ if (cast_stmt)
+ {
+ gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT);
+ gimple_set_location (cast_stmt, loc);
+ }
+
gsi_insert_before (&gsi, init_stmt, GSI_SAME_STMT);
- gimple_set_location (init_stmt, gimple_location (where->cand_stmt));
+ gimple_set_location (init_stmt, loc);
}
else
{
gimple_stmt_iterator gsi = gsi_last_bb (bb);
gimple *basis_stmt = lookup_cand (c->basis)->cand_stmt;
+ location_t loc = gimple_location (basis_stmt);
if (!gsi_end_p (gsi) && is_ctrl_stmt (gsi_stmt (gsi)))
- gsi_insert_before (&gsi, init_stmt, GSI_SAME_STMT);
+ {
+ if (cast_stmt)
+ {
+ gsi_insert_before (&gsi, cast_stmt, GSI_SAME_STMT);
+ gimple_set_location (cast_stmt, loc);
+ }
+ gsi_insert_before (&gsi, init_stmt, GSI_SAME_STMT);
+ }
else
- gsi_insert_after (&gsi, init_stmt, GSI_SAME_STMT);
+ {
+ if (cast_stmt)
+ {
+ gsi_insert_after (&gsi, cast_stmt, GSI_NEW_STMT);
+ gimple_set_location (cast_stmt, loc);
+ }
+ gsi_insert_after (&gsi, init_stmt, GSI_SAME_STMT);
+ }
gimple_set_location (init_stmt, gimple_location (basis_stmt));
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
+ if (cast_stmt)
+ {
+ fputs ("Inserting stride cast: ", dump_file);
+ print_gimple_stmt (dump_file, cast_stmt, 0, 0);
+ }
fputs ("Inserting initializer: ", dump_file);
print_gimple_stmt (dump_file, init_stmt, 0, 0);
}
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 26e9322dcff..0a3dc72ea21 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "selftest.h"
#include "gimple-pretty-print.h"
+#include "asan.h"
/* All the tuples have their operand vector (if present) at the very bottom
@@ -2629,6 +2630,8 @@ nonfreeing_call_p (gimple *call)
{
case IFN_ABNORMAL_DISPATCHER:
return true;
+ case IFN_ASAN_MARK:
+ return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNCLOBBER;
default:
if (gimple_call_flags (call) & ECF_LEAF)
return true;
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 1531582be11..d392450ddf5 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -59,6 +59,11 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-walk.h"
#include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */
#include "builtins.h"
+#include "asan.h"
+#include "dbgcnt.h"
+
+/* Hash set of poisoned variables in a bind expr. */
+static hash_set<tree> *asan_poisoned_variables = NULL;
enum gimplify_omp_var_data
{
@@ -151,6 +156,7 @@ struct gimplify_ctx
tree return_temp;
vec<tree> case_labels;
+ hash_set<tree> *live_switch_vars;
/* The formal temporary table. Should this be persistent? */
hash_table<gimplify_hasher> *temp_htab;
@@ -1088,6 +1094,121 @@ build_stack_save_restore (gcall **save, gcall **restore)
1, tmp_var);
}
+/* Generate IFN_ASAN_MARK call that poisons shadow of a for DECL variable. */
+
+static tree
+build_asan_poison_call_expr (tree decl)
+{
+ /* Do not poison variables that have size equal to zero. */
+ tree unit_size = DECL_SIZE_UNIT (decl);
+ if (zerop (unit_size))
+ return NULL_TREE;
+
+ tree base = build_fold_addr_expr (decl);
+
+ return build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_ASAN_MARK,
+ void_type_node, 3,
+ build_int_cst (integer_type_node,
+ ASAN_MARK_CLOBBER),
+ base, unit_size);
+}
+
+/* Generate IFN_ASAN_MARK call that would poison or unpoison, depending
+ on POISON flag, shadow memory of a DECL variable. The call will be
+ put on location identified by IT iterator, where BEFORE flag drives
+ position where the stmt will be put. */
+
+static void
+asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it,
+ bool before)
+{
+ /* When within an OMP context, do not emit ASAN_MARK internal fns. */
+ if (gimplify_omp_ctxp)
+ return;
+
+ tree unit_size = DECL_SIZE_UNIT (decl);
+ tree base = build_fold_addr_expr (decl);
+
+ /* Do not poison variables that have size equal to zero. */
+ if (zerop (unit_size))
+ return;
+
+ /* It's necessary to have all stack variables aligned to ASAN granularity
+ bytes. */
+ if (DECL_ALIGN_UNIT (decl) <= ASAN_SHADOW_GRANULARITY)
+ SET_DECL_ALIGN (decl, BITS_PER_UNIT * ASAN_SHADOW_GRANULARITY);
+
+ HOST_WIDE_INT flags = poison ? ASAN_MARK_CLOBBER : ASAN_MARK_UNCLOBBER;
+
+ gimple *g
+ = gimple_build_call_internal (IFN_ASAN_MARK, 3,
+ build_int_cst (integer_type_node, flags),
+ base, unit_size);
+
+ if (before)
+ gsi_insert_before (it, g, GSI_NEW_STMT);
+ else
+ gsi_insert_after (it, g, GSI_NEW_STMT);
+}
+
+/* Generate IFN_ASAN_MARK internal call that depending on POISON flag
+ either poisons or unpoisons a DECL. Created statement is appended
+ to SEQ_P gimple sequence. */
+
+static void
+asan_poison_variable (tree decl, bool poison, gimple_seq *seq_p)
+{
+ gimple_stmt_iterator it = gsi_last (*seq_p);
+ bool before = false;
+
+ if (gsi_end_p (it))
+ before = true;
+
+ asan_poison_variable (decl, poison, &it, before);
+}
+
+/* Sort pair of VAR_DECLs A and B by DECL_UID. */
+
+static int
+sort_by_decl_uid (const void *a, const void *b)
+{
+ const tree *t1 = (const tree *)a;
+ const tree *t2 = (const tree *)b;
+
+ int uid1 = DECL_UID (*t1);
+ int uid2 = DECL_UID (*t2);
+
+ if (uid1 < uid2)
+ return -1;
+ else if (uid1 > uid2)
+ return 1;
+ else
+ return 0;
+}
+
+/* Generate IFN_ASAN_MARK internal call for all VARIABLES
+ depending on POISON flag. Created statement is appended
+ to SEQ_P gimple sequence. */
+
+static void
+asan_poison_variables (hash_set<tree> *variables, bool poison, gimple_seq *seq_p)
+{
+ unsigned c = variables->elements ();
+ if (c == 0)
+ return;
+
+ auto_vec<tree> sorted_variables (c);
+
+ for (hash_set<tree>::iterator it = variables->begin ();
+ it != variables->end (); ++it)
+ sorted_variables.safe_push (*it);
+
+ sorted_variables.qsort (sort_by_decl_uid);
+
+ for (unsigned i = 0; i < sorted_variables.length (); i++)
+ asan_poison_variable (sorted_variables[i], poison, seq_p);
+}
+
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
static enum gimplify_status
@@ -1231,6 +1352,17 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
}
}
}
+
+ if (asan_poisoned_variables != NULL
+ && asan_poisoned_variables->contains (t))
+ {
+ asan_poisoned_variables->remove (t);
+ asan_poison_variable (t, true, &cleanup);
+ }
+
+ if (gimplify_ctxp->live_switch_vars != NULL
+ && gimplify_ctxp->live_switch_vars->contains (t))
+ gimplify_ctxp->live_switch_vars->remove (t);
}
if (ret_clauses)
@@ -1475,13 +1607,31 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
if (VAR_P (decl) && !DECL_EXTERNAL (decl))
{
tree init = DECL_INITIAL (decl);
+ bool is_vla = false;
if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST
|| (!TREE_STATIC (decl)
&& flag_stack_check == GENERIC_STACK_CHECK
&& compare_tree_int (DECL_SIZE_UNIT (decl),
STACK_CHECK_MAX_VAR_SIZE) > 0))
- gimplify_vla_decl (decl, seq_p);
+ {
+ gimplify_vla_decl (decl, seq_p);
+ is_vla = true;
+ }
+
+ if (asan_sanitize_use_after_scope ()
+ && !asan_no_sanitize_address_p ()
+ && !is_vla
+ && TREE_ADDRESSABLE (decl)
+ && !TREE_STATIC (decl)
+ && !DECL_HAS_VALUE_EXPR_P (decl)
+ && dbg_cnt (asan_use_after_scope))
+ {
+ asan_poisoned_variables->add (decl);
+ asan_poison_variable (decl, false, seq_p);
+ if (!DECL_ARTIFICIAL (decl) && gimplify_ctxp->live_switch_vars)
+ gimplify_ctxp->live_switch_vars->add (decl);
+ }
/* Some front ends do not explicitly declare all anonymous
artificial variables. We compensate here by declaring the
@@ -1591,6 +1741,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
/* Walk the sub-statements. */
*handled_ops_p = false;
break;
+ case GIMPLE_CALL:
+ if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
+ {
+ *handled_ops_p = false;
+ break;
+ }
+ /* Fall through. */
default:
/* Save the first "real" statement (not a decl/lexical scope/...). */
wi->info = stmt;
@@ -1802,6 +1959,8 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p,
if (find_label_entry (labels, label))
prev = gsi_stmt (*gsi_p);
}
+ else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK))
+ ;
else
prev = gsi_stmt (*gsi_p);
gsi_next (gsi_p);
@@ -2082,6 +2241,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
{
vec<tree> labels;
vec<tree> saved_labels;
+ hash_set<tree> *saved_live_switch_vars;
tree default_case = NULL_TREE;
gswitch *switch_stmt;
@@ -2093,6 +2253,8 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
labels. Save all the things from the switch body to append after. */
saved_labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels.create (8);
+ saved_live_switch_vars = gimplify_ctxp->live_switch_vars;
+ gimplify_ctxp->live_switch_vars = new hash_set<tree> (4);
bool old_in_switch_expr = gimplify_ctxp->in_switch_expr;
gimplify_ctxp->in_switch_expr = true;
@@ -2107,6 +2269,9 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p)
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
+ gcc_assert (gimplify_ctxp->live_switch_vars->elements () == 0);
+ delete gimplify_ctxp->live_switch_vars;
+ gimplify_ctxp->live_switch_vars = saved_live_switch_vars;
preprocess_case_label_vec_for_gimple (labels, index_type,
&default_case);
@@ -6164,6 +6329,9 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
tree init = TARGET_EXPR_INITIAL (targ);
enum gimplify_status ret;
+ bool unpoison_empty_seq = false;
+ gimple_stmt_iterator unpoison_it;
+
if (init)
{
tree cleanup = NULL_TREE;
@@ -6177,7 +6345,14 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
gimplify_vla_decl (temp, pre_p);
}
else
- gimple_add_tmp_var (temp);
+ {
+ /* Save location where we need to place unpoisoning. It's possible
+ that a variable will be converted to needs_to_live_in_memory. */
+ unpoison_it = gsi_last (*pre_p);
+ unpoison_empty_seq = gsi_end_p (unpoison_it);
+
+ gimple_add_tmp_var (temp);
+ }
/* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
expression is supposed to initialize the slot. */
@@ -6213,20 +6388,35 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
/* Add a clobber for the temporary going out of scope, like
gimplify_bind_expr. */
if (gimplify_ctxp->in_cleanup_point_expr
- && needs_to_live_in_memory (temp)
- && flag_stack_reuse == SR_ALL)
- {
- tree clobber = build_constructor (TREE_TYPE (temp),
- NULL);
- TREE_THIS_VOLATILE (clobber) = true;
- clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber);
- if (cleanup)
- cleanup = build2 (COMPOUND_EXPR, void_type_node, cleanup,
- clobber);
- else
- cleanup = clobber;
- }
+ && needs_to_live_in_memory (temp))
+ {
+ if (flag_stack_reuse == SR_ALL)
+ {
+ tree clobber = build_constructor (TREE_TYPE (temp),
+ NULL);
+ TREE_THIS_VOLATILE (clobber) = true;
+ clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber);
+ if (cleanup)
+ cleanup = build2 (COMPOUND_EXPR, void_type_node, cleanup,
+ clobber);
+ else
+ cleanup = clobber;
+ }
+ if (asan_sanitize_use_after_scope ()
+ && dbg_cnt (asan_use_after_scope))
+ {
+ tree asan_cleanup = build_asan_poison_call_expr (temp);
+ if (asan_cleanup)
+ {
+ if (unpoison_empty_seq)
+ unpoison_it = gsi_start (*pre_p);
+ asan_poison_variable (temp, false, &unpoison_it,
+ unpoison_empty_seq);
+ gimple_push_cleanup (temp, asan_cleanup, false, pre_p);
+ }
+ }
+ }
if (cleanup)
gimple_push_cleanup (temp, cleanup, false, pre_p);
@@ -10824,6 +11014,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
location_t saved_location;
enum gimplify_status ret;
gimple_stmt_iterator pre_last_gsi, post_last_gsi;
+ tree label;
save_expr = *expr_p;
if (save_expr == NULL_TREE)
@@ -11239,10 +11430,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
case LABEL_EXPR:
ret = gimplify_label_expr (expr_p, pre_p);
+ label = LABEL_EXPR_LABEL (*expr_p);
+ gcc_assert (decl_function_context (label) == current_function_decl);
+
+ /* If the label is used in a goto statement, or address of the label
+ is taken, we need to unpoison all variables that were seen so far.
+ Doing so would prevent us from reporting a false positives. */
+ if (asan_sanitize_use_after_scope ()
+ && asan_used_labels != NULL
+ && asan_used_labels->contains (label))
+ asan_poison_variables (asan_poisoned_variables, false, pre_p);
break;
case CASE_LABEL_EXPR:
ret = gimplify_case_label_expr (expr_p, pre_p);
+
+ if (gimplify_ctxp->live_switch_vars)
+ asan_poison_variables (gimplify_ctxp->live_switch_vars, false,
+ pre_p);
break;
case RETURN_EXPR:
@@ -12336,7 +12541,10 @@ gimplify_function_tree (tree fndecl)
&& !needs_to_live_in_memory (ret))
DECL_GIMPLE_REG_P (ret) = 1;
+ asan_poisoned_variables = new hash_set<tree> ();
bind = gimplify_body (fndecl, true);
+ delete asan_poisoned_variables;
+ asan_poisoned_variables = NULL;
/* The tree body of the function is no longer needed, replace it
with the new GIMPLE body. */
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index fcc2f9f9af9..9049bc37476 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-6d9929a1641b180e724c2fdcdd55f6a254f1dec0
+afe0456d25e3c6c0d91a8fd4c0fdfdbaa35cc251
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc
index ba55ea314c3..bcea63d5a6e 100644
--- a/gcc/go/gofrontend/escape.cc
+++ b/gcc/go/gofrontend/escape.cc
@@ -284,20 +284,19 @@ Node::op_format() const
op << "panic";
break;
- case Runtime::APPEND:
+ case Runtime::GROWSLICE:
op << "append";
break;
- case Runtime::COPY:
+ case Runtime::SLICECOPY:
+ case Runtime::SLICESTRINGCOPY:
+ case Runtime::TYPEDSLICECOPY:
op << "copy";
break;
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
- case Runtime::MAKESLICE1:
- case Runtime::MAKESLICE2:
- case Runtime::MAKESLICE1BIG:
- case Runtime::MAKESLICE2BIG:
+ case Runtime::MAKESLICE:
op << "make";
break;
@@ -419,10 +418,7 @@ Node::is_big(Escape_context* context) const
Func_expression* fn = call->fn()->func_expression();
if (fn != NULL
&& fn->is_runtime_function()
- && (fn->runtime_code() == Runtime::MAKESLICE1
- || fn->runtime_code() == Runtime::MAKESLICE2
- || fn->runtime_code() == Runtime::MAKESLICE1BIG
- || fn->runtime_code() == Runtime::MAKESLICE2BIG))
+ && fn->runtime_code() == Runtime::MAKESLICE)
{
// Second argument is length.
Expression_list::iterator p = call->args()->begin();
@@ -1201,13 +1197,25 @@ Escape_analysis_assign::expression(Expression** pexpr)
}
break;
- case Runtime::APPEND:
+ case Runtime::GROWSLICE:
{
- // Unlike gc/esc.go, a call to append has already had its
- // varargs lowered into a slice of arguments.
- // The content of the appended slice leaks.
- Node* appended = Node::make_node(call->args()->back());
- this->assign_deref(this->context_->sink(), appended);
+ // The contents being appended leak.
+ if (call->is_varargs())
+ {
+ Node* appended = Node::make_node(call->args()->back());
+ this->assign_deref(this->context_->sink(), appended);
+ }
+ else
+ {
+ for (Expression_list::const_iterator pa =
+ call->args()->begin();
+ pa != call->args()->end();
+ ++pa)
+ {
+ Node* arg = Node::make_node(*pa);
+ this->assign(this->context_->sink(), arg);
+ }
+ }
if (debug_level > 2)
go_error_at((*pexpr)->location(),
@@ -1219,7 +1227,9 @@ Escape_analysis_assign::expression(Expression** pexpr)
}
break;
- case Runtime::COPY:
+ case Runtime::SLICECOPY:
+ case Runtime::SLICESTRINGCOPY:
+ case Runtime::TYPEDSLICECOPY:
{
// Lose track of the copied content.
Node* copied = Node::make_node(call->args()->back());
@@ -1229,10 +1239,7 @@ Escape_analysis_assign::expression(Expression** pexpr)
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
- case Runtime::MAKESLICE1:
- case Runtime::MAKESLICE2:
- case Runtime::MAKESLICE1BIG:
- case Runtime::MAKESLICE2BIG:
+ case Runtime::MAKESLICE:
case Runtime::SLICEBYTETOSTRING:
case Runtime::SLICERUNETOSTRING:
case Runtime::STRINGTOSLICEBYTE:
@@ -1829,7 +1836,7 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
{
switch (fe->runtime_code())
{
- case Runtime::APPEND:
+ case Runtime::GROWSLICE:
{
// Append returns the first argument.
// The subsequent arguments are already leaked because
@@ -1841,10 +1848,7 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
- case Runtime::MAKESLICE1:
- case Runtime::MAKESLICE2:
- case Runtime::MAKESLICE1BIG:
- case Runtime::MAKESLICE2BIG:
+ case Runtime::MAKESLICE:
// DST = make(...).
case Runtime::SLICEBYTETOSTRING:
// DST = string([]byte{...}).
@@ -2608,7 +2612,7 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
{
switch (func->runtime_code())
{
- case Runtime::APPEND:
+ case Runtime::GROWSLICE:
{
// Propagate escape information to appendee.
Expression* appendee = call->args()->front();
@@ -2618,10 +2622,7 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
- case Runtime::MAKESLICE1:
- case Runtime::MAKESLICE2:
- case Runtime::MAKESLICE1BIG:
- case Runtime::MAKESLICE2BIG:
+ case Runtime::MAKESLICE:
case Runtime::SLICEBYTETOSTRING:
case Runtime::SLICERUNETOSTRING:
case Runtime::STRINGTOSLICEBYTE:
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 241dc36e5e1..69f4e016ba4 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -6951,7 +6951,9 @@ class Builtin_call_expression : public Call_expression
complex_type(Type*);
Expression*
- lower_make();
+ lower_make(Statement_inserter*);
+
+ Expression* flatten_append(Gogo*, Named_object*, Statement_inserter*);
bool
check_int_value(Expression*, bool is_length);
@@ -7052,7 +7054,7 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg)
// specific expressions. We also convert to a constant if we can.
Expression*
-Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
+Builtin_call_expression::do_lower(Gogo*, Named_object* function,
Statement_inserter* inserter, int)
{
if (this->is_error_expression())
@@ -7130,7 +7132,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
break;
case BUILTIN_MAKE:
- return this->lower_make();
+ return this->lower_make(inserter);
case BUILTIN_RECOVER:
if (function != NULL)
@@ -7144,30 +7146,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
}
break;
- case BUILTIN_APPEND:
- {
- // Lower the varargs.
- const Expression_list* args = this->args();
- if (args == NULL || args->empty())
- return this;
- Type* slice_type = args->front()->type();
- if (!slice_type->is_slice_type())
- {
- if (slice_type->is_nil_type())
- go_error_at(args->front()->location(), "use of untyped nil");
- else
- go_error_at(args->front()->location(),
- "argument 1 must be a slice");
- this->set_is_error();
- return this;
- }
- Type* element_type = slice_type->array_type()->element_type();
- this->lower_varargs(gogo, function, inserter,
- Type::make_array_type(element_type, NULL),
- 2, SLICE_STORAGE_DOES_NOT_ESCAPE);
- }
- break;
-
case BUILTIN_DELETE:
{
// Lower to a runtime function call.
@@ -7215,7 +7193,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
pa != this->args()->end();
++pa)
{
- if (!(*pa)->is_variable())
+ if (!(*pa)->is_variable() && !(*pa)->is_constant())
{
Temporary_statement* temp =
Statement::make_temporary(NULL, *pa, loc);
@@ -7233,7 +7211,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
// append into temporary expressions.
Expression*
-Builtin_call_expression::do_flatten(Gogo*, Named_object*,
+Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
Statement_inserter* inserter)
{
Location loc = this->location();
@@ -7244,6 +7222,8 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
break;
case BUILTIN_APPEND:
+ return this->flatten_append(gogo, function, inserter);
+
case BUILTIN_COPY:
{
Type* at = this->args()->front()->type();
@@ -7285,16 +7265,19 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
case BUILTIN_LEN:
case BUILTIN_CAP:
- Expression_list::iterator pa = this->args()->begin();
- if (!(*pa)->is_variable()
- && ((*pa)->type()->map_type() != NULL
- || (*pa)->type()->channel_type() != NULL))
- {
- Temporary_statement* temp =
- Statement::make_temporary(NULL, *pa, loc);
- inserter->insert(temp);
- *pa = Expression::make_temporary_reference(temp, loc);
- }
+ {
+ Expression_list::iterator pa = this->args()->begin();
+ if (!(*pa)->is_variable()
+ && ((*pa)->type()->map_type() != NULL
+ || (*pa)->type()->channel_type() != NULL))
+ {
+ Temporary_statement* temp =
+ Statement::make_temporary(NULL, *pa, loc);
+ inserter->insert(temp);
+ *pa = Expression::make_temporary_reference(temp, loc);
+ }
+ }
+ break;
}
return this;
@@ -7303,7 +7286,7 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
// Lower a make expression.
Expression*
-Builtin_call_expression::lower_make()
+Builtin_call_expression::lower_make(Statement_inserter* inserter)
{
Location loc = this->location();
@@ -7340,10 +7323,6 @@ Builtin_call_expression::lower_make()
return Expression::make_error(this->location());
}
- bool have_big_args = false;
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- int uintptr_bits = uintptr_type->integer_type()->bits();
-
Type_context int_context(Type::lookup_integer_type("int"), false);
++parg;
@@ -7363,9 +7342,6 @@ Builtin_call_expression::lower_make()
len_arg->determine_type(&int_context);
if (!this->check_int_value(len_arg, true))
return Expression::make_error(this->location());
- if (len_arg->type()->integer_type() != NULL
- && len_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
++parg;
}
@@ -7391,9 +7367,6 @@ Builtin_call_expression::lower_make()
return Expression::make_error(this->location());
}
- if (cap_arg->type()->integer_type() != NULL
- && cap_arg->type()->integer_type()->bits() > uintptr_bits)
- have_big_args = true;
++parg;
}
@@ -7404,34 +7377,236 @@ Builtin_call_expression::lower_make()
}
Location type_loc = first_arg->location();
- Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
Expression* call;
if (is_slice)
{
+ Type* et = type->array_type()->element_type();
+ Expression* type_arg = Expression::make_type_descriptor(et, type_loc);
if (cap_arg == NULL)
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE1BIG
- : Runtime::MAKESLICE1),
- loc, 2, type_arg, len_arg);
- else
- call = Runtime::make_call((have_big_args
- ? Runtime::MAKESLICE2BIG
- : Runtime::MAKESLICE2),
- loc, 3, type_arg, len_arg, cap_arg);
+ {
+ Temporary_statement* temp = Statement::make_temporary(NULL,
+ len_arg,
+ loc);
+ inserter->insert(temp);
+ len_arg = Expression::make_temporary_reference(temp, loc);
+ cap_arg = Expression::make_temporary_reference(temp, loc);
+ }
+ call = Runtime::make_call(Runtime::MAKESLICE, loc, 3, type_arg,
+ len_arg, cap_arg);
}
else if (is_map)
- call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
- Expression::make_nil(loc),
- Expression::make_nil(loc));
+ {
+ Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
+ call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
+ Expression::make_nil(loc),
+ Expression::make_nil(loc));
+ }
else if (is_chan)
- call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ {
+ Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
+ call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ }
else
go_unreachable();
return Expression::make_unsafe_cast(type, call, loc);
}
+// Flatten a call to the predeclared append function. We do this in
+// the flatten phase, not the lowering phase, so that we run after
+// type checking and after order_evaluations.
+
+Expression*
+Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
+ Statement_inserter* inserter)
+{
+ if (this->is_error_expression())
+ return this;
+
+ Location loc = this->location();
+
+ const Expression_list* args = this->args();
+ go_assert(args != NULL && !args->empty());
+
+ Type* slice_type = args->front()->type();
+ go_assert(slice_type->is_slice_type());
+ Type* element_type = slice_type->array_type()->element_type();
+
+ if (args->size() == 1)
+ {
+ // append(s) evaluates to s.
+ return args->front();
+ }
+
+ Type* int_type = Type::lookup_integer_type("int");
+ Type* uint_type = Type::lookup_integer_type("uint");
+
+ // Implementing
+ // append(s1, s2...)
+ // or
+ // append(s1, a1, a2, a3, ...)
+
+ // s1tmp := s1
+ Temporary_statement* s1tmp = Statement::make_temporary(NULL, args->front(),
+ loc);
+ inserter->insert(s1tmp);
+
+ // l1tmp := len(s1tmp)
+ Named_object* lenfn = gogo->lookup_global("len");
+ Expression* lenref = Expression::make_func_reference(lenfn, NULL, loc);
+ Expression_list* call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
+ Expression* len = Expression::make_call(lenref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &len);
+ gogo->flatten_expression(function, inserter, &len);
+ Temporary_statement* l1tmp = Statement::make_temporary(int_type, len, loc);
+ inserter->insert(l1tmp);
+
+ Temporary_statement* s2tmp = NULL;
+ Temporary_statement* l2tmp = NULL;
+ Expression_list* add = NULL;
+ Expression* len2;
+ if (this->is_varargs())
+ {
+ go_assert(args->size() == 2);
+
+ // s2tmp := s2
+ s2tmp = Statement::make_temporary(NULL, args->back(), loc);
+ inserter->insert(s2tmp);
+
+ // l2tmp := len(s2tmp)
+ lenref = Expression::make_func_reference(lenfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s2tmp, loc));
+ len = Expression::make_call(lenref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &len);
+ gogo->flatten_expression(function, inserter, &len);
+ l2tmp = Statement::make_temporary(int_type, len, loc);
+ inserter->insert(l2tmp);
+
+ // len2 = l2tmp
+ len2 = Expression::make_temporary_reference(l2tmp, loc);
+ }
+ else
+ {
+ // We have to ensure that all the arguments are in variables
+ // now, because otherwise if one of them is an index expression
+ // into the current slice we could overwrite it before we fetch
+ // it.
+ add = new Expression_list();
+ Expression_list::const_iterator pa = args->begin();
+ for (++pa; pa != args->end(); ++pa)
+ {
+ if ((*pa)->is_variable())
+ add->push_back(*pa);
+ else
+ {
+ Temporary_statement* tmp = Statement::make_temporary(NULL, *pa,
+ loc);
+ inserter->insert(tmp);
+ add->push_back(Expression::make_temporary_reference(tmp, loc));
+ }
+ }
+
+ // len2 = len(add)
+ len2 = Expression::make_integer_ul(add->size(), int_type, loc);
+ }
+
+ // ntmp := l1tmp + len2
+ Expression* ref = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* sum = Expression::make_binary(OPERATOR_PLUS, ref, len2, loc);
+ gogo->lower_expression(function, inserter, &sum);
+ gogo->flatten_expression(function, inserter, &sum);
+ Temporary_statement* ntmp = Statement::make_temporary(int_type, sum, loc);
+ inserter->insert(ntmp);
+
+ // s1tmp = uint(ntmp) > uint(cap(s1tmp)) ?
+ // growslice(type, s1tmp, ntmp) :
+ // s1tmp[:ntmp]
+ // Using uint here means that if the computation of ntmp overflowed,
+ // we will call growslice which will panic.
+
+ Expression* left = Expression::make_temporary_reference(ntmp, loc);
+ left = Expression::make_cast(uint_type, left, loc);
+
+ Named_object* capfn = gogo->lookup_global("cap");
+ Expression* capref = Expression::make_func_reference(capfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
+ Expression* right = Expression::make_call(capref, call_args, false, loc);
+ right = Expression::make_cast(uint_type, right, loc);
+
+ Expression* cond = Expression::make_binary(OPERATOR_GT, left, right, loc);
+
+ Expression* a1 = Expression::make_type_descriptor(element_type, loc);
+ Expression* a2 = Expression::make_temporary_reference(s1tmp, loc);
+ Expression* a3 = Expression::make_temporary_reference(ntmp, loc);
+ Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 3,
+ a1, a2, a3);
+ call = Expression::make_unsafe_cast(slice_type, call, loc);
+
+ ref = Expression::make_temporary_reference(s1tmp, loc);
+ Expression* zero = Expression::make_integer_ul(0, int_type, loc);
+ Expression* ref2 = Expression::make_temporary_reference(ntmp, loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ ref = Expression::make_index(ref, zero, ref2, NULL, loc);
+
+ Expression* rhs = Expression::make_conditional(cond, call, ref, loc);
+
+ gogo->lower_expression(function, inserter, &rhs);
+ gogo->flatten_expression(function, inserter, &rhs);
+
+ Expression* lhs = Expression::make_temporary_reference(s1tmp, loc);
+ Statement* assign = Statement::make_assignment(lhs, rhs, loc);
+ inserter->insert(assign);
+
+ if (this->is_varargs())
+ {
+ // copy(s1tmp[l1tmp:], s2tmp)
+ a1 = Expression::make_temporary_reference(s1tmp, loc);
+ ref = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* nil = Expression::make_nil(loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ a1 = Expression::make_index(a1, ref, nil, NULL, loc);
+
+ a2 = Expression::make_temporary_reference(s2tmp, loc);
+
+ Named_object* copyfn = gogo->lookup_global("copy");
+ Expression* copyref = Expression::make_func_reference(copyfn, NULL, loc);
+ call_args = new Expression_list();
+ call_args->push_back(a1);
+ call_args->push_back(a2);
+ call = Expression::make_call(copyref, call_args, false, loc);
+ gogo->lower_expression(function, inserter, &call);
+ gogo->flatten_expression(function, inserter, &call);
+ inserter->insert(Statement::make_statement(call, false));
+ }
+ else
+ {
+ // For each argument:
+ // s1tmp[l1tmp+i] = a
+ unsigned long i = 0;
+ for (Expression_list::const_iterator pa = add->begin();
+ pa != add->end();
+ ++pa, ++i)
+ {
+ ref = Expression::make_temporary_reference(s1tmp, loc);
+ ref2 = Expression::make_temporary_reference(l1tmp, loc);
+ Expression* off = Expression::make_integer_ul(i, int_type, loc);
+ ref2 = Expression::make_binary(OPERATOR_PLUS, ref2, off, loc);
+ // FIXME: Mark this index as not requiring bounds checks.
+ lhs = Expression::make_index(ref, ref2, NULL, NULL, loc);
+ gogo->lower_expression(function, inserter, &lhs);
+ gogo->flatten_expression(function, inserter, &lhs);
+ assign = Statement::make_assignment(lhs, *pa, loc);
+ inserter->insert(assign);
+ }
+ }
+
+ return Expression::make_temporary_reference(s1tmp, loc);
+}
+
// Return whether an expression has an integer value. Report an error
// if not. This is used when handling calls to the predeclared make
// function.
@@ -8011,6 +8186,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
bool is_print;
Type* arg_type = NULL;
+ Type* trailing_arg_types = NULL;
switch (this->code_)
{
case BUILTIN_PRINT:
@@ -8047,6 +8223,16 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
}
break;
+ case BUILTIN_APPEND:
+ if (!this->is_varargs()
+ && args != NULL
+ && !args->empty()
+ && args->front()->type()->is_slice_type())
+ trailing_arg_types =
+ args->front()->type()->array_type()->element_type();
+ is_print = false;
+ break;
+
default:
is_print = false;
break;
@@ -8103,6 +8289,12 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
}
(*pa)->determine_type(&subcontext);
+
+ if (trailing_arg_types != NULL)
+ {
+ arg_type = trailing_arg_types;
+ trailing_arg_types = NULL;
+ }
}
}
}
@@ -8309,54 +8501,102 @@ Builtin_call_expression::do_check_types(Gogo*)
case BUILTIN_APPEND:
{
const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
+ if (args == NULL || args->empty())
{
this->report_error(_("not enough arguments"));
break;
}
- if (args->size() > 2)
- {
- this->report_error(_("too many arguments"));
- break;
- }
- if (args->front()->type()->is_error()
- || args->back()->type()->is_error())
+
+ Type* slice_type = args->front()->type();
+ if (!slice_type->is_slice_type())
{
+ if (slice_type->is_error_type())
+ break;
+ if (slice_type->is_nil_type())
+ go_error_at(args->front()->location(), "use of untyped nil");
+ else
+ go_error_at(args->front()->location(),
+ "argument 1 must be a slice");
this->set_is_error();
break;
}
- Array_type* at = args->front()->type()->array_type();
- Type* e = at->element_type();
-
- // The language permits appending a string to a []byte, as a
- // special case.
- if (args->back()->type()->is_string_type())
+ Type* element_type = slice_type->array_type()->element_type();
+ if (this->is_varargs())
{
- if (e->integer_type() != NULL && e->integer_type()->is_byte())
- break;
- }
+ if (!args->back()->type()->is_slice_type()
+ && !args->back()->type()->is_string_type())
+ {
+ go_error_at(args->back()->location(),
+ "invalid use of %<...%> with non-slice/non-string");
+ this->set_is_error();
+ break;
+ }
- // The language says that the second argument must be
- // assignable to a slice of the element type of the first
- // argument. We already know the first argument is a slice
- // type.
- Type* arg2_type = Type::make_array_type(e, NULL);
- std::string reason;
- if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
- {
- if (reason.empty())
- this->report_error(_("argument 2 has invalid type"));
+ if (args->size() < 2)
+ {
+ this->report_error(_("not enough arguments"));
+ break;
+ }
+ if (args->size() > 2)
+ {
+ this->report_error(_("too many arguments"));
+ break;
+ }
+
+ if (args->back()->type()->is_string_type()
+ && element_type->integer_type() != NULL
+ && element_type->integer_type()->is_byte())
+ {
+ // Permit append(s1, s2...) when s1 is a slice of
+ // bytes and s2 is a string type.
+ }
else
{
- go_error_at(this->location(),
- "argument 2 has invalid type (%s)",
- reason.c_str());
- this->set_is_error();
+ // We have to test for assignment compatibility to a
+ // slice of the element type, which is not necessarily
+ // the same as the type of the first argument: the
+ // first argument might have a named type.
+ Type* check_type = Type::make_array_type(element_type, NULL);
+ std::string reason;
+ if (!Type::are_assignable(check_type, args->back()->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at(args->back()->location(),
+ "argument 2 has invalid type");
+ else
+ go_error_at(args->back()->location(),
+ "argument 2 has invalid type (%s)",
+ reason.c_str());
+ this->set_is_error();
+ break;
+ }
+ }
+ }
+ else
+ {
+ Expression_list::const_iterator pa = args->begin();
+ int i = 2;
+ for (++pa; pa != args->end(); ++pa, ++i)
+ {
+ std::string reason;
+ if (!Type::are_assignable(element_type, (*pa)->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at((*pa)->location(),
+ "argument %d has incompatible type", i);
+ else
+ go_error_at((*pa)->location(),
+ "argument %d has incompatible type (%s)",
+ i, reason.c_str());
+ this->set_is_error();
+ }
}
}
- break;
}
+ break;
case BUILTIN_REAL:
case BUILTIN_IMAG:
@@ -8719,97 +8959,39 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
Type* arg1_type = arg1->type();
Array_type* at = arg1_type->array_type();
go_assert(arg1->is_variable());
- Expression* arg1_val = at->get_value_pointer(gogo, arg1);
- Expression* arg1_len = at->get_length(gogo, arg1);
+
+ Expression* call;
Type* arg2_type = arg2->type();
go_assert(arg2->is_variable());
- Expression* arg2_val;
- Expression* arg2_len;
- if (arg2_type->is_slice_type())
- {
- at = arg2_type->array_type();
- arg2_val = at->get_value_pointer(gogo, arg2);
- arg2_len = at->get_length(gogo, arg2);
- }
+ if (arg2_type->is_string_type())
+ call = Runtime::make_call(Runtime::SLICESTRINGCOPY, location,
+ 2, arg1, arg2);
else
{
- go_assert(arg2->is_variable());
- arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
- location);
- arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
- location);
+ Type* et = at->element_type();
+ if (et->has_pointer())
+ {
+ Expression* td = Expression::make_type_descriptor(et,
+ location);
+ call = Runtime::make_call(Runtime::TYPEDSLICECOPY, location,
+ 3, td, arg1, arg2);
+ }
+ else
+ {
+ Expression* sz = Expression::make_type_info(et,
+ TYPE_INFO_SIZE);
+ call = Runtime::make_call(Runtime::SLICECOPY, location, 3,
+ arg1, arg2, sz);
+ }
}
- Expression* cond =
- Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location);
- Expression* length =
- Expression::make_conditional(cond, arg1_len, arg2_len, location);
-
- Type* element_type = at->element_type();
- int64_t element_size;
- bool ok = element_type->backend_type_size(gogo, &element_size);
- if (!ok)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_expression();
- }
- Expression* size_expr = Expression::make_integer_int64(element_size,
- length->type(),
- location);
- Expression* bytecount =
- Expression::make_binary(OPERATOR_MULT, size_expr, length, location);
- Expression* copy = Runtime::make_call(Runtime::COPY, location, 3,
- arg1_val, arg2_val, bytecount);
-
- Expression* compound = Expression::make_compound(copy, length, location);
- return compound->get_backend(context);
+ return call->get_backend(context);
}
case BUILTIN_APPEND:
- {
- const Expression_list* args = this->args();
- go_assert(args != NULL && args->size() == 2);
- Expression* arg1 = args->front();
- Expression* arg2 = args->back();
-
- Array_type* at = arg1->type()->array_type();
- Type* element_type = at->element_type()->forwarded();
-
- go_assert(arg2->is_variable());
- Expression* arg2_val;
- Expression* arg2_len;
- int64_t size;
- if (arg2->type()->is_string_type()
- && element_type->integer_type() != NULL
- && element_type->integer_type()->is_byte())
- {
- arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
- location);
- arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
- location);
- size = 1;
- }
- else
- {
- arg2_val = at->get_value_pointer(gogo, arg2);
- arg2_len = at->get_length(gogo, arg2);
- bool ok = element_type->backend_type_size(gogo, &size);
- if (!ok)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_expression();
- }
- }
- Expression* element_size =
- Expression::make_integer_int64(size, NULL, location);
-
- Expression* append = Runtime::make_call(Runtime::APPEND, location, 4,
- arg1, arg2_val, arg2_len,
- element_size);
- append = Expression::make_unsafe_cast(arg1->type(), append, location);
- return append->get_backend(context);
- }
+ // Handled in Builtin_call_expression::flatten_append.
+ go_unreachable();
case BUILTIN_REAL:
case BUILTIN_IMAG:
@@ -12020,12 +12202,10 @@ Expression::make_allocation(Type* type, Location location)
return new Allocation_expression(type, location);
}
-// Class Struct_construction_expression.
-
-// Traversal.
+// Class Ordered_value_list.
int
-Struct_construction_expression::do_traverse(Traverse* traverse)
+Ordered_value_list::traverse_vals(Traverse* traverse)
{
if (this->vals_ != NULL)
{
@@ -12036,8 +12216,8 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
}
else
{
- for (std::vector<int>::const_iterator p =
- this->traverse_order_->begin();
+ for (std::vector<unsigned long>::const_iterator p =
+ this->traverse_order_->begin();
p != this->traverse_order_->end();
++p)
{
@@ -12047,6 +12227,18 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
}
}
}
+ return TRAVERSE_CONTINUE;
+}
+
+// Class Struct_construction_expression.
+
+// Traversal.
+
+int
+Struct_construction_expression::do_traverse(Traverse* traverse)
+{
+ if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return TRAVERSE_CONTINUE;
@@ -12057,10 +12249,10 @@ Struct_construction_expression::do_traverse(Traverse* traverse)
bool
Struct_construction_expression::is_constant_struct() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL
@@ -12088,10 +12280,10 @@ Struct_construction_expression::is_constant_struct() const
bool
Struct_construction_expression::do_is_immutable() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL && !(*pv)->is_immutable())
@@ -12105,15 +12297,15 @@ Struct_construction_expression::do_is_immutable() const
void
Struct_construction_expression::do_determine_type(const Type_context*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
const Struct_field_list* fields = this->type_->struct_type()->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf, ++pv)
{
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
return;
if (*pv != NULL)
{
@@ -12123,7 +12315,7 @@ Struct_construction_expression::do_determine_type(const Type_context*)
}
// Extra values are an error we will report elsewhere; we still want
// to determine the type to avoid knockon errors.
- for (; pv != this->vals_->end(); ++pv)
+ for (; pv != this->vals()->end(); ++pv)
(*pv)->determine_type_no_context();
}
@@ -12132,24 +12324,24 @@ Struct_construction_expression::do_determine_type(const Type_context*)
void
Struct_construction_expression::do_check_types(Gogo*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Struct_type* st = this->type_->struct_type();
- if (this->vals_->size() > st->field_count())
+ if (this->vals()->size() > st->field_count())
{
this->report_error(_("too many expressions for struct"));
return;
}
const Struct_field_list* fields = st->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
int i = 0;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf, ++pv, ++i)
{
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
{
this->report_error(_("too few expressions for struct"));
break;
@@ -12173,7 +12365,7 @@ Struct_construction_expression::do_check_types(Gogo*)
this->set_is_error();
}
}
- go_assert(pv == this->vals_->end());
+ go_assert(pv == this->vals()->end());
}
// Flatten a struct construction expression. Store the values into
@@ -12183,7 +12375,7 @@ Expression*
Struct_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return this;
// If this is a constant struct, we don't need temporaries.
@@ -12191,8 +12383,8 @@ Struct_construction_expression::do_flatten(Gogo*, Named_object*,
return this;
Location loc = this->location();
- for (Expression_list::iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12222,18 +12414,18 @@ Struct_construction_expression::do_get_backend(Translate_context* context)
Gogo* gogo = context->gogo();
Btype* btype = this->type_->get_backend(gogo);
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return gogo->backend()->zero_expression(btype);
const Struct_field_list* fields = this->type_->struct_type()->fields();
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
std::vector<Bexpression*> init;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
{
Btype* fbtype = pf->type()->get_backend(gogo);
- if (pv == this->vals_->end())
+ if (pv == this->vals()->end())
init.push_back(gogo->backend()->zero_expression(fbtype));
else if (*pv == NULL)
{
@@ -12259,8 +12451,8 @@ Struct_construction_expression::do_export(Export* exp) const
{
exp->write_c_string("convert(");
exp->write_type(this->type_);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
exp->write_c_string(", ");
@@ -12278,7 +12470,7 @@ Struct_construction_expression::do_dump_expression(
{
ast_dump_context->dump_type(this->type_);
ast_dump_context->ostream() << "{";
- ast_dump_context->dump_expression_list(this->vals_);
+ ast_dump_context->dump_expression_list(this->vals());
ast_dump_context->ostream() << "}";
}
@@ -12299,8 +12491,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
int
Array_construction_expression::do_traverse(Traverse* traverse)
{
- if (this->vals_ != NULL
- && this->vals_->traverse(traverse) == TRAVERSE_EXIT)
+ if (this->traverse_vals(traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
@@ -12312,15 +12503,15 @@ Array_construction_expression::do_traverse(Traverse* traverse)
bool
Array_construction_expression::is_constant_array() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
// There are no constant constructors for interfaces.
if (this->type_->array_type()->element_type()->interface_type() != NULL)
return false;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL
@@ -12337,10 +12528,10 @@ Array_construction_expression::is_constant_array() const
bool
Array_construction_expression::do_is_immutable() const
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return true;
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL && !(*pv)->is_immutable())
@@ -12354,11 +12545,11 @@ Array_construction_expression::do_is_immutable() const
void
Array_construction_expression::do_determine_type(const Type_context*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Type_context subcontext(this->type_->array_type()->element_type(), false);
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12371,14 +12562,14 @@ Array_construction_expression::do_determine_type(const Type_context*)
void
Array_construction_expression::do_check_types(Gogo*)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return;
Array_type* at = this->type_->array_type();
int i = 0;
Type* element_type = at->element_type();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv, ++i)
{
if (*pv != NULL
@@ -12399,7 +12590,7 @@ Expression*
Array_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- if (this->vals_ == NULL)
+ if (this->vals() == NULL)
return this;
// If this is a constant array, we don't need temporaries.
@@ -12407,8 +12598,8 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*,
return this;
Location loc = this->location();
- for (Expression_list::iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
if (*pv != NULL)
@@ -12441,14 +12632,14 @@ Array_construction_expression::get_constructor(Translate_context* context,
std::vector<unsigned long> indexes;
std::vector<Bexpression*> vals;
Gogo* gogo = context->gogo();
- if (this->vals_ != NULL)
+ if (this->vals() != NULL)
{
size_t i = 0;
std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL)
pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv, ++i)
{
if (this->indexes_ != NULL)
@@ -12488,13 +12679,13 @@ Array_construction_expression::do_export(Export* exp) const
{
exp->write_c_string("convert(");
exp->write_type(this->type_);
- if (this->vals_ != NULL)
+ if (this->vals() != NULL)
{
std::vector<unsigned long>::const_iterator pi;
if (this->indexes_ != NULL)
pi = this->indexes_->begin();
- for (Expression_list::const_iterator pv = this->vals_->begin();
- pv != this->vals_->end();
+ for (Expression_list::const_iterator pv = this->vals()->begin();
+ pv != this->vals()->end();
++pv)
{
exp->write_c_string(", ");
@@ -12535,10 +12726,10 @@ Array_construction_expression::do_dump_expression(
this->dump_slice_storage_expression(ast_dump_context);
ast_dump_context->ostream() << "{" ;
if (this->indexes_ == NULL)
- ast_dump_context->dump_expression_list(this->vals_);
+ ast_dump_context->dump_expression_list(this->vals());
else
{
- Expression_list::const_iterator pv = this->vals_->begin();
+ Expression_list::const_iterator pv = this->vals()->begin();
for (std::vector<unsigned long>::const_iterator pi =
this->indexes_->begin();
pi != this->indexes_->end();
@@ -13167,7 +13358,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
size_t field_count = st->field_count();
std::vector<Expression*> vals(field_count);
- std::vector<int>* traverse_order = new(std::vector<int>);
+ std::vector<unsigned long>* traverse_order = new(std::vector<unsigned long>);
Expression_list::const_iterator p = this->vals_->begin();
Expression* external_expr = NULL;
const Named_object* external_no = NULL;
@@ -13299,7 +13490,7 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
type->named_type()->message_name().c_str());
vals[index] = val;
- traverse_order->push_back(index);
+ traverse_order->push_back(static_cast<unsigned long>(index));
}
if (!this->all_are_names_)
@@ -13330,15 +13521,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
return ret;
}
-// Used to sort an index/value array.
+// Index/value/traversal-order triple.
-class Index_value_compare
-{
- public:
- bool
- operator()(const std::pair<unsigned long, Expression*>& a,
- const std::pair<unsigned long, Expression*>& b)
- { return a.first < b.first; }
+struct IVT_triple {
+ unsigned long index;
+ unsigned long traversal_order;
+ Expression* expr;
+ IVT_triple(unsigned long i, unsigned long to, Expression *e)
+ : index(i), traversal_order(to), expr(e) { }
+ bool operator<(const IVT_triple& other) const
+ { return this->index < other.index; }
};
// Lower an array composite literal.
@@ -13442,35 +13634,45 @@ Composite_literal_expression::lower_array(Type* type)
indexes = NULL;
}
+ std::vector<unsigned long>* traverse_order = NULL;
if (indexes_out_of_order)
{
- typedef std::vector<std::pair<unsigned long, Expression*> > V;
+ typedef std::vector<IVT_triple> V;
V v;
v.reserve(indexes->size());
std::vector<unsigned long>::const_iterator pi = indexes->begin();
+ unsigned long torder = 0;
for (Expression_list::const_iterator pe = vals->begin();
pe != vals->end();
- ++pe, ++pi)
- v.push_back(std::make_pair(*pi, *pe));
+ ++pe, ++pi, ++torder)
+ v.push_back(IVT_triple(*pi, torder, *pe));
- std::sort(v.begin(), v.end(), Index_value_compare());
+ std::sort(v.begin(), v.end());
delete indexes;
delete vals;
+
indexes = new std::vector<unsigned long>();
indexes->reserve(v.size());
vals = new Expression_list();
vals->reserve(v.size());
+ traverse_order = new std::vector<unsigned long>();
+ traverse_order->reserve(v.size());
for (V::const_iterator p = v.begin(); p != v.end(); ++p)
{
- indexes->push_back(p->first);
- vals->push_back(p->second);
+ indexes->push_back(p->index);
+ vals->push_back(p->expr);
+ traverse_order->push_back(p->traversal_order);
}
}
- return this->make_array(type, indexes, vals);
+ Expression* ret = this->make_array(type, indexes, vals);
+ Array_construction_expression* ace = ret->array_literal();
+ if (ace != NULL && traverse_order != NULL)
+ ace->set_traverse_order(traverse_order);
+ return ret;
}
// Actually build the array composite literal. This handles
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 0d00f458c38..a02fd19feb3 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -3232,31 +3232,64 @@ class Composite_literal_expression : public Parser_expression
std::vector<bool> key_path_;
};
-// Construct a struct.
+// Helper/mixin class for struct and array construction expressions;
+// encapsulates a list of values plus an optional traversal order
+// recording the order in which the values should be visited.
-class Struct_construction_expression : public Expression
+class Ordered_value_list
{
public:
- Struct_construction_expression(Type* type, Expression_list* vals,
- Location location)
- : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
- type_(type), vals_(vals), traverse_order_(NULL)
+ Ordered_value_list(Expression_list* vals)
+ : vals_(vals), traverse_order_(NULL)
{ }
+ Expression_list*
+ vals() const
+ { return this->vals_; }
+
+ int
+ traverse_vals(Traverse* traverse);
+
+ // Get the traversal order (may be NULL)
+ std::vector<unsigned long>*
+ traverse_order()
+ { return traverse_order_; }
+
// Set the traversal order, used to ensure that we implement the
// order of evaluation rules. Takes ownership of the argument.
void
- set_traverse_order(std::vector<int>* traverse_order)
+ set_traverse_order(std::vector<unsigned long>* traverse_order)
{ this->traverse_order_ = traverse_order; }
- // Return whether this is a constant initializer.
+ private:
+ // The list of values, in order of the fields in the struct or in
+ // order of indices in an array. A NULL value of vals_ means that
+ // all fields/slots should be zero-initialized; a single NULL entry
+ // in the list means that the corresponding field or array slot
+ // should be zero-initialized.
+ Expression_list* vals_;
+ // If not NULL, the order in which to traverse vals_. This is used
+ // so that we implement the order of evaluation rules correctly.
+ std::vector<unsigned long>* traverse_order_;
+};
+
+// Construct a struct.
+
+class Struct_construction_expression : public Expression,
+ public Ordered_value_list
+{
+ public:
+ Struct_construction_expression(Type* type, Expression_list* vals,
+ Location location)
+ : Expression(EXPRESSION_STRUCT_CONSTRUCTION, location),
+ Ordered_value_list(vals),
+ type_(type)
+ { }
+
+ // Return whether this is a constant initializer.
bool
is_constant_struct() const;
- Expression_list*
- vals() const
- { return this->vals_; }
-
protected:
int
do_traverse(Traverse* traverse);
@@ -3279,12 +3312,12 @@ class Struct_construction_expression : public Expression
{
Struct_construction_expression* ret =
new Struct_construction_expression(this->type_,
- (this->vals_ == NULL
+ (this->vals() == NULL
? NULL
- : this->vals_->copy()),
+ : this->vals()->copy()),
this->location());
- if (this->traverse_order_ != NULL)
- ret->set_traverse_order(this->traverse_order_);
+ if (this->traverse_order() != NULL)
+ ret->set_traverse_order(this->traverse_order());
return ret;
}
@@ -3303,19 +3336,14 @@ class Struct_construction_expression : public Expression
private:
// The type of the struct to construct.
Type* type_;
- // The list of values, in order of the fields in the struct. A NULL
- // entry means that the field should be zero-initialized.
- Expression_list* vals_;
- // If not NULL, the order in which to traverse vals_. This is used
- // so that we implement the order of evaluation rules correctly.
- std::vector<int>* traverse_order_;
};
// Construct an array. This class is not used directly; instead we
// use the child classes, Fixed_array_construction_expression and
// Slice_construction_expression.
-class Array_construction_expression : public Expression
+class Array_construction_expression : public Expression,
+ public Ordered_value_list
{
protected:
Array_construction_expression(Expression_classification classification,
@@ -3323,7 +3351,8 @@ class Array_construction_expression : public Expression
const std::vector<unsigned long>* indexes,
Expression_list* vals, Location location)
: Expression(classification, location),
- type_(type), indexes_(indexes), vals_(vals)
+ Ordered_value_list(vals),
+ type_(type), indexes_(indexes)
{ go_assert(indexes == NULL || indexes->size() == vals->size()); }
public:
@@ -3334,12 +3363,7 @@ class Array_construction_expression : public Expression
// Return the number of elements.
size_t
element_count() const
- { return this->vals_ == NULL ? 0 : this->vals_->size(); }
-
- // The list of values.
- Expression_list*
- vals() const
- { return this->vals_; }
+ { return this->vals() == NULL ? 0 : this->vals()->size(); }
protected:
virtual int
@@ -3385,8 +3409,6 @@ protected:
// The list of indexes into the array, one for each value. This may
// be NULL, in which case the indexes start at zero and increment.
const std::vector<unsigned long>* indexes_;
- // The list of values. This may be NULL if there are no values.
- Expression_list* vals_;
};
// Construct a fixed array.
diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc
index 4072920b9d2..77c48ecbaaf 100644
--- a/gcc/go/gofrontend/runtime.cc
+++ b/gcc/go/gofrontend/runtime.cc
@@ -425,9 +425,9 @@ Runtime::name_to_code(const std::string& name)
else if (name == "close")
code = Runtime::CLOSE;
else if (name == "copy")
- code = Runtime::COPY;
+ code = Runtime::SLICECOPY;
else if (name == "append")
- code = Runtime::APPEND;
+ code = Runtime::GROWSLICE;
else if (name == "delete")
code = Runtime::MAPDELETE;
else
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index 3051624b66c..5d3ce67725d 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -87,12 +87,7 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
// Make a slice.
-DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
- R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE1BIG, "__go_make_slice1_big", P2(TYPE, UINT64),
- R1(SLICE))
-DEF_GO_RUNTIME(MAKESLICE2BIG, "__go_make_slice2_big", P3(TYPE, UINT64, UINT64),
+DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT64, INT64),
R1(SLICE))
@@ -211,11 +206,20 @@ DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0())
// Copy.
-DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0())
+DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy", P3(SLICE, SLICE, UINTPTR),
+ R1(INT))
-// Append.
-DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR),
- R1(SLICE))
+// Copy from string.
+DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy", P2(SLICE, STRING),
+ R1(INT))
+
+// Copy of value containing pointers.
+DEF_GO_RUNTIME(TYPEDSLICECOPY, "runtime.typedslicecopy",
+ P3(TYPE, SLICE, SLICE), R1(INT))
+
+
+// Grow a slice for append.
+DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice", P3(TYPE, SLICE, INT), R1(SLICE))
// Register roots (global variables) for the garbage collector.
diff --git a/gcc/incpath.c b/gcc/incpath.c
index ea40f4a9323..952d5c4727d 100644
--- a/gcc/incpath.c
+++ b/gcc/incpath.c
@@ -253,8 +253,9 @@ remove_duplicates (cpp_reader *pfile, struct cpp_dir *head,
if (stat (cur->name, &st))
{
- /* Dirs that don't exist are silently ignored, unless verbose. */
- if (errno != ENOENT)
+ /* Dirs that don't exist or have denied permissions are
+ silently ignored, unless verbose. */
+ if ((errno != ENOENT) && (errno != EPERM))
cpp_errno (pfile, CPP_DL_ERROR, cur->name);
else
{
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 111dfa7be4c..fd1cd8b6445 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -363,6 +363,15 @@ expand_ASAN_CHECK (internal_fn, gcall *)
gcc_unreachable ();
}
+/* This should get expanded in the sanopt pass. */
+
+static void
+expand_ASAN_MARK (internal_fn, gcall *)
+{
+ gcc_unreachable ();
+}
+
+
/* This should get expanded in the tsan pass. */
static void
@@ -973,56 +982,68 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs,
delete_insns_since (last);
}
- rtx_code_label *sub_check = gen_label_rtx ();
- int pos_neg = 3;
-
/* Compute the operation. On RTL level, the addition is always
unsigned. */
res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
- /* If we can prove one of the arguments (for MINUS_EXPR only
+ /* If we can prove that one of the arguments (for MINUS_EXPR only
the second operand, as subtraction is not commutative) is always
non-negative or always negative, we can do just one comparison
- and conditional jump instead of 2 at runtime, 3 present in the
- emitted code. If one of the arguments is CONST_INT, all we
- need is to make sure it is op1, then the first
- do_compare_rtx_and_jump will be just folded. Otherwise try
- to use range info if available. */
- if (code == PLUS_EXPR && CONST_INT_P (op0))
- std::swap (op0, op1);
- else if (CONST_INT_P (op1))
- ;
- else if (code == PLUS_EXPR && TREE_CODE (arg0) == SSA_NAME)
+ and conditional jump. */
+ int pos_neg = get_range_pos_neg (arg1);
+ if (code == PLUS_EXPR)
{
- pos_neg = get_range_pos_neg (arg0);
- if (pos_neg != 3)
- std::swap (op0, op1);
+ int pos_neg0 = get_range_pos_neg (arg0);
+ if (pos_neg0 != 3 && pos_neg == 3)
+ {
+ std::swap (op0, op1);
+ pos_neg = pos_neg0;
+ }
}
- if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
- pos_neg = get_range_pos_neg (arg1);
- /* If the op1 is negative, we have to use a different check. */
+ /* Addition overflows if and only if the two operands have the same sign,
+ and the result has the opposite sign. Subtraction overflows if and
+ only if the two operands have opposite sign, and the subtrahend has
+ the same sign as the result. Here 0 is counted as positive. */
if (pos_neg == 3)
- do_compare_rtx_and_jump (op1, const0_rtx, LT, false, mode, NULL_RTX,
- NULL, sub_check, PROB_EVEN);
+ {
+ /* Compute op0 ^ op1 (operands have opposite sign). */
+ rtx op_xor = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false,
+ OPTAB_LIB_WIDEN);
- /* Compare the result of the operation with one of the operands. */
- if (pos_neg & 1)
- do_compare_rtx_and_jump (res, op0, code == PLUS_EXPR ? GE : LE,
- false, mode, NULL_RTX, NULL, done_label,
- PROB_VERY_LIKELY);
+ /* Compute res ^ op1 (result and 2nd operand have opposite sign). */
+ rtx res_xor = expand_binop (mode, xor_optab, res, op1, NULL_RTX, false,
+ OPTAB_LIB_WIDEN);
- /* If we get here, we have to print the error. */
- if (pos_neg == 3)
- {
- emit_jump (do_error);
- emit_label (sub_check);
+ rtx tem;
+ if (code == PLUS_EXPR)
+ {
+ /* Compute (res ^ op1) & ~(op0 ^ op1). */
+ tem = expand_unop (mode, one_cmpl_optab, op_xor, NULL_RTX, false);
+ tem = expand_binop (mode, and_optab, res_xor, tem, NULL_RTX, false,
+ OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ /* Compute (op0 ^ op1) & ~(res ^ op1). */
+ tem = expand_unop (mode, one_cmpl_optab, res_xor, NULL_RTX, false);
+ tem = expand_binop (mode, and_optab, op_xor, tem, NULL_RTX, false,
+ OPTAB_LIB_WIDEN);
+ }
+
+ /* No overflow if the result has bit sign cleared. */
+ do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX,
+ NULL, done_label, PROB_VERY_LIKELY);
}
- /* We have k = a + b for b < 0 here. k <= a must hold. */
- if (pos_neg & 2)
- do_compare_rtx_and_jump (res, op0, code == PLUS_EXPR ? LE : GE,
+ /* Compare the result of the operation with the first operand.
+ No overflow for addition if second operand is positive and result
+ is larger or second operand is negative and result is smaller.
+ Likewise for subtraction with sign of second operand flipped. */
+ else
+ do_compare_rtx_and_jump (res, op0,
+ (pos_neg == 1) ^ (code == MINUS_EXPR) ? GE : LE,
false, mode, NULL_RTX, NULL, done_label,
PROB_VERY_LIKELY);
}
@@ -1950,12 +1971,11 @@ expand_arith_overflow (enum tree_code code, gimple *stmt)
return;
}
- /* For sub-word operations, if target doesn't have them, start
- with precres widening right away, otherwise do it only
- if the most simple cases can't be used. */
- if (WORD_REGISTER_OPERATIONS
- && orig_precres == precres
- && precres < BITS_PER_WORD)
+ /* For operations with low precision, if target doesn't have them, start
+ with precres widening right away, otherwise do it only if the most
+ simple cases can't be used. */
+ const int min_precision = targetm.min_arithmetic_precision ();
+ if (orig_precres == precres && precres < min_precision)
;
else if ((uns0_p && uns1_p && unsr_p && prec0 <= precres
&& prec1 <= precres)
@@ -1990,7 +2010,7 @@ expand_arith_overflow (enum tree_code code, gimple *stmt)
/* For sub-word operations, retry with a wider type first. */
if (orig_precres == precres && precop <= BITS_PER_WORD)
{
- int p = WORD_REGISTER_OPERATIONS ? BITS_PER_WORD : precop;
+ int p = MAX (min_precision, precop);
enum machine_mode m = smallest_mode_for_size (p, MODE_INT);
tree optype = build_nonstandard_integer_type (GET_MODE_PRECISION (m),
uns0_p && uns1_p
@@ -2346,6 +2366,53 @@ expand_LAUNDER (internal_fn, gcall *call)
expand_assignment (lhs, gimple_call_arg (call, 0), false);
}
+/* Expand DIVMOD() using:
+ a) optab handler for udivmod/sdivmod if it is available.
+ b) If optab_handler doesn't exist, generate call to
+ target-specific divmod libfunc. */
+
+static void
+expand_DIVMOD (internal_fn, gcall *call_stmt)
+{
+ tree lhs = gimple_call_lhs (call_stmt);
+ tree arg0 = gimple_call_arg (call_stmt, 0);
+ tree arg1 = gimple_call_arg (call_stmt, 1);
+
+ gcc_assert (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE);
+ tree type = TREE_TYPE (TREE_TYPE (lhs));
+ machine_mode mode = TYPE_MODE (type);
+ bool unsignedp = TYPE_UNSIGNED (type);
+ optab tab = (unsignedp) ? udivmod_optab : sdivmod_optab;
+
+ rtx op0 = expand_normal (arg0);
+ rtx op1 = expand_normal (arg1);
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+
+ rtx quotient, remainder, libfunc;
+
+ /* Check if optab_handler exists for divmod_optab for given mode. */
+ if (optab_handler (tab, mode) != CODE_FOR_nothing)
+ {
+ quotient = gen_reg_rtx (mode);
+ remainder = gen_reg_rtx (mode);
+ expand_twoval_binop (tab, op0, op1, quotient, remainder, unsignedp);
+ }
+
+ /* Generate call to divmod libfunc if it exists. */
+ else if ((libfunc = optab_libfunc (tab, mode)) != NULL_RTX)
+ targetm.expand_divmod_libfunc (libfunc, mode, op0, op1,
+ &quotient, &remainder);
+
+ else
+ gcc_unreachable ();
+
+ /* Wrap the return value (quotient, remainder) within COMPLEX_EXPR. */
+ expand_expr (build2 (COMPLEX_EXPR, TREE_TYPE (lhs),
+ make_tree (TREE_TYPE (arg0), quotient),
+ make_tree (TREE_TYPE (arg1), remainder)),
+ target, VOIDmode, EXPAND_NORMAL);
+}
+
/* Expand a call to FN using the operands in STMT. FN has a single
output operand and NARGS input operands. */
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 1a128b66a76..77ce63a6408 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -165,6 +165,7 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...")
+DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, ".R..")
DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
@@ -208,6 +209,9 @@ DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL)
/* To implement __builtin_launder. */
DEF_INTERNAL_FN (LAUNDER, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
+/* Divmod function. */
+DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL)
+
#undef DEF_INTERNAL_INT_FN
#undef DEF_INTERNAL_FLT_FN
#undef DEF_INTERNAL_OPTAB_FN
diff --git a/gcc/ipa-comdats.c b/gcc/ipa-comdats.c
index 6e0f7622366..321bc0fc788 100644
--- a/gcc/ipa-comdats.c
+++ b/gcc/ipa-comdats.c
@@ -416,7 +416,7 @@ public:
bool
pass_ipa_comdats::gate (function *)
{
- return optimize;
+ return HAVE_COMDAT_GROUP && optimize;
}
} // anon namespace
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 1dc5cb6749a..0f34682753e 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -1070,12 +1070,6 @@ ipcp_bits_lattice::meet_with (ipcp_bits_lattice& other, unsigned precision,
return set_to_bottom ();
}
- else if (code == NOP_EXPR)
- {
- adjusted_value = other.m_value;
- adjusted_mask = other.m_mask;
- }
-
else
return set_to_bottom ();
@@ -1225,13 +1219,19 @@ ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input)
return NULL_TREE;
if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
- == tcc_comparison)
- restype = boolean_type_node;
+ == tcc_unary)
+ res = fold_unary (ipa_get_jf_pass_through_operation (jfunc),
+ TREE_TYPE (input), input);
else
- restype = TREE_TYPE (input);
- res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype,
- input, ipa_get_jf_pass_through_operand (jfunc));
-
+ {
+ if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
+ == tcc_comparison)
+ restype = boolean_type_node;
+ else
+ restype = TREE_TYPE (input);
+ res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype,
+ input, ipa_get_jf_pass_through_operand (jfunc));
+ }
if (res && !is_gimple_ip_invariant (res))
return NULL_TREE;
@@ -1840,12 +1840,14 @@ propagate_bits_accross_jump_function (cgraph_edge *cs, int idx, ipa_jump_func *j
}
/* Propagate value range across jump function JFUNC that is associated with
- edge CS and update DEST_PLATS accordingly. */
+ edge CS with param of callee of PARAM_TYPE and update DEST_PLATS
+ accordingly. */
static bool
propagate_vr_accross_jump_function (cgraph_edge *cs,
ipa_jump_func *jfunc,
- struct ipcp_param_lattices *dest_plats)
+ struct ipcp_param_lattices *dest_plats,
+ tree param_type)
{
struct ipcp_param_lattices *src_lats;
ipcp_vr_lattice *dest_lat = &dest_plats->m_value_range;
@@ -1853,6 +1855,11 @@ propagate_vr_accross_jump_function (cgraph_edge *cs,
if (dest_lat->bottom_p ())
return false;
+ if (!param_type
+ || (!INTEGRAL_TYPE_P (param_type)
+ && !POINTER_TYPE_P (param_type)))
+ return dest_lat->set_to_bottom ();
+
if (jfunc->type == IPA_JF_PASS_THROUGH)
{
struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
@@ -1863,6 +1870,25 @@ propagate_vr_accross_jump_function (cgraph_edge *cs,
if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
return dest_lat->meet_with (src_lats->m_value_range);
+ else if (param_type
+ && (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
+ == tcc_unary))
+ {
+ value_range vr;
+ memset (&vr, 0, sizeof (vr));
+ tree operand_type = ipa_get_type (caller_info, src_idx);
+ enum tree_code operation = ipa_get_jf_pass_through_operation (jfunc);
+
+ if (src_lats->m_value_range.bottom_p ())
+ return false;
+
+ extract_range_from_unary_expr (&vr,
+ operation,
+ param_type,
+ &src_lats->m_value_range.m_vr,
+ operand_type);
+ return dest_lat->meet_with (&vr);
+ }
}
else if (jfunc->type == IPA_JF_CONST)
{
@@ -1871,6 +1897,7 @@ propagate_vr_accross_jump_function (cgraph_edge *cs,
{
if (TREE_OVERFLOW_P (val))
val = drop_tree_overflow (val);
+ val = fold_convert (param_type, val);
jfunc->vr_known = true;
jfunc->m_vr.type = VR_RANGE;
jfunc->m_vr.min = val;
@@ -2220,6 +2247,7 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
{
struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i);
struct ipcp_param_lattices *dest_plats;
+ tree param_type = ipa_get_callee_param_type (cs, i);
dest_plats = ipa_get_parm_lattices (callee_info, i);
if (availability == AVAIL_INTERPOSABLE)
@@ -2236,7 +2264,8 @@ propagate_constants_accross_call (struct cgraph_edge *cs)
dest_plats);
if (opt_for_fn (callee->decl, flag_ipa_vrp))
ret |= propagate_vr_accross_jump_function (cs,
- jump_func, dest_plats);
+ jump_func, dest_plats,
+ param_type);
else
ret |= dest_plats->m_value_range.set_to_bottom ();
}
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 16298703fa6..8312c5a9f6b 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -446,6 +446,18 @@ ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id,
jfunc->value.pass_through.agg_preserved = agg_preserved;
}
+/* Set JFUNC to be an unary pass through jump function. */
+
+static void
+ipa_set_jf_unary_pass_through (struct ipa_jump_func *jfunc, int formal_id,
+ enum tree_code operation)
+{
+ jfunc->type = IPA_JF_PASS_THROUGH;
+ jfunc->value.pass_through.operand = NULL_TREE;
+ jfunc->value.pass_through.formal_id = formal_id;
+ jfunc->value.pass_through.operation = operation;
+ jfunc->value.pass_through.agg_preserved = false;
+}
/* Set JFUNC to be an arithmetic pass through jump function. */
static void
@@ -849,21 +861,19 @@ parm_preserved_before_stmt_p (struct ipa_func_body_info *fbi, int index,
return !modified;
}
-/* If STMT is an assignment that loads a value from an parameter declaration,
- return the index of the parameter in ipa_node_params which has not been
- modified. Otherwise return -1. */
+/* Main worker for load_from_unmodified_param and load_from_param.
+ If STMT is an assignment that loads a value from an parameter declaration,
+ return the index of the parameter in ipa_node_params. Otherwise return -1. */
static int
-load_from_unmodified_param (struct ipa_func_body_info *fbi,
- vec<ipa_param_descriptor> descriptors,
- gimple *stmt)
+load_from_param_1 (struct ipa_func_body_info *fbi,
+ vec<ipa_param_descriptor> descriptors,
+ gimple *stmt)
{
int index;
tree op1;
- if (!gimple_assign_single_p (stmt))
- return -1;
-
+ gcc_checking_assert (is_gimple_assign (stmt));
op1 = gimple_assign_rhs1 (stmt);
if (TREE_CODE (op1) != PARM_DECL)
return -1;
@@ -876,6 +886,40 @@ load_from_unmodified_param (struct ipa_func_body_info *fbi,
return index;
}
+/* If STMT is an assignment that loads a value from an parameter declaration,
+ return the index of the parameter in ipa_node_params which has not been
+ modified. Otherwise return -1. */
+
+static int
+load_from_unmodified_param (struct ipa_func_body_info *fbi,
+ vec<ipa_param_descriptor> descriptors,
+ gimple *stmt)
+{
+ if (!gimple_assign_single_p (stmt))
+ return -1;
+
+ return load_from_param_1 (fbi, descriptors, stmt);
+}
+
+/* If STMT is an assignment that loads a value from an parameter declaration,
+ return the index of the parameter in ipa_node_params. Otherwise return -1. */
+
+static int
+load_from_param (struct ipa_func_body_info *fbi,
+ vec<ipa_param_descriptor> descriptors,
+ gimple *stmt)
+{
+ if (!is_gimple_assign (stmt))
+ return -1;
+
+ enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
+ if ((get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
+ && (get_gimple_rhs_class (rhs_code) != GIMPLE_UNARY_RHS))
+ return -1;
+
+ return load_from_param_1 (fbi, descriptors, stmt);
+}
+
/* Return true if memory reference REF (which must be a load through parameter
with INDEX) loads data that are known to be unmodified in this function
before reaching statement STMT. */
@@ -1109,6 +1153,7 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
tree op1, tc_ssa, base, ssa;
bool reverse;
int index;
+ gimple *stmt2 = stmt;
op1 = gimple_assign_rhs1 (stmt);
@@ -1117,13 +1162,16 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
if (SSA_NAME_IS_DEFAULT_DEF (op1))
index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
else
- index = load_from_unmodified_param (fbi, info->descriptors,
- SSA_NAME_DEF_STMT (op1));
+ {
+ index = load_from_param (fbi, info->descriptors,
+ SSA_NAME_DEF_STMT (op1));
+ stmt2 = SSA_NAME_DEF_STMT (op1);
+ }
tc_ssa = op1;
}
else
{
- index = load_from_unmodified_param (fbi, info->descriptors, stmt);
+ index = load_from_param (fbi, info->descriptors, stmt);
tc_ssa = gimple_assign_lhs (stmt);
}
@@ -1147,6 +1195,13 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, tc_ssa);
ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
}
+ else if (is_gimple_assign (stmt2)
+ && (gimple_expr_code (stmt2) != NOP_EXPR)
+ && (TREE_CODE_CLASS (gimple_expr_code (stmt2)) == tcc_unary))
+ {
+ ipa_set_jf_unary_pass_through (jfunc, index,
+ gimple_assign_rhs_code (stmt2));
+ }
return;
}
@@ -1595,7 +1650,10 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
}
}
-static tree
+/* Return the Ith param type of callee associated with call graph
+ edge E. */
+
+tree
ipa_get_callee_param_type (struct cgraph_edge *e, int i)
{
int n;
@@ -4663,6 +4721,11 @@ ipa_write_jump_function (struct output_block *ob,
bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1);
streamer_write_bitpack (&bp);
}
+ else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation)
+ == tcc_unary)
+ {
+ streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+ }
else
{
stream_write_tree (ob, jump_func->value.pass_through.operand, true);
@@ -4742,6 +4805,11 @@ ipa_read_jump_function (struct lto_input_block *ib,
bool agg_preserved = bp_unpack_value (&bp, 1);
ipa_set_jf_simple_pass_through (jump_func, formal_id, agg_preserved);
}
+ else if (TREE_CODE_CLASS (operation) == tcc_unary)
+ {
+ int formal_id = streamer_read_uhwi (ib);
+ ipa_set_jf_unary_pass_through (jump_func, formal_id, operation);
+ }
else
{
tree operand = stream_read_tree (ib, data_in);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 4eeae882f5f..0e75cf48c1a 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -818,6 +818,7 @@ ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *,
ipa_parm_adjustment_vec,
bool);
void ipa_release_body_info (struct ipa_func_body_info *);
+tree ipa_get_callee_param_type (struct cgraph_edge *e, int i);
/* From tree-sra.c: */
tree build_ref_for_offset (location_t, tree, HOST_WIDE_INT, bool, tree,
diff --git a/gcc/ira.c b/gcc/ira.c
index cd640fce589..f453ea9e604 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -792,78 +792,85 @@ setup_pressure_classes (void)
HARD_REG_SET temp_hard_regset2;
bool insert_p;
- n = 0;
- for (cl = 0; cl < N_REG_CLASSES; cl++)
- {
- if (ira_class_hard_regs_num[cl] == 0)
- continue;
- if (ira_class_hard_regs_num[cl] != 1
- /* A register class without subclasses may contain a few
- hard registers and movement between them is costly
- (e.g. SPARC FPCC registers). We still should consider it
- as a candidate for a pressure class. */
- && alloc_reg_class_subclasses[cl][0] < cl)
+ if (targetm.compute_pressure_classes)
+ n = targetm.compute_pressure_classes (pressure_classes);
+ else
+ {
+ n = 0;
+ for (cl = 0; cl < N_REG_CLASSES; cl++)
{
- /* Check that the moves between any hard registers of the
- current class are not more expensive for a legal mode
- than load/store of the hard registers of the current
- class. Such class is a potential candidate to be a
- register pressure class. */
- for (m = 0; m < NUM_MACHINE_MODES; m++)
+ if (ira_class_hard_regs_num[cl] == 0)
+ continue;
+ if (ira_class_hard_regs_num[cl] != 1
+ /* A register class without subclasses may contain a few
+ hard registers and movement between them is costly
+ (e.g. SPARC FPCC registers). We still should consider it
+ as a candidate for a pressure class. */
+ && alloc_reg_class_subclasses[cl][0] < cl)
{
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- AND_COMPL_HARD_REG_SET (temp_hard_regset,
- ira_prohibited_class_mode_regs[cl][m]);
- if (hard_reg_set_empty_p (temp_hard_regset))
+ /* Check that the moves between any hard registers of the
+ current class are not more expensive for a legal mode
+ than load/store of the hard registers of the current
+ class. Such class is a potential candidate to be a
+ register pressure class. */
+ for (m = 0; m < NUM_MACHINE_MODES; m++)
+ {
+ COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
+ AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
+ AND_COMPL_HARD_REG_SET (temp_hard_regset,
+ ira_prohibited_class_mode_regs[cl][m]);
+ if (hard_reg_set_empty_p (temp_hard_regset))
+ continue;
+ ira_init_register_move_cost_if_necessary ((machine_mode) m);
+ cost = ira_register_move_cost[m][cl][cl];
+ if (cost <= ira_max_memory_move_cost[m][cl][1]
+ || cost <= ira_max_memory_move_cost[m][cl][0])
+ break;
+ }
+ if (m >= NUM_MACHINE_MODES)
continue;
- ira_init_register_move_cost_if_necessary ((machine_mode) m);
- cost = ira_register_move_cost[m][cl][cl];
- if (cost <= ira_max_memory_move_cost[m][cl][1]
- || cost <= ira_max_memory_move_cost[m][cl][0])
- break;
}
- if (m >= NUM_MACHINE_MODES)
- continue;
- }
- curr = 0;
- insert_p = true;
- COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
- /* Remove so far added pressure classes which are subset of the
- current candidate class. Prefer GENERAL_REGS as a pressure
- register class to another class containing the same
- allocatable hard registers. We do this because machine
- dependent cost hooks might give wrong costs for the latter
- class but always give the right cost for the former class
- (GENERAL_REGS). */
- for (i = 0; i < n; i++)
- {
- cl2 = pressure_classes[i];
- COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]);
- AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
- if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2)
- && (! hard_reg_set_equal_p (temp_hard_regset, temp_hard_regset2)
- || cl2 == (int) GENERAL_REGS))
+ curr = 0;
+ insert_p = true;
+ COPY_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
+ AND_COMPL_HARD_REG_SET (temp_hard_regset, no_unit_alloc_regs);
+ /* Remove so far added pressure classes which are subset of the
+ current candidate class. Prefer GENERAL_REGS as a pressure
+ register class to another class containing the same
+ allocatable hard registers. We do this because machine
+ dependent cost hooks might give wrong costs for the latter
+ class but always give the right cost for the former class
+ (GENERAL_REGS). */
+ for (i = 0; i < n; i++)
{
+ cl2 = pressure_classes[i];
+ COPY_HARD_REG_SET (temp_hard_regset2, reg_class_contents[cl2]);
+ AND_COMPL_HARD_REG_SET (temp_hard_regset2, no_unit_alloc_regs);
+ if (hard_reg_set_subset_p (temp_hard_regset, temp_hard_regset2)
+ && (! hard_reg_set_equal_p (temp_hard_regset,
+ temp_hard_regset2)
+ || cl2 == (int) GENERAL_REGS))
+ {
+ pressure_classes[curr++] = (enum reg_class) cl2;
+ insert_p = false;
+ continue;
+ }
+ if (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset)
+ && (! hard_reg_set_equal_p (temp_hard_regset2,
+ temp_hard_regset)
+ || cl == (int) GENERAL_REGS))
+ continue;
+ if (hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset))
+ insert_p = false;
pressure_classes[curr++] = (enum reg_class) cl2;
- insert_p = false;
- continue;
}
- if (hard_reg_set_subset_p (temp_hard_regset2, temp_hard_regset)
- && (! hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset)
- || cl == (int) GENERAL_REGS))
- continue;
- if (hard_reg_set_equal_p (temp_hard_regset2, temp_hard_regset))
- insert_p = false;
- pressure_classes[curr++] = (enum reg_class) cl2;
+ /* If the current candidate is a subset of a so far added
+ pressure class, don't add it to the list of the pressure
+ classes. */
+ if (insert_p)
+ pressure_classes[curr++] = (enum reg_class) cl;
+ n = curr;
}
- /* If the current candidate is a subset of a so far added
- pressure class, don't add it to the list of the pressure
- classes. */
- if (insert_p)
- pressure_classes[curr++] = (enum reg_class) cl;
- n = curr;
}
#ifdef ENABLE_IRA_CHECKING
{
diff --git a/gcc/jump.c b/gcc/jump.c
index fafef05f5b2..b6828133cb3 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -62,7 +62,7 @@ static void init_label_info (rtx_insn *);
static void mark_all_labels (rtx_insn *);
static void mark_jump_label_1 (rtx, rtx_insn *, bool, bool);
static void mark_jump_label_asm (rtx, rtx_insn *);
-static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
+static void redirect_exp_1 (rtx *, rtx, rtx, rtx_insn *);
static int invert_exp_1 (rtx, rtx_insn *);
/* Worker for rebuild_jump_labels and rebuild_jump_labels_chain. */
@@ -1457,7 +1457,7 @@ redirect_target (rtx x)
NLABEL as a return. Accrue modifications into the change group. */
static void
-redirect_exp_1 (rtx *loc, rtx olabel, rtx nlabel, rtx insn)
+redirect_exp_1 (rtx *loc, rtx olabel, rtx nlabel, rtx_insn *insn)
{
rtx x = *loc;
RTX_CODE code = GET_CODE (x);
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index e49382bfb56..5c330f034b2 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -84,6 +84,7 @@ extern bool lhd_omp_mappable_type (tree);
extern const char *lhd_get_substring_location (const substring_loc &,
location_t *out_loc);
extern int lhd_decl_dwarf_attribute (const_tree, int);
+extern int lhd_type_dwarf_attribute (const_tree, int);
#define LANG_HOOKS_NAME "GNU unknown"
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct lang_identifier)
@@ -186,6 +187,7 @@ extern tree lhd_make_node (enum tree_code);
#define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE lhd_enum_underlying_base_type
#define LANG_HOOKS_GET_DEBUG_TYPE NULL
#define LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO NULL
+#define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE lhd_type_dwarf_attribute
#define LANG_HOOKS_FOR_TYPES_INITIALIZER { \
LANG_HOOKS_MAKE_TYPE, \
@@ -208,7 +210,8 @@ extern tree lhd_make_node (enum tree_code);
LANG_HOOKS_RECONSTRUCT_COMPLEX_TYPE, \
LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE, \
LANG_HOOKS_GET_DEBUG_TYPE, \
- LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO \
+ LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \
+ LANG_HOOKS_TYPE_DWARF_ATTRIBUTE \
}
/* Declaration hooks. */
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index 370990ef43b..6483dc1c6d6 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -702,6 +702,15 @@ lhd_decl_dwarf_attribute (const_tree, int)
return -1;
}
+/* Default implementation of LANG_HOOKS_TYPE_DWARF_ATTRIBUTE. Don't add
+ any attributes. */
+
+int
+lhd_type_dwarf_attribute (const_tree, int)
+{
+ return -1;
+}
+
/* Returns true if the current lang_hooks represents the GNU C frontend. */
bool
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index 8116b170f7b..150227c88d0 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -120,7 +120,7 @@ struct lang_hooks_for_types
/* Return TRUE if TYPE1 and TYPE2 are identical for type hashing purposes.
Called only after doing all language independent checks.
At present, this function is only called when both TYPE1 and TYPE2 are
- FUNCTION_TYPEs. */
+ FUNCTION_TYPE or METHOD_TYPE. */
bool (*type_hash_eq) (const_tree, const_tree);
/* Return TRUE if TYPE uses a hidden descriptor and fills in information
@@ -162,6 +162,10 @@ struct lang_hooks_for_types
for the debugger about scale factor, etc. */
bool (*get_fixed_point_type_info) (const_tree,
struct fixed_point_type_info *);
+
+ /* Returns -1 if dwarf ATTR shouldn't be added for TYPE, or the attribute
+ value otherwise. */
+ int (*type_dwarf_attribute) (const_tree, int);
};
/* Language hooks related to decls and the symbol table. */
diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c
index 551103fcf46..f617241ef0f 100644
--- a/gcc/loop-invariant.c
+++ b/gcc/loop-invariant.c
@@ -598,13 +598,17 @@ find_exits (struct loop *loop, basic_block *body,
FOR_EACH_EDGE (e, ei, body[i]->succs)
{
- if (flow_bb_inside_loop_p (loop, e->dest))
- continue;
-
- bitmap_set_bit (may_exit, i);
- bitmap_set_bit (has_exit, i);
- outermost_exit = find_common_loop (outermost_exit,
- e->dest->loop_father);
+ if (! flow_bb_inside_loop_p (loop, e->dest))
+ {
+ bitmap_set_bit (may_exit, i);
+ bitmap_set_bit (has_exit, i);
+ outermost_exit = find_common_loop (outermost_exit,
+ e->dest->loop_father);
+ }
+ /* If we enter a subloop that might never terminate treat
+ it like a possible exit. */
+ if (flow_loop_nested_p (loop, e->dest->loop_father))
+ bitmap_set_bit (may_exit, i);
}
continue;
}
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 4ce7ac76358..e350a13dc61 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,9 @@
+2016-10-31 Richard Biener <rguenther@suse.de>
+
+ PR lto/78129
+ * lto.c (do_whole_program_analysis): Bail out after errors
+ from WPA analysis.
+
2016-09-21 Kugan Vivekanandarajah <kuganv@linaro.org>
* lto-partition.c: Include tree-vrp.h.
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 7256ff9547b..c1567ca2ca3 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -3092,6 +3092,10 @@ do_whole_program_analysis (void)
execute_ipa_pass_list (g->get_passes ()->all_regular_ipa_passes);
+ /* When WPA analysis raises errors, do not bother to output anything. */
+ if (seen_error ())
+ return;
+
if (symtab->dump_file)
{
fprintf (symtab->dump_file, "Optimized ");
diff --git a/gcc/match.pd b/gcc/match.pd
index 48f73514a3f..29ddcd82a18 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -519,6 +519,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (TYPE_UNSIGNED (type))
(bit_and @0 (bit_not (lshift { build_all_ones_cst (type); } @1)))))
+/* PR35691: Transform
+ (x == 0 & y == 0) -> (x | typeof(x)(y)) == 0.
+ (x != 0 | y != 0) -> (x | typeof(x)(y)) != 0. */
+(for bitop (bit_and bit_ior)
+ cmp (eq ne)
+ (simplify
+ (bitop (cmp @0 integer_zerop@2) (cmp @1 integer_zerop))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
+ (cmp (bit_ior @0 (convert @1)) @2))))
+
/* Fold (A & ~B) - (A & B) into (A ^ B) - B. */
(simplify
(minus (bit_and:cs @0 (bit_not @1)) (bit_and:cs @0 @1))
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a4d7a5e8e46..7a1f02533bc 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -1712,8 +1712,9 @@ expand_binop (machine_mode mode, optab binoptab, rtx op0, rtx op1,
{
if (optab_handler (mov_optab, mode) != CODE_FOR_nothing)
{
- temp = emit_move_insn (target ? target : product, product);
- set_dst_reg_note (temp,
+ rtx_insn *move = emit_move_insn (target ? target : product,
+ product);
+ set_dst_reg_note (move,
REG_EQUAL,
gen_rtx_fmt_ee (MULT, mode,
copy_rtx (op0),
diff --git a/gcc/opts.c b/gcc/opts.c
index d381cb5227c..2f230cea315 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -979,6 +979,25 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
opts->x_flag_aggressive_loop_optimizations = 0;
opts->x_flag_strict_overflow = 0;
}
+
+ /* Enable -fsanitize-address-use-after-scope if address sanitizer is
+ enabled. */
+ if (opts->x_flag_sanitize
+ && !opts_set->x_flag_sanitize_address_use_after_scope)
+ opts->x_flag_sanitize_address_use_after_scope = true;
+
+ /* Force -fstack-reuse=none in case -fsanitize-address-use-after-scope
+ is enabled. */
+ if (opts->x_flag_sanitize_address_use_after_scope)
+ {
+ if (opts->x_flag_stack_reuse != SR_NONE
+ && opts_set->x_flag_stack_reuse != SR_NONE)
+ error_at (loc,
+ "-fsanitize-address-use-after-scope requires "
+ "-fstack-reuse=none option");
+
+ opts->x_flag_stack_reuse = SR_NONE;
+ }
}
#define LEFT_COLUMN 27
@@ -1452,8 +1471,8 @@ const struct sanitizer_opts_s sanitizer_opts[] =
{
#define SANITIZER_OPT(name, flags, recover) \
{ #name, flags, sizeof #name - 1, recover }
- SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS, true),
- SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS,
+ SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true),
+ SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
true),
SANITIZER_OPT (thread, SANITIZE_THREAD, false),
SANITIZER_OPT (leak, SANITIZE_LEAK, false),
@@ -1781,6 +1800,10 @@ common_handle_option (struct gcc_options *opts,
/* Deferred. */
break;
+ case OPT_fsanitize_address_use_after_scope:
+ opts->x_flag_sanitize_address_use_after_scope = value;
+ break;
+
case OPT_fsanitize_recover:
if (value)
opts->x_flag_sanitize_recover
diff --git a/gcc/params.def b/gcc/params.def
index ab3eb3d3b42..89f70936d2e 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -1168,6 +1168,12 @@ DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD,
"in function becomes greater or equal to this number.",
7000, 0, INT_MAX)
+DEFPARAM (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD,
+ "use-after-scope-direct-emission-threshold",
+ "Use direct poisoning/unpoisoning intructions for variables "
+ "smaller or equal to this number.",
+ 256, 0, INT_MAX)
+
DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS,
"uninit-control-dep-attempts",
"Maximum number of nested calls to search for control dependencies "
diff --git a/gcc/params.h b/gcc/params.h
index 97c8d565055..0a2905ce1ff 100644
--- a/gcc/params.h
+++ b/gcc/params.h
@@ -244,5 +244,7 @@ extern void init_param_values (int *params);
PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN)
#define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \
PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD)
+#define ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD \
+ ((unsigned) PARAM_VALUE (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD))
#endif /* ! GCC_PARAMS_H */
diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog
index f85cc0db0e4..c6c7a3effcb 100644
--- a/gcc/po/ChangeLog
+++ b/gcc/po/ChangeLog
@@ -1,3 +1,15 @@
+2016-11-07 Joseph Myers <joseph@codesourcery.com>
+
+ * es.po: Update.
+
+2016-11-05 Joseph Myers <joseph@codesourcery.com>
+
+ * es.po: Update.
+
+2016-11-01 Joseph Myers <joseph@codesourcery.com>
+
+ * es.po: Update.
+
2016-10-10 Joseph Myers <joseph@codesourcery.com>
* sv.po: Update.
diff --git a/gcc/po/es.po b/gcc/po/es.po
index 5049cc3c407..346cd9130fc 100644
--- a/gcc/po/es.po
+++ b/gcc/po/es.po
@@ -1,22 +1,44 @@
# Mensajes en español para gcc-4.7.2.
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2016 Free Software Foundation, Inc.
# This file is distributed under the same license as the gcc package.
# Cristian Othón Martínez Vera <cfuga@cfuga.mx>, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+# Antonio Ceballos Roa <aceballos@gmail.com>, 2016
#
# Agradezco a Juan Cuquejo Mira por sus comentarios sobre esta traducción
#
+# Glosario
+#
+# asan - asan
+# bug - error
+# callback - callback
+# cse - TBD
+# demangled - mutilado
+# hardware - hardware
+# hotness - calentura
+# insns - TBD
+# instruction - instrucción
+# iv optimization - optimización iv
+# omp (OpenMP) - omp
+# OS - S.O.
+# report - informe TODO
+# scheduler - planificador
+# SSA - SSA
+# statement - sentencia
+# ubsan - ubsan
+#
msgid ""
msgstr ""
-"Project-Id-Version: gcc 4.7.2\n"
+"Project-Id-Version: gcc 6.2.0\n"
"Report-Msgid-Bugs-To: http://gcc.gnu.org/bugs.html\n"
"POT-Creation-Date: 2016-08-19 21:03+0000\n"
-"PO-Revision-Date: 2012-09-24 13:50-0500\n"
-"Last-Translator: Cristian Othón Martínez Vera <cfuga@cfuga.mx>\n"
-"Language-Team: Spanish <es@li.org>\n"
+"PO-Revision-Date: 2016-11-06 21:49+0100\n"
+"Last-Translator: Antonio Ceballos <aceballos@gmail.com>\n"
+"Language-Team: Spanish <es@tp.org.es>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: cfgrtl.c:2656
@@ -120,24 +142,18 @@ msgid "compilation terminated due to -fmax-errors=%u.\n"
msgstr "compilación terminada debido a -fmax-errors=%u.\n"
#: diagnostic.c:481
-#, fuzzy, c-format
-#| msgid ""
-#| "Please submit a full bug report,\n"
-#| "with preprocessed source if appropriate.\n"
-#| "See %s for instructions.\n"
+#, c-format
msgid ""
"Please submit a full bug report,\n"
"with preprocessed source if appropriate.\n"
msgstr ""
-"Por favor envíe un reporte completo de bichos,\n"
+"Por favor, envíe un informe completo de errores,\n"
"con el código preprocesado si es apropiado.\n"
-"Vea %s para más instrucciones.\n"
#: diagnostic.c:487
-#, fuzzy, c-format
-#| msgid "Use fp double instructions"
+#, c-format
msgid "See %s for instructions.\n"
-msgstr "Usa instrucciones fp double"
+msgstr "Véase %s para instrucciones.\n"
#: diagnostic.c:496
#, c-format
@@ -285,19 +301,19 @@ msgstr "Opciones:\n"
#, fuzzy
#| msgid " -pass-exit-codes Exit with highest error code from a phase\n"
msgid " -pass-exit-codes Exit with highest error code from a phase.\n"
-msgstr " -pass-exit-codes Sale con el código de error más alto de una fase\n"
+msgstr " -pass-exit-codes Sale con el código de error más alto de una fase.\n"
#: gcc.c:3385
#, fuzzy
#| msgid " --help Display this information\n"
msgid " --help Display this information.\n"
-msgstr " --help Muestra esta información\n"
+msgstr " --help Muestra esta información.\n"
#: gcc.c:3386
#, fuzzy
#| msgid " --target-help Display target specific command line options\n"
msgid " --target-help Display target specific command line options.\n"
-msgstr " --target-help Muestra opciones de línea de órdenes específicas del objetivo\n"
+msgstr " --target-help Muestra opciones de línea de órdenes específicas del objetivo.\n"
#: gcc.c:3387
#, fuzzy
@@ -627,12 +643,12 @@ msgstr "controlador gcc versión %s %sejecutando gcc versión %s\n"
#: gcc.c:6683 gcc.c:6895
#, c-format
msgid "The bug is not reproducible, so it is likely a hardware or OS problem.\n"
-msgstr ""
+msgstr "El error no es repetible, por lo que probablemente sea un problema de hardware o de S.O.\n"
#: gcc.c:6819
#, c-format
msgid "Preprocessed source stored into %s file, please attach this to your bugreport.\n"
-msgstr ""
+msgstr "Fuente preprocesada almacenada en el fichero %s; por favor, adjúntelo a su informe de errores.\n"
#: gcc.c:7761
#, c-format
@@ -656,7 +672,7 @@ msgid ""
"For bug reporting instructions, please see:\n"
msgstr ""
"\n"
-"Para instrucciones de reporte de bichos, por favor vea:\n"
+"Para instrucciones de informe de errores, por favor vea:\n"
#: gcc.c:7899 gcov-tool.c:525
#, c-format
@@ -723,111 +739,106 @@ msgstr ""
#: gcov-tool.c:166
#, c-format
msgid " merge [options] <dir1> <dir2> Merge coverage file contents\n"
-msgstr ""
+msgstr " merge [opciones] <dir1> <dir2> Mezcla el contenido del fichero de cobertura\n"
#: gcov-tool.c:167 gcov-tool.c:261 gcov-tool.c:417
-#, fuzzy, c-format
-#| msgid " -v, --version Print version number, then exit\n"
+#, c-format
msgid " -v, --verbose Verbose mode\n"
-msgstr " -v, --version Muestra el número de versión, y finaliza\n"
+msgstr " -v, --verbose Modo expresivo\n"
#: gcov-tool.c:168 gcov-tool.c:262
-#, fuzzy, c-format
-#| msgid " -n, --no-output Do not create an output file\n"
+#, c-format
msgid " -o, --output <dir> Output directory\n"
-msgstr " -n, --no-output No crea un fichero de salida\n"
+msgstr " -o, --output <dir> Directorio de salida\n"
#: gcov-tool.c:169
#, c-format
msgid " -w, --weight <w1,w2> Set weights (float point values)\n"
-msgstr ""
+msgstr " -w, --weight <p1,p2> Establece los pesos (valores de coma flotante)\n"
#: gcov-tool.c:185
#, c-format
msgid "Merge subcomand usage:"
-msgstr ""
+msgstr "Modo de empleo de la suborden de mezcla:"
#: gcov-tool.c:260
#, c-format
msgid " rewrite [options] <dir> Rewrite coverage file contents\n"
-msgstr ""
+msgstr " rewrite [opciones] <dir> Reescribe el contenido del fichero de cobertura\n"
#: gcov-tool.c:263
#, c-format
msgid " -s, --scale <float or simple-frac> Scale the profile counters\n"
-msgstr ""
+msgstr " -s, --scale <float o frac-simple> Escala los contadores de perfil\n"
#: gcov-tool.c:264
#, c-format
msgid " -n, --normalize <long long> Normalize the profile\n"
-msgstr ""
+msgstr " -n, --normalize <long long> Normaliza el perfil\n"
#: gcov-tool.c:281
#, c-format
msgid "Rewrite subcommand usage:"
-msgstr ""
+msgstr "Modo de empleo de la suborden de reescritura:"
#: gcov-tool.c:326
#, c-format
msgid "scaling cannot co-exist with normalization, skipping\n"
-msgstr ""
+msgstr "escalado y normalización no pueden coexistir; se omite\n"
#: gcov-tool.c:339 gcov-tool.c:349
#, c-format
msgid "incorrect format in scaling, using 1/1\n"
-msgstr ""
+msgstr "formato de escalado incorrecto; se utiliza 1/1\n"
#: gcov-tool.c:359
#, c-format
msgid "normalization cannot co-exist with scaling\n"
-msgstr ""
+msgstr "normalización y escalado no pueden coexistir\n"
#: gcov-tool.c:416
#, c-format
msgid " overlap [options] <dir1> <dir2> Compute the overlap of two profiles\n"
-msgstr ""
+msgstr " overlap [opciones] <dir1> <dir2> Calcula el solapamiento de dos perfiles\n"
#: gcov-tool.c:418
-#, fuzzy, c-format
-#| msgid " -h, --help Print this help, then exit\n"
+#, c-format
msgid " -h, --hotonly Only print info for hot objects/functions\n"
-msgstr " -h, --help Muestra esta información, y finaliza\n"
+msgstr " -h, --hotonly Solo imprime información sobre objetos y funciones calientes\n"
#: gcov-tool.c:419
-#, fuzzy, c-format
-#| msgid " -p Enable function profiling\n"
+#, c-format
msgid " -f, --function Print function level info\n"
-msgstr " -p Activar el análisis de perfil de funciones\n"
+msgstr " -f, --function Imprime información sobre el nivel de funciones\n"
#: gcov-tool.c:420
-#, fuzzy, c-format
-#| msgid " -h, --help Print this help, then exit\n"
+#, c-format
msgid " -F, --fullname Print full filename\n"
-msgstr " -h, --help Muestra esta información, y finaliza\n"
+msgstr " -F, --fullname Imprime el nombre de fichero completo\n"
#: gcov-tool.c:421
-#, fuzzy, c-format
-#| msgid " -h, --help Print this help, then exit\n"
+#, c-format
msgid " -o, --object Print object level info\n"
-msgstr " -h, --help Muestra esta información, y finaliza\n"
+msgstr " -o, --object Imprime información sobre el nivel de objetos\n"
#: gcov-tool.c:422
#, c-format
msgid " -t <float>, --hot_threshold <float> Set the threshold for hotness\n"
-msgstr ""
+msgstr " -t <float>, --hot_threshold <float> Establece el umbral de calentura\n"
#: gcov-tool.c:442
#, c-format
msgid "Overlap subcomand usage:"
-msgstr ""
+msgstr "Modo de empleo de la suborden de solapamiento:"
#: gcov-tool.c:508
-#, fuzzy, c-format
-#| msgid "Usage: %s [OPTIONS]... CLASSNAMEmain [OUTFILE]\n"
+#, c-format
msgid ""
"Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n"
"\n"
-msgstr "Modo de empleo: %s [OPCIONES]... NOMBRECLASEmain [FICHERO-SALIDA]\n"
+msgstr ""
+"Modo de empleo: %s [OPCIÓN]... SUB_ORDEN [OPCIÓN]...\n"
+"\n"
#: gcov-tool.c:509
#, c-format
@@ -835,6 +846,8 @@ msgid ""
"Offline tool to handle gcda counts\n"
"\n"
msgstr ""
+"Herramienta «offline» para manejar contadores de gcda\n"
+"\n"
#: gcov-tool.c:510
#, fuzzy, c-format
@@ -856,7 +869,7 @@ msgid ""
"%s.\n"
msgstr ""
"\n"
-"Para instrucciones de reporte de bichos, por favor vea:\n"
+"Para instrucciones de informe de errores, por favor vea:\n"
"%s.\n"
#: gcov-tool.c:526
@@ -936,7 +949,7 @@ msgstr " -f, --function-summaries Muestra sumarios para cada función\n"
#: gcov.c:481
#, c-format
msgid " -i, --intermediate-format Output .gcov file in intermediate text format\n"
-msgstr ""
+msgstr " -t, --intermediate-format Fichero de salida .gcov en formato de texto intermedio\n"
#: gcov.c:482
#, c-format
@@ -950,7 +963,7 @@ msgstr ""
#: gcov.c:484
#, c-format
msgid " -m, --demangled-names Output demangled function names\n"
-msgstr ""
+msgstr " -m, --demangled-names Nombres de función mutilados de salida\n"
#: gcov.c:485
#, c-format
@@ -1327,30 +1340,27 @@ msgstr "no se pueden generar recargas para:"
#. What to print when a switch has no documentation.
#: opts.c:184
-#, fuzzy
-#| msgid "This switch lacks documentation"
msgid "This option lacks documentation."
-msgstr "Esta opción carece de documentación"
+msgstr "Esta opción carece de documentación."
#: opts.c:185
msgid "Uses of this option are diagnosed."
-msgstr ""
+msgstr "Los usos de esta opción están diagnosticados."
#: opts.c:1061
#, c-format
msgid "default %d minimum %d maximum %d"
-msgstr ""
+msgstr "predeterminado %d mínimo %d máximo %d"
#: opts.c:1128
#, c-format
msgid "Same as %s. Use the latter option instead."
-msgstr ""
+msgstr "Igual que %s. Utilice, en cambio, la última opción."
#: opts.c:1136
-#, fuzzy, c-format
-#| msgid "(%s %s %s %s %s"
+#, c-format
msgid "%s Same as %s."
-msgstr "(%s %s %s %s %s"
+msgstr "%s Igual que %s."
#: opts.c:1207
msgid "[default]"
@@ -1435,7 +1445,7 @@ msgstr "Plugins"
#: plugin.c:828
#, c-format
msgid "*** WARNING *** there are active plugins, do not report this as a bug unless you can reproduce it without enabling any plugins.\n"
-msgstr "*** AVISO *** hay plugins activos, no reporte esto como un bicho a menos que pueda reproducirlo sin activar ningún plugin.\n"
+msgstr "*** AVISO *** hay plugins activos, no informe esto como un error a menos que pueda reproducirlo sin activar ningún plugin.\n"
#. It's the compiler's fault.
#: reload1.c:6113
@@ -1636,10 +1646,8 @@ msgid "callee refers to comdat-local symbols"
msgstr ""
#: cif-code.def:125
-#, fuzzy
-#| msgid "optimization level attribute mismatch"
msgid "function attribute mismatch"
-msgstr "no coincide el atributo de nivel de optimización"
+msgstr "no coincide el atributo de función"
#: cif-code.def:129
#, fuzzy
@@ -1648,10 +1656,8 @@ msgid "caller function contains cilk spawn"
msgstr "función inválida en la declaración call"
#: cif-code.def:133
-#, fuzzy
-#| msgid "Unreachable statement"
msgid "unreachable"
-msgstr "Declaración inalcanzable"
+msgstr "inalcanzable"
#. The remainder are real diagnostic types.
#: diagnostic.def:33
@@ -1701,10 +1707,9 @@ msgid "permerror: "
msgstr "errorperm: "
#: params.def:49
-#, fuzzy, no-c-format
-#| msgid "Maximal estimated outcome of branch considered predictable"
+#, no-c-format
msgid "Maximal estimated outcome of branch considered predictable."
-msgstr "Salida estimada maximal de la ramificación considerada predecible"
+msgstr "Salida estimada máxima de la ramificación considerada predecible."
#: params.def:54
#, no-c-format
@@ -1712,695 +1717,592 @@ msgid "The minimal estimated speedup allowing inliner to ignore inline-insns-sin
msgstr ""
#: params.def:71
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions in a single function eligible for inlining"
+#, no-c-format
msgid "The maximum number of instructions in a single function eligible for inlining."
-msgstr "El número máximo de instrucciones en una sola función elegible para inclusión en línea"
+msgstr "El número máximo de instrucciones en una sola función elegible para inclusión en línea."
#: params.def:83
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions when automatically inlining"
+#, no-c-format
msgid "The maximum number of instructions when automatically inlining."
-msgstr "El número máximo de instrucciones cuando se hace inclusión en línea automáticamente"
+msgstr "El número máximo de instrucciones cuando se hace inclusión en línea automáticamente."
#: params.def:88
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions inline function can grow to via recursive inlining"
+#, no-c-format
msgid "The maximum number of instructions inline function can grow to via recursive inlining."
-msgstr "El número máximo de instrucciones que una función incluída en línea puede crecer a través de inclusión en línea recursiva"
+msgstr "El número máximo de instrucciones que una función incluida en línea puede crecer a través de inclusión en línea recursiva."
#: params.def:93
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions non-inline function can grow to via recursive inlining"
+#, no-c-format
msgid "The maximum number of instructions non-inline function can grow to via recursive inlining."
-msgstr "El número máximo de instrucciones que una función que no se incluye en línea puede crecer a través de inclusión en línea recursiva"
+msgstr "El número máximo de instrucciones que una función que no se incluye en línea puede crecer a través de inclusión en línea recursiva."
#: params.def:98
-#, fuzzy, no-c-format
-#| msgid "The maximum depth of recursive inlining for inline functions"
+#, no-c-format
msgid "The maximum depth of recursive inlining for inline functions."
-msgstr "La máxima profundidad para la inclusión en línea recursiva para funciones incluídas en línea"
+msgstr "La máxima profundidad para la inclusión en línea recursiva para funciones incluídas en línea."
#: params.def:103
-#, fuzzy, no-c-format
-#| msgid "The maximum depth of recursive inlining for non-inline functions"
+#, no-c-format
msgid "The maximum depth of recursive inlining for non-inline functions."
-msgstr "La máxima profundidad para la inclusión en línea recursiva para funciones que no son incluídas en línea"
+msgstr "La máxima profundidad para la inclusión en línea recursiva para funciones que no son incluídas en línea."
#: params.def:108
-#, fuzzy, no-c-format
-#| msgid "Inline recursively only when the probability of call being executed exceeds the parameter"
+#, no-c-format
msgid "Inline recursively only when the probability of call being executed exceeds the parameter."
-msgstr "Incluir en línea recursivamente sólo cuando la probabilidad de que la llamada se ejecute exceda el parámetro"
+msgstr "Incluir en línea recursivamente solo cuando la probabilidad de que la llamada se ejecute exceda el parámetro."
#: params.def:116
-#, fuzzy, no-c-format
-#| msgid "The maximum number of nested indirect inlining performed by early inliner"
+#, no-c-format
msgid "The maximum number of nested indirect inlining performed by early inliner."
-msgstr "El número máximo de inclusiones de instrucciones en línea anidadas realizado por el inlineador temprano"
+msgstr "El número máximo de inclusiones de instrucciones en línea anidadas realizado por el inlineador temprano."
#: params.def:122
-#, fuzzy, no-c-format
-#| msgid "Probability that COMDAT function will be shared with different compilation unit"
+#, no-c-format
msgid "Probability that COMDAT function will be shared with different compilation unit."
-msgstr "Probabilidad de que la función COMDAT se comparta con diferentes unidades de compilación"
+msgstr "Probabilidad de que la función COMDAT se comparta con diferentes unidades de compilación."
#: params.def:128
-#, fuzzy, no-c-format
-#| msgid "Maximum probability of the entry BB of split region (in percent relative to entry BB of the function) to make partial inlining happen"
+#, no-c-format
msgid "Maximum probability of the entry BB of split region (in percent relative to entry BB of the function) to make partial inlining happen."
-msgstr "Probabilidad máxima de la entrada BB de la región de división (en porcentaje relativo a la entrada BB de la función) para que suceda la inclusión en línea parcial"
+msgstr "Probabilidad máxima de la entrada BB de la región de división (en porcentaje relativo a la entrada BB de la función) para que suceda la inclusión en línea parcial."
#: params.def:135
-#, fuzzy, no-c-format
-#| msgid "If -fvariable-expansion-in-unroller is used, the maximum number of times that an individual variable will be expanded during loop unrolling"
+#, no-c-format
msgid "If -fvariable-expansion-in-unroller is used, the maximum number of times that an individual variable will be expanded during loop unrolling."
-msgstr "Si se usa -fvariable-expansion-in-unroller, el número máximo de veces que una variable individual se expandirá durante el desenrollo de bucles"
+msgstr "Si se usa -fvariable-expansion-in-unroller, el número máximo de veces que una variable individual se expandirá durante el desenrollo de bucles."
#: params.def:141
-#, fuzzy, no-c-format
-#| msgid "If -ftree-vectorize is used, the minimal loop bound of a loop to be considered for vectorization"
+#, no-c-format
msgid "If -ftree-vectorize is used, the minimal loop bound of a loop to be considered for vectorization."
-msgstr "Si se usa -ftree-vectorize, el límite de bucle minimal de un bucle para considerarse en la vectorización"
+msgstr "Si se usa -ftree-vectorize, el límite de bucle mínimo de un bucle para considerarse en la vectorización."
#: params.def:152
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions to consider to fill a delay slot"
+#, no-c-format
msgid "The maximum number of instructions to consider to fill a delay slot."
-msgstr "El número máximo de instrucciones para considerar el llenado de una ranura de retraso"
+msgstr "El número máximo de instrucciones para considerar el llenado de una ranura de retraso."
#: params.def:163
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions to consider to find accurate live register information"
+#, no-c-format
msgid "The maximum number of instructions to consider to find accurate live register information."
-msgstr "El número máximo de instruccions para considerar la búsqueda de información de registros en vivo exacta"
+msgstr "El número máximo de instrucciones para considerar la búsqueda de información de registros en vivo exacta."
#: params.def:173
-#, fuzzy, no-c-format
-#| msgid "The maximum length of scheduling's pending operations list"
+#, no-c-format
msgid "The maximum length of scheduling's pending operations list."
-msgstr "La longitud máxima de la lista de operaciones pendientes del calendarizador"
+msgstr "La longitud máxima de la lista de operaciones pendientes del planificador."
#: params.def:180
#, fuzzy, no-c-format
#| msgid "The maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop"
msgid "The maximum number of backtrack attempts the scheduler should make when modulo scheduling a loop."
-msgstr "El número máximo de intentos hacia atrás que debe hacer el calendarizador cuando calendarice un bucle módulo"
+msgstr "El número máximo de intentos hacia atrás que debe hacer el planificador cuando planifique un bucle módulo"
#: params.def:185
-#, fuzzy, no-c-format
-#| msgid "The size of function body to be considered large"
+#, no-c-format
msgid "The size of function body to be considered large."
-msgstr "El tamaño del cuerpo de la función a considerar grande"
+msgstr "El tamaño del cuerpo de la función que será considerado grande."
#: params.def:189
-#, fuzzy, no-c-format
-#| msgid "Maximal growth due to inlining of large function (in percent)"
+#, no-c-format
msgid "Maximal growth due to inlining of large function (in percent)."
-msgstr "Crecimiento de código maximal causado por la inclusión en línea de una función grande (en porcentaje)"
+msgstr "Máximo crecimiento causado por la inclusión en línea de una función grande (en porcentaje)."
#: params.def:193
-#, fuzzy, no-c-format
-#| msgid "The size of translation unit to be considered large"
+#, no-c-format
msgid "The size of translation unit to be considered large."
-msgstr "El tamaño de la unidad de traducción a considerar grande"
+msgstr "El tamaño de la unidad de traducción que será considerado grande."
#: params.def:197
-#, fuzzy, no-c-format
-#| msgid "How much can given compilation unit grow because of the inlining (in percent)"
+#, no-c-format
msgid "How much can given compilation unit grow because of the inlining (in percent)."
-msgstr "Cuánto puede crecer la unidad de compilación dada a causa de la inclusión en línea (en porcentaje)"
+msgstr "Cuánto puede crecer la unidad de compilación dada a causa de la inclusión en línea (en porcentaje)."
#: params.def:201
-#, fuzzy, no-c-format
-#| msgid "How much can given compilation unit grow because of the interprocedural constant propagation (in percent)"
+#, no-c-format
msgid "How much can given compilation unit grow because of the interprocedural constant propagation (in percent)."
-msgstr "Cuánto puede crecer la unidad de compilación dada a causa de la propagación constante interprocedural (en porcentaje)"
+msgstr "Cuánto puede crecer la unidad de compilación dada a causa de la propagación constante interprocedural (en porcentaje)."
#: params.def:205
-#, fuzzy, no-c-format
-#| msgid "Maximal estimated growth of function body caused by early inlining of single call"
+#, no-c-format
msgid "Maximal estimated growth of function body caused by early inlining of single call."
-msgstr "El crecimiento estimado maximal del cuerpo de la función causado por la inclusión en línea temprano de una sola llamada"
+msgstr "Máximo crecimiento estimado del cuerpo de la función causado por la inclusión temprana en línea de una sola llamada."
#: params.def:209
-#, fuzzy, no-c-format
-#| msgid "The size of stack frame to be considered large"
+#, no-c-format
msgid "The size of stack frame to be considered large."
-msgstr "El tamaño del marco de la pila a considerar grande"
+msgstr "El tamaño del marco de la pila que será considerado grande."
#: params.def:213
-#, fuzzy, no-c-format
-#| msgid "Maximal stack frame growth due to inlining (in percent)"
+#, no-c-format
msgid "Maximal stack frame growth due to inlining (in percent)."
-msgstr "Crecimiento de marco de pila maximal causado por la inclusión en línea (en porcentaje)"
+msgstr "Máximo crecimiento de marco de pila causado por la inclusión en línea (en porcentaje)."
#: params.def:220
-#, fuzzy, no-c-format
-#| msgid "The maximum amount of memory to be allocated by GCSE"
+#, no-c-format
msgid "The maximum amount of memory to be allocated by GCSE."
-msgstr "La cantidad máxima de memoria a ser asignada por GCSE"
+msgstr "La cantidad máxima de memoria a ser asignada por GCSE."
#: params.def:227
-#, fuzzy, no-c-format
-#| msgid "The maximum ratio of insertions to deletions of expressions in GCSE"
+#, no-c-format
msgid "The maximum ratio of insertions to deletions of expressions in GCSE."
-msgstr "La tasa máxima de inserciones para borrados de expresiones en GCSE"
+msgstr "La tasa máxima de inserciones para borrados de expresiones en GCSE."
#: params.def:238
-#, fuzzy, no-c-format
-#| msgid "The threshold ratio for performing partial redundancy elimination after reload"
+#, no-c-format
msgid "The threshold ratio for performing partial redundancy elimination after reload."
-msgstr "La tasa de intervalo para realizar la eliminación parcial de redundancia después de la recarga"
+msgstr "La tasa de intervalo para realizar la eliminación parcial de redundancia después de la recarga."
#: params.def:245
-#, fuzzy, no-c-format
-#| msgid "The threshold ratio of critical edges execution count that permit performing redundancy elimination after reload"
+#, no-c-format
msgid "The threshold ratio of critical edges execution count that permit performing redundancy elimination after reload."
-msgstr "La tasa de intervalo para la cuenta de ejecución de bordes críticos que permitan la eliminación de redundancia después de la recarga"
+msgstr "La tasa de intervalo para la cuenta de ejecución de bordes críticos que permitan la eliminación de redundancia después de la recarga."
#: params.def:253
-#, fuzzy, no-c-format
-#| msgid "Scaling factor in calculation of maximum distance an expression can be moved by GCSE optimizations"
+#, no-c-format
msgid "Scaling factor in calculation of maximum distance an expression can be moved by GCSE optimizations."
-msgstr "Factor de escala en el cálculo de la distancia máxima a la cual se puede mover una expresión por optimizaciones GCSE"
+msgstr "Factor de escala en el cálculo de la distancia máxima a la cual se puede mover una expresión por optimizaciones GCSE."
#: params.def:259
-#, fuzzy, no-c-format
-#| msgid "Cost at which GCSE optimizations will not constraint the distance an expression can travel"
+#, no-c-format
msgid "Cost at which GCSE optimizations will not constraint the distance an expression can travel."
-msgstr "Costo al cual las optimizaciones GCSE no restringirán la distancia que puede viajar una expresión"
+msgstr "Costo al cual las optimizaciones GCSE no restringirán la distancia que puede viajar una expresión."
#: params.def:267
-#, fuzzy, no-c-format
-#| msgid "Maximum depth of search in the dominator tree for expressions to hoist"
+#, no-c-format
msgid "Maximum depth of search in the dominator tree for expressions to hoist."
-msgstr "Profundidad máxima de la búsqueda en el árbol dominador por expresiones para levantar"
+msgstr "Profundidad máxima de la búsqueda en el árbol dominador por expresiones para levantar."
#: params.def:275
#, no-c-format
msgid "Maximum depth of sqrt chains to use when synthesizing exponentiation by a real constant."
-msgstr ""
+msgstr "Máxima profundidad de cadenas sqrt que se utilizará cuando se sintetice la exponenciación mediante una constante real."
#: params.def:287
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions to consider to unroll in a loop"
+#, no-c-format
msgid "The maximum number of instructions to consider to unroll in a loop."
-msgstr "El número máximo de instrucciones para considerar el desenrollo en un bucle"
+msgstr "El número máximo de instrucciones para considerar el desenrollo en un bucle."
#: params.def:293
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions to consider to unroll in a loop on average"
+#, no-c-format
msgid "The maximum number of instructions to consider to unroll in a loop on average."
-msgstr "El número máximo de instrucciones para considerar el desenrollo en un bucle en promedio"
+msgstr "El número máximo de instrucciones para considerar el desenrollo en un bucle en promedio."
#: params.def:298
-#, fuzzy, no-c-format
-#| msgid "The maximum number of unrollings of a single loop"
+#, no-c-format
msgid "The maximum number of unrollings of a single loop."
-msgstr "El número máximo de desenrollos de un solo bucle"
+msgstr "El número máximo de desenrollos de un solo bucle."
#: params.def:303
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns of a peeled loop"
+#, no-c-format
msgid "The maximum number of insns of a peeled loop."
-msgstr "El número máximo de insns en un bucle pelado"
+msgstr "El número máximo de insns en un bucle pelado."
#: params.def:308
-#, fuzzy, no-c-format
-#| msgid "The maximum number of peelings of a single loop"
+#, no-c-format
msgid "The maximum number of peelings of a single loop."
-msgstr "El número máximo de pelados en un solo bucle"
+msgstr "El número máximo de pelados en un solo bucle."
#: params.def:313
-#, fuzzy, no-c-format
-#| msgid "The maximum number of iterations through CFG to extend regions"
+#, no-c-format
msgid "The maximum number of branches on the path through the peeled sequence."
-msgstr "El número máximo de iteraciones a través de CFG para extender regiones"
+msgstr "El número máximo de ramificaciones en la ruta hacia una secuencia pelada."
#: params.def:318
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns of a completely peeled loop"
+#, no-c-format
msgid "The maximum number of insns of a completely peeled loop."
-msgstr "El número máximo de insns en un bucle completamente pelado"
+msgstr "El número máximo de insns en un bucle completamente pelado."
#: params.def:323
-#, fuzzy, no-c-format
-#| msgid "The maximum number of peelings of a single loop that is peeled completely"
+#, no-c-format
msgid "The maximum number of peelings of a single loop that is peeled completely."
-msgstr "El número máximo de pelados en un solo bucle que está completamente pelado"
+msgstr "El número máximo de pelados en un solo bucle que está completamente pelado."
#: params.def:328
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns of a peeled loop that rolls only once"
+#, no-c-format
msgid "The maximum number of insns of a peeled loop that rolls only once."
-msgstr "El número máximo de insns en un bucle pelado que se enrolla solamente una vez"
+msgstr "El número máximo de insns en un bucle pelado que se enrolla solamente una vez."
#: params.def:333
-#, fuzzy, no-c-format
-#| msgid "The maximum depth of a loop nest we completely peel"
+#, no-c-format
msgid "The maximum depth of a loop nest we completely peel."
-msgstr "La profundidad máxima de un bucle anidado que nosotros pelamos completamente"
+msgstr "La profundidad máxima de un bucle anidado que nosotros pelamos completamente."
#: params.def:339
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns of an unswitched loop"
+#, no-c-format
msgid "The maximum number of insns of an unswitched loop."
-msgstr "El número máximo de insns en un bucle sin switch"
+msgstr "El número máximo de insns en un bucle sin switch."
#: params.def:344
-#, fuzzy, no-c-format
-#| msgid "The maximum number of unswitchings in a single loop"
+#, no-c-format
msgid "The maximum number of unswitchings in a single loop."
-msgstr "El número máximo de eliminación de opciones en un solo bucle"
+msgstr "El número máximo de eliminación de opciones en un solo bucle."
#: params.def:351
-#, fuzzy, no-c-format
-#| msgid "Bound on the number of iterations the brute force # of iterations analysis algorithm evaluates"
+#, no-c-format
msgid "Bound on the number of iterations the brute force # of iterations analysis algorithm evaluates."
-msgstr "Límite en el número de iteraciones que evalúa el algoritmo de análisis de # de iteraciones de fuerza bruta"
+msgstr "Límite en el número de iteraciones que evalúa el algoritmo de análisis de número de iteraciones de fuerza bruta."
#: params.def:357
-#, fuzzy, no-c-format
-#| msgid "Bound on the cost of an expression to compute the number of iterations"
+#, no-c-format
msgid "Bound on the cost of an expression to compute the number of iterations."
-msgstr "Límite en el costo de una expresión para computar el número de iteraciones"
+msgstr "Límite en el coste de una expresión para calcular el número de iteraciones."
#: params.def:363
-#, fuzzy, no-c-format
-#| msgid "A factor for tuning the upper bound that swing modulo scheduler uses for scheduling a loop"
+#, no-c-format
msgid "A factor for tuning the upper bound that swing modulo scheduler uses for scheduling a loop."
-msgstr "Un factor para ajustar el límite superior que el calendarizador de cambio de módulo utiliza para calendarizar un bucle"
+msgstr "Factor para ajustar el límite superior que el planificador de cambio de módulo utiliza para planificar un bucle."
#: params.def:368
#, no-c-format
msgid "The minimum value of stage count that swing modulo scheduler will generate."
-msgstr "El valor mínimo de la cuenta de etapa que el calendarizador módulo swing generará."
+msgstr "El valor mínimo de la cuenta de etapa que el planificador módulo swing generará."
#: params.def:372
-#, fuzzy, no-c-format
-#| msgid "The number of cycles the swing modulo scheduler considers when checking conflicts using DFA"
+#, no-c-format
msgid "The number of cycles the swing modulo scheduler considers when checking conflicts using DFA."
-msgstr "El número de ciclos que el calendarizador de cambio de módulo considera al revisar conflictos utilizando DFA"
+msgstr "El número de ciclos que el planificador de cambio de módulo considera al revisar conflictos utilizando DFA."
#: params.def:376
-#, fuzzy, no-c-format
-#| msgid "A threshold on the average loop count considered by the swing modulo scheduler"
+#, no-c-format
msgid "A threshold on the average loop count considered by the swing modulo scheduler."
-msgstr "Un intervalo en la cuenta promedio de bucles considerado por el calendarizador de cambio de módulo"
+msgstr "Umbral en el número promedio de bucles considerado por el planificador de cambio de módulo."
#: params.def:381
#, no-c-format
msgid "A basic block profile count is considered hot if it contributes to the given permillage of the entire profiled execution."
-msgstr ""
+msgstr "El número de perfiles de bloque básicos se considera caliente si contribuye al pormillaje dado de la ejecución perfilada completa."
#: params.def:386
-#, fuzzy, no-c-format
-#| msgid "Select fraction of the maximal frequency of executions of basic block in function given basic block needs to have to be considered hot"
+#, no-c-format
msgid "Select fraction of the maximal frequency of executions of basic block in function given basic block needs to have to be considered hot."
-msgstr "La selección de fracción de la frecuencia maximal de ejecuciones de bloque básico en el bloque básico de función dado que necesita para ser considerado caliente"
+msgstr "La selección de fracción de la frecuencia máxima de ejecuciones de bloque básico en la función dada que el bloque básico necesita para ser considerado caliente."
#: params.def:391
#, no-c-format
msgid "The minimum fraction of profile runs a given basic block execution count must be not to be considered unlikely."
-msgstr ""
+msgstr "Fracción mínima de ejecuciones de perfil que el número de ejecuciones de un bloque básico dado no debe alcanzar para ser considerado improbable."
#: params.def:396
-#, fuzzy, no-c-format
-#| msgid "Select fraction of the maximal frequency of executions of basic block in function given basic block get alignment"
+#, no-c-format
msgid "Select fraction of the maximal frequency of executions of basic block in function given basic block get alignment."
-msgstr "La selección de fracción de la frecuencia maximal de ejecuciones de bloque básico en el bloque básico de función para alinear"
+msgstr "Selección de fracción de la frecuencia máxima de ejecuciones de bloque básico en la función dada para la que el bloque básico consigue alinear."
#: params.def:401
-#, fuzzy, no-c-format
-#| msgid "Loops iterating at least selected number of iterations will get loop alignement."
+#, no-c-format
msgid "Loops iterating at least selected number of iterations will get loop alignement.."
msgstr "Iterar ciclos por lo menos el número seleccionado de iteraciones que logrará alineación de bucles."
#: params.def:417
-#, fuzzy, no-c-format
-#| msgid "The maximum number of loop iterations we predict statically"
+#, no-c-format
msgid "The maximum number of loop iterations we predict statically."
-msgstr "El número máximo de iteraciones de bucle que se predicen estáticamente"
+msgstr "El número máximo de iteraciones de bucle que se predicen estáticamente."
#: params.def:430
#, no-c-format
msgid "Set the estimated probability in percentage for builtin expect. The default value is 90% probability."
-msgstr ""
+msgstr "Establece la probabilidad estimada en porcentaje de la expectativa incorporada. El valor predeterminado es 90% de probabilidad."
#: params.def:434
-#, fuzzy, no-c-format
-#| msgid "The percentage of function, weighted by execution frequency, that must be covered by trace formation. Used when profile feedback is available"
+#, no-c-format
msgid "The percentage of function, weighted by execution frequency, that must be covered by trace formation. Used when profile feedback is available."
-msgstr "El porcentaje de la función, evaluado por la frecuencia de ejecución, que debe ser cubierto por la información de rastreo. Se utiliza cuando está disponible la retroalimentación del análisis de perfil"
+msgstr "El porcentaje de la función, ponderado por la frecuencia de ejecución, que debe ser cubierto por la información de rastreo. Se utiliza cuando está disponible la retroalimentación del análisis de perfil."
#: params.def:438
-#, fuzzy, no-c-format
-#| msgid "The percentage of function, weighted by execution frequency, that must be covered by trace formation. Used when profile feedback is not available"
+#, no-c-format
msgid "The percentage of function, weighted by execution frequency, that must be covered by trace formation. Used when profile feedback is not available."
-msgstr "El porcentaje de la función, evaluado por la frecuencia de ejecución, que debe ser cubierto por la información de rastreo. Se utiliza cuando la retroalimentación de análisis de perfil no está disponible"
+msgstr "El porcentaje de la función, ponderado por la frecuencia de ejecución, que debe ser cubierto por la información de rastreo. Se utiliza cuando la retroalimentación de análisis de perfil no está disponible."
#: params.def:442
-#, fuzzy, no-c-format
-#| msgid "Maximal code growth caused by tail duplication (in percent)"
+#, no-c-format
msgid "Maximal code growth caused by tail duplication (in percent)."
-msgstr "Crecimiento de código maximal causado por duplicación de colas (en porcentaje)"
+msgstr "Máximo crecimiento de código causado por duplicación de colas (en porcentaje)."
#: params.def:446
-#, fuzzy, no-c-format
-#| msgid "Stop reverse growth if the reverse probability of best edge is less than this threshold (in percent)"
+#, no-c-format
msgid "Stop reverse growth if the reverse probability of best edge is less than this threshold (in percent)."
-msgstr "Detener el crecimiento inverso si la probabilidad reversa del mejor borde es menor a este intervalo (en porcentaje)"
+msgstr "Detener el crecimiento inverso si la probabilidad inversa del mejor borde es menor que este umbral (en porcentaje)."
#: params.def:450
-#, fuzzy, no-c-format
-#| msgid "Stop forward growth if the probability of best edge is less than this threshold (in percent). Used when profile feedback is available"
+#, no-c-format
msgid "Stop forward growth if the probability of best edge is less than this threshold (in percent). Used when profile feedback is available."
-msgstr "Detener el crecimiento hacia adelante si la probabilidad del mejor borde es menor que este intervalo (en porcentaje). Se utiliza cuando la retroalimentación de análisis de perfil está disponible"
+msgstr "Detener el crecimiento hacia adelante si la probabilidad del mejor borde es menor que este umbral (en porcentaje). Se utiliza cuando la retroalimentación de análisis de perfil está disponible."
#: params.def:454
-#, fuzzy, no-c-format
-#| msgid "Stop forward growth if the probability of best edge is less than this threshold (in percent). Used when profile feedback is not available"
+#, no-c-format
msgid "Stop forward growth if the probability of best edge is less than this threshold (in percent). Used when profile feedback is not available."
-msgstr "Detener el crecimiento hacia adelante si la probabilidad del mejor borde es menor a este intervalo (en porcentaje). Se utiliza cuando la retroalimentación de análisis de perfil no está disponible"
+msgstr "Detener el crecimiento hacia adelante si la probabilidad del mejor borde es menor que este umbral (en porcentaje). Se utiliza cuando la retroalimentación de análisis de perfil no está disponible."
#: params.def:460
-#, fuzzy, no-c-format
-#| msgid "The maximum number of incoming edges to consider for crossjumping"
+#, no-c-format
msgid "The maximum number of incoming edges to consider for crossjumping."
-msgstr "El número máximo de bordes de entrada para considerar el salto cruzado"
+msgstr "El número máximo de bordes entrantes para considerar el salto cruzado."
#: params.def:466
-#, fuzzy, no-c-format
-#| msgid "The minimum number of matching instructions to consider for crossjumping"
+#, no-c-format
msgid "The minimum number of matching instructions to consider for crossjumping."
-msgstr "El número máximo de instrucciones coincidentes para considerar el salto cruzado"
+msgstr "El número máximo de instrucciones coincidentes para considerar el salto cruzado."
#: params.def:472
-#, fuzzy, no-c-format
-#| msgid "The maximum expansion factor when copying basic blocks"
+#, no-c-format
msgid "The maximum expansion factor when copying basic blocks."
-msgstr "El factor de expansión máximo al copiar bloques básicos"
+msgstr "El factor de expansión máximo al copiar bloques básicos."
# 'desfactorizar' no me gusta. ¿Alguna sugerencia? - cfuga
#: params.def:478
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns to duplicate when unfactoring computed gotos"
+#, no-c-format
msgid "The maximum number of insns to duplicate when unfactoring computed gotos."
-msgstr "El número máximo de insns a duplicar al desfactorizar gotos calculados"
+msgstr "El número máximo de insns a duplicar al desfactorizar gotos calculados."
#: params.def:484
-#, fuzzy, no-c-format
-#| msgid "The maximum length of path considered in cse"
+#, no-c-format
msgid "The maximum length of path considered in cse."
-msgstr "La longitud máxima de la ruta considerada en cse"
+msgstr "La longitud máxima de la ruta considerada en cse."
#: params.def:488
-#, fuzzy, no-c-format
-#| msgid "The maximum instructions CSE process before flushing"
+#, no-c-format
msgid "The maximum instructions CSE process before flushing."
-msgstr "El número máximo de instrucciones que CSE procesa antes de descargar"
+msgstr "El número máximo de instrucciones que CSE procesa antes de descargar."
#: params.def:495
-#, fuzzy, no-c-format
-#| msgid "The minimum cost of an expensive expression in the loop invariant motion"
+#, no-c-format
msgid "The minimum cost of an expensive expression in the loop invariant motion."
-msgstr "El costo mínimo de una expresión costosa en el movimiento invariante del bucle"
+msgstr "El coste mínimo de una expresión costosa en el movimiento invariante del bucle."
#: params.def:504
-#, fuzzy, no-c-format
-#| msgid "Bound on number of candidates below that all candidates are considered in iv optimizations"
+#, no-c-format
msgid "Bound on number of candidates below that all candidates are considered in iv optimizations."
-msgstr "Límite en el número de candidatos bajo el cual todos los candidatos se consideran en optimizaciones iv"
+msgstr "Límite en el número de candidatos bajo el cual todos los candidatos se consideran en optimizaciones iv."
#: params.def:512
-#, fuzzy, no-c-format
-#| msgid "Bound on number of iv uses in loop optimized in iv optimizations"
+#, no-c-format
msgid "Bound on number of iv uses in loop optimized in iv optimizations."
-msgstr "Límite en el número de usos de iv en bucles optimizados en optimizaciones iv"
+msgstr "Límite en el número de usos de iv en bucles optimizados en optimizaciones iv."
#: params.def:520
-#, fuzzy, no-c-format
-#| msgid "If number of candidates in the set is smaller, we always try to remove unused ivs during its optimization"
+#, no-c-format
msgid "If number of candidates in the set is smaller, we always try to remove unused ivs during its optimization."
-msgstr "Si el número de candidatos en el conjunto es menor, siempre se tratará de eliminar ivs sin usar durante su optimización"
+msgstr "Si el número de candidatos en el conjunto es menor, siempre se tratará de eliminar los ivs sin usar durante su optimización."
#: params.def:525
-#, fuzzy, no-c-format
-#| msgid "Bound on size of expressions used in the scalar evolutions analyzer"
+#, no-c-format
msgid "Bound on size of expressions used in the scalar evolutions analyzer."
-msgstr "Límite en el tamaño de expresiones usadas en el analizador escalar de evoluciones"
+msgstr "Límite en el tamaño de expresiones usadas en el analizador escalar de evoluciones."
#: params.def:530
-#, fuzzy, no-c-format
-#| msgid "Bound on the complexity of the expressions in the scalar evolutions analyzer"
+#, no-c-format
msgid "Bound on the complexity of the expressions in the scalar evolutions analyzer."
-msgstr "Límite en la complejidad de expresiones en el analizador escalar de evoluciones"
+msgstr "Límite en la complejidad de expresiones en el analizador escalar de evoluciones."
#: params.def:535
-#, fuzzy, no-c-format
-#| msgid "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check"
+#, no-c-format
msgid "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alignment check."
-msgstr "Límite en el número de revisiones de tiempo de ejecución insertadas por las versiones de bucle del vectorizador para revisión de alineación"
+msgstr "Límite en el número de revisiones de tiempo de ejecución insertadas por las versiones de bucle del vectorizador para revisión de alineación."
#: params.def:540
-#, fuzzy, no-c-format
-#| msgid "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alias check"
+#, no-c-format
msgid "Bound on number of runtime checks inserted by the vectorizer's loop versioning for alias check."
-msgstr "Límite en el número de revisiones de tiempo de ejecución insertadas por las versiones de bucle del vectorizador para revisión de alias"
+msgstr "Límite en el número de revisiones de tiempo de ejecución insertadas por las versiones de bucle del vectorizador para revisión de alias."
#: params.def:545
#, no-c-format
msgid "Max number of loop peels to enhancement alignment of data references in a loop."
-msgstr ""
+msgstr "Número máximo de pelados de bucle para alineación de mejora de las referencias de datos en un bucle."
#: params.def:550
-#, fuzzy, no-c-format
-#| msgid "The maximum memory locations recorded by cselib"
+#, no-c-format
msgid "The maximum memory locations recorded by cselib."
-msgstr "El número máximo de ubicaciones grabadas por cselib"
+msgstr "El número máximo de ubicaciones grabadas por cselib."
#: params.def:563
-#, fuzzy, no-c-format
-#| msgid "Minimum heap expansion to trigger garbage collection, as a percentage of the total size of the heap"
+#, no-c-format
msgid "Minimum heap expansion to trigger garbage collection, as a percentage of the total size of the heap."
-msgstr "Expansión mínima de la pila para iniciar la recolección de basura, como un porcentaje del tamaño total de la pila"
+msgstr "Expansión mínima de la pila para iniciar la recolección de basura, como un porcentaje del tamaño total de la pila."
#: params.def:568
-#, fuzzy, no-c-format
-#| msgid "Minimum heap size before we start collecting garbage, in kilobytes"
+#, no-c-format
msgid "Minimum heap size before we start collecting garbage, in kilobytes."
-msgstr "Tamaño mínimo de la pila antes de comenzar a recolectar basura, en kilobytes"
+msgstr "Tamaño mínimo de la pila antes de comenzar a recolectar basura, en kilobytes."
#: params.def:576
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions to search backward when looking for equivalent reload"
+#, no-c-format
msgid "The maximum number of instructions to search backward when looking for equivalent reload."
-msgstr "El número máximo de instrucciones para buscar hacia atrás al buscar por una recarga equivalente"
+msgstr "El número máximo de instrucciones para buscar hacia atrás al buscar por una recarga equivalente."
#: params.def:581
-#, fuzzy, no-c-format
-#| msgid "Target block's relative execution frequency (as a percentage) required to sink a statement"
+#, no-c-format
msgid "Target block's relative execution frequency (as a percentage) required to sink a statement."
-msgstr "Frecuencia de ejecución relativa al bloque objetivo (como un porcentaje) requerida para hundir una declaración"
+msgstr "Frecuencia de ejecución relativa al bloque objetivo (como un porcentaje) requerida para hundir una declaración."
#: params.def:586 params.def:596
-#, fuzzy, no-c-format
-#| msgid "The maximum number of blocks in a region to be considered for interblock scheduling"
+#, no-c-format
msgid "The maximum number of blocks in a region to be considered for interblock scheduling."
-msgstr "El número máximo de bloques en una región para ser considerada para interbloqueo"
+msgstr "El número máximo de bloques en una región para ser considerada para planificación de interbloqueo."
#: params.def:591 params.def:601
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns in a region to be considered for interblock scheduling"
+#, no-c-format
msgid "The maximum number of insns in a region to be considered for interblock scheduling."
-msgstr "El número máximo de insns en una región para ser consideradas para calendarización de interbloqueo"
+msgstr "El número máximo de insns en una región para ser consideradas para planificación de interbloqueo"
#: params.def:606
-#, fuzzy, no-c-format
-#| msgid "The minimum probability of reaching a source block for interblock speculative scheduling"
+#, no-c-format
msgid "The minimum probability of reaching a source block for interblock speculative scheduling."
-msgstr "La probabilidad mínima de alcanzar un bloque fuente para la calendarización especulativa entre bloques"
+msgstr "La probabilidad mínima de alcanzar un bloque fuente para la planificación especulativa entre bloques."
#: params.def:611
-#, fuzzy, no-c-format
-#| msgid "The maximum number of iterations through CFG to extend regions"
+#, no-c-format
msgid "The maximum number of iterations through CFG to extend regions."
-msgstr "El número máximo de iteraciones a través de CFG para extender regiones"
+msgstr "El número máximo de iteraciones a través de CFG para extender regiones."
#: params.def:616
-#, fuzzy, no-c-format
-#| msgid "The maximum conflict delay for an insn to be considered for speculative motion"
+#, no-c-format
msgid "The maximum conflict delay for an insn to be considered for speculative motion."
-msgstr "El retraso de conflicto máximo para una insn para ser considerada para movimiento especulativo"
+msgstr "El retraso máximo de conflicto para que una insn sea considerada para movimiento especulativo."
#: params.def:621
#, no-c-format
msgid "The minimal probability of speculation success (in percents), so that speculative insn will be scheduled."
msgstr "La probabilidad mínima de éxito de especulación (en porcentaje), para que esa insn especulativa se calendarize."
+# TODO Mejorar traducción de 'across it'.
#: params.def:626
#, no-c-format
msgid "The minimum probability an edge must have for the scheduler to save its state across it."
-msgstr ""
+msgstr "Probabilidad mínima que debe tener un borde para que el planificador guarde su estado a través de él."
#: params.def:631
-#, fuzzy, no-c-format
-#| msgid "The maximum size of the lookahead window of selective scheduling"
+#, no-c-format
msgid "The maximum size of the lookahead window of selective scheduling."
-msgstr "El tamaño máximo de la ventana de búsqueda hacia adelante de la calendarización selectiva"
+msgstr "El tamaño máximo de la ventana de búsqueda hacia adelante de la planificación selectiva."
#: params.def:636
-#, fuzzy, no-c-format
-#| msgid "Maximum number of times that an insn could be scheduled"
+#, no-c-format
msgid "Maximum number of times that an insn could be scheduled."
-msgstr "El número máximo de veces que se puede calendarizar una insns"
+msgstr "El número máximo de veces que se puede planificar una insns."
#: params.def:641
-#, fuzzy, no-c-format
-#| msgid "Maximum number of instructions in the ready list that are considered eligible for renaming"
+#, no-c-format
msgid "Maximum number of instructions in the ready list that are considered eligible for renaming."
-msgstr "El número máximo de instrucciones en la lista ready que se consideran elegibles para renombrado"
+msgstr "El número máximo de instrucciones en la lista ready que se consideran elegibles para renombrado."
#: params.def:646
-#, fuzzy, no-c-format
-#| msgid "Minimal distance between possibly conflicting store and load"
+#, no-c-format
msgid "Minimal distance between possibly conflicting store and load."
-msgstr "La distancia mínima entre store y load en posible conflicto"
+msgstr "La distancia mínima entre store y load en posible conflicto."
#: params.def:651
#, no-c-format
msgid "Hardware autoprefetcher scheduler model control flag. Number of lookahead cycles the model looks into; at '0' only enable instruction sorting heuristic. Disabled by default."
-msgstr ""
+msgstr "Indicador de control del modelo de planificador de prebuscador automático hardware. Número de ciclos hacia delante que el modelo examina: con '0' solo se activa la heurística de ordenación de instrucciones. Desactivado de forma predeterminada."
#: params.def:656
-#, fuzzy, no-c-format
-#| msgid "The maximum number of RTL nodes that can be recorded as combiner's last value"
+#, no-c-format
msgid "The maximum number of RTL nodes that can be recorded as combiner's last value."
-msgstr "El número máximo de nodos RTL que se pueden grabar como el último valor del combinador"
+msgstr "El número máximo de nodos RTL que se pueden grabar como el último valor del combinador."
#: params.def:661
-#, fuzzy, no-c-format
-#| msgid "The maximum number of incoming edges to consider for crossjumping"
+#, no-c-format
msgid "The maximum number of insns combine tries to combine."
-msgstr "El número máximo de bordes de entrada para considerar el salto cruzado"
+msgstr "El número máximo de intentos de combinar insns para combinar."
#: params.def:670
-#, fuzzy, no-c-format
-#| msgid "The upper bound for sharing integer constants"
+#, no-c-format
msgid "The upper bound for sharing integer constants."
-msgstr "El límite superior para compartir constantes enteras"
+msgstr "El límite superior para compartir constantes enteras."
#: params.def:675
-#, fuzzy, no-c-format
-#| msgid "The lower bound for a buffer to be considered for stack smashing protection"
+#, no-c-format
msgid "The lower bound for a buffer to be considered for stack smashing protection."
-msgstr "El límite inferior para considerar un almacenamiento temporal para protección contra destrucción de pila"
+msgstr "El límite inferior para considerar un almacenamiento temporal para protección contra destrucción de pila."
#: params.def:680
#, no-c-format
msgid "The minimum size of variables taking part in stack slot sharing when not optimizing."
-msgstr ""
+msgstr "Tamaño mínimo de las variables que participan en la compartición de ranuras de pila cuando no hay optimización."
#: params.def:699
-#, fuzzy, no-c-format
-#| msgid "Maximum number of statements allowed in a block that needs to be duplicated when threading jumps"
+#, no-c-format
msgid "Maximum number of statements allowed in a block that needs to be duplicated when threading jumps."
-msgstr "Número máximo de sentencias permitidas en un bloque que necesitan ser duplicadas al hacer hilos de saltos"
+msgstr "Número máximo de sentencias permitidas en un bloque que necesitan ser duplicadas al hacer hilos de saltos."
#: params.def:708
-#, fuzzy, no-c-format
-#| msgid "Maximum number of fields in a structure before pointer analysis treats the structure as a single variable"
+#, no-c-format
msgid "Maximum number of fields in a structure before pointer analysis treats the structure as a single variable."
-msgstr "El número máximo de campos en una estructura antes de que el análisis de punteros trate a la estructura como una sola variable"
+msgstr "El número máximo de campos en una estructura antes de que el análisis de punteros trate a la estructura como una sola variable."
#: params.def:713
-#, fuzzy, no-c-format
-#| msgid "The maximum number of instructions ready to be issued to be considered by the scheduler during the first scheduling pass"
+#, no-c-format
msgid "The maximum number of instructions ready to be issued to be considered by the scheduler during the first scheduling pass."
-msgstr "El número máximo de instrucciones listas para ser ejecutadas para ser consideradas por el calendarizador durante el primer paso de calendarización"
+msgstr "El número máximo de instrucciones listas para ser ejecutadas que el planificador tendrá en cuenta durante el primer paso de planificación."
#: params.def:719
-#, fuzzy, no-c-format
-#| msgid "Maximum number of active local stores in RTL dead store elimination"
+#, no-c-format
msgid "Maximum number of active local stores in RTL dead store elimination."
-msgstr "Número máximo de almacenamientos locales activos en la eliminación de almacenamiento muerto RTL"
+msgstr "Número máximo de almacenamientos locales activos en la eliminación de almacenamiento muerto RTL."
#: params.def:729
-#, fuzzy, no-c-format
-#| msgid "The number of insns executed before prefetch is completed"
+#, no-c-format
msgid "The number of insns executed before prefetch is completed."
-msgstr "El número de insns ejecutadas antes de completar la precarga"
+msgstr "El número de insns ejecutadas antes de completar la precarga."
#: params.def:736
-#, fuzzy, no-c-format
-#| msgid "The number of prefetches that can run at the same time"
+#, no-c-format
msgid "The number of prefetches that can run at the same time."
-msgstr "El número de precargas que se pueden ejecutar simultánamente"
+msgstr "El número de precargas que se pueden ejecutar simultánamente."
#: params.def:743
-#, fuzzy, no-c-format
-#| msgid "The size of L1 cache"
+#, no-c-format
msgid "The size of L1 cache."
-msgstr "El tamaño del caché L1"
+msgstr "El tamaño del caché L1i."
#: params.def:750
-#, fuzzy, no-c-format
-#| msgid "The size of L1 cache line"
+#, no-c-format
msgid "The size of L1 cache line."
-msgstr "El tamaño de la línea del caché L1"
+msgstr "El tamaño de la línea del caché L1."
#: params.def:757
-#, fuzzy, no-c-format
-#| msgid "The size of L2 cache"
+#, no-c-format
msgid "The size of L2 cache."
-msgstr "El tamaño del caché L2"
+msgstr "El tamaño del caché L2."
#: params.def:768
-#, fuzzy, no-c-format
-#| msgid "Whether to use canonical types"
+#, no-c-format
msgid "Whether to use canonical types."
-msgstr "Decide si se usan tipos canónicos"
+msgstr "Decide si se usan tipos canónicos."
#: params.def:773
-#, fuzzy, no-c-format
-#| msgid "Maximum length of partial antic set when performing tree pre optimization"
+#, no-c-format
msgid "Maximum length of partial antic set when performing tree pre optimization."
-msgstr "Longitud máxima del conjunto antic parcial al realizar pre optimización de árbol"
+msgstr "Longitud máxima del conjunto antic parcial al realizar pre optimización de árbol."
#: params.def:783
-#, fuzzy, no-c-format
-#| msgid "Maximum size of a SCC before SCCVN stops processing a function"
+#, no-c-format
msgid "Maximum size of a SCC before SCCVN stops processing a function."
-msgstr "Tamaño máxmo de un SCC antes de que SCCVN detenga el procesamiento de una función"
+msgstr "Tamaño máxmo de un SCC antes de que SCCVN detenga el procesamiento de una función."
#: params.def:794
#, no-c-format
msgid "Maximum number of disambiguations to perform per memory access."
-msgstr ""
+msgstr "Número máximo de desambiguaciones que realizar por cada acceso a memoria."
#: params.def:799
-#, fuzzy, no-c-format
-#| msgid "Max loops number for regional RA"
+#, no-c-format
msgid "Max loops number for regional RA."
-msgstr "Número de bucles máximo para el RA regional"
+msgstr "Número de bucles máximo para el RA regional."
#: params.def:804
-#, fuzzy, no-c-format
-#| msgid "Max size of conflict table in MB"
+#, no-c-format
msgid "Max size of conflict table in MB."
-msgstr "Tamaño máximo de la tabla de conflictos en MB"
+msgstr "Tamaño máximo de la tabla de conflictos en MB."
#: params.def:809
-#, fuzzy, no-c-format
-#| msgid "The number of registers in each class kept unused by loop invariant motion"
+#, no-c-format
msgid "The number of registers in each class kept unused by loop invariant motion."
-msgstr "El número de registros conservados sin uso en cada clase por el movimiento invariante del bucle"
+msgstr "El número de registros conservados sin uso en cada clase por el movimiento invariante del bucle."
#: params.def:814
#, no-c-format
msgid "The max number of reload pseudos which are considered during spilling a non-reload pseudo."
-msgstr ""
+msgstr "El número máximo de pseudos de recarga que se tienen en cuenta durante el vaciado de pseudos de no recarga."
#: params.def:819
#, no-c-format
@@ -2408,63 +2310,54 @@ msgid "Minimal fall-through edge probability in percentage used to add BB to inh
msgstr ""
#: params.def:827
-#, fuzzy, no-c-format
-#| msgid "The maximum ratio between array size and switch branches for a switch conversion to take place"
+#, no-c-format
msgid "The maximum ratio between array size and switch branches for a switch conversion to take place."
-msgstr "La tasa máxima entre el tamaño de la matriz y las ramificaciones switch para que tome lugar una conversión switch"
+msgstr "La tasa máxima entre el tamaño de la matriz y las ramificaciones switch para que tenga lugar una conversión switch."
#: params.def:835
-#, fuzzy, no-c-format
-#| msgid "size of tiles for loop blocking"
+#, no-c-format
msgid "size of tiles for loop blocking."
-msgstr "tamaño de bloques para el bloqueo de bucles"
+msgstr "tamaño de bloques para el bloqueo de bucles."
#: params.def:842
-#, fuzzy, no-c-format
-#| msgid "maximum number of parameters in a SCoP"
+#, no-c-format
msgid "maximum number of parameters in a SCoP."
-msgstr "número máximo de parámetros en un SCoP"
+msgstr "número máximo de parámetros en un SCoP."
#: params.def:849
-#, fuzzy, no-c-format
-#| msgid "maximum number of basic blocks per function to be analyzed by Graphite"
+#, no-c-format
msgid "maximum number of basic blocks per function to be analyzed by Graphite."
-msgstr "número máximo de bloques básicos por función para analizar con Graphite"
+msgstr "número máximo de bloques básicos por función para analizar con Graphite."
#: params.def:856
-#, fuzzy, no-c-format
-#| msgid "maximum number of parameters in a SCoP"
+#, no-c-format
msgid "maximum number of arrays per scop."
-msgstr "número máximo de parámetros en un SCoP"
+msgstr "número máximo de arrays por scop."
#: params.def:863
-#, fuzzy, no-c-format
-#| msgid "maximum number of basic blocks per function to be analyzed by Graphite"
+#, no-c-format
msgid "minimal number of loops per function to be analyzed by Graphite."
-msgstr "número máximo de bloques básicos por función para analizar con Graphite"
+msgstr "número mínimo de bucles por función para analizar con Graphite."
#: params.def:868
-#, fuzzy, no-c-format
-#| msgid "The maximum number of insns of an unswitched loop"
+#, no-c-format
msgid "maximum number of isl operations, 0 means unlimited"
-msgstr "El número máximo de insns en un bucle sin switch"
+msgstr "número máximo de operaciones isl; 0 significa que no hay límite"
#: params.def:874
-#, fuzzy, no-c-format
-#| msgid "Maximum number of datarefs in loop for building loop data dependencies"
+#, no-c-format
msgid "Maximum number of datarefs in loop for building loop data dependencies."
-msgstr "Número máximo de referencia de datos en bucles para construir dependencia de datos de bucles"
+msgstr "Número máximo de referencia de datos en bucles para construir dependencias de datos de bucles."
#: params.def:881
-#, fuzzy, no-c-format
-#| msgid "Max basic blocks number in loop for loop invariant motion"
+#, no-c-format
msgid "Max basic blocks number in loop for loop invariant motion."
-msgstr "Número máximo de bloques básicos en el bucle para el movimiento invariante de bucle"
+msgstr "Número máximo de bloques básicos en bucles para movimiento invariante de bucle."
#: params.def:889
#, no-c-format
msgid "use internal function id in profile lookup."
-msgstr ""
+msgstr "utilizar id de función interno en búsqueda de perfil."
#: params.def:897
#, no-c-format
@@ -2472,179 +2365,159 @@ msgid "track topn target addresses in indirect-call profile."
msgstr ""
#: params.def:903
-#, fuzzy, no-c-format
-#| msgid "Maximum number of instructions in basic block to be considered for SLP vectorization"
+#, no-c-format
msgid "Maximum number of instructions in basic block to be considered for SLP vectorization."
-msgstr "El número máximo de instrucciones en bloque básico que se consideran para vectorización SLP"
+msgstr "El número máximo de instrucciones en bloque básico que se consideran para vectorización SLP."
#: params.def:908
-#, fuzzy, no-c-format
-#| msgid "Min. ratio of insns to prefetches to enable prefetching for a loop with an unknown trip count"
+#, no-c-format
msgid "Min. ratio of insns to prefetches to enable prefetching for a loop with an unknown trip count."
-msgstr "Tasa mínima de insns a precargar para activar la precarga para un bucle con una cuenta de viajes desconocida"
+msgstr "Tasa mínima de insns a precargar para activar la precarga para un bucle con una cuenta de viajes desconocida."
#: params.def:914
-#, fuzzy, no-c-format
-#| msgid "Min. ratio of insns to mem ops to enable prefetching in a loop"
+#, no-c-format
msgid "Min. ratio of insns to mem ops to enable prefetching in a loop."
-msgstr "Tasa mínima de insns a ops de mem para activar la precarga en un bucle"
+msgstr "Tasa mínima de insns a ops de mem para activar la precarga en un bucle."
#: params.def:921
-#, fuzzy, no-c-format
-#| msgid "Max. size of var tracking hash tables"
+#, no-c-format
msgid "Max. size of var tracking hash tables."
-msgstr "Tamaño máximo de las tablas de dispersión de rastreo de variables"
+msgstr "Tamaño máximo de las tablas de dispersión de rastreo de variables."
#: params.def:929
-#, fuzzy, no-c-format
-#| msgid "Max. recursion depth for expanding var tracking expressions"
+#, no-c-format
msgid "Max. recursion depth for expanding var tracking expressions."
-msgstr "Profundidad máxima de recursión para expandir expresiones de rastreo de variables"
+msgstr "Profundidad máxima de recursión para expandir expresiones de rastreo de variables."
#: params.def:937
#, no-c-format
msgid "Max. size of loc list for which reverse ops should be added."
-msgstr ""
+msgstr "Máximo tamaño de lista loc para que deban añadirse ops inversas."
#: params.def:944
-#, fuzzy, no-c-format
-#| msgid "The minimum UID to be used for a nondebug insn"
+#, no-c-format
msgid "The minimum UID to be used for a nondebug insn."
-msgstr "El UID mínimo a usar para una insn que no es de depuración"
+msgstr "El UID mínimo a usar para una insn que no es de depuración."
#: params.def:949
-#, fuzzy, no-c-format
-#| msgid "Maximum allowed growth of size of new parameters ipa-sra replaces a pointer to an aggregate with"
+#, no-c-format
msgid "Maximum allowed growth of size of new parameters ipa-sra replaces a pointer to an aggregate with."
-msgstr "El crecimiento máximo permitido de tamaño de los parámetros nuevos ipa-sra que reemplazan un puntero a un agregado con"
+msgstr "El crecimiento máximo permitido de tamaño de los parámetros nuevos ipa-sra que reemplazan un puntero a un agregado con."
#: params.def:955
-#, fuzzy, no-c-format
-#| msgid "Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs"
+#, no-c-format
msgid "Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs."
-msgstr "Tamaño en bytes después del cual los agregados thread-local se deben instrumentar con las funciones de registro en lugar de pares save/restore"
+msgstr "Tamaño en bytes después del cual los agregados thread-local se deben instrumentar con las funciones de registro en lugar de pares save/restore."
#: params.def:962
#, no-c-format
msgid "Maximum size, in storage units, of an aggregate which should be considered for scalarization when compiling for speed."
-msgstr ""
+msgstr "Máximo tamaño, en unidades de almacenamiento, de un agregado para tenerlo en cuenta en escalarización cuando se compila para velocidad."
#: params.def:968
#, no-c-format
msgid "Maximum size, in storage units, of an aggregate which should be considered for scalarization when compiling for size."
-msgstr ""
+msgstr "Máximo tamaño, en unidades de almacenamiento, de un agregado para tenerlo en cuenta en escalarización cuando se compila para tamaño."
#: params.def:974
-#, fuzzy, no-c-format
-#| msgid "Maximum size of a list of values associated with each parameter for interprocedural constant propagation"
+#, no-c-format
msgid "Maximum size of a list of values associated with each parameter for interprocedural constant propagation."
-msgstr "Tamaño máximo de una lista de valores asociada con cada parámetro para propagación constante entre procedimientos"
+msgstr "Tamaño máximo de una lista de valores asociada con cada parámetro para propagación constante entre procedimientos."
#: params.def:980
-#, fuzzy, no-c-format
-#| msgid "Threshold ipa-cp opportunity evaluation that is still considered beneficial to clone."
+#, no-c-format
msgid "Threshold ipa-cp opportunity evaluation that is still considered beneficial to clone.."
-msgstr "Rango de evaluación de oportunidad ipa-cp que aún se considera benéfico para clonar."
+msgstr "Rango de evaluación de oportunidad ipa-cp que aún se considera beneficioso para clonar.."
#: params.def:986
#, no-c-format
msgid "Percentage penalty the recursive functions will receive when they are evaluated for cloning.."
-msgstr ""
+msgstr "Penalización porcentual que recibirán las funciones recursivas cuando se evalúen para clonación.."
#: params.def:992
#, no-c-format
msgid "Percentage penalty functions containg a single call to another function will receive when they are evaluated for cloning.."
-msgstr ""
+msgstr "Penalización porcentual que recibirán las funciones que contien una sola llamada a otra función cuando se evalúen para clonación.."
#: params.def:998
#, no-c-format
msgid "Maximum number of aggregate content items for a parameter in jump functions and lattices."
-msgstr ""
+msgstr "Número máximo de elementos de contenido agregado de un parámetro en funciones de salto y celosías."
#: params.def:1004
#, no-c-format
msgid "Compile-time bonus IPA-CP assigns to candidates which make loop bounds or strides known.."
-msgstr ""
+msgstr "Bonificación de tiempo de compilación que IPA-CP asigna a los candidatos que dan a conocer los límites o los pasos de los bucles.."
#: params.def:1010
#, no-c-format
msgid "Compile-time bonus IPA-CP assigns to candidates which make an array index known.."
-msgstr ""
+msgstr "Bonificación de tiempo de compilación que IPA-CP asigna a los candidatos que dan conocer el índice de un array.."
#: params.def:1016
#, no-c-format
msgid "Maximum number of statements that will be visited by IPA formal parameter analysis based on alias analysis in any given function."
-msgstr ""
+msgstr "Número máximo de sentencias que visitará el análisis de parámetros formales de IPA basado en el análisis de alias de una función dada."
#: params.def:1024
-#, fuzzy, no-c-format
-#| msgid "Number of partitions the program should be split to"
+#, no-c-format
msgid "Number of partitions the program should be split to."
-msgstr "Número de particiones en las que se debe dividir el programa"
+msgstr "Número de particiones en las que se debe dividir el programa."
#: params.def:1029
-#, fuzzy, no-c-format
-#| msgid "Minimal size of a partition for LTO (in estimated instructions)"
+#, no-c-format
msgid "Minimal size of a partition for LTO (in estimated instructions)."
-msgstr "Tamaño minimal de una partición para LTO (en instrucciones estimadas)"
+msgstr "Tamaño minimal de una partición para LTO (en instrucciones estimadas)."
#: params.def:1036
-#, fuzzy, no-c-format
-#| msgid "Maximum number of namespaces to search for alternatives when name lookup fails"
+#, no-c-format
msgid "Maximum number of namespaces to search for alternatives when name lookup fails."
-msgstr "Número máximo de espacios de nombres a buscar por alternativas cuando falla la búsqueda de nombre"
+msgstr "Número máximo de espacios de nombres a buscar por alternativas cuando falla la búsqueda de nombre."
#: params.def:1043
-#, fuzzy, no-c-format
-#| msgid "Maximum number of conditional store pairs that can be sunk"
+#, no-c-format
msgid "Maximum number of conditional store pairs that can be sunk."
-msgstr "El número máximo de pares de almacenamiento condicional que se pueden hundir"
+msgstr "Número máximo de pares de almacenamiento condicional que se pueden hundir."
#: params.def:1051
-#, fuzzy, no-c-format
-#| msgid "The smallest number of different values for which it is best to use a jump-table instead of a tree of conditional branches, if 0, use the default for the machine"
+#, no-c-format
msgid "The smallest number of different values for which it is best to use a jump-table instead of a tree of conditional branches, if 0, use the default for the machine."
-msgstr "El número más pequeño de valores diferentes para los cuales es mejor usar una tabla-salto en lugar de un árbol de ramificaciones condicionales; si es 0, usa el valor por defecto para la máquina"
+msgstr "El número más pequeño de valores diferentes para los cuales es mejor usar una tabla-salto en lugar de un árbol de ramificaciones condicionales; si es 0, usa el valor por defecto para la máquina."
#: params.def:1059
-#, fuzzy, no-c-format
-#| msgid "Allow new data races on stores to be introduced"
+#, no-c-format
msgid "Allow new data races on stores to be introduced."
-msgstr "Permite que se introduzcan carreras de datos nuevos en stores"
+msgstr "Permite que se introduzcan carreras de datos nuevos en stores."
#: params.def:1065
-#, fuzzy, no-c-format
-#| msgid "Set the maximum number of instructions executed in parallel in reassociated tree. If 0, use the target dependent heuristic."
+#, no-c-format
msgid "Set the maximum number of instructions executed in parallel in reassociated tree. If 0, use the target dependent heuristic.."
-msgstr "Establece el número máximo de instrucciones ejecutadas en paralelo en el árbol de reasociación. Si es 0, usa la heurística dependiente del objetivo."
+msgstr "Establece el número máximo de instrucciones ejecutadas en paralelo en el árbol de reasociación. Si es 0, usa la heurística dependiente del objetivo.."
#: params.def:1071
-#, fuzzy, no-c-format
-#| msgid "Maximum amount of similar bbs to compare a bb with"
+#, no-c-format
msgid "Maximum amount of similar bbs to compare a bb with."
-msgstr "Cantidad máxima de bbs similares con las cuales comparar un bb"
+msgstr "Cantidad máxima de bbs similares con las cuales comparar un bb."
#: params.def:1076
-#, fuzzy, no-c-format
-#| msgid "Maximum amount of iterations of the pass over a function"
+#, no-c-format
msgid "Maximum amount of iterations of the pass over a function."
-msgstr "Cantidad máxima de iteraciones del paso sobre una función"
+msgstr "Cantidad máxima de iteraciones del paso sobre una función."
#: params.def:1083
-#, fuzzy, no-c-format
-#| msgid "Maximum number of strings for which strlen optimization pass will track string lengths"
+#, no-c-format
msgid "Maximum number of strings for which strlen optimization pass will track string lengths."
-msgstr "Número máximo de cadenas para las que el paso de optimización de strlen rastreará longitudes de cadenas"
+msgstr "Número máximo de cadenas para las que el paso de optimización de strlen rastreará longitudes de cadenas."
#: params.def:1090
#, no-c-format
msgid "Which -fsched-pressure algorithm to apply."
-msgstr ""
+msgstr "Qué algoritmo -fsched-pressure aplicar."
#: params.def:1096
#, no-c-format
msgid "Maximum length of candidate scans for straight-line strength reduction."
-msgstr ""
+msgstr "Longitud máxima de los rastreos de candidatos para reducción de fuerza de línea directa."
#: params.def:1102
#, fuzzy, no-c-format
@@ -2684,81 +2557,77 @@ msgstr ""
#: params.def:1132
#, no-c-format
msgid "Use callbacks instead of inline code if number of accesses in function becomes greater or equal to this number."
-msgstr ""
+msgstr "Utiliza callbacks en lugar de código en línea si el número de accesos en la función se hace mayor o igual que este número."
#: params.def:1138
-#, fuzzy, no-c-format
-#| msgid "Maximum number of namespaces to search for alternatives when name lookup fails"
+#, no-c-format
msgid "Maximum number of nested calls to search for control dependencies during uninitialized variable analysis."
-msgstr "Número máximo de espacios de nombres a buscar por alternativas cuando falla la búsqueda de nombre"
+msgstr "Número máximo de llamadas anidadas para buscar dependencias de control durante el análisis de variables sin inicializar."
#: params.def:1144
#, no-c-format
msgid "Maximum number of statements to be included into a single static constructor generated by Pointer Bounds Checker."
-msgstr ""
+msgstr "Número máximo de sentencias que se incluirán en un único constructor estático generado mediante comprobador de límites de puntero."
#: params.def:1150
#, no-c-format
msgid "Scale factor to apply to the number of statements in a threading path when comparing to the number of (scaled) blocks."
-msgstr ""
+msgstr "Factor de escala que se aplicará al número de sentencias en un camino de hilo cuando se compara con el número de bloques (escaladas)."
#: params.def:1155
#, no-c-format
msgid "Maximum number of arguments a PHI may have before the FSM threader will not try to thread through its block."
-msgstr ""
+msgstr "Número máximo de argumentos que un PHI puede tener antes de que el hilador FSM no intente hacer hilo a través de su bloque."
#: params.def:1160
#, no-c-format
msgid "Scale factor to apply to the number of blocks in a threading path when comparing to the number of (scaled) statements."
-msgstr ""
+msgstr "Factor de escala que se aplicará al número de bloques en un camibo de hilo cuando se compara con el número de sentencias (escaladas)."
#: params.def:1165
#, no-c-format
msgid "Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path."
-msgstr ""
+msgstr "Número máximo de instrucciones que se copiarán cuando se dupliquen bloques en un camino de hilo de salto de máquina de estados."
#: params.def:1170
-#, fuzzy, no-c-format
-#| msgid "maximum number of basic blocks per function to be analyzed by Graphite"
+#, no-c-format
msgid "Maximum number of basic blocks on a finite state automaton jump thread path."
-msgstr "número máximo de bloques básicos por función para analizar con Graphite"
+msgstr "Número máximo de bloques básicos en un camino de hilo de salto de máquina de estados."
#: params.def:1175
-#, fuzzy, no-c-format
-#| msgid "Maximum number of nops to insert for a hint (Default 2)"
+#, no-c-format
msgid "Maximum number of new jump thread paths to create for a finite state automaton."
-msgstr "Número máximo de nops a insertar para una pista (Por defecto 2)"
+msgstr "Número máximo de caminos de hilo de salto nuevos que se crearán para una máquina de estados."
#: params.def:1180
#, no-c-format
msgid "Chunk size of omp schedule for loops parallelized by parloops."
-msgstr ""
+msgstr "Tamaño de la porción de planificación omp para bucles paralelizadps por parloops."
#: params.def:1185
#, no-c-format
msgid "Schedule type of omp schedule for loops parallelized by parloops (static, dynamic, guided, auto, runtime)."
-msgstr ""
+msgstr "Tipo de planificación de planificación omp para bucles paralelizados por parloops (estático, dinámico, guiado, auto, en tiempo de ejecución)."
#: params.def:1192
#, no-c-format
msgid "Maximum recursion depth allowed when querying a property of an SSA name."
-msgstr ""
+msgstr "Máxima profundidad permitida de recursividad cuando se consulta una propiedad de un nombre SSA."
#: params.def:1198
-#, fuzzy, no-c-format
-#| msgid "Maximum number of instructions in basic block to be considered for SLP vectorization"
+#, no-c-format
msgid "Maximum number of insns in a basic block to consider for RTL if-conversion."
-msgstr "El número máximo de instrucciones en bloque básico que se consideran para vectorización SLP"
+msgstr "Número máximo de insns en bloque básico que se consideran para conversión-if RTL."
#: params.def:1204
#, no-c-format
msgid "Level of hsa debug stores verbosity"
-msgstr ""
+msgstr "Nivel de expresividad de los almacenes de depuración hsa"
#: params.def:1209
#, no-c-format
msgid "Maximum number of may-defs visited when devirtualizing speculatively"
-msgstr ""
+msgstr "Número máximo de definiciones posibles visitadas cuando se desvirtualiza especulativamente"
#: c-family/c-format.c:417
msgid "format"
@@ -3043,16 +2912,15 @@ msgstr "No se admite el operando para el código '%c'"
#: config/aarch64/aarch64.c:4492 config/aarch64/aarch64.c:4504
#: config/aarch64/aarch64.c:4515 config/aarch64/aarch64.c:4538
#: config/aarch64/aarch64.c:4591 config/aarch64/aarch64.c:4794
-#, fuzzy, c-format
-#| msgid "invalid operand for code '%c'"
+#, c-format
msgid "invalid operand for '%%%c'"
-msgstr "operando inválido para el código '%c'"
+msgstr "operando no válido para '%%%c'"
#: config/aarch64/aarch64.c:4558 config/aarch64/aarch64.c:4571
#: config/aarch64/aarch64.c:4581
#, c-format
msgid "incompatible floating point / vector register operand for '%%%c'"
-msgstr ""
+msgstr "coma flotante incompatible / operando de registro de vector para '%%%c'"
#: config/aarch64/aarch64.c:4627 config/arm/arm.c:22504
#, c-format
@@ -3060,22 +2928,19 @@ msgid "missing operand"
msgstr "falta un operando"
#: config/aarch64/aarch64.c:4689
-#, fuzzy, c-format
-#| msgid "invalid insn:"
+#, c-format
msgid "invalid constant"
-msgstr "insn inválida:"
+msgstr "constante no válida"
#: config/aarch64/aarch64.c:4692
-#, fuzzy, c-format
-#| msgid "invalid %%d operand"
+#, c-format
msgid "invalid operand"
-msgstr "operando %%d inválido"
+msgstr "operando no válido"
#: config/aarch64/aarch64.c:4805
-#, fuzzy, c-format
-#| msgid "invalid operand code '%c'"
+#, c-format
msgid "invalid operand prefix '%%%c'"
-msgstr "código de operando '%c' inválido"
+msgstr "prefijo de operando no válido '%%%c'"
#: config/alpha/alpha.c:5102 config/i386/i386.c:17140
#: config/rs6000/rs6000.c:21150 config/sparc/sparc.c:8749
@@ -3308,7 +3173,7 @@ msgstr "error interno del compilador. Dirección errónea:"
#: config/avr/avr.c:2418
#, c-format
msgid "Unsupported code '%c' for fixed-point:"
-msgstr ""
+msgstr "Código '%c' no admitido para coma fija:"
#: config/avr/avr.c:2426
msgid "internal compiler error. Unknown mode:"
@@ -3340,18 +3205,17 @@ msgid "internal compiler error. Incorrect shift:"
msgstr "error interno del compilador. Desplazamiento incorrecto:"
#: config/avr/avr.c:7975
-#, fuzzy
-#| msgid "unsupported version"
msgid "unsupported fixed-point conversion"
-msgstr "versión sin soporte"
+msgstr "conversión de coma fija no admitida"
#: config/avr/driver-avr.c:71
-#, fuzzy, c-format
-#| msgid "unknown spec function %qs"
+#, c-format
msgid ""
"Running spec function '%s' with %d args\n"
"\n"
-msgstr "función de especificación %qs desconocida"
+msgstr ""
+"función de especificación '%s' con %d args\n"
+"\n"
#: config/avr/driver-avr.c:118
#, c-format
@@ -3360,6 +3224,9 @@ msgid ""
"'%s': specfile='%s'\n"
"\n"
msgstr ""
+"'%s': mmcu='%s'\n"
+"'%s': specfile='%s'\n"
+"\n"
#: config/bfin/bfin.c:1385
#, c-format
@@ -3894,7 +3761,7 @@ msgstr "Pruebe ejecutar '%s' en el intérprete de órdenes para elevar su límit
#: config/rs6000/rs6000.c:3959
msgid "-maltivec=le not allowed for big-endian targets"
-msgstr ""
+msgstr "-maltivec=le no permitida para destinos big-endian"
#: config/rs6000/rs6000.c:3971
msgid "-mvsx requires hardware floating point"
@@ -3917,30 +3784,24 @@ msgid "-mno-altivec disables vsx"
msgstr "-mno-altivec desactiva vsx"
#: config/rs6000/rs6000.c:4129
-#, fuzzy
-#| msgid "--resource requires -o"
msgid "-mquad-memory requires 64-bit mode"
-msgstr "--resource requiere -o"
+msgstr "-mquad-memory requiere modo de 64 bits"
#: config/rs6000/rs6000.c:4132
msgid "-mquad-memory-atomic requires 64-bit mode"
-msgstr ""
+msgstr "-mquad-memory-atomic requiere modo de 64 bits"
#: config/rs6000/rs6000.c:4144
-#, fuzzy
-#| msgid "Generate code in little endian mode"
msgid "-mquad-memory is not available in little endian mode"
-msgstr "Genera código en modo little endian"
+msgstr "-mquad-memory no está disponible en modo little endian"
#: config/rs6000/rs6000.c:4212
-#, fuzzy
-#| msgid "--resource requires -o"
msgid "-mtoc-fusion requires 64-bit"
-msgstr "--resource requiere -o"
+msgstr "-mtoc-fusion requiere 64 bits"
#: config/rs6000/rs6000.c:4219
msgid "-mtoc-fusion requires medium/large code model"
-msgstr ""
+msgstr "-mtoc-fusion requiere modelo de código medio/grande"
#: config/rs6000/rs6000.c:9919
msgid "bad move"
@@ -3948,13 +3809,12 @@ msgstr "move erróneo"
#: config/rs6000/rs6000.c:20411
msgid "Bad 128-bit move"
-msgstr ""
+msgstr "Movimiento de 128 bits erróneo"
#: config/rs6000/rs6000.c:20602
-#, fuzzy, c-format
-#| msgid "invalid %%H value"
+#, c-format
msgid "invalid %%e value"
-msgstr "valor %%H inválido"
+msgstr "valor %%e no válido"
#: config/rs6000/rs6000.c:20623
#, c-format
@@ -4028,59 +3888,55 @@ msgstr "valor %%y inválido, pruebe usando la restricción 'Z'"
#: config/rs6000/rs6000.c:21814
msgid "__float128 and __ibm128 cannot be used in the same expression"
-msgstr ""
+msgstr "__float128 y __ibm128 no pueden utilizarse en la misma expresión"
#: config/rs6000/rs6000.c:21820
msgid "__ibm128 and long double cannot be used in the same expression"
-msgstr ""
+msgstr "__ibm128 y long double no pueden utilizarse en la misma expresión"
#: config/rs6000/rs6000.c:21826
msgid "__float128 and long double cannot be used in the same expression"
-msgstr ""
+msgstr "__float128 y long double no pueden utilizarse en la misma expresión"
#: config/rs6000/rs6000.c:35706
msgid "AltiVec argument passed to unprototyped function"
msgstr "Se pasó un argumento Altivec a una función sin prototipo"
#: config/rs6000/rs6000.c:37429
-#, fuzzy
-#| msgid "Do not generate code for a Sun FPA"
msgid "Could not generate addis value for fusion"
-msgstr "No generar código para un FPA de Sun"
+msgstr "No se ha podido generar valor addis para fusión"
#: config/rs6000/rs6000.c:37501
-#, fuzzy
-#| msgid "unable to generate reloads for:"
msgid "Unable to generate load/store offset for fusion"
-msgstr "no se pueden generar recargas para:"
+msgstr "No se puede generar desplazamiento de carga/almacenamiento para fusión"
#: config/rs6000/rs6000.c:37605
msgid "Bad GPR fusion"
-msgstr ""
+msgstr "Fusión GPR errónea"
#: config/rs6000/rs6000.c:37823
msgid "emit_fusion_p9_load, bad reg #1"
-msgstr ""
+msgstr "emit_fusion_p9_load, reg #1 erróneo"
#: config/rs6000/rs6000.c:37860
msgid "emit_fusion_p9_load, bad reg #2"
-msgstr ""
+msgstr "emit_fusion_p9_load, reg #2 erróneo"
#: config/rs6000/rs6000.c:37863
msgid "emit_fusion_p9_load not MEM"
-msgstr ""
+msgstr "emit_fusion_p9_load no MEM"
#: config/rs6000/rs6000.c:37901
msgid "emit_fusion_p9_store, bad reg #1"
-msgstr ""
+msgstr "emit_fusion_p9_store, reg #1 erróneo"
#: config/rs6000/rs6000.c:37938
msgid "emit_fusion_p9_store, bad reg #2"
-msgstr ""
+msgstr "emit_fusion_p9_store, reg #2 erróneo"
#: config/rs6000/rs6000.c:37941
msgid "emit_fusion_p9_store not MEM"
-msgstr ""
+msgstr "emit_fusion_p9_store no MEM"
#: config/s390/s390.c:7168
#, c-format
@@ -4159,30 +4015,24 @@ msgid "invalid expression for output modifier '%c'"
msgstr "expresión inválida para el modificador de salida '%c'"
#: config/s390/s390.c:11377
-#, fuzzy
-#| msgid "AltiVec argument passed to unprototyped function"
msgid "Vector argument passed to unprototyped function"
-msgstr "Se pasó un argumento Altivec a una función sin prototipo"
+msgstr "Se pasó un argumento vector a una función sin prototipo"
#: config/s390/s390.c:15036
-#, fuzzy
-#| msgid "pointer targets in return differ in signedness"
msgid "types differ in signess"
-msgstr "el puntero que apunta en la devolución difiere en signo"
+msgstr "los tipos difieren en el signo"
#: config/s390/s390.c:15046
msgid "binary operator does not support two vector bool operands"
-msgstr ""
+msgstr "el operador binario no admite dos operadores bool vector"
#: config/s390/s390.c:15049
-#, fuzzy
-#| msgid "profiling does not support code models other than medlow"
msgid "binary operator does not support vector bool operand"
-msgstr "el análisis de perfil no soporta modelos de código que no sean medlow"
+msgstr "el operador binario no admite operador bool vector"
#: config/s390/s390.c:15057
msgid "binary operator does not support mixing vector bool with floating point vector operands"
-msgstr ""
+msgstr "el operador binario no admite que se mezclen operandos bool vector y vector de coma flotante"
#: config/sh/sh.c:1313
#, c-format
@@ -4444,7 +4294,7 @@ msgstr "el desplazamiento de dirección no es una constante"
#: c/c-objc-common.c:160
msgid "aka"
-msgstr ""
+msgstr "también conocido como"
#: c/c-objc-common.c:187
msgid "({anonymous})"
@@ -4548,21 +4398,19 @@ msgstr "se esperaba %<:%>"
#: c/c-parser.c:5185 cp/semantics.c:613
msgid "Cilk array notation cannot be used as a computed goto expression"
-msgstr ""
+msgstr "La notaicón de array de Cilk no puede utilizarse como una expresión goto calculada"
#: c/c-parser.c:5244
-#, fuzzy
-#| msgid "expression %qE of abstract class type %qT cannot be used in throw-expression"
msgid "Cilk array notation cannot be used for a throw expression"
-msgstr "no se puede usar la expresión %qE del tipo de clase abstracta %qT en las expresiones throw"
+msgstr "La notaicón de array de Cilk no puede utilizarse para expresiones throw"
#: c/c-parser.c:5556 cp/semantics.c:1136
msgid "Cilk array notation cannot be used as a condition for switch statement"
-msgstr ""
+msgstr "La notaicón de array de Cilk no puede utilizarse para sentencias switch"
#: c/c-parser.c:5605 cp/semantics.c:791
msgid "Cilk array notation cannot be used as a condition for while statement"
-msgstr ""
+msgstr "La notaicón de array de Cilk no puede utilizarse para sentencias while"
#: c/c-parser.c:5656 cp/parser.c:26897
#, gcc-internal-format
@@ -4571,11 +4419,11 @@ msgstr "se esperaba %<while%>"
#: c/c-parser.c:5663 cp/semantics.c:850
msgid "Cilk array notation cannot be used as a condition for a do-while statement"
-msgstr ""
+msgstr "La notaicón de array de Cilk no puede utilizarse para sentencias do-while"
#: c/c-parser.c:5866 cp/semantics.c:969
msgid "Cilk array notation cannot be used in a condition for a for-loop"
-msgstr ""
+msgstr "La notaicón de array de Cilk no puede utilizarse para sentencias do-while"
#: c/c-parser.c:7497
msgid "expected %<.%>"
@@ -4724,21 +4572,19 @@ msgstr "<expresión-throw>"
#: cp/error.c:2115
msgid "<ubsan routine call>"
-msgstr ""
+msgstr "<llamada a rutina ubsan>"
#: cp/error.c:2572
msgid "<unparsed>"
msgstr "<sidecodificar>"
#: cp/error.c:2723
-#, fuzzy
-#| msgid "<lambda"
msgid "<lambda>"
-msgstr "<lambda"
+msgstr "<lambda>"
#: cp/error.c:2766
msgid "*this"
-msgstr ""
+msgstr "*this"
#: cp/error.c:2776
msgid "<expression error>"
@@ -4998,30 +4844,24 @@ msgid "arguments '%s' and '%s' for intrinsic '%s'"
msgstr "argumentos '%s' y '%s' para el intrínseco '%s'"
#: fortran/error.c:871
-#, fuzzy
-#| msgid "Fortran 2008 obsolescent feature: ENTRY statement at %C"
msgid "Fortran 2008 obsolescent feature:"
-msgstr "Característica obsoleta de Fortran 2008: declaración ENTRY en %C"
+msgstr "Característica obsoleta de Fortran 2008:"
#: fortran/error.c:880
msgid "GNU Extension:"
-msgstr ""
+msgstr "Extensión GNU:"
#: fortran/error.c:883
msgid "Legacy Extension:"
-msgstr ""
+msgstr "Extensión antigua:"
#: fortran/error.c:886
-#, fuzzy
-#| msgid "Obsolescent feature: Computed GOTO at %C"
msgid "Obsolescent feature:"
-msgstr "Característica obsoleta: GOTO computado en %C"
+msgstr "Característica obsoleta:"
#: fortran/error.c:889
-#, fuzzy
-#| msgid "expected operator"
msgid "Deleted feature:"
-msgstr "operador inesperado"
+msgstr "Característica borrada:"
#: fortran/expr.c:622
#, c-format
@@ -5060,10 +4900,8 @@ msgid "Nonnegative width required"
msgstr "Se requiere una anchura que no sea negativa"
#: fortran/io.c:552
-#, fuzzy
-#| msgid "Unexpected element '%c' in format string at %L"
msgid "Unexpected element %qc in format string at %L"
-msgstr "Elemento '%c' inesperado en la cadena de formato en %L"
+msgstr "Elemento %qc inesperado en la cadena de formato en %L"
#: fortran/io.c:554
msgid "Unexpected end of format string"
@@ -5078,10 +4916,8 @@ msgid "Missing leading left parenthesis"
msgstr "Falta el paréntesis izquierdo inicial"
#: fortran/io.c:604
-#, fuzzy
-#| msgid "Left parenthesis required after '*'"
msgid "Left parenthesis required after %<*%>"
-msgstr "Se requiere paréntesis izquierdo después de '*'"
+msgstr "Se requiere paréntesis izquierdo después de %<*%>"
#: fortran/io.c:635
msgid "Expected P edit descriptor"
@@ -5254,34 +5090,24 @@ msgid "elemental procedure"
msgstr "procedimiento elemental"
#: fortran/resolve.c:2254
-#, fuzzy
-#| msgid "invalid type argument"
msgid "allocatable argument"
-msgstr "argumento de tipo inválido"
+msgstr "argumento asignable"
#: fortran/resolve.c:2259
-#, fuzzy
-#| msgid "not enough arguments"
msgid "asynchronous argument"
-msgstr "faltan argumentos"
+msgstr "argumento asíncrono"
#: fortran/resolve.c:2264
-#, fuzzy
-#| msgid "invalid PHI argument"
msgid "optional argument"
-msgstr "argumento PHI inválido"
+msgstr "argumento opcional"
#: fortran/resolve.c:2269
-#, fuzzy
-#| msgid "pointer assignment"
msgid "pointer argument"
-msgstr "asignación de puntero"
+msgstr "argumento puntero"
#: fortran/resolve.c:2274
-#, fuzzy
-#| msgid "too many arguments"
msgid "target argument"
-msgstr "demasiados argumentos"
+msgstr "argumento destino"
#: fortran/resolve.c:2279
#, fuzzy
@@ -5290,10 +5116,8 @@ msgid "value argument"
msgstr "argumento de tipo inválido"
#: fortran/resolve.c:2284
-#, fuzzy
-#| msgid "no arguments"
msgid "volatile argument"
-msgstr "sin argumentos"
+msgstr "argumento volátil"
#: fortran/resolve.c:2289
#, fuzzy
@@ -5302,16 +5126,12 @@ msgid "assumed-shape argument"
msgstr "no coinciden los argumentos"
#: fortran/resolve.c:2294
-#, fuzzy
-#| msgid "mismatched arguments"
msgid "assumed-rank argument"
-msgstr "no coinciden los argumentos"
+msgstr "se asume argumento de rango"
#: fortran/resolve.c:2299
-#, fuzzy
-#| msgid "array assignment"
msgid "coarray argument"
-msgstr "asignación de matriz"
+msgstr "argumento de coarray"
#: fortran/resolve.c:2304
#, fuzzy
@@ -5320,14 +5140,12 @@ msgid "parametrized derived type argument"
msgstr "no se han implementado las estructuras parametrizadas"
#: fortran/resolve.c:2309
-#, fuzzy
-#| msgid "no arguments"
msgid "polymorphic argument"
-msgstr "sin argumentos"
+msgstr "argumento polimórfico"
#: fortran/resolve.c:2314
msgid "NO_ARG_CHECK attribute"
-msgstr ""
+msgstr "atributo NO_ARG_CHECK"
#. As assumed-type is unlimited polymorphic (cf. above).
#. See also TS 29113, Note 6.1.
@@ -5339,13 +5157,11 @@ msgstr "argumento de tipo inválido"
#: fortran/resolve.c:2332
msgid "array result"
-msgstr ""
+msgstr "resultado array"
#: fortran/resolve.c:2337
-#, fuzzy
-#| msgid "Coindexed allocatable object at %L"
msgid "pointer or allocatable result"
-msgstr "Objeto alojable coindizado en %L"
+msgstr "puntero o resultado asignable"
#: fortran/resolve.c:2344
#, fuzzy
@@ -5365,16 +5181,14 @@ msgid "Invalid context for NULL() pointer at %%L"
msgstr "Contexto inválido para el puntero NULL() en %%L"
#: fortran/resolve.c:3574
-#, fuzzy, c-format
-#| msgid "Operand of unary numeric operator '%s' at %%L is %s"
+#, c-format
msgid "Operand of unary numeric operator %%<%s%%> at %%L is %s"
-msgstr "El operando del operador numérico unario '%s' en %%L es %s"
+msgstr "El operando del operador numérico unitario %%<%s%%> en %%L es %s"
#: fortran/resolve.c:3590
-#, fuzzy, c-format
-#| msgid "Operands of binary numeric operator '%s' at %%L are %s/%s"
+#, c-format
msgid "Operands of binary numeric operator %%<%s%%> at %%L are %s/%s"
-msgstr "Los operandos del operador binario numérico '%s' en %%L son %s/%s"
+msgstr "Los operandos del operador numérico binario %%<%s%%> en %%L son %s/%s"
#: fortran/resolve.c:3605
#, c-format
@@ -5382,10 +5196,9 @@ msgid "Operands of string concatenation operator at %%L are %s/%s"
msgstr "Los operandos del operador de concatenación de cadenas en %%L son %s/%s"
#: fortran/resolve.c:3624
-#, fuzzy, c-format
-#| msgid "Operands of logical operator '%s' at %%L are %s/%s"
+#, c-format
msgid "Operands of logical operator %%<%s%%> at %%L are %s/%s"
-msgstr "Los operandos del operador lógico '%s' en %%L son %s/%s"
+msgstr "Los operandos del operador lógico %%<%s%%> en %%L son %s/%s"
#: fortran/resolve.c:3638
#, c-format
@@ -5402,28 +5215,24 @@ msgid "Logicals at %%L must be compared with %s instead of %s"
msgstr "Los lógicos en %%L se deben comparar con %s en lugar de %s"
#: fortran/resolve.c:3709
-#, fuzzy, c-format
-#| msgid "Operands of comparison operator '%s' at %%L are %s/%s"
+#, c-format
msgid "Operands of comparison operator %%<%s%%> at %%L are %s/%s"
-msgstr "Los operandos del operador de comparación '%s' en %%L son %s/%s"
+msgstr "Los operandos del operador de comparación %%<%s%%> en %%L son %s/%s"
#: fortran/resolve.c:3717
-#, fuzzy, c-format
-#| msgid "Unknown operator '%s' at %%L"
+#, c-format
msgid "Unknown operator %%<%s%%> at %%L"
-msgstr "Operador '%s' desconocido en %%L"
+msgstr "Operador %%<%s%%> desconocido en %%L"
#: fortran/resolve.c:3720
-#, fuzzy, c-format
-#| msgid "Operand of user operator '%s' at %%L is %s"
+#, c-format
msgid "Operand of user operator %%<%s%%> at %%L is %s"
-msgstr "El operando del operador de usuario '%s' en %%L es %s"
+msgstr "El operando del operador de usuario %%<%s%%> en %%L es %s"
#: fortran/resolve.c:3724
-#, fuzzy, c-format
-#| msgid "Operands of user operator '%s' at %%L are %s/%s"
+#, c-format
msgid "Operands of user operator %%<%s%%> at %%L are %s/%s"
-msgstr "Los operandos del operador de usuario '%s' en %%L son %s/%s"
+msgstr "Los operandos del operador de usuario %%<%s%%> en %%L son %s/%s"
#: fortran/resolve.c:3812
#, c-format
@@ -5500,7 +5309,7 @@ msgstr "El objetivo del remapeo de rango es demasiado pequeño (%ld < %ld)"
#: fortran/trans-expr.c:9375
msgid "Assignment of scalar to unallocated array"
-msgstr ""
+msgstr "Asignación de escalar a un array sin espacio asignado"
#: fortran/trans-intrinsic.c:897
#, c-format
@@ -5769,7 +5578,7 @@ msgid ""
"For bug reporting instructions, please see:\n"
"%s.\n"
msgstr ""
-"Para instrucciones de reporte de bichos, por favor vea:\n"
+"Para instrucciones de informe de errores, por favor vea:\n"
"%s.\n"
#: java/jcf-dump.c:1258 java/jcf-dump.c:1326
@@ -5813,16 +5622,12 @@ msgid "<unnamed>"
msgstr "<sinnombre>"
#: gcc.c:747 gcc.c:751 gcc.c:806
-#, fuzzy
-#| msgid "-m%s not supported in this configuration"
msgid "-gz is not supported in this configuration"
-msgstr "no se admite -m%s en esta configuración"
+msgstr "no se admite -gz en esta configuración"
#: gcc.c:757 gcc.c:817
-#, fuzzy
-#| msgid "ifunc is not supported in this configuration"
msgid "-gz=zlib is not supported in this configuration"
-msgstr "ifunc no se admite en esta configuración"
+msgstr "no se admite -gz=zlib en esta configuración"
#: gcc.c:961
msgid "-fuse-linker-plugin is not supported in this configuration"
@@ -5830,11 +5635,11 @@ msgstr "-fuse-linker-plugin no se admite en esta configuración"
#: gcc.c:976
msgid "cannot specify -static with -fsanitize=address"
-msgstr ""
+msgstr "no se puede especificar -static con -fsanitize=address"
#: gcc.c:978
msgid "cannot specify -static with -fsanitize=thread"
-msgstr ""
+msgstr "no se puede especificar -static con -fsanitize=thread"
#: gcc.c:1122 ada/gcc-interface/lang-specs.h:33 java/jvspec.c:79
msgid "-pg and -fomit-frame-pointer are incompatible"
@@ -5964,14 +5769,12 @@ msgid "-msingle-float and -msoft-float cannot both be specified"
msgstr "no se pueden especificar -msingle-float y -msoft-float al mismo tiempo"
#: config/moxie/moxiebox.h:43
-#, fuzzy
-#| msgid "Assume target CPU is configured as little endian"
msgid "this target is little-endian"
-msgstr "Asume que el CPU destino está configurado como little endian"
+msgstr "este destino es little endian"
#: config/nios2/elf.h:44
msgid "You need a C startup file for -msys-crt0="
-msgstr ""
+msgstr "Se necesita un fichero de arranque de C para -msys-crt0="
#: config/pa/pa-hpux10.h:102 config/pa/pa-hpux10.h:105
#: config/pa/pa-hpux10.h:113 config/pa/pa-hpux10.h:116
@@ -6076,54 +5879,40 @@ msgid "objc++-cpp-output is deprecated; please use objective-c++-cpp-output inst
msgstr "objc++-cpp-output es obsoleto; pr favor use en su lugar objective-c++-cpp-output"
#: fortran/lang.opt:146
-#, fuzzy
-#| msgid "-J<directory>\tPut MODULE files in 'directory'"
msgid "-J<directory>\tPut MODULE files in 'directory'."
-msgstr "-J<directorio>\tColoca los ficheros MODULE en el 'directorio'"
+msgstr "-J<directorio>\tColoca los ficheros MODULE en el 'directorio'."
#: fortran/lang.opt:198
-#, fuzzy
-#| msgid "Warn about possible aliasing of dummy arguments"
msgid "Warn about possible aliasing of dummy arguments."
-msgstr "Avisa sobre posibles aliases de argumentos de relleno"
+msgstr "Avisa sobre posibles aliases de argumentos de relleno."
#: fortran/lang.opt:202
-#, fuzzy
-#| msgid "Warn about alignment of COMMON blocks"
msgid "Warn about alignment of COMMON blocks."
-msgstr "Avisa sobre la alineación de bloques COMMON"
+msgstr "Avisa sobre la alineación de bloques COMMON."
#: fortran/lang.opt:206
-#, fuzzy
-#| msgid "Warn about missing ampersand in continued character constants"
msgid "Warn about missing ampersand in continued character constants."
-msgstr "Avisa sobre '&' faltantes en las literales de carácter continuadas"
+msgstr "Avisa sobre '&' faltantes en las literales de carácter continuadas."
#: fortran/lang.opt:210
-#, fuzzy
-#| msgid "Warn about creation of array temporaries"
msgid "Warn about creation of array temporaries."
-msgstr "Avisa sobre la creación de matrices temporales"
+msgstr "Avisa sobre la creación de matrices temporales."
#: fortran/lang.opt:214
msgid "Warn if the type of a variable might be not interoperable with C."
-msgstr ""
+msgstr "Avisa si el tipo de una variable podría no ser interoperable con C."
#: fortran/lang.opt:222
-#, fuzzy
-#| msgid "Warn about truncated character expressions"
msgid "Warn about truncated character expressions."
-msgstr "Avisa sobre expresiones de carácter truncadas"
+msgstr "Avisa sobre expresiones de carácter truncadas."
#: fortran/lang.opt:226
msgid "Warn about equality comparisons involving REAL or COMPLEX expressions."
-msgstr ""
+msgstr "Avisa sobre comparaciones de igualdad que involucran expresiones REAL o COMPLEX."
#: fortran/lang.opt:234
-#, fuzzy
-#| msgid "Warn about most implicit conversions"
msgid "Warn about most implicit conversions."
-msgstr "Avisa sobre la mayoría de las conversiones implícitas"
+msgstr "Avisa sobre la mayoría de las conversiones implícitas."
#: fortran/lang.opt:242
#, fuzzy
@@ -8264,7 +8053,7 @@ msgstr "Asume que los valores de tipo de enumeración están siempre dentro del
#, fuzzy
#| msgid "-ftabstop=<number>\tDistance between tab stops for column reporting"
msgid "-ftabstop=<number>\tDistance between tab stops for column reporting."
-msgstr "-ftabstop=<número>\tDistancia entre topes de tabulador para reportes en columnas"
+msgstr "-ftabstop=<número>\tDistancia entre topes de tabulador para informes en columnas"
#: c-family/c.opt:1507
#, fuzzy
@@ -9494,13 +9283,13 @@ msgstr "Especifica el tamaño de bit para los desplazamientos TLS inmediatos"
#, fuzzy
#| msgid "-mcpu=CPU\tUse features of and schedule code for given CPU"
msgid "-march=ARCH\tUse features of architecture ARCH."
-msgstr "-mcpu=CPU\tUsa las características y el código de calendarizador para el CPU dado"
+msgstr "-mcpu=CPU\tUsa las características y el código de planificador para el CPU dado"
#: config/aarch64/aarch64.opt:124
#, fuzzy
#| msgid "-mcpu=CPU\tUse features of and schedule code for given CPU"
msgid "-mcpu=CPU\tUse features of and optimize for CPU."
-msgstr "-mcpu=CPU\tUsa las características y el código de calendarizador para el CPU dado"
+msgstr "-mcpu=CPU\tUsa las características y el código de planificador para el CPU dado"
#: config/aarch64/aarch64.opt:128
msgid "-mtune=CPU\tOptimize for CPU."
@@ -9704,7 +9493,7 @@ msgstr "Especifica el tamaño de bit para los desplazamientos TLS inmediatos"
#, fuzzy
#| msgid "Schedule code for given CPU"
msgid "Schedule code for given CPU."
-msgstr "Código de calendarizador para el CPU dado"
+msgstr "Código de planificador para el CPU dado"
#: config/ia64/ia64.opt:126
msgid "Known Itanium CPUs (for use with the -mtune= option):"
@@ -10660,7 +10449,7 @@ msgstr ""
#, fuzzy
#| msgid "Do dispatch scheduling if processor is bdver1 or bdver2 and Haifa scheduling"
msgid "Do dispatch scheduling if processor is bdver1, bdver2, bdver3, bdver4"
-msgstr "Despacha al calendarizador si el procesador es bdver1 o bdver2 y la calendarización es Haifa"
+msgstr "Despacha al planificador si el procesador es bdver1 o bdver2 y la calendarización es Haifa"
#: config/i386/i386.opt:582
msgid "Use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer."
@@ -12235,7 +12024,7 @@ msgstr ""
#, fuzzy
#| msgid "Use features of and schedule code for given CPU"
msgid "Use features of and schedule code for given CPU."
-msgstr "Usa las características y el código de calendarizador para el CPU dado"
+msgstr "Usa las características y el código de planificador para el CPU dado"
#: config/sparc/sparc.opt:206
#, fuzzy
@@ -12653,13 +12442,13 @@ msgstr "se usa long double de precisión extendida de IBM"
#, fuzzy
#| msgid "-mcpu=\tUse features of and schedule code for given CPU"
msgid "-mcpu=\tUse features of and schedule code for given CPU."
-msgstr "-mcpu=\tUsa las características y el código de calendarizador para el CPU dado"
+msgstr "-mcpu=\tUsa las características y el código de planificador para el CPU dado"
#: config/rs6000/rs6000.opt:414
#, fuzzy
#| msgid "-mtune=\tSchedule code for given CPU"
msgid "-mtune=\tSchedule code for given CPU."
-msgstr "-mtune=\tCódigo de calendarizador para el CPU dado"
+msgstr "-mtune=\tCódigo de planificador para el CPU dado"
#: config/rs6000/rs6000.opt:418
#, fuzzy
@@ -13113,7 +12902,7 @@ msgstr "Emite rdval en lugar de rduniq para un puntero thread"
#, fuzzy
#| msgid "Use features of and schedule given CPU"
msgid "Use features of and schedule given CPU."
-msgstr "Usa las características y el calendarizador del CPU dado"
+msgstr "Usa las características y el planificador del CPU dado"
#: config/alpha/alpha.opt:110
#, fuzzy
@@ -13153,7 +12942,7 @@ msgstr "Compila con longs y punteros de 32 bit, el cual es el único admitido"
#, fuzzy
#| msgid "-mcpu=CPU\tUse features of and schedule code for given CPU"
msgid "-mcpu=CPU\tUse features of and schedule code for given CPU."
-msgstr "-mcpu=CPU\tUsa las características y el código de calendarizador para el CPU dado"
+msgstr "-mcpu=CPU\tUsa las características y el código de planificador para el CPU dado"
#: config/tilepro/tilepro.opt:32
msgid "Known TILEPro CPUs (for use with the -mcpu= option):"
@@ -14039,7 +13828,7 @@ msgstr "Usa las optimización de búsqueda de tabla para divisiones enteras smal
#, fuzzy
#| msgid "-mcpu=PROCESSOR\t\tUse features of and schedule code for given CPU"
msgid "-mcpu=PROCESSOR\t\tUse features of and schedule code for given CPU."
-msgstr "-mcpu=PROCESADOR\t\tUsa las características y el código de calendarizador para el CPU dado"
+msgstr "-mcpu=PROCESADOR\t\tUsa las características y el código de planificador para el CPU dado"
#: config/microblaze/microblaze.opt:56
#, fuzzy
@@ -14369,7 +14158,7 @@ msgstr "Permite establecer los GPRs al resultado de las comparaciones"
#, fuzzy
#| msgid "Change the amount of scheduler lookahead"
msgid "Change the amount of scheduler lookahead."
-msgstr "Cambia la cantidad de vista hacia adelante del calendarizador"
+msgstr "Cambia la cantidad de vista hacia adelante del planificador"
#: config/frv/frv.opt:219
#, fuzzy
@@ -14423,7 +14212,7 @@ msgstr "Apunta al procesador AM34"
#, fuzzy
#| msgid "Work around hardware multiply bug"
msgid "Work around hardware multiply bug."
-msgstr "Evita el bicho de multiplicación de hardware"
+msgstr "Evita el error de multiplicación de hardware"
#: config/mn10300/mn10300.opt:55
#, fuzzy
@@ -14591,7 +14380,7 @@ msgstr "Junto con -fpic y -fPIC, no utiliza referencias GOTPLT"
#, fuzzy
#| msgid "Work around bug in multiplication instruction"
msgid "Work around bug in multiplication instruction."
-msgstr "Evita el bicho en la instrucción de multiplicación"
+msgstr "Evita el error en la instrucción de multiplicación"
#: config/cris/cris.opt:51
#, fuzzy
@@ -18036,7 +17825,7 @@ msgstr "Permite el movimiento especulativo de más loads"
#, fuzzy
#| msgid "-fsched-verbose=<number>\tSet the verbosity level of the scheduler"
msgid "-fsched-verbose=<number>\tSet the verbosity level of the scheduler."
-msgstr "-fsched-verbose=<número>\tEstablece el nivel de detalle del calendarizador"
+msgstr "-fsched-verbose=<número>\tEstablece el nivel de detalle del planificador"
#: common.opt:2031
#, fuzzy
@@ -18118,37 +17907,37 @@ msgstr "-fsched-stalled-insns-dep=<número>\tEstablece la revisión de distancia
#, fuzzy
#| msgid "Enable the group heuristic in the scheduler"
msgid "Enable the group heuristic in the scheduler."
-msgstr "Activa la heurística de grupo en el calendarizador"
+msgstr "Activa la heurística de grupo en el planificador"
#: common.opt:2100
#, fuzzy
#| msgid "Enable the critical path heuristic in the scheduler"
msgid "Enable the critical path heuristic in the scheduler."
-msgstr "Activa la heurística de ruta crítica en el calendarizador"
+msgstr "Activa la heurística de ruta crítica en el planificador"
#: common.opt:2104
#, fuzzy
#| msgid "Enable the speculative instruction heuristic in the scheduler"
msgid "Enable the speculative instruction heuristic in the scheduler."
-msgstr "Activa la heurística de instrucción especulativa en el calendarizador"
+msgstr "Activa la heurística de instrucción especulativa en el planificador"
#: common.opt:2108
#, fuzzy
#| msgid "Enable the rank heuristic in the scheduler"
msgid "Enable the rank heuristic in the scheduler."
-msgstr "Activa la heurística de rango en el calendarizador"
+msgstr "Activa la heurística de rango en el planificador"
#: common.opt:2112
#, fuzzy
#| msgid "Enable the last instruction heuristic in the scheduler"
msgid "Enable the last instruction heuristic in the scheduler."
-msgstr "Activa la heurística de última instrucción en el calendarizador"
+msgstr "Activa la heurística de última instrucción en el planificador"
#: common.opt:2116
#, fuzzy
#| msgid "Enable the dependent count heuristic in the scheduler"
msgid "Enable the dependent count heuristic in the scheduler."
-msgstr "Activa la heurística de cuenta dependiente en el calendarizador"
+msgstr "Activa la heurística de cuenta dependiente en el planificador"
#: common.opt:2120
#, fuzzy
@@ -24102,7 +23891,7 @@ msgstr "se solicitó seguimiento de variables, pero no se admite este formato de
#: toplev.c:1471
#, gcc-internal-format
msgid "var-tracking-assignments changes selective scheduling"
-msgstr "las asignaciones-de-rastreo-de-variable cambian el calendarizador selectivo"
+msgstr "las asignaciones-de-rastreo-de-variable cambian el planificador selectivo"
#: toplev.c:1497
#, gcc-internal-format
@@ -37228,17 +37017,17 @@ msgstr "se usaron al mismo tiempo %<long%> y %<void%> en los especificadores de
#: c/c-parser.c:12101 cp/parser.c:31327
#, gcc-internal-format
msgid "schedule %<runtime%> does not take a %<chunk_size%> parameter"
-msgstr "el calendarizador %<runtime%> no toma un parámetro %<chunk_size%>"
+msgstr "el planificador %<runtime%> no toma un parámetro %<chunk_size%>"
#: c/c-parser.c:12105 cp/parser.c:31330
#, gcc-internal-format
msgid "schedule %<auto%> does not take a %<chunk_size%> parameter"
-msgstr "el calendarizador %<auto%> no toma un parámetro %<chunk_size%>"
+msgstr "el planificador %<auto%> no toma un parámetro %<chunk_size%>"
#: c/c-parser.c:12127 cp/parser.c:31350
#, gcc-internal-format
msgid "invalid schedule kind"
-msgstr "género de calendarizador inválido"
+msgstr "género de planificador inválido"
#: c/c-parser.c:12188
#, fuzzy, gcc-internal-format
@@ -37292,7 +37081,7 @@ msgstr "%Hel argumento de collapse necesita ser una expresión entera constante
#, fuzzy, gcc-internal-format
#| msgid "invalid schedule kind"
msgid "invalid depend kind"
-msgstr "género de calendarizador inválido"
+msgstr "género de planificador inválido"
#: c/c-parser.c:12768 cp/parser.c:31917
#, fuzzy, gcc-internal-format
@@ -37304,13 +37093,13 @@ msgstr "máscara inválida"
#, fuzzy, gcc-internal-format
#| msgid "invalid schedule kind"
msgid "invalid dist_schedule kind"
-msgstr "género de calendarizador inválido"
+msgstr "género de planificador inválido"
#: c/c-parser.c:12931
#, fuzzy, gcc-internal-format
#| msgid "invalid schedule kind"
msgid "invalid proc_bind kind"
-msgstr "género de calendarizador inválido"
+msgstr "género de planificador inválido"
#: c/c-parser.c:13144 cp/parser.c:32292
#, fuzzy, gcc-internal-format
@@ -68207,10 +67996,10 @@ msgstr "se crea un selector para el método %qE que no existe"
#~ msgstr "%Hdemasiadas cláusulas %qs"
#~ msgid "%Hschedule %<runtime%> does not take a %<chunk_size%> parameter"
-#~ msgstr "%Hel calendarizador %<runtime%> no toma un parámetro %<chunk_size%>"
+#~ msgstr "%Hel planificador %<runtime%> no toma un parámetro %<chunk_size%>"
#~ msgid "%Hschedule %<auto%> does not take a %<chunk_size%> parameter"
-#~ msgstr "%Hel calendarizador %<auto%> no toma un parámetro %<chunk_size%>"
+#~ msgstr "%Hel planificador %<auto%> no toma un parámetro %<chunk_size%>"
#~ msgid "%H%qs is not valid for %qs"
#~ msgstr "%H%qs no es válido para %qs"
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 26871e8d12b..8a4456238c4 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -41,10 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "dbgcnt.h"
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
static int reload_cse_noop_set_p (rtx);
static bool reload_cse_simplify (rtx_insn *, rtx);
static void reload_cse_regs_1 (void);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 341ecdfedb8..3f15a216c96 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -564,6 +564,43 @@ rtx_writer::print_rtx_operand (const_rtx in_rtx, int idx)
}
}
+/* Subroutine of rtx_writer::print_rtx.
+ In compact mode, determine if operand IDX of IN_RTX is interesting
+ to dump, or (if in a trailing position) it can be omitted. */
+
+bool
+rtx_writer::operand_has_default_value_p (const_rtx in_rtx, int idx)
+{
+ const char *format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
+
+ switch (format_ptr[idx])
+ {
+ case 'e':
+ case 'u':
+ return XEXP (in_rtx, idx) == NULL_RTX;
+
+ case 's':
+ return XSTR (in_rtx, idx) == NULL;
+
+ case '0':
+ switch (GET_CODE (in_rtx))
+ {
+ case JUMP_INSN:
+ /* JUMP_LABELs are always omitted in compact mode, so treat
+ any value here as omittable, so that earlier operands can
+ potentially be omitted also. */
+ return m_compact;
+
+ default:
+ return false;
+
+ }
+
+ default:
+ return false;
+ }
+}
+
/* Print IN_RTX onto m_outfile. This is the recursive part of printing. */
void
@@ -681,9 +718,18 @@ rtx_writer::print_rtx (const_rtx in_rtx)
fprintf (m_outfile, " %d", INSN_UID (in_rtx));
}
+ /* Determine which is the final operand to print.
+ In compact mode, skip trailing operands that have the default values
+ e.g. trailing "(nil)" values. */
+ int limit = GET_RTX_LENGTH (GET_CODE (in_rtx));
+ if (m_compact)
+ while (limit > idx && operand_has_default_value_p (in_rtx, limit - 1))
+ limit--;
+
/* Get the format string and skip the first elements if we have handled
them already. */
- for (; idx < GET_RTX_LENGTH (GET_CODE (in_rtx)); idx++)
+
+ for (; idx < limit; idx++)
print_rtx_operand (in_rtx, idx);
switch (GET_CODE (in_rtx))
diff --git a/gcc/print-rtl.h b/gcc/print-rtl.h
index 8496ffa1491..68db057b201 100644
--- a/gcc/print-rtl.h
+++ b/gcc/print-rtl.h
@@ -39,6 +39,7 @@ class rtx_writer
void print_rtx_operand_code_r (const_rtx in_rtx);
void print_rtx_operand_code_u (const_rtx in_rtx, int idx);
void print_rtx_operand (const_rtx in_rtx, int idx);
+ bool operand_has_default_value_p (const_rtx in_rtx, int idx);
private:
FILE *m_outfile;
diff --git a/gcc/profile.c b/gcc/profile.c
index 2564f07abf7..ef38f988a34 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -192,15 +192,9 @@ instrument_values (histogram_values values)
gimple_gen_ior_profiler (hist, t, 0);
break;
- case HIST_TYPE_TIME_PROFILE:
- {
- basic_block bb =
- split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
- gimple_stmt_iterator gsi = gsi_start_bb (bb);
-
- gimple_gen_time_profiler (t, 0, gsi);
- break;
- }
+ case HIST_TYPE_TIME_PROFILE:
+ gimple_gen_time_profiler (t, 0);
+ break;
default:
gcc_unreachable ();
@@ -1305,7 +1299,7 @@ branch_prob (void)
{
unsigned n_instrumented;
- gimple_init_edge_profiler ();
+ gimple_init_gcov_profiler ();
n_instrumented = instrument_edges (el);
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index 5374169b9a4..962dbb8007e 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -149,6 +149,11 @@ REG_NOTE (CFA_REGISTER)
store of a register to an arbitrary (non-validated) memory address. */
REG_NOTE (CFA_EXPRESSION)
+/* Attached to insns that are RTX_FRAME_RELATED_P, but are too complex
+ for FRAME_RELATED_EXPR intuition. The DWARF expression computes the value of
+ the given register. */
+REG_NOTE (CFA_VAL_EXPRESSION)
+
/* Attached to insns that are RTX_FRAME_RELATED_P, with the information
that this is a restore operation, i.e. will result in DW_CFA_restore
or the like. Either the attached rtx, or the destination of the insn's
diff --git a/gcc/reload.c b/gcc/reload.c
index 3ec4b310f50..7d1681772b4 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -1064,7 +1064,6 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
|| MEM_P (SUBREG_REG (in)))
&& ((GET_MODE_PRECISION (inmode)
> GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in))))
-#ifdef LOAD_EXTEND_OP
|| (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
<= UNITS_PER_WORD)
@@ -1072,15 +1071,12 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
> GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in))))
&& INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != UNKNOWN)
-#endif
-#if WORD_REGISTER_OPERATIONS
- || ((GET_MODE_PRECISION (inmode)
- < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in))))
+ || (WORD_REGISTER_OPERATIONS
+ && (GET_MODE_PRECISION (inmode)
+ < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (in))))
&& ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1)
- / UNITS_PER_WORD)))
-#endif
- ))
+ / UNITS_PER_WORD)))))
|| (REG_P (SUBREG_REG (in))
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
/* The case where out is nonzero
@@ -1111,13 +1107,14 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
#endif
inloc = &SUBREG_REG (in);
in = *inloc;
-#if ! defined (LOAD_EXTEND_OP)
+
if (!WORD_REGISTER_OPERATIONS
+ && LOAD_EXTEND_OP (GET_MODE (in)) == UNKNOWN
&& MEM_P (in))
/* This is supposed to happen only for paradoxical subregs made by
combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */
gcc_assert (GET_MODE_SIZE (GET_MODE (in)) <= GET_MODE_SIZE (inmode));
-#endif
+
inmode = GET_MODE (in);
}
@@ -1175,14 +1172,12 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
|| MEM_P (SUBREG_REG (out)))
&& ((GET_MODE_PRECISION (outmode)
> GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out))))
-#if WORD_REGISTER_OPERATIONS
- || ((GET_MODE_PRECISION (outmode)
- < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out))))
+ || (WORD_REGISTER_OPERATIONS
+ && (GET_MODE_PRECISION (outmode)
+ < GET_MODE_PRECISION (GET_MODE (SUBREG_REG (out))))
&& ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
- / UNITS_PER_WORD)))
-#endif
- ))
+ / UNITS_PER_WORD)))))
|| (REG_P (SUBREG_REG (out))
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
/* The case of a word mode subreg
@@ -3139,24 +3134,21 @@ find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known,
|| ((MEM_P (operand)
|| (REG_P (operand)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
-#if !WORD_REGISTER_OPERATIONS
- && (((GET_MODE_BITSIZE (GET_MODE (operand))
- < BIGGEST_ALIGNMENT)
- && (GET_MODE_SIZE (operand_mode[i])
- > GET_MODE_SIZE (GET_MODE (operand))))
+ && (WORD_REGISTER_OPERATIONS
+ || ((GET_MODE_BITSIZE (GET_MODE (operand))
+ < BIGGEST_ALIGNMENT)
+ && (GET_MODE_SIZE (operand_mode[i])
+ > GET_MODE_SIZE (GET_MODE (operand))))
|| BYTES_BIG_ENDIAN
-#ifdef LOAD_EXTEND_OP
- || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
+ || ((GET_MODE_SIZE (operand_mode[i])
+ <= UNITS_PER_WORD)
&& (GET_MODE_SIZE (GET_MODE (operand))
<= UNITS_PER_WORD)
&& (GET_MODE_SIZE (operand_mode[i])
> GET_MODE_SIZE (GET_MODE (operand)))
&& INTEGRAL_MODE_P (GET_MODE (operand))
- && LOAD_EXTEND_OP (GET_MODE (operand)) != UNKNOWN)
-#endif
- )
-#endif
- )
+ && LOAD_EXTEND_OP (GET_MODE (operand))
+ != UNKNOWN)))
)
force_reload = 1;
}
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 4b9c7c7dcaf..4ee3840850e 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -2819,18 +2819,16 @@ eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn,
if (MEM_P (new_rtx)
&& ((x_size < new_size
-#if WORD_REGISTER_OPERATIONS
- /* On these machines, combine can create rtl of the form
+ /* On RISC machines, combine can create rtl of the form
(set (subreg:m1 (reg:m2 R) 0) ...)
where m1 < m2, and expects something interesting to
happen to the entire word. Moreover, it will use the
(reg:m2 R) later, expecting all bits to be preserved.
So if the number of words is the same, preserve the
subreg so that push_reload can see it. */
- && ! ((x_size - 1) / UNITS_PER_WORD
- == (new_size -1 ) / UNITS_PER_WORD)
-#endif
- )
+ && !(WORD_REGISTER_OPERATIONS
+ && (x_size - 1) / UNITS_PER_WORD
+ == (new_size -1 ) / UNITS_PER_WORD))
|| x_size == new_size)
)
return adjust_address_nv (new_rtx, GET_MODE (x), SUBREG_BYTE (x));
@@ -8703,7 +8701,6 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
#endif
else if (REG_P (out) && UNARY_P (in))
{
- rtx insn;
rtx op1;
rtx out_moded;
rtx_insn *set;
@@ -8728,13 +8725,13 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
gen_reload (out_moded, op1, opnum, type);
- insn = gen_rtx_SET (out, gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in),
- out_moded));
- insn = emit_insn_if_valid_for_reload (insn);
+ rtx temp = gen_rtx_SET (out, gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in),
+ out_moded));
+ rtx_insn *insn = emit_insn_if_valid_for_reload (temp);
if (insn)
{
set_unique_reg_note (insn, REG_EQUIV, in);
- return as_a <rtx_insn *> (insn);
+ return insn;
}
fatal_insn ("failure trying to reload:", set);
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 799d27b064f..caad82a0305 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -222,11 +222,11 @@ static void steal_delay_list_from_fallthrough (rtx_insn *, rtx, rtx_sequence *,
static void try_merge_delay_insns (rtx_insn *, rtx_insn *);
static rtx_insn *redundant_insn (rtx, rtx_insn *, const vec<rtx_insn *> &);
static int own_thread_p (rtx, rtx, int);
-static void update_block (rtx_insn *, rtx);
+static void update_block (rtx_insn *, rtx_insn *);
static int reorg_redirect_jump (rtx_jump_insn *, rtx);
static void update_reg_dead_notes (rtx_insn *, rtx_insn *);
static void fix_reg_dead_note (rtx_insn *, rtx);
-static void update_reg_unused_notes (rtx, rtx);
+static void update_reg_unused_notes (rtx_insn *, rtx);
static void fill_simple_delay_slots (int);
static void fill_slots_from_thread (rtx_jump_insn *, rtx, rtx, rtx,
int, int, int, int,
@@ -1703,7 +1703,7 @@ own_thread_p (rtx thread, rtx label, int allow_fallthrough)
BARRIER in relax_delay_slots. */
static void
-update_block (rtx_insn *insn, rtx where)
+update_block (rtx_insn *insn, rtx_insn *where)
{
/* Ignore if this was in a delay slot and it came from the target of
a branch. */
@@ -1805,7 +1805,7 @@ fix_reg_dead_note (rtx_insn *start_insn, rtx stop_insn)
does. */
static void
-update_reg_unused_notes (rtx insn, rtx redundant_insn)
+update_reg_unused_notes (rtx_insn *insn, rtx redundant_insn)
{
rtx link, next;
@@ -3118,7 +3118,6 @@ relax_delay_slots (rtx_insn *first)
{
rtx_insn *insn, *next;
rtx_sequence *pat;
- rtx trial;
rtx_insn *delay_insn;
rtx target_label;
@@ -3271,10 +3270,10 @@ relax_delay_slots (rtx_insn *first)
for (i = 0; i < XVECLEN (pat, 0); i++)
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
- trial = PREV_INSN (insn);
+ rtx_insn *prev = PREV_INSN (insn);
delete_related_insns (insn);
gcc_assert (GET_CODE (pat) == SEQUENCE);
- add_insn_after (delay_insn, trial, NULL);
+ add_insn_after (delay_insn, prev, NULL);
after = delay_insn;
for (i = 1; i < pat->len (); i++)
after = emit_copy_of_insn_after (pat->insn (i), after);
@@ -3295,9 +3294,9 @@ relax_delay_slots (rtx_insn *first)
/* If this jump goes to another unconditional jump, thread it, but
don't convert a jump into a RETURN here. */
- trial = skip_consecutive_labels (follow_jumps (target_label,
- delay_jump_insn,
- &crossing));
+ rtx trial = skip_consecutive_labels (follow_jumps (target_label,
+ delay_jump_insn,
+ &crossing));
if (ANY_RETURN_P (trial))
trial = find_end_label (trial);
@@ -3401,10 +3400,10 @@ relax_delay_slots (rtx_insn *first)
for (i = 0; i < XVECLEN (pat, 0); i++)
INSN_FROM_TARGET_P (XVECEXP (pat, 0, i)) = 0;
- trial = PREV_INSN (insn);
+ rtx_insn *prev = PREV_INSN (insn);
delete_related_insns (insn);
gcc_assert (GET_CODE (pat) == SEQUENCE);
- add_insn_after (delay_jump_insn, trial, NULL);
+ add_insn_after (delay_jump_insn, prev, NULL);
after = delay_jump_insn;
for (i = 1; i < pat->len (); i++)
after = emit_copy_of_insn_after (pat->insn (i), after);
diff --git a/gcc/rtl-tests.c b/gcc/rtl-tests.c
index 4e534b2316f..228226bbb68 100644
--- a/gcc/rtl-tests.c
+++ b/gcc/rtl-tests.c
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgbuild.h"
#include "print-rtl.h"
#include "selftest.h"
+#include "selftest-rtl.h"
#include "function.h"
#include "memmodel.h"
#include "emit-rtl.h"
@@ -60,7 +61,7 @@ verify_print_pattern (const char *expected, rtx pat)
/* Verify that X is dumped as EXPECTED_DUMP, using compact mode.
Use LOC as the effective location when reporting errors. */
-static void
+void
assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x)
{
named_temp_file tmp_out (".rtl");
@@ -74,18 +75,13 @@ assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x)
free (dump);
}
-/* Verify that RTX is dumped as EXPECTED_DUMP, using compact mode. */
-
-#define ASSERT_RTL_DUMP_EQ(EXPECTED_DUMP, RTX) \
- assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX))
-
/* Verify that regs are dumped as expected (in compact mode). */
static void
test_dumping_regs ()
{
/* Dumps of hard regs contain a target-specific name, so we don't test
- it here. */
+ it here; this can be tested in target-specific selftests. */
/* Test dumping of virtual regs. The various virtual regs are inited as
Pmode, so this is target-specific. The tests below assume DImode, so
@@ -126,7 +122,7 @@ test_dumping_insns ()
/* Labels. */
rtx_insn *label = gen_label_rtx ();
CODE_LABEL_NUMBER (label) = 42;
- ASSERT_RTL_DUMP_EQ ("(clabel 0 42 \"\")\n", label);
+ ASSERT_RTL_DUMP_EQ ("(clabel 0 42)\n", label);
LABEL_NAME (label)= "some_label";
ASSERT_RTL_DUMP_EQ ("(clabel 0 42 (\"some_label\"))\n", label);
@@ -180,8 +176,7 @@ test_uncond_jump ()
ASSERT_TRUE (control_flow_insn_p (jump_insn));
ASSERT_RTL_DUMP_EQ ("(cjump_insn 1 (set (pc)\n"
- " (label_ref 0))\n"
- " (nil))\n",
+ " (label_ref 0)))\n",
jump_insn);
}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index d054c6c905d..7a44e3bd3ef 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2858,7 +2858,7 @@ extern rtx_call_insn *last_call_insn (void);
extern rtx_insn *previous_insn (rtx_insn *);
extern rtx_insn *next_insn (rtx_insn *);
extern rtx_insn *prev_nonnote_insn (rtx_insn *);
-extern rtx_insn *prev_nonnote_insn_bb (rtx);
+extern rtx_insn *prev_nonnote_insn_bb (rtx_insn *);
extern rtx_insn *next_nonnote_insn (rtx_insn *);
extern rtx_insn *next_nonnote_insn_bb (rtx_insn *);
extern rtx_insn *prev_nondebug_insn (rtx_insn *);
@@ -3019,7 +3019,8 @@ extern rtx alloc_reg_note (enum reg_note, rtx, rtx);
extern void add_reg_note (rtx, enum reg_note, rtx);
extern void add_int_reg_note (rtx, enum reg_note, int);
extern void add_shallow_copy_of_reg_note (rtx_insn *, rtx);
-extern void remove_note (rtx, const_rtx);
+extern rtx duplicate_reg_note (rtx);
+extern void remove_note (rtx_insn *, const_rtx);
extern void remove_reg_equal_equiv_notes (rtx_insn *);
extern void remove_reg_equal_equiv_notes_for_regno (unsigned int);
extern int side_effects_p (const_rtx);
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 4e600c0de6d..4d7aad0dff0 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -2304,10 +2304,24 @@ add_shallow_copy_of_reg_note (rtx_insn *insn, rtx note)
add_reg_note (insn, REG_NOTE_KIND (note), XEXP (note, 0));
}
+/* Duplicate NOTE and return the copy. */
+rtx
+duplicate_reg_note (rtx note)
+{
+ reg_note kind = REG_NOTE_KIND (note);
+
+ if (GET_CODE (note) == INT_LIST)
+ return gen_rtx_INT_LIST ((machine_mode) kind, XINT (note, 0), NULL_RTX);
+ else if (GET_CODE (note) == EXPR_LIST)
+ return alloc_reg_note (kind, copy_insn_1 (XEXP (note, 0)), NULL_RTX);
+ else
+ return alloc_reg_note (kind, XEXP (note, 0), NULL_RTX);
+}
+
/* Remove register note NOTE from the REG_NOTES of INSN. */
void
-remove_note (rtx insn, const_rtx note)
+remove_note (rtx_insn *insn, const_rtx note)
{
rtx link;
@@ -2328,7 +2342,7 @@ remove_note (rtx insn, const_rtx note)
{
case REG_EQUAL:
case REG_EQUIV:
- df_notes_rescan (as_a <rtx_insn *> (insn));
+ df_notes_rescan (insn);
break;
default:
break;
@@ -4361,13 +4375,11 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
return UINTVAL (x);
case MEM:
-#ifdef LOAD_EXTEND_OP
/* In many, if not most, RISC machines, reading a byte from memory
zeros the rest of the register. Noticing that fact saves a lot
of extra zero-extends. */
if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND)
nonzero &= GET_MODE_MASK (GET_MODE (x));
-#endif
break;
case EQ: case NE:
@@ -4567,19 +4579,17 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
known_x, known_mode, known_ret);
-#ifdef LOAD_EXTEND_OP
- /* If this is a typical RISC machine, we only have to worry
- about the way loads are extended. */
- if (WORD_REGISTER_OPERATIONS
- && ((LOAD_EXTEND_OP (inner_mode) == SIGN_EXTEND
+ /* On many CISC machines, accessing an object in a wider mode
+ causes the high-order bits to become undefined. So they are
+ not known to be zero. */
+ if (!WORD_REGISTER_OPERATIONS
+ /* If this is a typical RISC machine, we only have to worry
+ about the way loads are extended. */
+ || ((LOAD_EXTEND_OP (inner_mode) == SIGN_EXTEND
? val_signbit_known_set_p (inner_mode, nonzero)
: LOAD_EXTEND_OP (inner_mode) != ZERO_EXTEND)
|| !MEM_P (SUBREG_REG (x))))
-#endif
{
- /* On many CISC machines, accessing an object in a wider mode
- causes the high-order bits to become undefined. So they are
- not known to be zero. */
if (GET_MODE_PRECISION (GET_MODE (x))
> GET_MODE_PRECISION (inner_mode))
nonzero |= (GET_MODE_MASK (GET_MODE (x))
@@ -4824,10 +4834,7 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
than a word and loads of that size don't sign extend, we can say
nothing about the high order bits. */
if (GET_MODE_PRECISION (GET_MODE (x)) < BITS_PER_WORD
-#ifdef LOAD_EXTEND_OP
- && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
-#endif
- )
+ && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND)
return 1;
}
@@ -4868,12 +4875,10 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
break;
case MEM:
-#ifdef LOAD_EXTEND_OP
/* Some RISC machines sign-extend all loads of smaller than a word. */
if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND)
return MAX (1, ((int) bitwidth
- (int) GET_MODE_PRECISION (GET_MODE (x)) + 1));
-#endif
break;
case CONST_INT:
@@ -4910,7 +4915,6 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
- bitwidth)));
}
-#ifdef LOAD_EXTEND_OP
/* For paradoxical SUBREGs on machines where all register operations
affect the entire register, just look inside. Note that we are
passing MODE to the recursive call, so the number of sign bit copies
@@ -4927,7 +4931,6 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
&& MEM_P (SUBREG_REG (x)))
return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
known_x, known_mode, known_ret);
-#endif
break;
case SIGN_EXTRACT:
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 303c1e46df4..3db08a7b702 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -34,7 +34,7 @@ DEF_BUILTIN_STUB(BEGIN_SANITIZER_BUILTINS, (const char *)0)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_VERSION_MISMATCH_CHECK,
- "__asan_version_mismatch_check_v6",
+ "__asan_version_mismatch_check_v8",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
/* Do not reorder the BUILT_IN_ASAN_{REPORT,CHECK}* builtins, e.g. cfgcleanup.c
relies on this order. */
@@ -165,6 +165,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT,
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT,
"__asan_after_dynamic_init",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_CLOBBER_N, "__asan_poison_stack_memory",
+ BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNCLOBBER_N, "__asan_unpoison_stack_memory",
+ BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
/* Thread Sanitizer */
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 8a6fbe9da95..320e14e9421 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -732,6 +732,9 @@ pass_sanopt::execute (function *fun)
case IFN_ASAN_CHECK:
no_next = asan_expand_check_ifn (&gsi, use_calls);
break;
+ case IFN_ASAN_MARK:
+ no_next = asan_expand_mark_ifn (&gsi);
+ break;
default:
break;
}
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index 26bc1422167..02157b4c736 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -5762,6 +5762,11 @@ create_copy_of_insn_rtx (rtx insn_rtx)
res = create_insn_rtx_from_pattern (copy_rtx (PATTERN (insn_rtx)),
NULL_RTX);
+ /* Locate the end of existing REG_NOTES in NEW_RTX. */
+ rtx *ptail = &REG_NOTES (res);
+ while (*ptail != NULL_RTX)
+ ptail = &XEXP (*ptail, 1);
+
/* Copy all REG_NOTES except REG_EQUAL/REG_EQUIV and REG_LABEL_OPERAND
since mark_jump_label will make them. REG_LABEL_TARGETs are created
there too, but are supposed to be sticky, so we copy them. */
@@ -5770,11 +5775,8 @@ create_copy_of_insn_rtx (rtx insn_rtx)
&& REG_NOTE_KIND (link) != REG_EQUAL
&& REG_NOTE_KIND (link) != REG_EQUIV)
{
- if (GET_CODE (link) == EXPR_LIST)
- add_reg_note (res, REG_NOTE_KIND (link),
- copy_insn_1 (XEXP (link, 0)));
- else
- add_reg_note (res, REG_NOTE_KIND (link), XEXP (link, 0));
+ *ptail = duplicate_reg_note (link);
+ ptail = &XEXP (*ptail, 1);
}
return res;
diff --git a/gcc/selftest-rtl.h b/gcc/selftest-rtl.h
new file mode 100644
index 00000000000..0f0e1673ab3
--- /dev/null
+++ b/gcc/selftest-rtl.h
@@ -0,0 +1,45 @@
+/* A self-testing framework, for use by -fself-test.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_SELFTEST_RTL_H
+#define GCC_SELFTEST_RTL_H
+
+/* The selftest code should entirely disappear in a production
+ configuration, hence we guard all of it with #if CHECKING_P. */
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that X is dumped as EXPECTED_DUMP, using compact mode.
+ Use LOC as the effective location when reporting errors. */
+
+extern void
+assert_rtl_dump_eq (const location &loc, const char *expected_dump, rtx x);
+
+/* Verify that RTX is dumped as EXPECTED_DUMP, using compact mode. */
+
+#define ASSERT_RTL_DUMP_EQ(EXPECTED_DUMP, RTX) \
+ assert_rtl_dump_eq (SELFTEST_LOCATION, (EXPECTED_DUMP), (RTX))
+
+} /* end of namespace selftest. */
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_SELFTEST_RTL_H */
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 54a9b0f6c7e..a4cdb555436 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "selftest.h"
#include "tree.h"
+#include "target.h"
#include "langhooks.h"
/* This function needed to be split out from selftest.c as it references
@@ -77,6 +78,12 @@ selftest::run_tests ()
/* This one relies on most of the above. */
function_tests_c_tests ();
+ /* Run any target-specific selftests. */
+ if (targetm.run_target_selftests)
+ targetm.run_target_selftests ();
+
+ store_merging_c_tests ();
+
/* Run any lang-specific selftests. */
lang_hooks.run_lang_selftests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 845eb01b125..dcce474be6e 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -179,6 +179,7 @@ extern void selftest_c_tests ();
extern void spellcheck_c_tests ();
extern void spellcheck_tree_c_tests ();
extern void sreal_c_tests ();
+extern void store_merging_c_tests ();
extern void typed_splay_tree_c_tests ();
extern void tree_c_tests ();
extern void tree_cfg_c_tests ();
diff --git a/gcc/target.def b/gcc/target.def
index 7dc1d6ec02d..2b357494ede 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2639,7 +2639,7 @@ DEFHOOK
insns are saved in @var{gen_seq}. They will be emitted when all the\n\
compares in the the conditional comparision are generated without error.\n\
@var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}.",
- rtx, (rtx *prep_seq, rtx *gen_seq, int code, tree op0, tree op1),
+ rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, int code, tree op0, tree op1),
NULL)
DEFHOOK
@@ -2656,7 +2656,7 @@ DEFHOOK
be appropriate for passing to @code{gen_ccmp_next} or @code{cbranch_optab}.\n\
@var{code} is the @code{rtx_code} of the compare for @var{op0} and @var{op1}.\n\
@var{bit_code} is @code{AND} or @code{IOR}, which is the op on the compares.",
- rtx, (rtx *prep_seq, rtx *gen_seq, rtx prev, int cmp_code, tree op0, tree op1, int bit_code),
+ rtx, (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev, int cmp_code, tree op0, tree op1, int bit_code),
NULL)
/* Return a new value for loop unroll size. */
@@ -5051,6 +5051,16 @@ DEFHOOK
machine_mode, (enum insn_code icode),
default_cstore_mode)
+/* This target hook allows the backend to compute the register pressure
+ classes to use. */
+DEFHOOK
+(compute_pressure_classes,
+ "A target hook which lets a backend compute the set of pressure classes to\
+ be used by those optimization passes which take register pressure into\
+ account, as opposed to letting IRA compute them. It returns the number of\
+ register classes stored in the array @var{pressure_classes}.",
+ int, (enum reg_class *pressure_classes), NULL)
+
/* True if a structure, union or array with MODE containing FIELD should
be accessed using BLKmode. */
DEFHOOK
@@ -5067,6 +5077,15 @@ Normally, this is not needed.",
bool, (const_tree field, machine_mode mode),
default_member_type_forces_blk)
+/* See tree-ssa-math-opts.c:divmod_candidate_p for conditions
+ that gate the divod transform. */
+DEFHOOK
+(expand_divmod_libfunc,
+ "Define this hook for enabling divmod transform if the port does not have\n\
+hardware divmod insn but defines target-specific divmod libfuncs.",
+ void, (rtx libfunc, machine_mode mode, rtx op0, rtx op1, rtx *quot, rtx *rem),
+ NULL)
+
/* Return the class for a secondary reload, and fill in extra information. */
DEFHOOK
(secondary_reload,
@@ -5944,6 +5963,24 @@ comparison code or operands.",
void, (int *code, rtx *op0, rtx *op1, bool op0_preserve_value),
default_canonicalize_comparison)
+DEFHOOK
+(min_arithmetic_precision,
+ "On some RISC architectures with 64-bit registers, the processor also\n\
+maintains 32-bit condition codes that make it possible to do real 32-bit\n\
+arithmetic, although the operations are performed on the full registers.\n\
+\n\
+On such architectures, defining this hook to 32 tells the compiler to try\n\
+using 32-bit arithmetical operations setting the condition codes instead\n\
+of doing full 64-bit arithmetic.\n\
+\n\
+More generally, define this hook on RISC architectures if you want the\n\
+compiler to try using arithmetical operations setting the condition codes\n\
+with a precision lower than the word precision.\n\
+\n\
+You need not define this hook if @code{WORD_REGISTER_OPERATIONS} is not\n\
+defined to 1.",
+ unsigned int, (void), default_min_arithmetic_precision)
+
DEFHOOKPOD
(atomic_test_and_set_trueval,
"This value should be set if the result written by\
@@ -6141,6 +6178,12 @@ HOOK_VECTOR_END (mode_switching)
#include "target-insns.def"
#undef DEF_TARGET_INSN
+DEFHOOK
+(run_target_selftests,
+ "If selftests are enabled, run any selftests for this target.",
+ void, (void),
+ NULL)
+
/* Close the 'struct gcc_target' definition. */
HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index d6fd8b8a77f..866747a9ddf 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2127,4 +2127,12 @@ default_max_noce_ifcvt_seq_cost (edge e)
return BRANCH_COST (true, predictable_p) * COSTS_N_INSNS (3);
}
+/* Default implementation of TARGET_MIN_ARITHMETIC_PRECISION. */
+
+unsigned int
+default_min_arithmetic_precision (void)
+{
+ return WORD_REGISTER_OPERATIONS ? BITS_PER_WORD : BITS_PER_UNIT;
+}
+
#include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index afb1c00caf4..94f5e31f80f 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -260,7 +260,7 @@ extern void default_setup_incoming_vararg_bounds (cumulative_args_t ca ATTRIBUTE
int second_time ATTRIBUTE_UNUSED);
extern bool default_optab_supported_p (int, machine_mode, machine_mode,
optimization_type);
-
extern unsigned int default_max_noce_ifcvt_seq_cost (edge);
+extern unsigned int default_min_arithmetic_precision (void);
#endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3a4041de42d..5da9220fe71 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,6 +1,603 @@
+2016-11-09 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ PR testsuite/78269
+ * g++.dg/cpp1z/noexcept-type9.C: Make it a compile test.
+
+2016-11-09 Paul Thomas <pault@gcc.gnu.org>
+
+ * gfortran.dg/move_alloc_18.f90: New test.
+
+2016-11-09 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ PR middle-end/78256
+ * gcc.dg/pr35691-1.c (foo): Use & instead of &&.
+ * gcc.dg/pr35691-2.c (foo): Use | instead of ||.
+
+2016-11-09 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/71894
+ * gfortran.dg/class_59.f90: New test.
+
+2016-11-09 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78007
+ * gcc.dg/vect/vect-bswap32.c: Adjust.
+ * gcc.dg/vect/vect-bswap64.c: Likewise.
+
+2016-11-09 Kugan Vivekanandarajah <kuganv@linaro.org>
+
+ * gcc.dg/ipa/vrp7.c: New test.
+
+2016-11-09 Kugan Vivekanandarajah <kuganv@linaro.org>
+
+ PR ipa/78121
+ * gcc.dg/ipa/pr78121.c: New test.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * c-c++-common/asan/default_options.h: New file.
+ * c-c++-common/asan/strcasestr-1.c: New test.
+ * c-c++-common/asan/strcasestr-2.c: Likewise.
+ * c-c++-common/asan/strcspn-1.c: Likewise.
+ * c-c++-common/asan/strcspn-2.c: Likewise.
+ * c-c++-common/asan/strpbrk-1.c: Likewise.
+ * c-c++-common/asan/strpbrk-2.c: Likewise.
+ * c-c++-common/asan/strspn-1.c: Likewise.
+ * c-c++-common/asan/strspn-2.c: Likewise.
+ * c-c++-common/asan/strstr-1.c: Likewise.
+ * c-c++-common/asan/strstr-2.c: Likewise.
+ * c-c++-common/asan/halt_on_error_suppress_equal_pcs-1.c: Likewise.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * c-c++-common/asan/null-deref-1.c: Adjust testcase.
+
+2016-11-08 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/68440
+ * gfortran.dg/class_58.f90: New test.
+
+2016-11-08 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/70799
+ * gcc.target/i386/pr70799-2.c: New test.
+
+2016-11-08 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/77596
+ * gfortran.dg/proc_ptr_comp_46.f90: New test.
+
+2016-11-08 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/vect/pr56541.c: Xfail on !vect_cond_mixed targets.
+
+2016-11-08 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/pr71347.c: Drop xfail.
+
+2016-11-08 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/vect/vect-cond-2.c: Drop xfail.
+
+2016-11-08 Martin Liska <mliska@suse.cz>
+
+ PR testsuite/78242
+ * g++.dg/asan/use-after-scope-4.C: New test.
+ * g++.dg/asan/use-after-scope-types-4.C: Update scanned pattern.
+ * gcc.dg/asan/use-after-scope-8.c: Remove.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/vect/vect-nb-iter-ub-2.c: Adjust.
+
+2016-11-08 Tamar Christina <tamar.christina@arm.com>
+
+ PR testsuite/78136
+ * gcc.dg/cpp/trad/trad.exp
+ (dg-runtest): Added $srcdir/$subdir/ to Include dirs.
+ * gcc.dg/cpp/trad/include.c: Use local header file.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78205
+ * gcc.dg/vect/bb-slp-pr78205.c: New testcase.
+
+2016-11-08 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78224
+ * g++.dg/torture/pr78224.C: New testcase.
+
+2016-11-08 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
+
+ * gcc.dg/store_merging_1.c: Require store_merge.
+ * gcc.dg/store_merging_2.c: Likewise.
+ * gcc.dg/store_merging_4.c: Likewise.
+ * gcc.dg/store_merging_5.c: Likewise.
+ * gcc.dg/store_merging_6.c: Likewise.
+ * gcc.dg/store_merging_7.c: Likewise.
+ * gcc.dg/store_merging_8.c: Likewise.
+ * lib/target-supports.exp (check_effective_target_store_merge): New.
+
+2016-11-07 David Edelsohn <dje.gcc@gmail.com>
+
+ * gcc.target/powerpc/fold-vec-add-1.c: Add dg-options -maltivec.
+ * gcc.target/powerpc/fold-vec-add-2.c: Add dg-options -maltivec.
+ * gcc.target/powerpc/fold-vec-add-3.c: Add dg-options -maltivec.
+ * gcc.target/powerpc/fold-vec-add-4.c: Add dg-options -maltivec
+ -mvsx -mpower8-vector.
+ * gcc.target/powerpc/fold-vec-add-5.c: Add dg-options -maltivec -mno-vsx.
+ * gcc.target/powerpc/fold-vec-add-6.c: Add dg-options -maltivec -mvsx.
+ * gcc.target/powerpc/fold-vec-add-7.c: Add dg-options -maltivec
+ -mvsx -mpower8-vector.
+
+2016-11-07 David Edelsohn <dje.gcc@gmail.com>
+
+ * lib/scanasm.exp (hidden-scan-for): Add XCOFF support.
+
+ * gfortran.dg/implicit_class_1.f90: Skip on AIX.
+ * gcc.dg/visibility-14.c: XFAIL AIX.
+ * gcc.dg/visibility-15.c: XFAIL AIX.
+ * gcc.dg/visibility-16.c: XFAIL AIX.
+ * gcc.dg/visibility-17.c: XFAIL AIX.
+ * gcc.dg/visibility-18.c: XFAIL AIX.
+ * gcc.dg/visibility-19.c: XFAIL AIX.
+ * g++.dg/ext/visibility/anon1.C: XFAIL AIX.
+ * g++.dg/ext/visibility/anon2.C: XFAIL AIX.
+ * g++.dg/ext/visibility/pragma-override1.C: XFAIL AIX.
+ * g++.dg/ext/visibility/pragma-override2.C: XFAIL AIX.
+
+2016-11-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/78227
+ * gcc.target/i386/pr78227-1.c: New test.
+ * gcc.target/i386/pr78227-2.c: New test.
+
+2016-11-07 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ PR middle-end/35691
+ * gcc.dg/pr35691-1.c: New test-case.
+ * gcc.dg/pr35691-2.c: Likewise.
+
+2016-11-07 Bernd Schmidt <bschmidt@redhat.com>
+
+ PR rtl-optimization/77309
+ * gcc.dg/torture/pr77309.c: New test.
+
+2016-11-07 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/71529
+ * gcc.target/i386/pr71529.C: Moved to ...
+ * g++.dg/opt/pr71529.C: ... here. New test. Guard for i?86/x86_64.
+
+ PR target/64411
+ * gcc.target/i386/pr64411.C: Moved to ...
+ * g++.dg/opt/pr64411.C: ... here. New test. Guard for i?86/x86_64
+ lp64.
+
+ PR target/65105
+ * gcc.target/i386/pr65105-4.C: Moved to ...
+ * g++.dg/opt/pr65105-4.C: ... here. New test. Guard for i?86/x86_64.
+ Run into compile test rather than execute test.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR target/78229
+ * g++.dg/pr78229.C: New testcase.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78218
+ * gcc.dg/torture/pr78218.c: New testcase.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78228
+ * gcc.dg/tree-ssa/phi-opt-15.c: New testcase.
+
+2016-11-07 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR target/77822
+ * g++.dg/torture/pr77822.C: New test.
+
+2016-11-07 Martin Liska <mliska@suse.cz>
+
+ * c-c++-common/asan/force-inline-opt0-1.c: Disable
+ -f-sanitize-address-use-after-scope.
+ * c-c++-common/asan/inc.c: Change number of expected ASAN_CHECK
+ internal fn calls.
+ * g++.dg/asan/use-after-scope-1.C: New test.
+ * g++.dg/asan/use-after-scope-2.C: Likewise.
+ * g++.dg/asan/use-after-scope-3.C: Likewise.
+ * g++.dg/asan/use-after-scope-types-1.C: Likewise.
+ * g++.dg/asan/use-after-scope-types-2.C: Likewise.
+ * g++.dg/asan/use-after-scope-types-3.C: Likewise.
+ * g++.dg/asan/use-after-scope-types-4.C: Likewise.
+ * g++.dg/asan/use-after-scope-types-5.C: Likewise.
+ * g++.dg/asan/use-after-scope-types.h: Likewise.
+ * gcc.dg/asan/use-after-scope-1.c: Likewise.
+ * gcc.dg/asan/use-after-scope-2.c: Likewise.
+ * gcc.dg/asan/use-after-scope-3.c: Likewise.
+ * gcc.dg/asan/use-after-scope-4.c: Likewise.
+ * gcc.dg/asan/use-after-scope-5.c: Likewise.
+ * gcc.dg/asan/use-after-scope-6.c: Likewise.
+ * gcc.dg/asan/use-after-scope-7.c: Likewise.
+ * gcc.dg/asan/use-after-scope-8.c: Likewise.
+ * gcc.dg/asan/use-after-scope-9.c: Likewise.
+ * gcc.dg/asan/use-after-scope-switch-1.c: Likewise.
+ * gcc.dg/asan/use-after-scope-switch-2.c: Likewise.
+ * gcc.dg/asan/use-after-scope-switch-3.c: Likewise.
+ * gcc.dg/asan/use-after-scope-goto-1.c: Likewise.
+ * gcc.dg/asan/use-after-scope-goto-2.c: Likewise.
+
+2016-11-07 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78189
+ * g++.dg/torture/pr78189.C: New testcase.
+
+2016-11-06 David Edelsohn <dje.gcc@gmail.com>
+
+ * gcc.dg/Wtrampolines.c: XFAIL AIX.
+
+2016-11-06 Andre Vehreschild <vehre@gcc.gnu.org>
+
+ * gfortran.dg/allocate_with_source_14.f03: Fixed number mallocs
+ occuring.
+
+2016-11-06 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/78221
+ * arith.c (gfc_complex2real): Change gfc_warning_now to
+ gfc_warning.
+
+2016-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ * gfortran.dg/move_alloc_17.f03: New test.
+
+2016-11-05 Richard Biener <rguenther@suse.de>
+
+ PR bootstrap/78188
+ * g++.dg/ipa/pr78188.C: New test.
+
+2016-11-05 Janus Weil <janus@gcc.gnu.org>
+ Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR fortran/69495
+ * gfortran.dg/elemental_optional_args_6.f90: Use -Wpedantic flag.
+
+2016-11-05 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/67564
+ * gfortran.dg/select_type_39.f03: New test.
+
+2016-11-04 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/64933
+ * gfortran.dg/associate_23.f90: New test.
+
+2016-11-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/77834
+ * gcc.dg/pr77834.c: New test.
+
+2016-11-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/67980
+ * g++.dg/cpp1y/pr67980.C: New.
+
+2016-11-04 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-add-1.c: New.
+ * gcc.target/powerpc/fold-vec-add-2.c: New.
+ * gcc.target/powerpc/fold-vec-add-3.c: New.
+ * gcc.target/powerpc/fold-vec-add-4.c: New.
+ * gcc.target/powerpc/fold-vec-add-5.c: New.
+ * gcc.target/powerpc/fold-vec-add-6.c: New.
+ * gcc.target/powerpc/fold-vec-add-7.c: New.
+
+2016-11-04 Toma Tabacu <toma.tabacu@imgtec.com>
+
+ * gcc.target/mips/mips.exp (mips-dg-options): Downgrade to R5
+ for -mbranch-likely, infer -mno-branch-likely for R6.
+
+2016-11-04 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR c++/71973
+ * g++.dg/cpp1y/lambda-generic-udt.C: Fix builtin function declaration.
+ * g++.dg/init/new15.C: Likewise.
+ * g++.dg/ipa/inline-1.C: Likewise.
+ * g++.dg/ipa/inline-2.C: Likewise.
+ * g++.dg/lto/20080908-1_0.C: Likewise.
+ * g++.dg/tc1/dr20.C: Likewise.
+ * g++.dg/tree-ssa/inline-1.C: Likewise.
+ * g++.dg/tree-ssa/inline-2.C: Likewise.
+ * g++.old-deja/g++.law/except1.C: Likewise.
+ * g++.old-deja/g++.other/vbase5.C: Likewise.
+ * obj-c++.dg/lto/trivial-1_0.mm: Likewise.
+
+2016-11-04 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/78210
+ * gcc.dg/tree-ssa/slsr-8.c: Fix slsr scan to include the
+ possibility of widening multiplies.
+
+2016-11-04 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/78185
+ * gcc.dg/pr78185.c: New testcase.
+
+2016-10-04 David Edelsohn <dje.gcc@gmail.com>
+
+ * g++.dg/debug/dwarf2/ref-3.C: XFAIL AIX.
+ * g++.dg/debug/dwarf2/ref-4.C: XFAIL AIX.
+
+2016-11-03 Jakub Jelinek <jakub@redhat.com>
+ Alexandre Oliva <aoliva@redhat.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR debug/28767
+ PR debug/56974
+ * g++.dg/debug/dwarf2/ptrdmem-1.C: New test.
+ * g++.dg/debug/dwarf2/ref-3.C: New test.
+ * g++.dg/debug/dwarf2/ref-4.C: New test.
+ * g++.dg/debug/dwarf2/refqual-1.C: New test.
+ * g++.dg/debug/dwarf2/refqual-2.C: New test.
+
+2016-11-03 Fritz Reese <fritzoreese@gmail.com>
+
+ * gfortran.dg/dec_exp_1.f90: New test.
+ * gfortran.dg/dec_exp_2.f90: Likewise.
+ * gfortran.dg/dec_exp_3.f90: Likewise.
+
+2016-11-03 Fritz O. Reese <fritzoreese@gmail.com>
+
+ * gfortran.dg/dec_parameter_1.f: New test.
+ * gfortran.dg/dec_parameter_2.f90: Likewise.
+ * gfortran.dg/dec_parameter_3.f90: Likewise.
+ * gfortran.dg/dec_parameter_4.f90: Likewise.
+
+2016-11-03 Martin Liska <mliska@suse.cz>
+
+ * gcc.dg/no_profile_instrument_function-attr-1.c: Update scanned
+ output.
+ * gcc.dg/tree-prof/time-profiler-3.c: New test.
+
+2016-11-03 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR libgcc/78067
+ * gcc.dg/torture/fp-int-convert.h: Add more conversion tests.
+
+2016-11-03 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
+
+ * gcc.c-torture/execute/pr78170.c: Require int32plus.
+
+2016-11-02 Max Filippov <jcmvbkbc@gmail.com>
+
+ * gcc.c-torture/compile/20001226-1.c: Don't xfail on xtensa.
+
+2016-11-01 Tamar Christina <tamar.christina@arm.com>
+
+ * gcc.target/arm/simd/vmaxnm_f32_1.c (dg-require-effective-target):
+ Check for arm_v8_neon_hw.
+ * gcc.target/arm/simd/vmaxnmq_f32_1.c (dg-require-effective-target):
+ Likewise.
+ * gcc.target/arm/simd/vminnm_f32_1.c (dg-require-effective-target):
+ Likewise.
+ * gcc.target/arm/simd/vminnmq_f32_1.c(dg-require-effective-target):
+ Likewise.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/store_merging_8.c: New testcase.
+
+2016-11-02 Fritz O. Reese <fritzoreese@gmail.com>
+
+ * gfortran.dg/warn_argument_mismatch_1.f90: New test.
+
+2016-11-02 David Edelsohn <dje.gcc@gmail.com>
+
+ * gcc.dg/debug/dwarf2/prod-options.c: XFAIL AIX.
+ * gcc.dg/debug/dwarf2/pr71855.c: XFAIL AIX.
+ * gcc.dg/addr_equal_1.c: XFAIL AIX.
+ * gcc.dg/pr65779.c: XFAIL AIX.
+ * gcc.dg/pr70405.c: XFAIL AIX.
+
+ * g++.dg/debug/dwarf2/inline-var-1.C: XFAIL AIX.
+ * g++.dg/debug/dwarf2/ref-2.C: XFAIL AIX.
+ * g++.dg/debug/dwarf2/constexpr-var-1.C: XFAIL AIX.
+
+2016-11-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * lib/target-supports.exp (check_gc_sections_available): Use
+ -print-prog-name=ld to determine linker used.
+
+2016-11-02 Martin Liska <mliska@suse.cz>
+
+ * gcc.dg/tree-ssa/builtins-folding-gimple-ub.c (main): Add
+ test case.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR tree-optimization/78170
+ * gcc.c-torture/execute/pr78170.c: New test.
+
+2016-11-02 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ PR tree-optimization/78162
+ * gcc.c-torture/compile/pr78162.c: New test.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/78035
+ PR tree-optimization/77964
+ * gcc.target/i386/pr78035.c: New testcase.
+
+2016-11-02 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/tree-ssa/vrp111.c: New testcase.
+ * gcc.dg/tree-ssa/pr20702.c: Disable EVRP.
+ * gcc.dg/tree-ssa/pr21086.c: Likewise.
+ * gcc.dg/tree-ssa/pr58480.c: Likewise.
+ * gcc.dg/tree-ssa/vrp08.c: Likewise.
+
+2016-11-01 David Edelsohn <dje.gcc@gmail.com>
+
+ * gfortran.dg/pr70937.f90: require-effective-target lto.
+
+2016-11-01 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/69544
+ * gfortran.dg/where_6.f90: New test.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/debug/dwarf2/inline-var-1.C: New test.
+
+2016-11-01 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/69544
+ * gfortran.dg/where_5.f90: New test.
+
+2016-11-01 Bilyan Borisov <bilyan.borisov@arm.com>
+
+ * gcc.target/arm/simd/vmaxnm_f32_1.c: New.
+ * gcc.target/arm/simd/vmaxnmq_f32_1.c: Likewise.
+ * gcc.target/arm/simd/vminnm_f32_1.c: Likewise.
+ * gcc.target/arm/simd/vminnmq_f32_1.c: Likewise.
+
+2016-11-01 Uros Bizjak <ubizjak@gmail.com>
+
+ * lib/target-supports.exp: Normalize order of i?86 and x86_64 targets.
+ Whitespace fixes.
+ (check_effective_target_vect_cmdline_needed): Check
+ is-effective-target ia32 for x86 targets.
+ (check_effective_target_vect_simd_clones): Simplify condition.
+ (check_effective_target_vect_double): Ditto.
+ (check_effective_target_vect_aligned_arrays): Check
+ is-effective-target ia32 for x86 targets. Simplify condition.
+ (check_effective_target_vect_multiple_sizes): Simplify condition.
+ (check_effective_target_sqrt_insn): Add i?86-*-* target.
+ (check_effective_target_sync_int_128): Simplify condition.
+ (check_effective_target_sync_int_128_runtime): Ditto.
+ (check_effective_target_sync_long_long_runtime): Ditto.
+ (check_effective_target_divmod): Add i?86-*-* target.
+
+2016-10-31 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/vsx-extract-4.c: New test.
+ * gcc.target/powerpc/vsx-extract-5.c: Likewise.
+
+2016-10-31 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/54679
+ * gfortran.dg/fmt_l.f90: Update test.
+ * gfortran.dg/fmt_l0.f90: New test.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/78089
+ * c-c++-common/builtin-shuffle-1.c: New test.
+ * g++.dg/cpp0x/addressof3.C: New test.
+
+2016-10-31 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Add tests for a const member and a reference member for launder.
+ * g++.dg/cpp1z/launder3.C: New.
+ * g++.dg/cpp1z/launder4.C: Likewise.
+ * g++.dg/cpp1z/launder5.C: Likewise.
+ * g++.dg/cpp1z/launder5.cc: Likewise.
+ * g++.dg/cpp1z/launder5.h: Likewise.
+ * g++.dg/cpp1z/launder6.C: Likewise.
+ * g++.dg/cpp1z/launder6.cc: Likewise.
+ * g++.dg/cpp1z/launder6.h: Likewise.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77948
+ * g++.dg/cpp0x/pr77948-1.C: New test.
+ * g++.dg/cpp0x/pr77948-2.C: New test.
+ * g++.dg/cpp0x/pr77948-3.C: New test.
+ * g++.dg/cpp0x/pr77948-4.C: New test.
+ * g++.dg/cpp0x/pr77948-5.C: New test.
+ * g++.dg/cpp0x/pr77948-6.C: New test.
+
+ PR tree-optimization/77860
+ * gcc.dg/pr77860.c: New test.
+
+2016-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/77886
+ * g++.dg/warn/Wimplicit-fallthrough-2.C: New test.
+
+2016-10-31 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
+
+ * gcc.dg/lto/pr60449_0.c: Skip for avr.
+
+2016-10-30 Le-Chun Wu <lcwu@google.com>
+ Mark Wielaard <mjw@redhat.com>
+
+ * gcc.dg/Wshadow-compatible-local-1.c: New test.
+ * gcc.dg/Wshadow-local-1.c: Likewise.
+ * gcc.dg/Wshadow-local-2.c: Likewise.
+ * g++.dg/warn/Wshadow-compatible-local-1.C: Likewise.
+ * g++.dg/warn/Wshadow-local-1.C: Likewise.
+ * g++.dg/warn/Wshadow-local-2.C: Likewise.
+
+2016-10-30 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/71915
+ PR tree-optimization/71490
+ * gcc.dg/tree-ssa/pr54245.c: Delete.
+ * gcc.dg/tree-ssa/slsr-8.c: Adjust for new optimization and
+ document why.
+
+2016-10-30 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/78123
+ * gfortran.dg/fmt_t_9.f: New test.
+
+2016-10-30 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/67219
+ * gfortran.dg/pr67219.f90: New test.
+
+2016-10-29 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/77919
+ * g++.dg/torture/pr77919-2.C: New test.
+
+ PR target/78148
+ * gcc.dg/pr78148.c: New test.
+
+2016-10-28 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.target/sparc/overflow-3.c: Replace and move old one to...
+ * gcc.target/sparc/overflow-4.c: ...here.
+ * gcc.target/sparc/overflow-5.c: New test.
+
+2016-10-28 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+ Kugan Vivekanandarajah <kuganv@linaro.org>
+ Jim Wilson <jim.wilson@linaro.org>
+
+ PR tree-optimization/43721
+ * lib/target-supports.exp (check_effective_target_divmod): New.
+ (check_effective_target_divmod_simode): Likewise.
+ (check_effective_target_arm_divmod_simode): Likewise.
+ * gcc.dg/divmod-1-simode.c: New test.
+ * gcc.dg/divmod-1.c: Likewise.
+ * gcc.dg/divmod-2-simode.c: Likewise.
+ * gcc.dg/divmod-2.c: Likewise.
+ * gcc.dg/divmod-3-simode.c: Likewise.
+ * gcc.dg/divmod-3.c: Likewise.
+ * gcc.dg/divmod-4-simode.c: Likewise.
+ * gcc.dg/divmod-4.c: Likewise.
+ * gcc.dg/divmod-5.c: Likewise.
+ * gcc.dg/divmod-6-simode.c: Likewise.
+ * gcc.dg/divmod-6.c: Likewise.
+ * gcc.dg/divmod-7.c: Likewise.
+
2016-10-28 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
- Jakub Jelinek <jakub@redhat.com>
- Andrew Pinski <pinskia@gmail.com>
+ Jakub Jelinek <jakub@redhat.com>
+ Andrew Pinski <pinskia@gmail.com>
PR middle-end/22141
PR rtl-optimization/23684
@@ -19,7 +616,7 @@
* gcc.target/i386/pr34012.c: Add -fno-store-merging to dg-options.
* g++.dg/init/new17.C: Likewise.
-2016-10-26 Will Schmidt <will_schmidt@vnet.ibm.com>
+2016-10-26 Will Schmidt <will_schmidt@vnet.ibm.com>
PR middle-end/72747
* c-c++-common/pr72747-1.c: New test.
@@ -95,7 +692,7 @@
* gcc.dg/fold-convmaxconv-1.c: New test.
* gcc.dg/fold-convminconv-1.c: New test.
-2016-10-26 Steven G. Kargl <kargl@gcc.gnu.org>
+2016-10-26 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/78092
* gfortran.dg/pr78092.f90: New test.
@@ -13087,6 +13684,7 @@
2016-01-28 Ilya Enkovich <enkovich.gnu@gmail.com>
* gcc.dg/declare-simd.c: New test.
+
2016-01-28 Richard Biener <rguenther@suse.de>
PR tree-optimization/69466
diff --git a/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c b/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
index 0576155c284..2e156f70d06 100644
--- a/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
+++ b/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
@@ -2,6 +2,7 @@
(before and after inlining) */
/* { dg-do compile } */
+/* { dg-options "-fno-sanitize-address-use-after-scope" } */
/* { dg-final { scan-assembler-not "__asan_report_load" } } */
__attribute__((always_inline))
diff --git a/gcc/testsuite/c-c++-common/asan/inc.c b/gcc/testsuite/c-c++-common/asan/inc.c
index 5abf3731818..98121d2d2b4 100644
--- a/gcc/testsuite/c-c++-common/asan/inc.c
+++ b/gcc/testsuite/c-c++-common/asan/inc.c
@@ -16,5 +16,6 @@ main ()
return 0;
}
-/* { dg-final { scan-tree-dump-times "ASAN_" 1 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_" 4 "asan0" } } */
/* { dg-final { scan-tree-dump "ASAN_CHECK \\(.*, 4\\);" "asan0" } } */
+/* { dg-final { scan-tree-dump "ASAN_CHECK \\(.*, 8\\);" "asan0" } } */
diff --git a/gcc/testsuite/c-c++-common/asan/null-deref-1.c b/gcc/testsuite/c-c++-common/asan/null-deref-1.c
index 45d35ac2de3..f4f8f37a795 100644
--- a/gcc/testsuite/c-c++-common/asan/null-deref-1.c
+++ b/gcc/testsuite/c-c++-common/asan/null-deref-1.c
@@ -17,6 +17,6 @@ int main()
}
/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address\[^\n\r]*" } */
-/* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]* #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+.*(\n|\r\n|\r)" } */
+/* { dg-output " #0 0x\[0-9a-f\]+ +(in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #1 0x\[0-9a-f\]+ +(in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/builtin-shuffle-1.c b/gcc/testsuite/c-c++-common/builtin-shuffle-1.c
new file mode 100644
index 00000000000..30fd69082dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-shuffle-1.c
@@ -0,0 +1,22 @@
+/* PR c++/78089 */
+/* { dg-do run } */
+
+typedef int V __attribute__((vector_size (16)));
+V a, b, c;
+
+int
+foo ()
+{
+ return __builtin_shuffle (a, b, c)[3];
+}
+
+int
+main ()
+{
+ a = (V) { 1, 2, 3, 4 };
+ b = (V) { 5, 6, 7, 8 };
+ c = (V) { 7, 2, 5, 6 };
+ if (foo () != 7)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-1.C b/gcc/testsuite/g++.dg/asan/use-after-scope-1.C
new file mode 100644
index 00000000000..fd875ad7a13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-1.C
@@ -0,0 +1,21 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include <functional>
+
+int main() {
+ std::function<int()> function;
+ {
+ int v = 0;
+ function = [&v]()
+ {
+ return v;
+ };
+ }
+ return function();
+}
+
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at.*" }
+// { dg-output ".*'v' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-2.C b/gcc/testsuite/g++.dg/asan/use-after-scope-2.C
new file mode 100644
index 00000000000..92a4bd13029
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-2.C
@@ -0,0 +1,40 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include <stdio.h>
+
+struct Test
+{
+ Test ()
+ {
+ my_value = 0;
+ }
+
+ ~Test ()
+ {
+ fprintf (stderr, "Value: %d\n", *my_value);
+ }
+
+ void init (int *v)
+ {
+ my_value = v;
+ }
+
+ int *my_value;
+};
+
+int main(int argc, char **argv)
+{
+ Test t;
+
+ {
+ int x = argc;
+ t.init(&x);
+ }
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at.*" }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-3.C b/gcc/testsuite/g++.dg/asan/use-after-scope-3.C
new file mode 100644
index 00000000000..172f374704b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-3.C
@@ -0,0 +1,22 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+struct IntHolder {
+ int val;
+};
+
+const IntHolder *saved;
+
+void save(const IntHolder &holder) {
+ saved = &holder;
+}
+
+int main(int argc, char *argv[]) {
+ save({10});
+ int x = saved->val; // BOOM
+ return x;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at.*" }
+// { dg-output ".*'<unknown>' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-4.C b/gcc/testsuite/g++.dg/asan/use-after-scope-4.C
new file mode 100644
index 00000000000..c3b6932609b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-4.C
@@ -0,0 +1,36 @@
+/* Caused ICE in in make_decl_rtl, at varasm.c:1311. */
+/* { dg-do compile } */
+
+class A
+{
+public:
+ A () : value (123) {}
+ int value;
+};
+
+template <typename StoredFunction> class B
+{
+public:
+ template <typename F> B (F p1) : mFunction (p1) { mFunction (); }
+ StoredFunction mFunction;
+};
+template <typename Function>
+void
+NS_NewRunnableFunction (Function p1)
+{
+ (B<Function> (p1));
+}
+class C
+{
+ void DispatchConnectionCloseEvent (A);
+ void AsyncCloseConnectionWithErrorMsg (const A &);
+};
+void
+C::AsyncCloseConnectionWithErrorMsg (const A &)
+{
+ {
+ A message;
+ NS_NewRunnableFunction (
+ [this, message] { DispatchConnectionCloseEvent (message); });
+ }
+}
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C
new file mode 100644
index 00000000000..bedcfa4edb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include "use-after-scope-types.h"
+
+int main()
+{
+ using Tests = void (*)();
+ Tests t = &test<bool>;
+ t();
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size " }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C
new file mode 100644
index 00000000000..75a01d9eb36
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include "use-after-scope-types.h"
+
+int main()
+{
+ using Tests = void (*)();
+ Tests t = &test<float>;
+ t();
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size " }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C
new file mode 100644
index 00000000000..3350c69c6ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include "use-after-scope-types.h"
+
+int main()
+{
+ using Tests = void (*)();
+ Tests t = &test<void *>;
+ t();
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size " }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C
new file mode 100644
index 00000000000..44f4d3b09f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include "use-after-scope-types.h"
+
+int main()
+{
+ using Tests = void (*)();
+ Tests t = &test<std::vector<std::string>>;
+ t();
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size " }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C
new file mode 100644
index 00000000000..42abc2a0ccd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+#include "use-after-scope-types.h"
+
+int main()
+{
+ using Tests = void (*)();
+ Tests t = &test<char[1000]>;
+ t();
+
+ return 0;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size " }
+// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types.h b/gcc/testsuite/g++.dg/asan/use-after-scope-types.h
new file mode 100644
index 00000000000..b96b02ba88c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types.h
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <string>
+#include <vector>
+
+template <class T> struct Ptr {
+ void Store(T *ptr) { t = ptr; }
+
+ void Access() { *t = {}; }
+
+ T *t;
+};
+
+template <class T, size_t N> struct Ptr<T[N]> {
+ using Type = T[N];
+ void Store(Type *ptr) { t = *ptr; }
+
+ void Access() { *t = {}; }
+
+ T *t;
+};
+
+template <class T> __attribute__((noinline)) void test() {
+ Ptr<T> ptr;
+ {
+ T x;
+ ptr.Store(&x);
+ }
+
+ ptr.Access();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/addressof3.C b/gcc/testsuite/g++.dg/cpp0x/addressof3.C
new file mode 100644
index 00000000000..fa517908ae3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/addressof3.C
@@ -0,0 +1,9 @@
+// { dg-do compile }
+
+struct S { int foo (); int s; };
+int a[10];
+int b;
+S c;
+int d = __builtin_addressof (a)[0][0];
+int e = __builtin_addressof (b)[0];
+int f = __builtin_addressof (c)->foo ();
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
index ee8757f4dcf..98691101e86 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-inhctor1.C
@@ -9,7 +9,7 @@ struct A
struct B : A
{
- using A::A; // { dg-error "A::i" }
+ using A::A; // { dg-prune-output "A::i" }
};
-constexpr B b(0); // { dg-error "B::B" }
+constexpr B b(0); // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
index 228e8ec6609..4fc67a4a56a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11.C
@@ -1,4 +1,5 @@
// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
struct A
{
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C
new file mode 100644
index 00000000000..61b251eb0ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor11a.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A
+{
+ A(int, ...);
+};
+
+struct B: A
+{
+ using A::A;
+};
+
+B b1(42);
+B b2(42, 1.0); // { dg-bogus "ellipsis" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
index c2d33bff4ff..a0b518c19d3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15.C
@@ -2,6 +2,7 @@
// constructors was a deliberate choice.
// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
struct A { A(int); };
struct B: public A
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C
new file mode 100644
index 00000000000..a9abb8428a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor15a.C
@@ -0,0 +1,14 @@
+// P0136 caused us to start inheriting base copy constructors.
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A { A(int); };
+struct B: public A
+{
+ using A::A;
+};
+
+A a (42);
+
+B b1 (24); // inherited
+B b2 (a); // also inherited now
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor22.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor22.C
new file mode 100644
index 00000000000..1b0e2425cc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor22.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+class A { };
+template<typename> using UniquePtr = int;
+template<typename AllocPolicy> struct BufferList {
+ BufferList(unsigned, unsigned, unsigned, AllocPolicy = AllocPolicy());
+};
+class D : BufferList<A> {
+ using BufferList::BufferList;
+};
+template<typename , typename... Args> UniquePtr<D> MakeUnique(Args... aArgs)
+{
+ D d(aArgs...);
+ return 0;
+}
+UniquePtr<D> setCloneBuffer_impl_buf = MakeUnique<D>(0, 0, 0);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
index e8dc84d32ec..8cbeed66047 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3.C
@@ -1,4 +1,5 @@
// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
struct B1 {
B1(int);
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C
new file mode 100644
index 00000000000..c9b4ea11412
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor3a.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct B1 {
+ B1(int);
+};
+struct B2 {
+ B2(int);
+};
+struct D1 : B1, B2 {
+ using B1::B1;
+ using B2::B2;
+}; // ambiguous
+struct D2 : B1, B2 {
+ using B1::B1;
+ using B2::B2;
+ D2(int); // OK: user declaration supersedes both implicit declarations
+};
+
+D2 d2(42);
+D1 d1(42); // { dg-error "ambiguous" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
index 8c79c833a32..d0038c16a14 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor5.C
@@ -15,7 +15,7 @@ void test() {
D1 e; // { dg-error "deleted" } D1 has no default constructor
}
struct D2 : B2 {
- using B2::B2; // { dg-error "no match" } implicitly declares D2(double)
+ using B2::B2; // { dg-error "B1::B1" }
B1 b;
};
D2 f(1.0); // { dg-error "deleted" } B1 has no default constructor
diff --git a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
index 676605db9e9..5bfdd499d46 100644
--- a/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
+++ b/gcc/testsuite/g++.dg/cpp0x/inh-ctor9.C
@@ -9,7 +9,7 @@ protected:
struct B: A
{
- using A::A; // { dg-message "protected" }
+ using A::A;
};
B b(42); // { dg-error "this context" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-1.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-1.C
new file mode 100644
index 00000000000..e7795e95b7f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-1.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=c++11 -std=gnu++11" }
+
+void
+foo ()
+{
+ auto qfp = 1.0q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+ auto Qfp = 1.0Q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-2.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-2.C
new file mode 100644
index 00000000000..7b84c5fdea1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-2.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=gnu++11 -std=c++11" }
+
+void
+foo ()
+{
+ auto qfp = 1.0q; // { dg-error "unable to find numeric literal operator" }
+ auto Qfp = 1.0Q; // { dg-error "unable to find numeric literal operator" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-3.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-3.C
new file mode 100644
index 00000000000..64d4f5b14cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-3.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=c++11 -std=gnu++98" }
+
+void
+foo ()
+{
+ double qfp = 1.0q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+ double Qfp = 1.0Q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-4.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-4.C
new file mode 100644
index 00000000000..7b66b983bfa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-4.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=c++11 -std=c++98" }
+
+void
+foo ()
+{
+ double qfp = 1.0q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+ double Qfp = 1.0Q; // { dg-error "unsupported" "" { target { ! has_q_floating_suffix } } }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-5.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-5.C
new file mode 100644
index 00000000000..bec34a15fbd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-5.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=gnu++98 -std=c++11" }
+
+void
+foo ()
+{
+ auto qfp = 1.0q; // { dg-error "unable to find numeric literal operator" }
+ auto Qfp = 1.0Q; // { dg-error "unable to find numeric literal operator" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr77948-6.C b/gcc/testsuite/g++.dg/cpp0x/pr77948-6.C
new file mode 100644
index 00000000000..b8a13b5540a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr77948-6.C
@@ -0,0 +1,10 @@
+// PR c++/77948
+// { dg-do compile }
+// { dg-options "-std=c++98 -std=c++11" }
+
+void
+foo ()
+{
+ auto qfp = 1.0q; // { dg-error "unable to find numeric literal operator" }
+ auto Qfp = 1.0Q; // { dg-error "unable to find numeric literal operator" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
index 6928d6bcbd8..2f3b01efc38 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx11.C
@@ -109,8 +109,8 @@
#ifndef __cpp_inheriting_constructors
# error "__cpp_inheriting_constructors"
-#elif __cpp_inheriting_constructors!= 200802
-# error "__cpp_inheriting_constructors != 200802"
+#elif __cpp_inheriting_constructors!= 201511
+# error "__cpp_inheriting_constructors != 201511"
#endif
#ifndef __cpp_ref_qualifiers
diff --git a/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
index dc30a9b3cf8..3b141ef67c4 100644
--- a/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
+++ b/gcc/testsuite/g++.dg/cpp1y/feat-cxx14.C
@@ -102,8 +102,8 @@
#ifndef __cpp_inheriting_constructors
# error "__cpp_inheriting_constructors"
-#elif __cpp_inheriting_constructors!= 200802
-# error "__cpp_inheriting_constructors != 200802"
+#elif __cpp_inheriting_constructors!= 201511
+# error "__cpp_inheriting_constructors != 201511"
#endif
#ifndef __cpp_ref_qualifiers
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
index 3597fa8053a..1b0f65e6381 100644
--- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-udt.C
@@ -14,7 +14,7 @@ struct S
bool shadow = false;
};
-extern "C" void printf(...);
+extern "C" int printf(const char*, ...);
#define assert(e) if (e); else \
printf ("%s:%d: !(%s)\n", __FILE__, __LINE__, #e), __builtin_abort ();
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr67980.C b/gcc/testsuite/g++.dg/cpp1y/pr67980.C
new file mode 100644
index 00000000000..1b8154538fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr67980.C
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++14 } }
+
+template <int Y, class T>
+constexpr T cpp14_constexpr_then(T value) {
+ if (Y < 0)
+ return (value << -Y);
+ else
+ return 0;
+}
+
+template <int Y, class T>
+constexpr T cpp14_constexpr_else(T value) {
+ if (Y > 0)
+ return 0;
+ else
+ return (value << -Y);
+}
+
+int main()
+{
+ cpp14_constexpr_then<1>(0);
+ cpp14_constexpr_else<1>(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
index e023e6a622d..f4658a96067 100644
--- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
+++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
@@ -90,8 +90,8 @@
#ifndef __cpp_inheriting_constructors
# error "__cpp_inheriting_constructors"
-#elif __cpp_inheriting_constructors!= 200802
-# error "__cpp_inheriting_constructors != 200802"
+#elif __cpp_inheriting_constructors!= 201511
+# error "__cpp_inheriting_constructors != 201511"
#endif
#ifndef __cpp_ref_qualifiers
@@ -380,6 +380,12 @@
# error "__cpp_capture_star_this != 201603"
#endif
+#ifndef __cpp_noexcept_function_type
+# error "__cpp_noexcept_function_type"
+#elif __cpp_noexcept_function_type != 201510
+# error "__cpp_noexcept_function_type != 201510"
+#endif
+
#ifdef __has_cpp_attribute
# if ! __has_cpp_attribute(maybe_unused)
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C
new file mode 100644
index 00000000000..bf9df415c05
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor1.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B: A { };
+struct C: B { using A::A; }; // { dg-error "direct" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C
new file mode 100644
index 00000000000..02ec58a3e8e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor22.C
@@ -0,0 +1,33 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+
+struct B1 {
+ template <class... Ts>
+ B1(int, Ts...) { }
+};
+
+struct B2 {
+ B2(double) { }
+};
+
+int get();
+
+struct D1 : B1 { // { dg-message "B1::B1" }
+ using B1::B1; // inherits B1(int, ...)
+ int x;
+ int y = get();
+};
+
+void test() {
+ D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
+ // then d.x is default-initialized (no initialization is performed),
+ // then d.y is initialized by calling get()
+ D1 e; // { dg-error "" } D1 has a deleted default constructor
+}
+
+struct D2 : B2 {
+ using B2::B2; // { dg-message "B1::B1" }
+ B1 b;
+};
+
+D2 f(1.0); // { dg-error "" } B1 has no default constructor
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
new file mode 100644
index 00000000000..0c862f7573f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor23.C
@@ -0,0 +1,19 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options "-fnew-inheriting-ctors -fdump-tree-gimple" }
+
+struct W { W(int); };
+struct V: W { using W::W; };
+struct X : virtual V { using V::V; X() = delete; };
+struct Y : X { using X::X; };
+struct Z : Y, virtual V { using Y::Y; };
+Z z(0); // OK: initialization of Y does not invoke default constructor of X
+
+// Check that we're passing this and __vtt along to the Y inheriting
+// constructor, but not the int parameter.
+// { dg-final { scan-assembler "_ZN1YCI21WEi" } }
+// { dg-final { scan-tree-dump "Y::Y ._2, _3.;" "gimple" } }
+
+// And that we *are* passing the int along to V::V.
+// { dg-final { scan-assembler "_ZN1VCI21WEi" } }
+// { dg-final { scan-tree-dump "V::V .this, _1.;" "gimple" } }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C
new file mode 100644
index 00000000000..21450196da0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor24.C
@@ -0,0 +1,27 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A { A(int); };
+struct B : A { using A::A; };
+
+struct C1 : B { using B::B; };
+struct C2 : B { using B::B; };
+
+struct D1 : C1, C2 {
+ using C1::C1;
+ using C2::C2;
+};
+
+struct V1 : virtual B { using B::B; };
+struct V2 : virtual B { using B::B; };
+
+struct D2 : V1, V2 {
+ using V1::V1;
+ using V2::V2;
+};
+
+D1 d1(0); // { dg-error "" } ambiguous
+D2 d2(0); // OK: initializes virtual B base class, which initializes the A base
+ // class then initializes the V1 and V2 base classes as if by a
+ // defaulted default constructor
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C
new file mode 100644
index 00000000000..66cd2dabb0d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor25.C
@@ -0,0 +1,9 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+
+struct M { M(); M(int); };
+struct N : M { using M::M; };
+struct O : M {};
+struct P : N, O { using N::N; using O::O; };
+P p(0); // OK: use M(0) to initialize N's base class,
+ // use M() to initialize O's base class
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C
new file mode 100644
index 00000000000..28dc33227a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor26.C
@@ -0,0 +1,17 @@
+// Testcase from P0136
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A {
+ template<typename T> A(T, typename T::type = 0);
+ A(int);
+};
+struct B : A {
+ using A::A;
+ B(int);
+};
+B b(42L); // now calls B(int), used to call B<long>(long),
+ // which called A(int) due to substitution failure
+ // in A<long>(long).
+
+// { dg-final { scan-assembler "_ZN1BC1Ei" } }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C
new file mode 100644
index 00000000000..97f26346b78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor27.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A(int = 0);
+};
+
+struct B: A
+{
+ B();
+ using A::A;
+};
+
+B b1(1);
+B b;
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C
new file mode 100644
index 00000000000..55e1d8c943f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor28.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct V { V(int); };
+struct W : virtual V { using V::V; };
+struct X : virtual W, virtual V { using W::W; };
+X x(0);
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C
new file mode 100644
index 00000000000..97f26346b78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor29.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A(int = 0);
+};
+
+struct B: A
+{
+ B();
+ using A::A;
+};
+
+B b1(1);
+B b;
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C
new file mode 100644
index 00000000000..494dd91bb80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor30.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A(double);
+};
+
+struct B: A
+{
+ B(short);
+ using A::A;
+};
+
+int main()
+{
+ B b(1); // { dg-error "ambiguous" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C
new file mode 100644
index 00000000000..3ce080d115b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor31.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct B;
+struct A
+{
+ A(const B&, int = 0);
+};
+
+struct B: A
+{
+ using A::A;
+};
+
+extern B b;
+B b2{b};
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C
new file mode 100644
index 00000000000..7ce85b0af2e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor32.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++11 } }
+
+struct B;
+struct A
+{
+ A(const B&, int = 0);
+};
+
+struct B: A
+{
+ using A::A;
+ B(B&);
+};
+
+extern const B b;
+B b2{b}; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C
new file mode 100644
index 00000000000..0e8520745a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor33.C
@@ -0,0 +1,23 @@
+// { dg-do link { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+struct A
+{
+ A() { }
+ A(const A&); // should never be called
+};
+
+struct B
+{
+ B(A) { }
+};
+
+struct C: B
+{
+ using B::B;
+};
+
+int main()
+{
+ C c{A()};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C
new file mode 100644
index 00000000000..f47b2a4dc2f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor34.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+class A
+{
+ A(int);
+ friend void f();
+};
+
+struct B: A
+{
+ using A::A;
+};
+
+void f()
+{
+ B b(42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C
new file mode 100644
index 00000000000..87f4452c666
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35.C
@@ -0,0 +1,21 @@
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fno-new-inheriting-ctors }
+
+template<class T> struct S {
+private:
+ typedef int X;
+ friend struct B;
+};
+
+struct B {
+ template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+ using B::B; // { dg-prune-output "private" }
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // { dg-error "" } was an error before P0136
diff --git a/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C
new file mode 100644
index 00000000000..47f69de41b8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/inh-ctor35a.C
@@ -0,0 +1,21 @@
+// Core 1715
+// { dg-do compile { target c++11 } }
+// { dg-options -fnew-inheriting-ctors }
+
+template<class T> struct S {
+private:
+ typedef int X;
+ friend struct B;
+};
+
+struct B {
+ template<class T> B(T, typename T::X);
+};
+
+struct D: B {
+ using B::B;
+};
+
+S<int> s;
+B b(s, 2); // Okay, thanks to friendship.
+D d(s, 2); // Now OK as well.
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder3.C b/gcc/testsuite/g++.dg/cpp1z/launder3.C
new file mode 100644
index 00000000000..2a2afc5cad1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder3.C
@@ -0,0 +1,38 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-O2" }
+
+#include <cassert>
+
+void *
+operator new (decltype (sizeof (0)), void *p)
+{
+ return p;
+}
+
+namespace std
+{
+ template <typename T>
+ T *
+ launder (T *p)
+ {
+ return __builtin_launder (p);
+ }
+}
+
+struct A
+{
+ const int x;
+};
+
+struct B
+{
+ A a;
+};
+
+int
+main ()
+{
+ B b{{42}};
+ new (&b.a) A{666};
+ assert(std::launder(&b.a)->x == 666);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder4.C b/gcc/testsuite/g++.dg/cpp1z/launder4.C
new file mode 100644
index 00000000000..3a65eb27f2e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder4.C
@@ -0,0 +1,40 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-O2" }
+
+#include <cassert>
+
+void *
+operator new (decltype (sizeof (0)), void *p)
+{
+ return p;
+}
+
+namespace std
+{
+ template <typename T>
+ T *
+ launder (T *p)
+ {
+ return __builtin_launder (p);
+ }
+}
+
+struct A
+{
+ int& x;
+};
+
+struct B
+{
+ A a;
+};
+
+int
+main ()
+{
+ int x = 42;
+ B b{{x}};
+ int y = 666;
+ new (&b.a) A{y};
+ assert(std::launder(&b.a)->x == 666);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder5.C b/gcc/testsuite/g++.dg/cpp1z/launder5.C
new file mode 100644
index 00000000000..483d6f29297
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder5.C
@@ -0,0 +1,25 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-O2" }
+// { dg-additional-sources "launder5.cc" }
+
+#include <cassert>
+#include "launder5.h"
+
+namespace std
+{
+ template <typename T>
+ T *
+ launder (T *p)
+ {
+ return __builtin_launder (p);
+ }
+}
+
+
+int
+main ()
+{
+ B b{{42}};
+ f(b);
+ assert(std::launder(&b.a)->x == 666);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder5.cc b/gcc/testsuite/g++.dg/cpp1z/launder5.cc
new file mode 100644
index 00000000000..f9d867db332
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder5.cc
@@ -0,0 +1,12 @@
+#include "launder5.h"
+
+void *
+operator new (decltype (sizeof (0)), void *p)
+{
+ return p;
+}
+
+void f(B& b)
+{
+ new (&b.a) A{666};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder5.h b/gcc/testsuite/g++.dg/cpp1z/launder5.h
new file mode 100644
index 00000000000..b66103aefba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder5.h
@@ -0,0 +1,16 @@
+#ifndef GCC_TEST_LAUNDER5_H
+#define GCC_TEST_LAUNDER5_H
+
+struct A
+{
+ const int x;
+};
+
+struct B
+{
+ A a;
+};
+
+void f(B& b);
+
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder6.C b/gcc/testsuite/g++.dg/cpp1z/launder6.C
new file mode 100644
index 00000000000..babc4b433ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder6.C
@@ -0,0 +1,24 @@
+// { dg-do run { target c++11 } }
+// { dg-additional-options "-O2" }
+// { dg-additional-sources "launder6.cc" }
+#include <cassert>
+#include "launder6.h"
+
+namespace std
+{
+ template <typename T>
+ T *
+ launder (T *p)
+ {
+ return __builtin_launder (p);
+ }
+}
+
+int
+main ()
+{
+ int x = 42;
+ B b{{x}};
+ f(b);
+ assert(std::launder(&b.a)->x == 666);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder6.cc b/gcc/testsuite/g++.dg/cpp1z/launder6.cc
new file mode 100644
index 00000000000..1822891a0a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder6.cc
@@ -0,0 +1,14 @@
+#include "launder6.h"
+
+void *
+operator new (decltype (sizeof (0)), void *p)
+{
+ return p;
+}
+
+int y = 666;
+
+void f(B& b)
+{
+ new (&b.a) A{y};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/launder6.h b/gcc/testsuite/g++.dg/cpp1z/launder6.h
new file mode 100644
index 00000000000..eca2ad46f18
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/launder6.h
@@ -0,0 +1,16 @@
+#ifndef GCC_TEST_LAUNDER6_H
+#define GCC_TEST_LAUNDER6_H
+
+struct A
+{
+ int& x;
+};
+
+struct B
+{
+ A a;
+};
+
+void f(B& b);
+
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C
new file mode 100644
index 00000000000..62e1322e35a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type1.C
@@ -0,0 +1,8 @@
+// Testcase from P0012r1
+// { dg-options -std=c++1z }
+
+void (*p)() throw(int);
+void (**pp)() noexcept = &p; // { dg-error "" } cannot convert to pointer to noexcept function
+
+struct S { typedef void (*p)(); operator p(); };
+void (*q)() noexcept = S(); // { dg-error "" } cannot convert to pointer to noexcept function
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C
new file mode 100644
index 00000000000..bcd4d8d613d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type11.C
@@ -0,0 +1,3 @@
+// { dg-options "-Wall -std=c++14" }
+
+void f(int(*)() noexcept) { } // { dg-warning "mangled" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C
new file mode 100644
index 00000000000..39820af136e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type12.C
@@ -0,0 +1,23 @@
+// { dg-options -std=c++1z }
+
+template <class R, class... A, bool B>
+void f(R (*)(A...) noexcept(B)) { }
+
+template <class R, class... A, bool B>
+void f2(R (*)(A...) noexcept(B)) { }
+
+void g(int);
+void h(int) noexcept;
+
+int main()
+{
+ f(g);
+ f2(h);
+}
+
+// { dg-final { scan-assembler "_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E" } }
+// { dg-final { scan-assembler "_Z2f2IvJiELb1EEvPDOT1_EFT_DpT0_E" } }
+
+void f3(void (*)() noexcept) { }
+
+// { dg-final { scan-assembler "_Z2f3PDoFvvE" } }
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C
new file mode 100644
index 00000000000..747bb194c30
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type2.C
@@ -0,0 +1,10 @@
+// Test for function pointer conversion on template arguments.
+// { dg-options -std=c++1z }
+
+template <void (*P)()> struct A { };
+
+void f() noexcept { };
+constexpr void (*p)() noexcept = f;
+
+A<f> a;
+A<p> b;
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C
new file mode 100644
index 00000000000..9303da87b8c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type3.C
@@ -0,0 +1,13 @@
+// Test for overload resolution.
+// { dg-options -std=c++1z }
+
+void f(void (*)() noexcept) = delete;
+void f(void (*)()) { }
+void g() {}
+void h() noexcept {}
+
+int main()
+{
+ f(g);
+ f(h); // { dg-error "deleted" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C
new file mode 100644
index 00000000000..621da9341ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type4.C
@@ -0,0 +1,16 @@
+// Test for deduction.
+// { dg-options -std=c++1z }
+
+template <class R, class... A>
+void f(R (*)(A...));
+void g(int) noexcept;
+
+template <class R, class... A>
+void h(R (*)(A...) noexcept);
+void i(int);
+
+int main()
+{
+ f(g);
+ h(i); // { dg-error "" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C
new file mode 100644
index 00000000000..9e5d20224e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type5.C
@@ -0,0 +1,25 @@
+// Test for composite pointer type.
+// { dg-options -std=c++1z }
+
+typedef void (*P)();
+typedef void (*NP)() noexcept;
+
+void f();
+void g() noexcept;
+
+bool b;
+
+template <class T, class U> struct Same;
+template <class T> struct Same<T,T> { };
+
+Same<decltype(b ? &f : &g),P> s;
+
+int main()
+{
+ P p = 0;
+ NP np = 0;
+
+ p == np;
+ p != np;
+ p < np;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C
new file mode 100644
index 00000000000..50684571b62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type6.C
@@ -0,0 +1,13 @@
+// Test for lambda conversion.
+// { dg-options -std=c++1z }
+
+void f()
+{
+ auto l = []() noexcept { return 0; };
+ int (*p)() noexcept = l;
+ int (*q)() = l;
+
+ auto l2 = []{ return 0; };
+ p = l2; // { dg-error "" }
+ q = l2;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C
new file mode 100644
index 00000000000..1f78114dc74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type7.C
@@ -0,0 +1,14 @@
+// Test for static_cast.
+// { dg-options -std=c++1z }
+
+void f()
+{
+ typedef void (*P)();
+ typedef void (*NP)() noexcept;
+
+ P p;
+ NP np;
+
+ static_cast<P>(np);
+ static_cast<NP>(p); // { dg-error "" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C
new file mode 100644
index 00000000000..0182e3a3111
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type8.C
@@ -0,0 +1,22 @@
+// Test for exception handling.
+// { dg-options -std=c++1z }
+// { dg-do run }
+
+void f() {}
+void g() noexcept {}
+
+int main()
+{
+ try { throw g; }
+ catch (void (*)()) { }
+
+ try { throw g; }
+ catch (void (*)() noexcept) { }
+
+ try { throw f; }
+ catch (void (*)()) { }
+
+ try { throw f; }
+ catch (void (*)() noexcept) { __builtin_abort(); }
+ catch (...) { }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C
new file mode 100644
index 00000000000..a29618a3001
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type9.C
@@ -0,0 +1,18 @@
+// Test for PMF template args.
+// { dg-options -std=c++1z }
+// { dg-do compile }
+
+struct A
+{
+ void f() noexcept;
+ void g();
+};
+
+template <void (A::*)()> struct B { };
+template <void (A::*)() noexcept> struct C { };
+
+B<&A::f> b1;
+B<&A::g> b2;
+
+C<&A::f> c1;
+C<&A::g> c2; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/using1.C b/gcc/testsuite/g++.dg/cpp1z/using1.C
new file mode 100644
index 00000000000..1ed939d45fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/using1.C
@@ -0,0 +1,23 @@
+// Test for hiding of used base functions when all the conversion sequences are
+// equivalent, needed to avoid a regression on inherited default ctors.
+
+struct A
+{
+ void f(short,int=0);
+ void g(char,int=0);
+};
+
+struct B:A
+{
+ using A::f;
+ void f(short);
+ using A::g;
+ void g(short);
+};
+
+int main()
+{
+ B().f(1); // OK, derived f hides base f for single arg
+ B().f(1,2); // OK, base f can still be called with two args
+ B().g(1); // { dg-error "" } signatures differ, ambiguous
+}
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/constexpr-var-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/constexpr-var-1.C
index 045d5fed744..19062e29fd5 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/constexpr-var-1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/constexpr-var-1.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
-// { dg-final { scan-assembler-times " DW_AT_const_expr" 2 } }
+// { dg-final { scan-assembler-times " DW_AT_const_expr" 2 { xfail *-*-aix* } } }
constexpr int a = 5;
struct S
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/inline-var-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/inline-var-1.C
new file mode 100644
index 00000000000..f4f4b6d77d1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/inline-var-1.C
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++1z -g -dA -gno-strict-dwarf" }
+// { dg-require-weak "" }
+// { dg-final { scan-assembler-times "0x3\[^\n\r]* DW_AT_inline" 6 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times "0x1\[^\n\r]* DW_AT_inline" 2 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_declaration" 6 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_specification" 6 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_\[^\n\r]*linkage_name" 7 { xfail *-*-aix* } } }
+
+inline int a;
+struct S
+{
+ static inline double b = 4.0;
+ static constexpr int c = 2;
+ static constexpr inline char d = 3;
+} s;
+template <int N>
+inline int e = N;
+int &f = e<2>;
+template <int N>
+struct T
+{
+ static inline double g = 4.0;
+ static constexpr int h = 2;
+ static inline constexpr char i = 3;
+};
+T<5> t;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C
new file mode 100644
index 00000000000..5d65196f7af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ptrdmem-1.C
@@ -0,0 +1,9 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_use_location" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_reference" { xfail { powerpc-ibm-aix* } } } }
+
+struct S;
+typedef int S::*pdm;
+pdm pmf = 0;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ref-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/ref-2.C
index dd1f457d3ec..43939c9d697 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/ref-2.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ref-2.C
@@ -1,7 +1,7 @@
// { dg-do compile { target c++11 } }
// { dg-options "-g -gno-strict-dwarf -dA" }
-// { dg-final { scan-assembler-times " DW_AT_reference" 1 } }
-// { dg-final { scan-assembler-times " DW_AT_rvalue_reference" 1 } }
+// { dg-final { scan-assembler-times " DW_AT_reference" 1 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_rvalue_reference" 1 { xfail *-*-aix* } } }
struct S
{
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ref-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/ref-3.C
new file mode 100644
index 00000000000..d7932d8a237
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ref-3.C
@@ -0,0 +1,56 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-g -gno-strict-dwarf -dA" }
+// { dg-final { scan-assembler-times " DW_AT_reference" 5 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_rvalue_reference" 5 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_subroutine_type" 6 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 7 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times " DW_AT_use_location" 1 { xfail *-*-aix* } } }
+
+struct S
+{
+ void foo1 ();
+ void bar1 () &;
+ void baz1 () &&;
+ void foo2 () const;
+ void bar2 () const &;
+ void baz2 () const &&;
+ void foo3 () const;
+ void bar3 () const &;
+ void baz3 () const &&;
+ int d;
+};
+
+void
+test ()
+{
+ S s;
+ auto o1 = &S::foo1;
+ auto r1 = &S::bar1;
+ auto z1 = &S::baz1;
+ auto o2 = &S::foo2;
+ auto r2 = &S::bar2;
+ auto z2 = &S::baz2;
+ auto o3 = &S::foo3;
+ auto r3 = &S::bar3;
+ auto z3 = &S::baz3;
+ auto d1 = &S::d;
+ void (S::*o4) () const;
+ o4 = &S::foo3;
+ void (S::*r4) () const &;
+ r4 = &S::bar3;
+ void (S::*z4) () const &&;
+ z4 = &S::baz3;
+ (s.*o1) ();
+ (s.*r1) ();
+ (S ().*z1) ();
+ (s.*o2) ();
+ (s.*r2) ();
+ (S ().*z2) ();
+ (s.*o3) ();
+ (s.*r3) ();
+ (S ().*z3) ();
+ (s.*o4) ();
+ (s.*r4) ();
+ (S ().*z4) ();
+ s.*d1 = 2;
+}
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/ref-4.C b/gcc/testsuite/g++.dg/debug/dwarf2/ref-4.C
new file mode 100644
index 00000000000..00cf81f4bcc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/ref-4.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-g -gno-strict-dwarf -dA" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_typedef" 2 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 2 { xfail *-*-aix* } } }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_subroutine_type" 1 { xfail *-*-aix* } } }
+
+struct A { void foo (); int a; };
+typedef void (A::*PMF) ();
+typedef int A::*PMI;
+PMF pmf;
+PMI pmi;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C
new file mode 100644
index 00000000000..221008e9981
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-1.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_reference" 2 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_use_location" { xfail { powerpc-ibm-aix* } } } }
+/* It is not clear what if anything we should output for
+ DW_AT_use_location in a pointer to member function, so we don't
+ output it for now. */
+
+struct S {
+ void mf(void) &;
+};
+
+void S::mf() & {}
+
+typedef void (S::*pmft)(void) &;
+pmft pmf = &S::mf;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C
new file mode 100644
index 00000000000..ddf33c1971e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/refqual-2.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O -std=c++11 -g -dA -gno-strict-dwarf" }
+// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_ptr_to_member_type" 1 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-times " DW_AT_rvalue_reference" 2 { xfail { powerpc-ibm-aix* } } } }
+// { dg-final { scan-assembler-not " DW_AT_use_location" { xfail { powerpc-ibm-aix* } } } }
+/* It is not clear what if anything we should output for
+ DW_AT_use_location in a pointer to member function, so we don't
+ output it for now. */
+
+struct S {
+ void mf(void) &&;
+};
+
+void S::mf() && {}
+
+typedef void (S::*pmft)(void) &&;
+pmft pmf = &S::mf;
diff --git a/gcc/testsuite/g++.dg/eh/spec2.C b/gcc/testsuite/g++.dg/eh/spec2.C
index 64807dd2677..8107f019eb7 100644
--- a/gcc/testsuite/g++.dg/eh/spec2.C
+++ b/gcc/testsuite/g++.dg/eh/spec2.C
@@ -2,9 +2,9 @@
struct S { void f (void); };
-typedef void f1 (void) throw (int); // { dg-error "exception" }
-typedef void (*f2) (void) throw (int); // { dg-error "exception" }
-typedef void (S::*f3) (void) throw (int); // { dg-error "exception" }
+typedef void f1 (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
+typedef void (*f2) (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
+typedef void (S::*f3) (void) throw (int); // { dg-error "exception" "" { target c++14_down } }
void (*f4) (void) throw (int);
void (S::*f5) (void) throw (int);
diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon1.C b/gcc/testsuite/g++.dg/ext/visibility/anon1.C
index 1f3be3b774b..0135f931a6f 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/anon1.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/anon1.C
@@ -2,7 +2,7 @@
// Test for anonymous namespace internal linkage
// { dg-do compile }
-// { dg-final { scan-assembler-not "globl.*_ZN.*1fEv" } }
+// { dg-final { scan-assembler-not "globl.*_ZN.*1fEv" { xfail *-*-aix* } } }
// { dg-require-visibility "" }
namespace
diff --git a/gcc/testsuite/g++.dg/ext/visibility/anon2.C b/gcc/testsuite/g++.dg/ext/visibility/anon2.C
index 49022963127..dcf0e64fa23 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/anon2.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/anon2.C
@@ -1,7 +1,7 @@
// Test for propagation of anonymous namespace internal linkage
// { dg-do compile }
-// { dg-final { scan-assembler-not "globl.*_Z1fv" } }
+// { dg-final { scan-assembler-not "globl.*_Z1fv" { xfail *-*-aix* } } }
// { dg-require-visibility "" }
namespace
diff --git a/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C b/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C
index c13161d3ceb..b6bc0c5466a 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/pragma-override1.C
@@ -1,7 +1,7 @@
/* Test that #pragma GCC visibility does not override class member specific settings. */
/* { dg-do compile } */
/* { dg-require-visibility "internal" } */
-/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" { target { ! { *-*-solaris2* *-*-darwin* } } } } } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" { target { ! { *-*-solaris2* *-*-darwin* *-*-aix* } } } } } */
/* { dg-final { scan-assembler "\\.(internal|hidden).*Foo.methodEv" { target *-*-solaris2* } } } */
#pragma GCC visibility push(hidden)
diff --git a/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C b/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C
index 25e9ceac076..8499ceff60a 100644
--- a/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C
+++ b/gcc/testsuite/g++.dg/ext/visibility/pragma-override2.C
@@ -1,7 +1,7 @@
/* Test that #pragma GCC visibility does not override class member specific settings. */
/* { dg-do compile } */
/* { dg-require-visibility "internal" } */
-/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" { target { ! { *-*-solaris2* *-*-darwin* } } } } } */
+/* { dg-final { scan-assembler "\\.internal.*Foo.methodEv" { target { ! { *-*-solaris2* *-*-darwin* *-*-aix* } } } } } */
/* { dg-final { scan-assembler "\\.(internal|hidden).*Foo.methodEv" { target *-*-solaris2* } } } */
#pragma GCC visibility push(hidden)
diff --git a/gcc/testsuite/g++.dg/init/new15.C b/gcc/testsuite/g++.dg/init/new15.C
index b93b43c833f..1f57f07dfc3 100644
--- a/gcc/testsuite/g++.dg/init/new15.C
+++ b/gcc/testsuite/g++.dg/init/new15.C
@@ -1,6 +1,6 @@
// PR c++/9782
-extern "C" void printf(const char*, ...);
+extern "C" int printf(const char*, ...);
template <int>
struct A {
diff --git a/gcc/testsuite/g++.dg/ipa/inline-1.C b/gcc/testsuite/g++.dg/ipa/inline-1.C
index 9ea614b295d..d570dc67e28 100644
--- a/gcc/testsuite/g++.dg/ipa/inline-1.C
+++ b/gcc/testsuite/g++.dg/ipa/inline-1.C
@@ -3,7 +3,7 @@
/* { dg-add-options bind_pic_locally } */
namespace std {
- extern "C" void puts(const char *s);
+ extern "C" int puts(const char *s);
}
template <class T, class E> void
diff --git a/gcc/testsuite/g++.dg/ipa/inline-2.C b/gcc/testsuite/g++.dg/ipa/inline-2.C
index cc5b2559ae7..eb0f21b1247 100644
--- a/gcc/testsuite/g++.dg/ipa/inline-2.C
+++ b/gcc/testsuite/g++.dg/ipa/inline-2.C
@@ -3,7 +3,7 @@
/* { dg-add-options bind_pic_locally } */
namespace std {
- extern "C" void puts(const char *s);
+ extern "C" int puts(const char *s);
}
template <class T, class E> void
diff --git a/gcc/testsuite/g++.dg/ipa/pr78188.C b/gcc/testsuite/g++.dg/ipa/pr78188.C
new file mode 100644
index 00000000000..f6ee654471e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/pr78188.C
@@ -0,0 +1,20 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-exceptions" }
+
+int a;
+static void __attribute__((noinline)) foo () { a = 1; }
+static void __attribute__((noinline)) foo2 () { a = 2; }
+
+struct X
+{
+ virtual void bar (int i) { if (!i) { foo (); __builtin_abort (); } }
+};
+
+void baz (int i)
+{
+ if (!i)
+ { foo2 (); __builtin_abort (); }
+}
+
+X xx;
+
diff --git a/gcc/testsuite/g++.dg/lto/20080908-1_0.C b/gcc/testsuite/g++.dg/lto/20080908-1_0.C
index 8b761c0844c..42b20cb3b3a 100644
--- a/gcc/testsuite/g++.dg/lto/20080908-1_0.C
+++ b/gcc/testsuite/g++.dg/lto/20080908-1_0.C
@@ -1,5 +1,5 @@
/* { dg-lto-do run } */
-extern "C" { extern void *memcpy (void *, const void *, unsigned); }
+extern "C" { extern void *memcpy (void *, const void *, __SIZE_TYPE__); }
inline int
bci (const float &source)
diff --git a/gcc/testsuite/gcc.target/i386/pr64411.C b/gcc/testsuite/g++.dg/opt/pr64411.C
index 55858fb48eb..122b9eec414 100644
--- a/gcc/testsuite/gcc.target/i386/pr64411.C
+++ b/gcc/testsuite/g++.dg/opt/pr64411.C
@@ -1,5 +1,6 @@
-/* { dg-do compile } */
-/* { dg-options "-Os -mcmodel=medium -fPIC -fschedule-insns -fselective-scheduling" } */
+// PR target/64411
+// { dg-do compile { target { { i?86-*-* x86_64-*-* } && lp64 } } }
+// { dg-options "-Os -mcmodel=medium -fPIC -fschedule-insns -fselective-scheduling" }
typedef __SIZE_TYPE__ size_t;
diff --git a/gcc/testsuite/gcc.target/i386/pr65105-4.C b/gcc/testsuite/g++.dg/opt/pr65105-4.C
index 9acf368e1fc..d79ba1abab0 100644
--- a/gcc/testsuite/gcc.target/i386/pr65105-4.C
+++ b/gcc/testsuite/g++.dg/opt/pr65105-4.C
@@ -1,6 +1,6 @@
-/* PR target/pr65105 */
-/* { dg-do run { target { ia32 } } } */
-/* { dg-options "-O2 -march=slm" } */
+// PR target/65105
+// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } }
+// { dg-options "-O2 -march=slm" }
struct s {
long long l1, l2, l3, l4, l5;
diff --git a/gcc/testsuite/g++.dg/opt/pr71529.C b/gcc/testsuite/g++.dg/opt/pr71529.C
new file mode 100644
index 00000000000..148527f00c4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr71529.C
@@ -0,0 +1,22 @@
+// PR middle-end/71529
+// { dg-do compile { target { { i?86-*-* x86_64-*-* } && { ! x32 } } } }
+// { dg-options "-fcheck-pointer-bounds -mmpx -O2" }
+
+class c1
+{
+ public:
+ virtual ~c1 ();
+};
+
+class c2
+{
+ public:
+ virtual ~c2 ();
+};
+
+class c3 : c1, c2 { };
+
+int main (int, char **)
+{
+ c3 obj;
+}
diff --git a/gcc/testsuite/g++.dg/pr78229.C b/gcc/testsuite/g++.dg/pr78229.C
new file mode 100644
index 00000000000..a52141b6b83
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr78229.C
@@ -0,0 +1,24 @@
+/* { dg-do compile { target x86_64-*-* i?86-*-* } } */
+/* { dg-options "-O2 -mbmi -w" } */
+
+void a();
+inline int b(int c) {
+ int d = c;
+ return __builtin_ia32_tzcnt_u32(d);
+}
+struct e {};
+int f, g, h;
+void fn3() {
+ float j;
+ &j;
+ {
+ e k;
+ while (h) {
+ if (g == 0)
+ continue;
+ int i = b(g);
+ f = i;
+ }
+ a();
+ }
+}
diff --git a/gcc/testsuite/g++.dg/tc1/dr20.C b/gcc/testsuite/g++.dg/tc1/dr20.C
index fe586212995..93338518190 100644
--- a/gcc/testsuite/g++.dg/tc1/dr20.C
+++ b/gcc/testsuite/g++.dg/tc1/dr20.C
@@ -2,7 +2,7 @@
// Origin: Giovanni Bajo <giovannibajo at gcc dot gnu dot org>
// DR20: Some clarifications needed for 12.8 para 15
-extern "C" void printf(const char*, ...);
+extern "C" int printf(const char*, ...);
extern "C" void abort(void);
int count = 0;
diff --git a/gcc/testsuite/g++.dg/template/func2.C b/gcc/testsuite/g++.dg/template/func2.C
index b0f691d242b..746f0e279a7 100644
--- a/gcc/testsuite/g++.dg/template/func2.C
+++ b/gcc/testsuite/g++.dg/template/func2.C
@@ -5,7 +5,7 @@ fptr zeroptr = 0;
template<typename T, fptr F> struct foo { };
template<typename T> struct foo<T,zeroptr> { };
// { dg-error "not a valid template argument" "not valid" { target *-*-* } 6 }
-// { dg-error "must be the address" "must be the address " { target *-*-* } 6 }
+// { dg-message "must be the address" "must be the address " { target *-*-* } 6 }
// The rest is needed to trigger the ICE in 4.0 to 4.3:
void f() { }
diff --git a/gcc/testsuite/g++.dg/torture/pr77822.C b/gcc/testsuite/g++.dg/torture/pr77822.C
new file mode 100644
index 00000000000..4dc428b63ee
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr77822.C
@@ -0,0 +1,30 @@
+// PR target/77822
+// { dg-do compile }
+
+using UINT8 = char;
+using UINT32 = int;
+using UINT64 = long;
+class A
+{
+ void m_fn1 ();
+ struct B
+ {
+ UINT32 m_multiplier;
+ };
+ UINT8 m_datawidth;
+ UINT8 m_subunits;
+ B m_subunit_infos[];
+};
+int a;
+UINT64 b;
+void
+A::m_fn1 ()
+{
+ int c = 32, d = m_datawidth / c;
+ for (int e = 0; e < d; e++)
+ {
+ UINT32 f = e * 32;
+ if (b >> f & 1)
+ m_subunit_infos[m_subunits].m_multiplier = a;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/torture/pr77919-2.C b/gcc/testsuite/g++.dg/torture/pr77919-2.C
new file mode 100644
index 00000000000..d61e704cb44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr77919-2.C
@@ -0,0 +1,10 @@
+// PR rtl-optimization/77919
+// { dg-do compile }
+
+typedef _Complex long long B;
+struct A { A (double) {} _Complex double i; };
+typedef struct { B b; } C;
+struct D { D (const B &x) : b (x) {} B b; };
+static inline B foo (const double *x) { C *a; a = (C *) x; return a->b; }
+static inline D baz (const A &x) { return foo ((double *) &x); }
+D b = baz (0);
diff --git a/gcc/testsuite/g++.dg/torture/pr78189.C b/gcc/testsuite/g++.dg/torture/pr78189.C
new file mode 100644
index 00000000000..9b65d2b5a63
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr78189.C
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-slp-vectorize -fno-vect-cost-model" } */
+
+#include <cstddef>
+
+struct A
+{
+ void * a;
+ void * b;
+};
+
+struct alignas(16) B
+{
+ void * pad;
+ void * misaligned;
+ void * pad2;
+
+ A a;
+
+ void Null();
+};
+
+void B::Null()
+{
+ a.a = nullptr;
+ a.b = nullptr;
+}
+
+void __attribute__((noinline,noclone))
+NullB(void * misalignedPtr)
+{
+ B* b = reinterpret_cast<B*>(reinterpret_cast<char *>(misalignedPtr) - offsetof(B, misaligned));
+ b->Null();
+}
+
+int main()
+{
+ B b;
+ NullB(&b.misaligned);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/torture/pr78224.C b/gcc/testsuite/g++.dg/torture/pr78224.C
new file mode 100644
index 00000000000..bb85339e8f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr78224.C
@@ -0,0 +1,51 @@
+// { dg-do compile }
+
+extern "C"{
+ float sqrtf(float);
+}
+
+inline float squareroot(const float f)
+{
+ return sqrtf(f);
+}
+
+inline int squareroot(const int f)
+{
+ return static_cast<int>(sqrtf(static_cast<float>(f)));
+}
+
+template <class T>
+class vector2d
+{
+public:
+ vector2d(T nx, T ny) : X(nx), Y(ny) {}
+ T getLength() const { return squareroot( X*X + Y*Y ); }
+ T X;
+ T Y;
+};
+
+vector2d<int> getMousePos();
+
+class Client
+{
+public:
+ Client();
+ ~Client();
+};
+
+void the_game(float turn_amount)
+{
+ Client client;
+ bool first = true;
+
+ while (1) {
+ if (first) {
+ first = false;
+ } else {
+ int dx = getMousePos().X;
+ int dy = getMousePos().Y;
+
+ turn_amount = vector2d<float>(dx, dy).getLength();
+ }
+ }
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/inline-1.C b/gcc/testsuite/g++.dg/tree-ssa/inline-1.C
index 1abfa324ad5..4497facb87b 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/inline-1.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/inline-1.C
@@ -3,7 +3,7 @@
/* { dg-add-options bind_pic_locally } */
namespace std {
- extern "C" void puts(const char *s);
+ extern "C" int puts(const char *s);
}
template <class T, class E> void
diff --git a/gcc/testsuite/g++.dg/tree-ssa/inline-2.C b/gcc/testsuite/g++.dg/tree-ssa/inline-2.C
index 53e609ecd8f..79f807cd220 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/inline-2.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/inline-2.C
@@ -3,7 +3,7 @@
/* { dg-add-options bind_pic_locally } */
namespace std {
- extern "C" void puts(const char *s);
+ extern "C" int puts(const char *s);
}
template <class T, class E> void
diff --git a/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C b/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C
new file mode 100644
index 00000000000..cacaf55bb49
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wimplicit-fallthrough-2.C
@@ -0,0 +1,66 @@
+// PR c++/77886
+// { dg-do compile }
+// { dg-options "-Wimplicit-fallthrough" }
+
+template <int N>
+int
+foo (int x, int y)
+{
+ switch (x)
+ {
+ case 1:
+ x++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ // FALLTHROUGH
+ case 2:
+ x++;
+ break;
+ case 3:
+ x++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ // FALLTHROUGH
+ lab:
+ case 4:
+ x++;
+ break;
+ case 5:
+ x++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ // FALLTHROUGH
+ default:
+ x++;
+ break;
+ case 26:
+ goto lab;
+ }
+#if __cplusplus >= 201103L
+ switch (y)
+ {
+ case 1:
+ y++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ [[fallthrough]];
+ case 2:
+ y++;
+ break;
+ case 3:
+ y++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ [[fallthrough]];
+ lab2:
+ case 4:
+ y++;
+ break;
+ case 5:
+ y++; // { dg-bogus "this statement may f\[ahlotu\]*gh" }
+ [[fallthrough]];
+ default:
+ y++;
+ break;
+ case 26:
+ goto lab2;
+ }
+#endif
+ return x + y;
+}
+
+int
+bar (int x, int y)
+{
+ return foo<0> (x, y);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-compatible-local-1.C b/gcc/testsuite/g++.dg/warn/Wshadow-compatible-local-1.C
new file mode 100644
index 00000000000..aac68619c3a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wshadow-compatible-local-1.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options -Wshadow=compatible-local } */
+
+class Bar {
+};
+
+class ChildBar : public Bar {
+};
+
+Bar bar;
+
+class Foo {
+ private:
+ int val;
+
+ public:
+ int func1(int x) {
+ int val;
+ val = x;
+ return val;
+ }
+
+ int func2(int i) { // { dg-message "note: shadowed declaration is here" }
+ int a = 3; // { dg-message "note: shadowed declaration is here" }
+
+ for (int i = 0; i < 5; ++i) { // { dg-warning "shadows a parameter" }
+ for (int i = 0; i < 3; ++i) { // { dg-warning "shadows a previous local" }
+ int a = i; // { dg-warning "shadows a previous local" }
+ func1(a);
+ }
+ }
+
+ return a;
+ }
+
+ int func3() {
+ int bar;
+ float func1 = 0.3;
+ int f = 5; // { dg-message "note: shadowed declaration is here" }
+
+ if (func1 > 1) {
+ float f = 2.0; // { dg-warning "shadows a previous local" }
+ bar = f;
+ }
+ else
+ bar = 1;
+ return bar;
+ }
+
+ void func4() {
+ Bar *bar; // { dg-bogus "shadowed declaration" }
+ ChildBar *cbp; // { dg-bogus "shadowed declaration" }
+ Bar *bp; // { dg-message "note: shadowed declaration is here" }
+ if (val) {
+ int bar; // { dg-bogus "shadows a previous local" }
+ Bar *cbp; // { dg-bogus "shadows a previous local" }
+ ChildBar *bp; // { dg-warning "shadows a previous local" }
+ func1(bar);
+ }
+ }
+};
+
+// { dg-message "note: shadowed declaration" "" { target *-*-* } 26 }
diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-local-1.C b/gcc/testsuite/g++.dg/warn/Wshadow-local-1.C
new file mode 100644
index 00000000000..dba6db5d1c2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wshadow-local-1.C
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options -Wshadow=local } */
+
+struct status
+{
+ int member;
+ void foo2 ();
+
+ inline static int foo3 (int member)
+ {
+ return member;
+ }
+};
+
+int decl1; // { dg-bogus "shadowed declaration" }
+int decl2; // { dg-bogus "shadowed declaration" }
+void foo (struct status &status,
+ double decl1) // { dg-bogus "shadows a global" }
+{
+}
+
+void foo1 (int d)
+{
+ double d; // { dg-error "shadows a parameter" }
+}
+
+void status::foo2 ()
+{
+ int member; // { dg-bogus "shadows a member" }
+ int decl2; // { dg-bogus "shadows a global" }
+ int local; // { dg-message "note: shadowed declaration is here" }
+ {
+ int local; // { dg-warning "shadows a previous local" }
+ }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-local-2.C b/gcc/testsuite/g++.dg/warn/Wshadow-local-2.C
new file mode 100644
index 00000000000..fe42c89d242
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wshadow-local-2.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options -Wshadow=local } */
+
+class Bar {
+};
+
+class ChildBar : public Bar {
+};
+
+Bar bar; // { dg-bogus "shadowed declaration" }
+
+class Foo {
+ private:
+ int val;
+
+ public:
+ int func1(int x) {
+ int val; // { dg-bogus "shadows a member" }
+ val = x;
+ return val;
+ }
+
+ int func2(int i) { // { dg-message "shadowed declaration is here" }
+ int a = 3; // { dg-message "shadowed declaration is here" }
+
+ for (int i = 0; i < 5; ++i) { // { dg-warning "shadows a parameter" }
+ for (int i = 0; i < 3; ++i) { // { dg-warning "shadows a previous local" }
+ int a = i; // { dg-warning "shadows a previous local" }
+ func1(a);
+ }
+ }
+
+ return a;
+ }
+
+ int func3() {
+ int bar; // { dg-bogus "shadows a global" }
+ float func1 = 0.3; // { dg-bogus "shadows a member" }
+ int f = 5; // { dg-message "shadowed declaration is here" }
+
+ if (func1 > 1) {
+ float f = 2.0; // { dg-warning "shadows a previous local" }
+ bar = f;
+ }
+ else
+ bar = 1;
+ return bar;
+ }
+
+ void func4() {
+ Bar *bar; // { dg-message "shadowed declaration is here" }
+ ChildBar *cbp; // { dg-message "shadowed declaration is here" }
+ Bar *bp; // { dg-message "shadowed declaration is here" }
+ if (val) {
+ int bar; // { dg-warning "shadows a previous local" }
+ Bar *cbp; // { dg-warning "shadows a previous local" }
+ ChildBar *bp; // { dg-warning "shadows a previous local" }
+ func1(bar);
+ }
+ }
+};
+
+// { dg-message "shadowed declaration is here" "" { target *-*-* } 26 }
diff --git a/gcc/testsuite/g++.old-deja/g++.eh/spec7.C b/gcc/testsuite/g++.old-deja/g++.eh/spec7.C
index 2ef88a24900..2a4a989913d 100644
--- a/gcc/testsuite/g++.old-deja/g++.eh/spec7.C
+++ b/gcc/testsuite/g++.old-deja/g++.eh/spec7.C
@@ -10,7 +10,7 @@ struct A
static void (A::*pmf)() throw ();
};
-void (A::* A::pmf)() = &A::g;
+void (A::* A::pmf)() throw() = &A::g;
int main()
{
diff --git a/gcc/testsuite/g++.old-deja/g++.law/except1.C b/gcc/testsuite/g++.old-deja/g++.law/except1.C
index 9a2123c3e86..d11afc8b64f 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/except1.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/except1.C
@@ -7,7 +7,7 @@
// Subject: Bugs
// Date: Wed, 22 Jul 92 08:29:30 EDT
-extern "C" void puts(const char *);
+extern "C" int puts(const char *);
class foo {
public:
diff --git a/gcc/testsuite/g++.old-deja/g++.other/vbase5.C b/gcc/testsuite/g++.old-deja/g++.other/vbase5.C
index 10c2f313157..3d22ff50dff 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/vbase5.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/vbase5.C
@@ -6,7 +6,7 @@
// vbases. Normally that's just a pessimization, unfortunately during
// constructoring it leads to uninitialized reads.
-extern "C" int printf (...);
+extern "C" int printf (const char*,...);
int fail = 0;
diff --git a/gcc/testsuite/gcc.c-torture/compile/20001226-1.c b/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
index 127c4daec45..687b43a6bcb 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20001226-1.c
@@ -1,7 +1,6 @@
/* { dg-do assemble } */
/* { dg-skip-if "too much code for avr" { "avr-*-*" } { "*" } { "" } } */
/* { dg-skip-if "too much code for pdp11" { "pdp11-*-*" } { "*" } { "" } } */
-/* { dg-xfail-if "jump beyond 128K not supported" { xtensa*-*-* } { "-O0" } { "" } } */
/* { dg-xfail-if "PR36698" { spu-*-* } { "-O0" } { "" } } */
/* { dg-skip-if "" { m32c-*-* } { "*" } { "" } } */
/* { dg-timeout-factor 4.0 } */
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr78162.c b/gcc/testsuite/gcc.c-torture/compile/pr78162.c
new file mode 100644
index 00000000000..743d4e678b5
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr78162.c
@@ -0,0 +1,10 @@
+/* PR tree-optimization/78162.
+ Handle negative offsets in store merging gracefully. */
+
+int a, b[1][2];
+
+void fn1()
+{
+ for (a = 0; a < 2; a++)
+ b[-1][a] = 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr78170.c b/gcc/testsuite/gcc.c-torture/execute/pr78170.c
new file mode 100644
index 00000000000..dce8a3eee36
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr78170.c
@@ -0,0 +1,39 @@
+/* { dg-require-effective-target int32plus } */
+
+/* PR tree-optimization/78170.
+ Check that sign-extended store to a bitfield
+ doesn't overwrite other fields. */
+
+int a, b, d;
+
+struct S0
+{
+ int f0;
+ int f1;
+ int f2;
+ int f3;
+ int f4;
+ int f5:15;
+ int f6:17;
+ int f7:2;
+ int f8:30;
+} c;
+
+void fn1 ()
+{
+ d = b = 1;
+ for (; b; b = a)
+ {
+ struct S0 e = { 0, 0, 0, 0, 0, 0, 1, 0, 1 };
+ c = e;
+ c.f6 = -1;
+ }
+}
+
+int main ()
+{
+ fn1 ();
+ if (c.f7 != 0)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wshadow-compatible-local-1.c b/gcc/testsuite/gcc.dg/Wshadow-compatible-local-1.c
new file mode 100644
index 00000000000..ed7b2e45ef1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wshadow-compatible-local-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-Wshadow=compatible-local" } */
+
+struct Bar {
+};
+
+struct Bar bar; /* { dg-bogus "shadowed declaration" } */
+
+int val; /* { dg-bogus "shadowed declaration" } */
+
+int func1(int x) { /* { dg-bogus "shadowed declaration" } */
+ int val; /* { dg-bogus "shadows a global" } */
+ val = x;
+ return val;
+}
+
+int func2(int i) {
+ int a = 3; /* { dg-message "shadowed declaration" } */
+ int j; /* { dg-message "shadowed declaration" } */
+
+ for (j = 0; j < i; ++j) {
+ int a = j; /* { dg-warning "shadows a previous local" } */
+ int j = a + 1; /* { dg-warning "shadows a previous local" } */
+ func1(j);
+ }
+
+ return a;
+}
+
+void func4() {
+ struct Bar bar; /* { dg-bogus "shadowed declaration" } */
+ if (val) {
+ int bar; /* { dg-bogus "shadows a previous local" } */
+ func1(bar);
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/Wshadow-local-1.c b/gcc/testsuite/gcc.dg/Wshadow-local-1.c
new file mode 100644
index 00000000000..161f9941fb6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wshadow-local-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-Wshadow=local" } */
+
+int decl1; /* should not warn */
+void foo (double decl1) /* should not warn */
+{
+}
+
+void foo2 (int d) /* { dg-message "shadowed declaration" } */
+{
+ {
+ double d; /* { dg-warning "shadows a parameter" } */
+ }
+}
+
+void foo3 ()
+{
+ int local; /* { dg-message "shadowed declaration" } */
+ {
+ int local; /* { dg-warning "shadows a previous local" } */
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/Wshadow-local-2.c b/gcc/testsuite/gcc.dg/Wshadow-local-2.c
new file mode 100644
index 00000000000..8f6b132f66d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wshadow-local-2.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-Wshadow=local" } */
+
+struct Bar {
+};
+
+struct Bar bar; /* { dg-bogus "shadowed declaration" } */
+
+int val; /* { dg-bogus "shadowed declaration" } */
+
+int func1(int x) { /* { dg-bogus "shadowed declaration" } */
+ int val; /* { dg-bogus "shadows a global" } */
+ val = x;
+ return val;
+}
+
+int func2(int i) {
+ int a = 3; /* { dg-message "shadowed declaration" } */
+ int j; /* { dg-message "shadowed declaration" } */
+
+ for (j = 0; j < i; ++j) {
+ int a = j; /* { dg-warning "shadows a previous local" } */
+ int j = a + 1; /* { dg-warning "shadows a previous local" } */
+ func1(j);
+ }
+
+ return a;
+}
+
+int func3() {
+ int bar; /* { dg-bogus "shadows a global" } */
+ float func1 = 0.3; /* { dg-bogus "shadows a global" } */
+
+ if (func1 > 1)
+ bar = 2;
+ else
+ bar = 1;
+ return bar;
+}
+
+void func4() {
+ struct Bar bar; /* { dg-message "shadowed declaration" } */
+ if (val) {
+ int bar; /* { dg-warning "shadows a previous local" } */
+ func1(bar);
+ }
+}
+
+/* { dg-bogus "shadows a global" "" { target *-*-* } 42 } */
diff --git a/gcc/testsuite/gcc.dg/Wshadow-local-3.c b/gcc/testsuite/gcc.dg/Wshadow-local-3.c
new file mode 100644
index 00000000000..429df37f541
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wshadow-local-3.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-shadow" } */
+
+void func() {
+ int i;
+ {
+ int i; /* should not warn */
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/Wtrampolines.c b/gcc/testsuite/gcc.dg/Wtrampolines.c
index 62b782a8bf0..e2e9cd4c8fd 100644
--- a/gcc/testsuite/gcc.dg/Wtrampolines.c
+++ b/gcc/testsuite/gcc.dg/Wtrampolines.c
@@ -28,7 +28,7 @@ void foo (void)
double a (int k, pfun x1, pfun x2, pfun x3, pfun x4, pfun x5)
{
- double b (void) /* { dg-warning "trampoline generated for nested function 'b'" "standard descriptors" { xfail ia64-*-* powerpc64-*-* } } */
+ double b (void) /* { dg-warning "trampoline generated for nested function 'b'" "standard descriptors" { xfail ia64-*-* powerpc64-*-* *-*-aix* } } */
{
k = k - 1;
return a (k, b, x1, x2, x3, x4 );
diff --git a/gcc/testsuite/gcc.dg/addr_equal-1.c b/gcc/testsuite/gcc.dg/addr_equal-1.c
index 94499f067b4..dd237a7d3cd 100644
--- a/gcc/testsuite/gcc.dg/addr_equal-1.c
+++ b/gcc/testsuite/gcc.dg/addr_equal-1.c
@@ -3,6 +3,7 @@
/* { dg-require-weak "" } */
/* { dg-require-alias "" } */
/* { dg-options "-O2" } */
+/* { dg-skip-if "" { powerpc-ibm-aix* } } */
void abort (void);
extern int undef_var0, undef_var1;
extern __attribute__ ((weak)) int weak_undef_var0;
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c
new file mode 100644
index 00000000000..bdbc97becae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c
@@ -0,0 +1,18 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+int
+main (void)
+{
+ char *ptr;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ }
+
+ return *(ptr+8);
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 1 at.*" }
+// { dg-output ".*'my_char' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c
new file mode 100644
index 00000000000..dedb73400cd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c
@@ -0,0 +1,47 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+int *bar (int *x, int *y) { return y; }
+
+int foo (void)
+{
+ char *p;
+ {
+ char a = 0;
+ p = &a;
+ }
+
+ if (*p)
+ return 1;
+ else
+ return 0;
+}
+
+int
+main (void)
+{
+ char *ptr;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ }
+
+ int a[16];
+ int *p, *q = a;
+ {
+ int b[16];
+ p = bar (a, b);
+ }
+ bar (a, q);
+ {
+ int c[16];
+ q = bar (a, c);
+ }
+ int v = *bar (a, q);
+ return v;
+}
+
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at.*" }
+// { dg-output ".*'c' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c
new file mode 100644
index 00000000000..9aeed51a770
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c
@@ -0,0 +1,20 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+int
+main (void)
+{
+ char *ptr;
+ char *ptr2;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2));
+ }
+
+ *(ptr2+9) = 'c';
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size 1 at.*" }
+// { dg-output ".*'my_char' <== Memory access at offset \[0-9\]* overflows this variable.*" }
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c
new file mode 100644
index 00000000000..77d7052bd19
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c
@@ -0,0 +1,16 @@
+// { dg-do run }
+
+int
+__attribute__((no_sanitize_address))
+main (void)
+{
+ char *ptr;
+ char *ptr2;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2));
+ }
+
+ *(ptr2+9) = 'c';
+}
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c
new file mode 100644
index 00000000000..b53712daa34
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c
@@ -0,0 +1,27 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+int *ptr;
+
+__attribute__((always_inline))
+inline static void
+foo(int v)
+{
+ int values[10];
+ for (unsigned i = 0; i < 10; i++)
+ values[i] = v;
+
+ ptr = &values[3];
+}
+
+int
+main (int argc, char **argv)
+{
+ foo (argc);
+
+ return *ptr;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at.*" }
+// { dg-output ".*'values' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c
new file mode 100644
index 00000000000..bb13cecbd1a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c
@@ -0,0 +1,15 @@
+// { dg-do run }
+// { dg-additional-options "--param asan-stack=0" }
+
+int
+main (void)
+{
+ char *ptr;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ }
+
+ *ptr = 'c';
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c
new file mode 100644
index 00000000000..41152059160
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c
@@ -0,0 +1,15 @@
+// { dg-do run }
+// { dg-additional-options "-fno-sanitize-address-use-after-scope" }
+
+int
+main (void)
+{
+ char *ptr;
+ {
+ char my_char[9];
+ ptr = &my_char[0];
+ }
+
+ *ptr = 'c';
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c
new file mode 100644
index 00000000000..2e30deffa18
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c
@@ -0,0 +1,20 @@
+// { dg-do run }
+// { dg-shouldfail "asan" }
+
+int
+main (int argc, char **argv)
+{
+ int *ptr = 0;
+
+ {
+ int a;
+ ptr = &a;
+ *ptr = 12345;
+ }
+
+ return *ptr;
+}
+
+// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" }
+// { dg-output "READ of size .*" }
+// { dg-output ".*'a' <== Memory access at offset \[0-9\]* is inside this variable.*" }
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c
new file mode 100644
index 00000000000..c47a5e8db02
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c
@@ -0,0 +1,47 @@
+// { dg-do run }
+// { dg-additional-options "-fdump-tree-asan0" }
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+
+int main(int argc, char **argv)
+{
+ int a = 123;
+ int b = 123;
+ int c = 123;
+ int d = 123;
+ int e = 123;
+ int f = 123;
+
+ if (argc == 0)
+ {
+ int *ptr;
+ int *ptr2;
+ int *ptr3;
+ int *ptr4;
+ int *ptr5;
+ int *ptr6;
+ label:
+ {
+ ptr = &a;
+ *ptr = 1;
+ ptr2 = &b;
+ *ptr2 = 1;
+ ptr3 = &c;
+ *ptr3 = 1;
+ ptr4 = &d;
+ *ptr4 = 1;
+ ptr5 = &e;
+ *ptr5 = 1;
+ ptr6 = &f;
+ *ptr6 = 1;
+ return 0;
+ }
+ }
+ else
+ goto label;
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, 4\\);" 2 "asan0" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &e, 4\\);" 2 "asan0" } } */
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c
new file mode 100644
index 00000000000..73ef4e0eb1e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-additional-options "-fdump-tree-asan0" }
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
+
+int main(int argc, char **argv)
+{
+ int a = 123;
+
+ if (argc == 0)
+ {
+ int *ptr;
+ /* The label is not used in &label or goto label. Thus '&a' should be
+ marked just once. */
+ label:
+ {
+ ptr = &a;
+ *ptr = 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 1 "asan0" } } */
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c
new file mode 100644
index 00000000000..a8342686d4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c
@@ -0,0 +1,25 @@
+// { dg-do run }
+// { dg-additional-options "-fdump-tree-gimple" }
+
+int
+main (int argc, char **argv)
+{
+ int *ptr = 0;
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ switch (argc)
+ {
+ int a;
+ default:
+ ptr = &a;
+ *ptr = 12345;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c
new file mode 100644
index 00000000000..8aeca5a3b7a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c
@@ -0,0 +1,33 @@
+// { dg-do run }
+// { dg-additional-options "-fdump-tree-gimple" }
+
+int
+main (int argc, char **argv)
+{
+ int *ptr = 0;
+ int *ptr2 = 0;
+ int *ptr3 = 0;
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ switch (argc)
+ {
+ case 1111:;
+ int a, b, c;
+ default:
+ ptr = &a;
+ ptr2 = &b;
+ ptr3 = &c;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &b, \[0-9\]\\);" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, \[0-9\]\\);" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &b, \[0-9\]\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &c, \[0-9\]\\);" 1 "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c
new file mode 100644
index 00000000000..828cb7c3b2a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c
@@ -0,0 +1,36 @@
+// { dg-do run }
+// { dg-additional-options "-fdump-tree-gimple" }
+
+int
+main (int argc, char **argv)
+{
+ int *ptr = 0;
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ switch (argc)
+ {
+ case 11111:;
+ int a;
+ ptr = &a;
+ break;
+ {
+ default:
+ ptr = &a;
+ *ptr = 12345;
+ case 222222:
+ my_label:
+ ptr = &a;
+ break;
+ }
+ }
+ }
+
+ if (argc == 333333)
+ goto my_label;
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 4 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/cpp/trad/include.c b/gcc/testsuite/gcc.dg/cpp/trad/include.c
index 94d25f815c6..967476d3a1f 100644
--- a/gcc/testsuite/gcc.dg/cpp/trad/include.c
+++ b/gcc/testsuite/gcc.dg/cpp/trad/include.c
@@ -2,11 +2,5 @@
/* Test that macros are not expanded in the <> quotes of #inlcude. */
-/* vxWorksCommon.h uses the "#" operator to construct the name of an
- include file, thus making the file incompatible with -traditional-cpp.
- Newlib uses ## when including stdlib.h as of 2007-09-07. */
-/* { dg-do preprocess { target { { ! vxworks_kernel } && { ! newlib } } } } */
-
-#define __STDC__ 1 /* Stop complaints about non-ISO compilers. */
-#define stdlib 1
-#include <stdlib.h> /* { dg-bogus "o such file or directory" } */
+#define builtins 1
+#include <builtins.h> /* { dg-bogus "o such file or directory" } */
diff --git a/gcc/testsuite/gcc.dg/cpp/trad/trad.exp b/gcc/testsuite/gcc.dg/cpp/trad/trad.exp
index 5f090ac54a0..01e1400b3c3 100644
--- a/gcc/testsuite/gcc.dg/cpp/trad/trad.exp
+++ b/gcc/testsuite/gcc.dg/cpp/trad/trad.exp
@@ -37,7 +37,7 @@ dg-init
# Main loop.
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
- "" $DEFAULT_TRADCPPFLAGS
+ "-I$srcdir/$subdir/" $DEFAULT_TRADCPPFLAGS
# All done.
dg-finish
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr71855.c b/gcc/testsuite/gcc.dg/debug/dwarf2/pr71855.c
index 4fd8b74f329..3842dbc0270 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/pr71855.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr71855.c
@@ -8,4 +8,4 @@ foo (const char *format, ...)
{
}
-// { dg-final { scan-assembler-times "DIE.*DW_TAG_unspecified_parameters" 1 } }
+// { dg-final { scan-assembler-times "DIE.*DW_TAG_unspecified_parameters" 1 { xfail { powerpc-ibm-aix* } } } }
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/prod-options.c b/gcc/testsuite/gcc.dg/debug/dwarf2/prod-options.c
index e6bc1371f26..6577eff3548 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/prod-options.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/prod-options.c
@@ -4,7 +4,7 @@
as well. */
/* { dg-do compile } */
/* { dg-options "-O2 -gdwarf -dA -fdebug-prefix-map=a=b" } */
-/* { dg-final { scan-assembler "DW_AT_producer: \"GNU C" { target { { { ! *-*-solaris2* } || gas } && { ! hppa*64*-*-* } } } } } */
+/* { dg-final { scan-assembler "DW_AT_producer: \"GNU C" { target { { { ! *-*-solaris2* } || gas } && { { ! hppa*64*-*-* } && { ! powerpc-ibm-aix* } } } } } } */
/* { dg-final { scan-assembler "\"GNU C\[^\\n\\r\]+ DW_AT_producer" { target { { *-*-solaris2* && { ! gas } } || { hppa*64*-*-* } } } } } */
/* { dg-final { scan-assembler-not "debug-prefix-map" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-1-simode.c b/gcc/testsuite/gcc.dg/divmod-1-simode.c
new file mode 100644
index 00000000000..9e477997bcf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-1-simode.c
@@ -0,0 +1,25 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* div dominates mod. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ if (cond) \
+ foo (); \
+ bigtype r = x % y; \
+ return q + r; \
+}
+
+FOO(SImode, SImode, 1)
+FOO(SImode, USImode, 2)
+FOO(USImode, USImode, 3)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-1.c b/gcc/testsuite/gcc.dg/divmod-1.c
new file mode 100644
index 00000000000..edcc2a107da
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-1.c
@@ -0,0 +1,32 @@
+/* { dg-require-effective-target divmod } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* div dominates mod. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+typedef int DImode __attribute__((mode(DI)));
+typedef unsigned UDImode __attribute__((mode(DI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ if (cond) \
+ foo (); \
+ bigtype r = x % y; \
+ return q + r; \
+}
+
+FOO(SImode, DImode, 1)
+FOO(SImode, UDImode, 2)
+FOO(USImode, DImode, 3)
+FOO(USImode, UDImode, 4)
+FOO(DImode, DImode, 5)
+FOO(DImode, UDImode, 6)
+FOO(UDImode, UDImode, 7)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-2-simode.c b/gcc/testsuite/gcc.dg/divmod-2-simode.c
new file mode 100644
index 00000000000..fa28beb3cef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-2-simode.c
@@ -0,0 +1,25 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* mod dominates div. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype r = x % y; \
+ if (cond) \
+ foo (); \
+ bigtype q = x / y; \
+ return q + r; \
+}
+
+FOO(SImode, SImode, 1)
+FOO(SImode, USImode, 2)
+FOO(USImode, USImode, 3)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-2.c b/gcc/testsuite/gcc.dg/divmod-2.c
new file mode 100644
index 00000000000..ded732e121d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-2.c
@@ -0,0 +1,32 @@
+/* { dg-require-effective-target divmod } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* mod dominates div. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+typedef int DImode __attribute__((mode(DI)));
+typedef unsigned UDImode __attribute__((mode(DI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype r = x % y; \
+ if (cond) \
+ foo (); \
+ bigtype q = x / y; \
+ return q + r; \
+}
+
+FOO(SImode, DImode, 1)
+FOO(SImode, UDImode, 2)
+FOO(USImode, DImode, 3)
+FOO(USImode, UDImode, 4)
+FOO(DImode, DImode, 5)
+FOO(DImode, UDImode, 6)
+FOO(UDImode, UDImode, 7)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-3-simode.c b/gcc/testsuite/gcc.dg/divmod-3-simode.c
new file mode 100644
index 00000000000..9dee5bf603b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-3-simode.c
@@ -0,0 +1,23 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* div comes before mod in same bb. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ bigtype r = x % y; \
+ return q + r; \
+}
+
+FOO(SImode, SImode, 1)
+FOO(SImode, USImode, 2)
+FOO(USImode, USImode, 3)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-3.c b/gcc/testsuite/gcc.dg/divmod-3.c
new file mode 100644
index 00000000000..02aa367ac6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-3.c
@@ -0,0 +1,30 @@
+/* { dg-require-effective-target divmod } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* div comes before mod in same bb. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+typedef int DImode __attribute__((mode(DI)));
+typedef unsigned UDImode __attribute__((mode(DI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ bigtype r = x % y; \
+ return q + r; \
+}
+
+FOO(SImode, DImode, 1)
+FOO(SImode, UDImode, 2)
+FOO(USImode, DImode, 3)
+FOO(USImode, UDImode, 4)
+FOO(DImode, DImode, 5)
+FOO(DImode, UDImode, 6)
+FOO(UDImode, UDImode, 7)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-4-simode.c b/gcc/testsuite/gcc.dg/divmod-4-simode.c
new file mode 100644
index 00000000000..dbe29cb761d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-4-simode.c
@@ -0,0 +1,23 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* mod comes before div in same bb. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype r = x % y; \
+ bigtype q = x / y; \
+ return q + r; \
+}
+
+FOO(SImode, SImode, 1)
+FOO(SImode, USImode, 2)
+FOO(USImode, USImode, 3)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-4.c b/gcc/testsuite/gcc.dg/divmod-4.c
new file mode 100644
index 00000000000..861ecbdec4b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-4.c
@@ -0,0 +1,30 @@
+/* { dg-require-effective-target divmod } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* mod comes before div in same bb. */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+typedef int DImode __attribute__((mode(DI)));
+typedef unsigned UDImode __attribute__((mode(DI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype r = x % y; \
+ bigtype q = x / y; \
+ return q + r; \
+}
+
+FOO(SImode, DImode, 3)
+FOO(SImode, UDImode, 4)
+FOO(USImode, DImode, 6)
+FOO(USImode, UDImode, 7)
+FOO(DImode, DImode, 8)
+FOO(DImode, UDImode, 9)
+FOO(UDImode, UDImode, 10)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-5.c b/gcc/testsuite/gcc.dg/divmod-5.c
new file mode 100644
index 00000000000..8a8cee50ae2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-5.c
@@ -0,0 +1,19 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+/* div and mod are not in same bb and
+ bb's containing div and mod don't dominate each other. */
+
+int f(int x, int y)
+{
+ int q = 0;
+ int r = 0;
+ extern int cond;
+
+ if (cond)
+ q = x / y;
+
+ r = x % y;
+ return q + r;
+}
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 0 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-6-simode.c b/gcc/testsuite/gcc.dg/divmod-6-simode.c
new file mode 100644
index 00000000000..1107f760b42
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-6-simode.c
@@ -0,0 +1,26 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ bigtype r1 = 0, r2 = 0; \
+ if (cond) \
+ r1 = x % y; \
+ else \
+ r2 = x % y; \
+ return q + r1 + r2; \
+}
+
+FOO(SImode, SImode, 1)
+FOO(SImode, USImode, 2)
+FOO(USImode, USImode, 3)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 3 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-6.c b/gcc/testsuite/gcc.dg/divmod-6.c
new file mode 100644
index 00000000000..495ebaff805
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-6.c
@@ -0,0 +1,33 @@
+/* { dg-require-effective-target divmod } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+
+typedef int SImode __attribute__((mode(SI)));
+typedef unsigned USImode __attribute__((mode(SI)));
+
+typedef int DImode __attribute__((mode(DI)));
+typedef unsigned UDImode __attribute__((mode(DI)));
+
+extern int cond;
+void foo(void);
+
+#define FOO(smalltype, bigtype, no) \
+bigtype f_##no(smalltype x, bigtype y) \
+{ \
+ bigtype q = x / y; \
+ bigtype r1 = 0, r2 = 0; \
+ if (cond) \
+ r1 = x % y; \
+ else \
+ r2 = x % y; \
+ return q + r1 + r2; \
+}
+
+FOO(SImode, DImode, 3)
+FOO(SImode, UDImode, 4)
+FOO(USImode, DImode, 6)
+FOO(USImode, UDImode, 7)
+FOO(DImode, DImode, 8)
+FOO(DImode, UDImode, 9)
+FOO(UDImode, UDImode, 10)
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 7 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/divmod-7.c b/gcc/testsuite/gcc.dg/divmod-7.c
new file mode 100644
index 00000000000..faa90b3ac8f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/divmod-7.c
@@ -0,0 +1,21 @@
+/* { dg-require-effective-target divmod_simode } */
+/* { dg-options "-O2 -fdump-tree-widening_mul-details" } */
+
+int f(int x, int y)
+{
+ int q = 0, r1 = 0, r2 = 0;
+ extern int cond;
+
+ if (cond)
+ q = x / y;
+ else
+ {
+ r1 = x % y;
+ return q + r1;
+ }
+
+ r2 = x % y;
+ return q + r2;
+}
+
+/* { dg-final { scan-tree-dump-times "DIVMOD" 1 "widening_mul" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/pr78121.c b/gcc/testsuite/gcc.dg/ipa/pr78121.c
new file mode 100644
index 00000000000..4a0ae187256
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr78121.c
@@ -0,0 +1,16 @@
+/* PR ipa/78121 */
+/* { dg-do compile } */
+/* { dg-options "-ansi -O2 -fdump-ipa-cp-details" } */
+
+void fn2 (unsigned char c);
+int a;
+static void fn1(c) unsigned char c;
+{
+ if (a)
+ fn2 (c);
+ fn1('#');
+}
+
+void fn3() { fn1 (267); }
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[11, 35\\\]" 1 "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp7.c b/gcc/testsuite/gcc.dg/ipa/vrp7.c
new file mode 100644
index 00000000000..e4e0bc66a64
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/vrp7.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-ipa-cp-details" } */
+
+volatile int cond;
+int abs (int);
+
+static __attribute__((noinline, noclone))
+int foo (int i)
+{
+ if (i < 5)
+ __builtin_abort ();
+ return 0;
+}
+
+static __attribute__((noinline, noclone))
+int bar (int j)
+{
+ foo (~j);
+ foo (abs (j));
+ foo (j);
+ return 0;
+}
+
+int main ()
+{
+ for (unsigned int i = 0; i < 10; ++i)
+ bar (i);
+
+ return 0;
+}
+
+/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[-10, 9\\\]" 1 "cp" } } */
diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_0.c b/gcc/testsuite/gcc.dg/lto/pr60449_0.c
index a430830cbed..5b878a640db 100644
--- a/gcc/testsuite/gcc.dg/lto/pr60449_0.c
+++ b/gcc/testsuite/gcc.dg/lto/pr60449_0.c
@@ -1,4 +1,5 @@
/* { dg-lto-do link } */
+/* { dg-skip-if "Needs gettimeofday" { "avr-*-*" } } */
extern int printf (const char *__restrict __format, ...);
typedef long int __time_t;
diff --git a/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c b/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
index c93d1718b64..e0c2600b400 100644
--- a/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
+++ b/gcc/testsuite/gcc.dg/no_profile_instrument_function-attr-1.c
@@ -19,5 +19,5 @@ int main ()
/* { dg-final { scan-tree-dump-times "__gcov0\\.main.* = PROF_edge_counter" 1 "optimized"} } */
/* { dg-final { scan-tree-dump-times "__gcov_indirect_call_profiler_v2" 1 "optimized" } } */
-/* { dg-final { scan-tree-dump-times "__gcov_time_profiler" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "__gcov_time_profiler_counter = " 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times "__gcov_init" 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr35691-1.c b/gcc/testsuite/gcc.dg/pr35691-1.c
new file mode 100644
index 00000000000..125923dd24c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop-details" } */
+
+int foo(int z0, unsigned z1)
+{
+ int t0 = (z0 == 0);
+ int t1 = (z1 == 0);
+ int t2 = (t0 & t1);
+ return t2;
+}
+
+/* { dg-final { scan-tree-dump "gimple_simplified to _\[0-9\]* = \\(int\\) z1_\[0-9\]*\\(D\\);" "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/pr35691-2.c b/gcc/testsuite/gcc.dg/pr35691-2.c
new file mode 100644
index 00000000000..70f68a685d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop-details" } */
+
+int foo(int z0, unsigned z1)
+{
+ int t0 = (z0 != 0);
+ int t1 = (z1 != 0);
+ int t2 = (t0 | t1);
+ return t2;
+}
+
+/* { dg-final { scan-tree-dump "gimple_simplified to _\[0-9\]* = \\(int\\) z1_\[0-9\]*\\(D\\);" "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/pr65779.c b/gcc/testsuite/gcc.dg/pr65779.c
index 7d5c522d042..814cb2cdeef 100644
--- a/gcc/testsuite/gcc.dg/pr65779.c
+++ b/gcc/testsuite/gcc.dg/pr65779.c
@@ -1,6 +1,7 @@
/* PR debug/65779 */
/* { dg-do assemble } */
/* { dg-options "-O2 -fcompare-debug" } */
+/* { dg-xfail-if "" { powerpc-ibm-aix* } { "*" } { "" } } */
unsigned long
foo (unsigned long x, unsigned char *y, unsigned int z)
diff --git a/gcc/testsuite/gcc.dg/pr70405.c b/gcc/testsuite/gcc.dg/pr70405.c
index bff390ff06d..a2bc96ac241 100644
--- a/gcc/testsuite/gcc.dg/pr70405.c
+++ b/gcc/testsuite/gcc.dg/pr70405.c
@@ -2,6 +2,7 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fcompare-debug" } */
/* { dg-additional-options "-mavx512f" { target i?86-*-* x86_64-*-* } } */
+/* { dg-xfail-if "" { powerpc-ibm-aix* } { "*" } { "" } } */
typedef short V __attribute__ ((vector_size (32)));
diff --git a/gcc/testsuite/gcc.dg/pr77834.c b/gcc/testsuite/gcc.dg/pr77834.c
new file mode 100644
index 00000000000..a9085b95393
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr77834.c
@@ -0,0 +1,18 @@
+/* PR target/77834 */
+/* { dg-do compile } */
+/* { dg-options "-O -ftree-pre -Wno-psabi" } */
+/* { dg-additional-options "-mstringop-strategy=libcall" { target i?86-*-* x86_64-*-* } } */
+
+typedef int V __attribute__ ((vector_size (64)));
+
+V
+foo (V u, V v, int w)
+{
+ do
+ {
+ if (u[0]) v ^= u[w];
+ }
+ while ((V) { 0, u[w] }[1]);
+ u = (V) { v[v[0]], u[u[0]] };
+ return v + u;
+}
diff --git a/gcc/testsuite/gcc.dg/pr77860.c b/gcc/testsuite/gcc.dg/pr77860.c
new file mode 100644
index 00000000000..04346b16e77
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr77860.c
@@ -0,0 +1,13 @@
+/* PR tree-optimization/77860 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vrp -fno-tree-forwprop -Wno-psabi" } */
+
+typedef unsigned short V __attribute__((vector_size (16)));
+
+V
+foo (V x, V y)
+{
+ V a = -x;
+ V b = -y;
+ return a * b;
+}
diff --git a/gcc/testsuite/gcc.dg/pr78148.c b/gcc/testsuite/gcc.dg/pr78148.c
new file mode 100644
index 00000000000..c3c9b2e9a89
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr78148.c
@@ -0,0 +1,31 @@
+/* PR target/78148 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcompare-debug" } */
+
+struct A { int a, b; };
+struct B { char c, d; };
+extern void bar (struct A, struct B);
+struct C { char e, f; } a;
+struct D
+{
+ int g;
+ struct C h[4];
+};
+struct D *e;
+
+struct D
+foo (void)
+{
+ int b;
+ struct B c;
+ struct A d;
+ d.b = c.c = c.d = 0;
+ bar (d, c);
+}
+
+void
+baz ()
+{
+ e->h[0].e = e->h[0].f = 0;
+ foo ();
+}
diff --git a/gcc/testsuite/gcc.dg/pr78185.c b/gcc/testsuite/gcc.dg/pr78185.c
new file mode 100644
index 00000000000..405f7489dae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr78185.c
@@ -0,0 +1,28 @@
+/* { dg-do run { target *-*-linux* *-*-gnu* } } */
+/* { dg-options "-O" } */
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static char var1 = 0L;
+static char *var2 = &var1;
+
+void do_exit (int i)
+{
+ exit (0);
+}
+
+int main(void)
+{
+ struct sigaction s;
+ sigemptyset (&s.sa_mask);
+ s.sa_handler = do_exit;
+ s.sa_flags = 0;
+ sigaction (SIGALRM, &s, NULL);
+ alarm (1);
+ /* The following loop is infinite, the division by zero should not
+ be hoisted out of it. */
+ for (; (var1 == 0 ? 0 : (100 / var1)) == *var2; );
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/store_merging_1.c b/gcc/testsuite/gcc.dg/store_merging_1.c
index 35f4d82e6b2..4cc43dfd9e1 100644
--- a/gcc/testsuite/gcc.dg/store_merging_1.c
+++ b/gcc/testsuite/gcc.dg/store_merging_1.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
struct bar {
diff --git a/gcc/testsuite/gcc.dg/store_merging_2.c b/gcc/testsuite/gcc.dg/store_merging_2.c
index 8e2acf39089..8cd29f4243c 100644
--- a/gcc/testsuite/gcc.dg/store_merging_2.c
+++ b/gcc/testsuite/gcc.dg/store_merging_2.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
struct bar
diff --git a/gcc/testsuite/gcc.dg/store_merging_4.c b/gcc/testsuite/gcc.dg/store_merging_4.c
index a3d67697d64..719c2c038e4 100644
--- a/gcc/testsuite/gcc.dg/store_merging_4.c
+++ b/gcc/testsuite/gcc.dg/store_merging_4.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
/* Check that we can merge interleaving stores that are guaranteed
diff --git a/gcc/testsuite/gcc.dg/store_merging_5.c b/gcc/testsuite/gcc.dg/store_merging_5.c
index 4ffe512b842..e6c349767bc 100644
--- a/gcc/testsuite/gcc.dg/store_merging_5.c
+++ b/gcc/testsuite/gcc.dg/store_merging_5.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
/* Make sure that non-aliasing non-constant interspersed stores do not
diff --git a/gcc/testsuite/gcc.dg/store_merging_6.c b/gcc/testsuite/gcc.dg/store_merging_6.c
index 42b5c4f92dc..314829da6d3 100644
--- a/gcc/testsuite/gcc.dg/store_merging_6.c
+++ b/gcc/testsuite/gcc.dg/store_merging_6.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
/* Check that we can widen accesses to bitfields. */
diff --git a/gcc/testsuite/gcc.dg/store_merging_7.c b/gcc/testsuite/gcc.dg/store_merging_7.c
index 4be352fef4a..c744ece6407 100644
--- a/gcc/testsuite/gcc.dg/store_merging_7.c
+++ b/gcc/testsuite/gcc.dg/store_merging_7.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-require-effective-target non_strict_align } */
+/* { dg-require-effective-target store_merge } */
/* { dg-options "-O2 -fdump-tree-store-merging" } */
/* Check that we can merge consecutive array members through the pointer.
diff --git a/gcc/testsuite/gcc.dg/store_merging_8.c b/gcc/testsuite/gcc.dg/store_merging_8.c
new file mode 100644
index 00000000000..e710a544ff0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/store_merging_8.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target store_merge } */
+/* { dg-options "-O2 -fdump-tree-store-merging" } */
+
+struct baz {
+ struct bar {
+ int a;
+ char b;
+ char c;
+ char d;
+ char e;
+ char f;
+ char g;
+ } a[4];
+} x;
+struct baz *xx = &x;
+
+void
+foo1 (int i)
+{
+ x.a[i].b = 0;
+ x.a[i].a = 0;
+ x.a[i].c = 0;
+ x.a[i].d = 0;
+ x.a[i].e = 0;
+}
+
+void
+foo2 (int i)
+{
+ x.a[i].b = 0;
+ x.a[i].a = 0;
+ x.a[i].c = 1;
+ x.a[i].d = 0;
+ x.a[i].e = 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Merging successful" 2 "store-merging" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert.h b/gcc/testsuite/gcc.dg/torture/fp-int-convert.h
index 59773e34fa8..bbe96668d0b 100644
--- a/gcc/testsuite/gcc.dg/torture/fp-int-convert.h
+++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert.h
@@ -53,6 +53,8 @@ do { \
TEST_I_F_VAL (U, F, HVAL1U (P, U), P_OK (P, U)); \
TEST_I_F_VAL (U, F, HVAL1U (P, U) + 1, P_OK (P, U)); \
TEST_I_F_VAL (U, F, HVAL1U (P, U) - 1, P_OK (P, U)); \
+ TEST_I_F_VAL (I, F, WVAL0S (I), 1); \
+ TEST_I_F_VAL (I, F, -WVAL0S (I), 1); \
} while (0)
#define P_OK(P, T) ((P) >= sizeof(T) * CHAR_BIT)
@@ -74,6 +76,7 @@ do { \
? (S)1 \
: (((S)1 << (sizeof(S) * CHAR_BIT - 2)) \
+ ((S)3 << (sizeof(S) * CHAR_BIT - 2 - P))))
+#define WVAL0S(S) (S)((S)1 << (sizeof(S) * CHAR_BIT / 2 - 1))
#define TEST_I_F_VAL(IT, FT, VAL, PREC_OK) \
do { \
diff --git a/gcc/testsuite/gcc.dg/torture/pr77309.c b/gcc/testsuite/gcc.dg/torture/pr77309.c
new file mode 100644
index 00000000000..5bdbc0a0b83
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr77309.c
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+
+int a, b;
+
+int main ()
+{
+ long c = 1 % (2 ^ b);
+ c = -c & ~(~(b ^ ~b) || a);
+
+ if (c >= 0)
+ __builtin_abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr78218.c b/gcc/testsuite/gcc.dg/torture/pr78218.c
new file mode 100644
index 00000000000..b3e2892429d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr78218.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+
+struct
+{
+ int v;
+} a[2];
+
+int b;
+
+void __attribute__((noinline,noclone))
+check ()
+{
+ if (a[0].v != 1)
+ __builtin_abort ();
+}
+
+int main ()
+{
+ a[1].v = 1;
+ a[0] = a[1];
+ a[1].v = 0;
+ check (a);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/time-profiler-3.c b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-3.c
new file mode 100644
index 00000000000..69ce0260828
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/time-profiler-3.c
@@ -0,0 +1,22 @@
+/* { dg-options "-O2 -fdump-ipa-profile -fprofile-update=atomic" } */
+/* { dg-require-effective-target profile_update_atomic } */
+
+__attribute__ ((noinline))
+int foo()
+{
+ return 0;
+}
+
+__attribute__ ((noinline))
+int bar()
+{
+ return 1;
+}
+
+int main ()
+{
+ return foo ();
+}
+/* { dg-final-use-not-autofdo { scan-ipa-dump-times "Read tp_first_run: 0" 1 "profile"} } */
+/* { dg-final-use-not-autofdo { scan-ipa-dump-times "Read tp_first_run: 1" 1 "profile"} } */
+/* { dg-final-use-not-autofdo { scan-ipa-dump-times "Read tp_first_run: 2" 1 "profile"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c b/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c
index df0ede2ba5e..e1658d183c3 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtins-folding-gimple-ub.c
@@ -17,6 +17,10 @@ main (void)
if (__builtin_memchr (foo1, 'x', 1000)) /* Not folded away. */
__builtin_abort ();
+ /* STRNCMP. */
+ if (strncmp ("a", "b", -1)) /* { dg-warning "implicit declaration of function" } */
+ __builtin_abort ();
+
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-15.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-15.c
new file mode 100644
index 00000000000..ac3018ef533
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-15.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int
+foo (int i)
+{
+ if (i > 0)
+ i = -i;
+ return i;
+}
+
+/* { dg-final { scan-tree-dump-not "ABS" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20702.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20702.c
index cc7370cad4e..c896857748c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr20702.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20702.c
@@ -4,7 +4,7 @@
immediate successors of the basic block. */
/* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fno-tree-dominator-opts -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
extern void bar (int);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr21086.c b/gcc/testsuite/gcc.dg/tree-ssa/pr21086.c
index e8b62c2ca1f..950371ba55d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr21086.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr21086.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdump-tree-dce2 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdump-tree-dce2 -fdelete-null-pointer-checks" } */
int
foo (int *p)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr54245.c b/gcc/testsuite/gcc.dg/tree-ssa/pr54245.c
deleted file mode 100644
index b96e3e51f5b..00000000000
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr54245.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O1 -fdump-tree-slsr-details" } */
-
-#include <stdio.h>
-
-#define W1 22725
-#define W2 21407
-#define W3 19266
-#define W6 8867
-
-void idct_row(short *row, int *dst)
-{
- int a0, a1, b0, b1;
-
- a0 = W1 * row[0];
- a1 = a0;
-
- a0 += W2 * row[2];
- a1 += W6 * row[2];
-
- b0 = W1 * row[1];
- b1 = W3 * row[1];
-
- dst[0] = a0 + b0;
- dst[1] = a0 - b0;
- dst[2] = a1 + b1;
- dst[3] = a1 - b1;
-}
-
-static short block[8] = { 1, 2, 3, 4 };
-
-int main(void)
-{
- int out[4];
- int i;
-
- idct_row(block, out);
-
- for (i = 0; i < 4; i++)
- printf("%d\n", out[i]);
-
- return !(out[2] == 87858 && out[3] == 10794);
-}
-
-/* For now, disable inserting an initializer when the multiplication will
- take place in a smaller type than originally. This test may be deleted
- in future when this case is handled more precisely. */
-/* { dg-final { scan-tree-dump-times "Inserting initializer" 0 "slsr" { target { ! int16 } } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr58480.c b/gcc/testsuite/gcc.dg/tree-ssa/pr58480.c
index 7df8f8affbd..42898e72d4e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr58480.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr58480.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */
-/* { dg-options "-O2 -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fdisable-tree-evrp -fdump-tree-vrp1 -fdelete-null-pointer-checks" } */
extern void eliminate (void);
extern void* f1 (void *a, void *b) __attribute__((nonnull));
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr71347.c b/gcc/testsuite/gcc.dg/tree-ssa/pr71347.c
index 428e41bc3bc..d2f7f059f33 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr71347.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr71347.c
@@ -14,4 +14,4 @@ void foo (void)
}
/* Load of X[i - i] can be omitted by reusing X[i] in previous iteration. */
-/* { dg-final { scan-tree-dump-not ".* = MEM.*;" "optimized" { xfail { ia64-*-* arm*-*-* m68k*-*-* } } } } */
+/* { dg-final { scan-tree-dump-not ".* = MEM.*;" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/slsr-8.c b/gcc/testsuite/gcc.dg/tree-ssa/slsr-8.c
index 2bd60aad546..585b660886b 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/slsr-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/slsr-8.c
@@ -4,7 +4,7 @@
/* { dg-options "-O3 -fdump-tree-optimized" } */
int*
-f (int s, int *c)
+f (int s, int *c, int *d)
{
int a1, a2, a3, *x1, *x2, *x3;
@@ -14,10 +14,16 @@ f (int s, int *c)
x2 = c - a2;
a3 = 6 * s;
x3 = c - a3;
- return x1 ? x2 : x3;
+ return x1 == d ? x2 : x3;
}
+/* Note that since some branch prediction heuristics changed, the
+ calculations of x2 and x3 are pushed downward into the legs
+ of the conditional, changing the code presented to SLSR.
+ However, this proves to be a useful test for introducing an
+ initializer with a cast, so we'll keep it as is. */
+
/* There are 4 ' * ' instances in the decls (since "int * iftmp.0;" is
- added), 1 parm, 2 in the code. The second one in the code can be
- a widening mult. */
-/* { dg-final { scan-tree-dump-times " w?\\* " 7 "optimized" } } */
+ added), 2 parms, 3 in the code. The second one in the code may
+ be a widening multiply (for example, on AArch64). */
+/* { dg-final { scan-tree-dump-times " w?\\* " 9 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp08.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp08.c
index 023b4eb3b94..c2da30b4b68 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp08.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp08.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
+/* { dg-options "-O2 -fno-tree-fre -fdisable-tree-evrp -fdump-tree-vrp1-details -fdelete-null-pointer-checks" } */
/* Compile with -fno-tree-fre -O2 to prevent CSEing *p. */
int
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp111.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp111.c
new file mode 100644
index 00000000000..2511c1964bb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp111.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void foo (void *p) __attribute__((nonnull(1)));
+
+void bar (void *p)
+{
+ foo (p);
+ if (!p)
+ __builtin_abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "evrp" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr78205.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr78205.c
new file mode 100644
index 00000000000..e02502a3fc1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr78205.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_double } */
+/* { dg-additional-options "-fdump-tree-optimized" } */
+
+double x[2], a[4], b[4], c[5];
+
+void foo ()
+{
+ a[0] = c[0];
+ a[1] = c[1];
+ a[2] = c[0];
+ a[3] = c[1];
+ b[0] = c[2];
+ b[1] = c[3];
+ b[2] = c[2];
+ b[3] = c[3];
+ x[0] = c[4];
+ x[1] = c[4];
+}
+
+/* We may not vectorize the store to x[] as it accesses c out-of bounds
+ but we do want to vectorize the other two store groups. */
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized" 1 "slp2" } } */
+/* { dg-final { scan-tree-dump-times "x\\\[\[0-1\]\\\] = " 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr56541.c b/gcc/testsuite/gcc.dg/vect/pr56541.c
index 16b8d7cb75b..d5def6899e4 100644
--- a/gcc/testsuite/gcc.dg/vect/pr56541.c
+++ b/gcc/testsuite/gcc.dg/vect/pr56541.c
@@ -24,4 +24,4 @@ void foo()
}
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail { ! vect_cond_mixed } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-bswap32.c b/gcc/testsuite/gcc.dg/vect/vect-bswap32.c
index 17132baf57b..7f3a915ee97 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-bswap32.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-bswap32.c
@@ -1,4 +1,4 @@
-/* { dg-require-effective-target vect_bswap } */
+/* { dg-additional-options "-msse4" { target sse4_runtime } } */
#include "tree-vect.h"
@@ -42,4 +42,4 @@ main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_bswap || sse4_runtime } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-bswap64.c b/gcc/testsuite/gcc.dg/vect/vect-bswap64.c
index 745a7e73265..b9e421d1de4 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-bswap64.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-bswap64.c
@@ -1,4 +1,4 @@
-/* { dg-require-effective-target vect_bswap } */
+/* { dg-additional-options "-msse4" { target sse4_runtime } } */
#include "tree-vect.h"
@@ -42,4 +42,4 @@ main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_bswap || sse4_runtime } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-2.c b/gcc/testsuite/gcc.dg/vect/vect-cond-2.c
index 9a628567214..d7da8034f0c 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-cond-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-cond-2.c
@@ -39,8 +39,6 @@ int main (void)
return 0;
}
-/* The order of computation should not be changed for cond_expr, therefore,
- it cannot be vectorized in reduction. */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-nb-iter-ub-2.c b/gcc/testsuite/gcc.dg/vect/vect-nb-iter-ub-2.c
index bc07b4bea0f..4e13702621f 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-nb-iter-ub-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-nb-iter-ub-2.c
@@ -3,7 +3,7 @@
#include "tree-vect.h"
int ii[32];
-char cc[66] =
+char cc[66] __attribute__((aligned(1))) =
{ 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0,
10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0,
20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0,
diff --git a/gcc/testsuite/gcc.dg/visibility-14.c b/gcc/testsuite/gcc.dg/visibility-14.c
index 1c01f8399db..e1d85f0ed25 100644
--- a/gcc/testsuite/gcc.dg/visibility-14.c
+++ b/gcc/testsuite/gcc.dg/visibility-14.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern void foo(void) __attribute__ ((visibility ("hidden")));
int f () {
diff --git a/gcc/testsuite/gcc.dg/visibility-15.c b/gcc/testsuite/gcc.dg/visibility-15.c
index 8d331d76cae..4e69fa1db4c 100644
--- a/gcc/testsuite/gcc.dg/visibility-15.c
+++ b/gcc/testsuite/gcc.dg/visibility-15.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern void foo(void) __attribute__ ((visibility ("hidden")));
typedef void (*foo_t)(void);
diff --git a/gcc/testsuite/gcc.dg/visibility-16.c b/gcc/testsuite/gcc.dg/visibility-16.c
index 52a25cdef81..dcd5448d182 100644
--- a/gcc/testsuite/gcc.dg/visibility-16.c
+++ b/gcc/testsuite/gcc.dg/visibility-16.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern int foo __attribute__ ((visibility ("hidden")));
int f () {
diff --git a/gcc/testsuite/gcc.dg/visibility-17.c b/gcc/testsuite/gcc.dg/visibility-17.c
index 0ff3e83de4b..dc90d35839f 100644
--- a/gcc/testsuite/gcc.dg/visibility-17.c
+++ b/gcc/testsuite/gcc.dg/visibility-17.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern int foo __attribute__ ((visibility ("hidden")));
int *f () {
diff --git a/gcc/testsuite/gcc.dg/visibility-18.c b/gcc/testsuite/gcc.dg/visibility-18.c
index f54c73b198a..653e3b1971f 100644
--- a/gcc/testsuite/gcc.dg/visibility-18.c
+++ b/gcc/testsuite/gcc.dg/visibility-18.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern int foo __attribute__ ((visibility ("hidden")));
int *test = &foo;
diff --git a/gcc/testsuite/gcc.dg/visibility-19.c b/gcc/testsuite/gcc.dg/visibility-19.c
index 3c2455fb291..2b0b9beb401 100644
--- a/gcc/testsuite/gcc.dg/visibility-19.c
+++ b/gcc/testsuite/gcc.dg/visibility-19.c
@@ -2,7 +2,7 @@
/* { dg-do compile } */
/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
/* { dg-require-visibility "" } */
-/* { dg-final { scan-hidden "foo" } } */
+/* { dg-final { scan-hidden "foo" { xfail *-*-aix* } } } */
extern void foo(void) __attribute__ ((visibility ("hidden")));
typedef void (*foo_t)(void);
diff --git a/gcc/testsuite/gcc.target/arm/simd/vmaxnm_f32_1.c b/gcc/testsuite/gcc.target/arm/simd/vmaxnm_f32_1.c
new file mode 100644
index 00000000000..79a3b970398
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/simd/vmaxnm_f32_1.c
@@ -0,0 +1,159 @@
+/* Test the `vmaxnmf32' ARM Neon intrinsic. */
+
+/* { dg-do run } */
+/* { dg-require-effective-target arm_v8_neon_hw } */
+/* { dg-options "-save-temps -O3 -march=armv8-a" } */
+/* { dg-add-options arm_v8_neon } */
+
+#include "arm_neon.h"
+
+extern void abort ();
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__regular_input1 ()
+{
+ float32_t a1[] = {1,2};
+ float32_t b1[] = {3,4};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != b1[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__regular_input2 ()
+{
+ float32_t a1[] = {3,2};
+ float32_t b1[] = {1,4};
+ float32_t e[] = {3,4};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__quiet_NaN_one_arg ()
+{
+ /* When given a quiet NaN, vmaxnm returns the other operand.
+ In this test case we have NaNs in only one operand. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {1,2};
+ float32_t b1[] = {n,n};
+ float32_t e[] = {1,2};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__quiet_NaN_both_args ()
+{
+ /* When given a quiet NaN, vmaxnm returns the other operand.
+ In this test case we have NaNs in both operands. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,2};
+ float32_t b1[] = {1,n};
+ float32_t e[] = {1,2};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__zero_both_args ()
+{
+ /* For 0 and -0, vmaxnm returns 0. Since 0 == -0, check sign bit. */
+ float32_t a1[] = {0.0, 0.0};
+ float32_t b1[] = {-0.0, -0.0};
+ float32_t e[] = {0.0, 0.0};
+
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+
+ float32_t actual1[2];
+ vst1_f32 (actual1, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual1[i] != e[i] || __builtin_signbit (actual1[i]) != 0)
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__inf_both_args ()
+{
+ /* The max of inf and inf is inf. The max of -inf and -inf is -inf. */
+ float32_t inf = __builtin_huge_valf ();
+ float32_t a1[] = {inf, -inf};
+ float32_t b1[] = {inf, -inf};
+ float32_t e[] = {inf, -inf};
+
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+
+ float32_t actual1[2];
+ vst1_f32 (actual1, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual1[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnm_f32__two_quiet_NaNs_both_args ()
+{
+ /* When given 2 NaNs, return a NaN. Since a NaN is not equal to anything,
+ not even another NaN, use __builtin_isnan () to check. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,n};
+ float32_t b1[] = {n,n};
+ float32_t e[] = {n,n};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vmaxnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (!__builtin_isnan (actual[i]))
+ abort ();
+}
+
+int
+main ()
+{
+ test_vmaxnm_f32__regular_input1 ();
+ test_vmaxnm_f32__regular_input2 ();
+ test_vmaxnm_f32__quiet_NaN_one_arg ();
+ test_vmaxnm_f32__quiet_NaN_both_args ();
+ test_vmaxnm_f32__zero_both_args ();
+ test_vmaxnm_f32__inf_both_args ();
+ test_vmaxnm_f32__two_quiet_NaNs_both_args ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "vmaxnm\.f32\t\[dD\]\[0-9\]+, ?\[dD\]\[0-9\]+, ?\[dD\]\[0-9\]+\n" 7 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/vmaxnmq_f32_1.c b/gcc/testsuite/gcc.target/arm/simd/vmaxnmq_f32_1.c
new file mode 100644
index 00000000000..07ea7098c52
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/simd/vmaxnmq_f32_1.c
@@ -0,0 +1,160 @@
+/* Test the `vmaxnmqf32' ARM Neon intrinsic. */
+
+/* { dg-do run } */
+/* { dg-require-effective-target arm_v8_neon_hw } */
+/* { dg-options "-save-temps -O3 -march=armv8-a" } */
+/* { dg-add-options arm_v8_neon } */
+
+#include "arm_neon.h"
+
+extern void abort ();
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__regular_input1 ()
+{
+ float32_t a1[] = {1,2,5,6};
+ float32_t b1[] = {3,4,7,8};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != b1[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__regular_input2 ()
+{
+ float32_t a1[] = {3,2,7,6};
+ float32_t b1[] = {1,4,5,8};
+ float32_t e[] = {3,4,7,8};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__quiet_NaN_one_arg ()
+{
+ /* When given a quiet NaN, vmaxnmq returns the other operand.
+ In this test case we have NaNs in only one operand. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {1,2,3,4};
+ float32_t b1[] = {n,n,n,n};
+ float32_t e[] = {1,2,3,4};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__quiet_NaN_both_args ()
+{
+ /* When given a quiet NaN, vmaxnmq returns the other operand.
+ In this test case we have NaNs in both operands. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,2,n,4};
+ float32_t b1[] = {1,n,3,n};
+ float32_t e[] = {1,2,3,4};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__zero_both_args ()
+{
+ /* For 0 and -0, vmaxnmq returns 0. Since 0 == -0, check sign bit. */
+ float32_t a1[] = {0.0, 0.0, -0.0, -0.0};
+ float32_t b1[] = {-0.0, -0.0, 0.0, 0.0};
+ float32_t e[] = {0.0, 0.0, 0.0, 0.0};
+
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+
+ float32_t actual1[4];
+ vst1q_f32 (actual1, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual1[i] != e[i] || __builtin_signbit (actual1[i]) != 0)
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__inf_both_args ()
+{
+ /* The max of inf and inf is inf. The max of -inf and -inf is -inf. */
+ float32_t inf = __builtin_huge_valf ();
+ float32_t a1[] = {inf, -inf, inf, inf};
+ float32_t b1[] = {inf, -inf, -inf, -inf};
+ float32_t e[] = {inf, -inf, inf, inf};
+
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+
+ float32_t actual1[4];
+ vst1q_f32 (actual1, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual1[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vmaxnmq_f32__two_quiet_NaNs_both_args ()
+{
+ /* When given 2 NaNs, return a NaN. Since a NaN is not equal to anything,
+ not even another NaN, use __builtin_isnan () to check. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,n,n,n};
+ float32_t b1[] = {n,n,n,n};
+ float32_t e[] = {n,n};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vmaxnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (!__builtin_isnan (actual[i]))
+ abort ();
+}
+
+int
+main ()
+{
+ test_vmaxnmq_f32__regular_input1 ();
+ test_vmaxnmq_f32__regular_input2 ();
+ test_vmaxnmq_f32__quiet_NaN_one_arg ();
+ test_vmaxnmq_f32__quiet_NaN_both_args ();
+ test_vmaxnmq_f32__zero_both_args ();
+ test_vmaxnmq_f32__inf_both_args ();
+ test_vmaxnmq_f32__two_quiet_NaNs_both_args ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "vmaxnm\.f32\t\[qQ\]\[0-9\]+, ?\[qQ\]\[0-9\]+, ?\[qQ\]\[0-9\]+\n" 7 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/vminnm_f32_1.c b/gcc/testsuite/gcc.target/arm/simd/vminnm_f32_1.c
new file mode 100644
index 00000000000..7ebed5d228d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/simd/vminnm_f32_1.c
@@ -0,0 +1,159 @@
+/* Test the `vminnmf32' ARM Neon intrinsic. */
+
+/* { dg-do run } */
+/* { dg-require-effective-target arm_v8_neon_hw } */
+/* { dg-options "-save-temps -O3 -march=armv8-a" } */
+/* { dg-add-options arm_v8_neon } */
+
+#include "arm_neon.h"
+
+extern void abort ();
+
+void __attribute__ ((noinline))
+test_vminnm_f32__regular_input1 ()
+{
+ float32_t a1[] = {1,2};
+ float32_t b1[] = {3,4};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != a1[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__regular_input2 ()
+{
+ float32_t a1[] = {3,2};
+ float32_t b1[] = {1,4};
+ float32_t e[] = {1,2};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__quiet_NaN_one_arg ()
+{
+ /* When given a quiet NaN, vminnm returns the other operand.
+ In this test case we have NaNs in only one operand. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {1,2};
+ float32_t b1[] = {n,n};
+ float32_t e[] = {1,2};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__quiet_NaN_both_args ()
+{
+ /* When given a quiet NaN, vminnm returns the other operand.
+ In this test case we have NaNs in both operands. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,2};
+ float32_t b1[] = {1,n};
+ float32_t e[] = {1,2};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__zero_both_args ()
+{
+ /* For 0 and -0, vminnm returns -0. Since 0 == -0, check sign bit. */
+ float32_t a1[] = {0.0,0.0};
+ float32_t b1[] = {-0.0, -0.0};
+ float32_t e[] = {-0.0, -0.0};
+
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+
+ float32_t actual1[2];
+ vst1_f32 (actual1, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual1[i] != e[i] || __builtin_signbit (actual1[i]) == 0)
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__inf_both_args ()
+{
+ /* The min of inf and inf is inf. The min of -inf and -inf is -inf. */
+ float32_t inf = __builtin_huge_valf ();
+ float32_t a1[] = {inf, -inf};
+ float32_t b1[] = {inf, -inf};
+ float32_t e[] = {inf, -inf};
+
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+
+ float32_t actual1[2];
+ vst1_f32 (actual1, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (actual1[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnm_f32__two_quiet_NaNs_both_args ()
+{
+ /* When given 2 NaNs, return a NaN. Since a NaN is not equal to anything,
+ not even another NaN, use __builtin_isnan () to check. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,n};
+ float32_t b1[] = {n,n};
+ float32_t e[] = {n,n};
+ float32x2_t a = vld1_f32 (a1);
+ float32x2_t b = vld1_f32 (b1);
+ float32x2_t c = vminnm_f32 (a, b);
+ float32_t actual[2];
+ vst1_f32 (actual, c);
+
+ for (int i = 0; i < 2; ++i)
+ if (!__builtin_isnan (actual[i]))
+ abort ();
+}
+
+int
+main ()
+{
+ test_vminnm_f32__regular_input1 ();
+ test_vminnm_f32__regular_input2 ();
+ test_vminnm_f32__quiet_NaN_one_arg ();
+ test_vminnm_f32__quiet_NaN_both_args ();
+ test_vminnm_f32__zero_both_args ();
+ test_vminnm_f32__inf_both_args ();
+ test_vminnm_f32__two_quiet_NaNs_both_args ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "vminnm\.f32\t\[dD\]\[0-9\]+, ?\[dD\]\[0-9\]+, ?\[dD\]\[0-9\]+\n" 7 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/vminnmq_f32_1.c b/gcc/testsuite/gcc.target/arm/simd/vminnmq_f32_1.c
new file mode 100644
index 00000000000..892fb7a0aa0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/simd/vminnmq_f32_1.c
@@ -0,0 +1,159 @@
+/* Test the `vminnmqf32' ARM Neon intrinsic. */
+
+/* { dg-do run } */
+/* { dg-require-effective-target arm_v8_neon_hw } */
+/* { dg-options "-save-temps -O3 -march=armv8-a" } */
+/* { dg-add-options arm_v8_neon } */
+
+#include "arm_neon.h"
+
+extern void abort ();
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__regular_input1 ()
+{
+ float32_t a1[] = {1,2,5,6};
+ float32_t b1[] = {3,4,7,8};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != a1[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__regular_input2 ()
+{
+ float32_t a1[] = {3,2,7,6};
+ float32_t b1[] = {1,4,5,8};
+ float32_t e[] = {1,2,5,6};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__quiet_NaN_one_arg ()
+{
+ /* When given a quiet NaN, vminnmq returns the other operand.
+ In this test case we have NaNs in only one operand. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {1,2,3,4};
+ float32_t b1[] = {n,n,n,n};
+ float32_t e[] = {1,2,3,4};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__quiet_NaN_both_args ()
+{
+ /* When given a quiet NaN, vminnmq returns the other operand.
+ In this test case we have NaNs in both operands. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,2,n,4};
+ float32_t b1[] = {1,n,3,n};
+ float32_t e[] = {1,2,3,4};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__zero_both_args ()
+{
+ /* For 0 and -0, vminnmq returns -0. Since 0 == -0, check sign bit. */
+ float32_t a1[] = {0.0, 0.0, -0.0, -0.0};
+ float32_t b1[] = {-0.0, -0.0, 0.0, 0.0};
+ float32_t e[] = {-0.0, -0.0, -0.0, -0.0};
+
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+
+ float32_t actual1[4];
+ vst1q_f32 (actual1, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual1[i] != e[i] || __builtin_signbit (actual1[i]) == 0)
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__inf_both_args ()
+{
+ /* The min of inf and inf is inf. The min of -inf and -inf is -inf. */
+ float32_t inf = __builtin_huge_valf ();
+ float32_t a1[] = {inf, -inf, inf, inf};
+ float32_t b1[] = {inf, -inf, -inf, -inf};
+ float32_t e[] = {inf, -inf, -inf, -inf};
+
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+
+ float32_t actual1[4];
+ vst1q_f32 (actual1, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (actual1[i] != e[i])
+ abort ();
+}
+
+void __attribute__ ((noinline))
+test_vminnmq_f32__two_quiet_NaNs_both_args ()
+{
+ /* When given 2 NaNs, return a NaN. Since a NaN is not equal to anything,
+ not even another NaN, use __builtin_isnan () to check. */
+ float32_t n = __builtin_nanf ("");
+ float32_t a1[] = {n,n,n,n};
+ float32_t b1[] = {n,n,n,n};
+ float32_t e[] = {n,n};
+ float32x4_t a = vld1q_f32 (a1);
+ float32x4_t b = vld1q_f32 (b1);
+ float32x4_t c = vminnmq_f32 (a, b);
+ float32_t actual[4];
+ vst1q_f32 (actual, c);
+
+ for (int i = 0; i < 4; ++i)
+ if (!__builtin_isnan (actual[i]))
+ abort ();
+}
+
+int
+main ()
+{
+ test_vminnmq_f32__regular_input1 ();
+ test_vminnmq_f32__regular_input2 ();
+ test_vminnmq_f32__quiet_NaN_one_arg ();
+ test_vminnmq_f32__quiet_NaN_both_args ();
+ test_vminnmq_f32__zero_both_args ();
+ test_vminnmq_f32__inf_both_args ();
+ test_vminnmq_f32__two_quiet_NaNs_both_args ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler-times "vminnm\.f32\t\[qQ\]\[0-9\]+, ?\[qQ\]\[0-9\]+, ?\[qQ\]\[0-9\]+\n" 7 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr70799-2.c b/gcc/testsuite/gcc.target/i386/pr70799-2.c
new file mode 100644
index 00000000000..47810511f97
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr70799-2.c
@@ -0,0 +1,17 @@
+/* PR target/pr70799 */
+/* { dg-do compile { target { ia32 } } } */
+/* { dg-options "-O2 -march=slm -mno-stackrealign" } */
+/* { dg-final { scan-assembler "psllq" } } */
+/* { dg-final { scan-assembler "psrlq" } } */
+
+unsigned long long a, b;
+
+void test1 (void)
+{
+ a = b << 21;
+}
+
+void test2 (void)
+{
+ a = b >> 21;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr71529.C b/gcc/testsuite/gcc.target/i386/pr71529.C
deleted file mode 100644
index 3169101e1a7..00000000000
--- a/gcc/testsuite/gcc.target/i386/pr71529.C
+++ /dev/null
@@ -1,22 +0,0 @@
-/* PR71529 */
-/* { dg-do compile { target { ! x32 } } } */
-/* { dg-options "-fcheck-pointer-bounds -mmpx -O2" } */
-
-class c1
-{
- public:
- virtual ~c1 ();
-};
-
-class c2
-{
- public:
- virtual ~c2 ();
-};
-
-class c3 : c1, c2 { };
-
-int main (int, char **)
-{
- c3 obj;
-}
diff --git a/gcc/testsuite/gcc.target/i386/pr78035.c b/gcc/testsuite/gcc.target/i386/pr78035.c
new file mode 100644
index 00000000000..2e673a8ce2d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78035.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int a;
+extern int b;
+extern int c;
+
+int foo(int choose_a)
+{
+ int *p;
+ if (choose_a)
+ p = &a;
+ else
+ p = &b;
+ return p != &c;
+}
+
+int bar ()
+{
+ return &a != &c;
+}
+
+/* We should not optimize away either comparison. */
+/* { dg-final { scan-assembler-times "cmp" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78227-1.c b/gcc/testsuite/gcc.target/i386/pr78227-1.c
new file mode 100644
index 00000000000..9dc97dd738f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78227-1.c
@@ -0,0 +1,30 @@
+/* PR target/78227 */
+/* { dg-do compile } */
+/* { dg-options "-mavx512f -O0 -Wno-psabi" } */
+
+typedef int V __attribute__((vector_size (64)));
+typedef long long int W __attribute__((vector_size (64)));
+
+V
+foo1 (V v)
+{
+ return v > 0;
+}
+
+V
+bar1 (V v)
+{
+ return v != 0;
+}
+
+W
+foo2 (W w)
+{
+ return w > 0;
+}
+
+W
+bar2 (W w)
+{
+ return w != 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78227-2.c b/gcc/testsuite/gcc.target/i386/pr78227-2.c
new file mode 100644
index 00000000000..c557c8f12b4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78227-2.c
@@ -0,0 +1,30 @@
+/* PR target/78227 */
+/* { dg-do compile } */
+/* { dg-options "-mavx512bw -O0 -Wno-psabi" } */
+
+typedef signed char V __attribute__((vector_size (64)));
+typedef short int W __attribute__((vector_size (64)));
+
+V
+foo1 (V v)
+{
+ return v > 0;
+}
+
+V
+bar1 (V v)
+{
+ return v != 0;
+}
+
+W
+foo2 (W w)
+{
+ return w > 0;
+}
+
+W
+bar2 (W w)
+{
+ return w != 0;
+}
diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp
index 7c241400b73..39f44ffc9d6 100644
--- a/gcc/testsuite/gcc.target/mips/mips.exp
+++ b/gcc/testsuite/gcc.target/mips/mips.exp
@@ -1176,7 +1176,8 @@ proc mips-dg-options { args } {
|| [mips_have_test_option_p options "-mpaired-single"]
|| [mips_have_test_option_p options "-mnan=legacy"]
|| [mips_have_test_option_p options "-mabs=legacy"]
- || [mips_have_test_option_p options "!HAS_LSA"]) } {
+ || [mips_have_test_option_p options "!HAS_LSA"]
+ || [mips_have_test_option_p options "-mbranch-likely"]) } {
if { $gp_size == 32 } {
mips_make_test_option options "-mips32r5"
} else {
@@ -1345,6 +1346,7 @@ proc mips-dg-options { args } {
mips_make_test_option options "-mno-paired-single"
mips_make_test_option options "-mnan=2008"
mips_make_test_option options "-mabs=2008"
+ mips_make_test_option options "-mno-branch-likely"
}
if { [regexp {^-march=(octeon|loongson)} $arch] } {
mips_make_test_option options "-mno-micromips"
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-1.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-1.c
new file mode 100644
index 00000000000..4ffdb81e709
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-1.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_add with char
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec" } */
+
+#include <altivec.h>
+
+vector signed char
+test1 (vector bool char x, vector signed char y)
+{
+ return vec_add (x, y);
+}
+
+vector signed char
+test2 (vector signed char x, vector bool char y)
+{
+ return vec_add (x, y);
+}
+
+vector signed char
+test3 (vector signed char x, vector signed char y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned char
+test4 (vector bool char x, vector unsigned char y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned char
+test5 (vector unsigned char x, vector bool char y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned char
+test6 (vector unsigned char x, vector unsigned char y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vaddubm" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-2.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-2.c
new file mode 100644
index 00000000000..c3b5e1d4aec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-2.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_add with short
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec" } */
+
+#include <altivec.h>
+
+vector signed short
+test1 (vector bool short x, vector signed short y)
+{
+ return vec_add (x, y);
+}
+
+vector signed short
+test2 (vector signed short x, vector bool short y)
+{
+ return vec_add (x, y);
+}
+
+vector signed short
+test3 (vector signed short x, vector signed short y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned short
+test4 (vector bool short x, vector unsigned short y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned short
+test5 (vector unsigned short x, vector bool short y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned short
+test6 (vector unsigned short x, vector unsigned short y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vadduhm" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-3.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-3.c
new file mode 100644
index 00000000000..bb7e644caad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-3.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_add with int
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec" } */
+
+#include <altivec.h>
+
+vector signed int
+test1 (vector bool int x, vector signed int y)
+{
+ return vec_add (x, y);
+}
+
+vector signed int
+test2 (vector signed int x, vector bool int y)
+{
+ return vec_add (x, y);
+}
+
+vector signed int
+test3 (vector signed int x, vector signed int y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned int
+test4 (vector bool int x, vector unsigned int y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned int
+test5 (vector unsigned int x, vector bool int y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned int
+test6 (vector unsigned int x, vector unsigned int y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vadduwm" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-4.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-4.c
new file mode 100644
index 00000000000..389a20ccfd2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-4.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_add with long long
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-maltivec -mvsx -mpower8-vector" } */
+
+#include <altivec.h>
+
+vector signed long long
+test1 (vector bool long long x, vector signed long long y)
+{
+ return vec_add (x, y);
+}
+
+vector signed long long
+test2 (vector signed long long x, vector bool long long y)
+{
+ return vec_add (x, y);
+}
+
+vector signed long long
+test3 (vector signed long long x, vector signed long long y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned long long
+test4 (vector bool long long x, vector unsigned long long y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned long long
+test5 (vector unsigned long long x, vector bool long long y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned long long
+test6 (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vaddudm" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-5.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-5.c
new file mode 100644
index 00000000000..cc1d8c443a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-5.c
@@ -0,0 +1,16 @@
+/* Verify that overloaded built-ins for vec_add with float
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -mno-vsx" } */
+
+#include <altivec.h>
+
+vector float
+test1 (vector float x, vector float y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vaddfp" 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-6.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-6.c
new file mode 100644
index 00000000000..559b3e15a4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-6.c
@@ -0,0 +1,23 @@
+/* Verify that overloaded built-ins for vec_add with float and
+ double inputs for VSX produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-maltivec -mvsx" } */
+
+#include <altivec.h>
+
+vector float
+test1 (vector float x, vector float y)
+{
+ return vec_add (x, y);
+}
+
+vector double
+test2 (vector double x, vector double y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "xvaddsp" 1 } } */
+/* { dg-final { scan-assembler-times "xvadddp" 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-add-7.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-7.c
new file mode 100644
index 00000000000..185a90340c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-add-7.c
@@ -0,0 +1,23 @@
+/* Verify that overloaded built-ins for vec_add with __int128
+ inputs produce the right results. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-maltivec -mvsx -mpower8-vector" } */
+/* { dg-additional-options "-maix64" { target powerpc-ibm-aix* } } */
+
+#include "altivec.h"
+
+vector signed __int128
+test1 (vector signed __int128 x, vector signed __int128 y)
+{
+ return vec_add (x, y);
+}
+
+vector unsigned __int128
+test2 (vector unsigned __int128 x, vector unsigned __int128 y)
+{
+ return vec_add (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vadduqm" 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx-extract-4.c b/gcc/testsuite/gcc.target/powerpc/vsx-extract-4.c
new file mode 100644
index 00000000000..3b498f4bc2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx-extract-4.c
@@ -0,0 +1,76 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-O2 -mcpu=power8" } */
+
+/* { dg-final { scan-assembler-times "vspltw" 6 } } */
+/* { dg-final { scan-assembler-times "xvcvsxwdp" 4 } } */
+/* { dg-final { scan-assembler-times "xvcvuxwdp" 4 } } */
+/* { dg-final { scan-assembler-not "mtvsrd" } } */
+/* { dg-final { scan-assembler-not "mtvsrwa" } } */
+/* { dg-final { scan-assembler-not "mtvsrwz" } } */
+/* { dg-final { scan-assembler-not "mfvsrd" } } */
+/* { dg-final { scan-assembler-not "mfvsrwz" } } */
+
+#include <altivec.h>
+
+#ifndef TYPE
+#define TYPE double
+#endif
+
+TYPE
+foo_0s (vector int v)
+{
+ int i = vec_extract (v, 0);
+ return (TYPE) i;
+}
+
+TYPE
+foo_1s (vector int v)
+{
+ int i = vec_extract (v, 1);
+ return (TYPE) i;
+}
+
+TYPE
+foo_2s (vector int v)
+{
+ int i = vec_extract (v, 2);
+ return (TYPE) i;
+}
+
+TYPE
+foo_3s (vector int v)
+{
+ int i = vec_extract (v, 3);
+ return (TYPE) i;
+}
+
+TYPE
+foo_0u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 0);
+ return (TYPE) u;
+}
+
+TYPE
+foo_1u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 1);
+ return (TYPE) u;
+}
+
+TYPE
+foo_2u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 2);
+ return (TYPE) u;
+}
+
+TYPE
+foo_3u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 3);
+ return (TYPE) u;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx-extract-5.c b/gcc/testsuite/gcc.target/powerpc/vsx-extract-5.c
new file mode 100644
index 00000000000..1338c6b1de5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/vsx-extract-5.c
@@ -0,0 +1,77 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-O2 -mcpu=power8" } */
+
+/* { dg-final { scan-assembler-times "vspltw" 6 } } */
+/* { dg-final { scan-assembler-times "xvcvsxwdp" 4 } } */
+/* { dg-final { scan-assembler-times "xvcvuxwdp" 4 } } */
+/* { dg-final { scan-assembler-times "frsp\|xsrsp" 8 } } */
+/* { dg-final { scan-assembler-not "mtvsrd" } } */
+/* { dg-final { scan-assembler-not "mtvsrwa" } } */
+/* { dg-final { scan-assembler-not "mtvsrwz" } } */
+/* { dg-final { scan-assembler-not "mfvsrd" } } */
+/* { dg-final { scan-assembler-not "mfvsrwz" } } */
+
+#include <altivec.h>
+
+#ifndef TYPE
+#define TYPE float
+#endif
+
+TYPE
+foo_0s (vector int v)
+{
+ int i = vec_extract (v, 0);
+ return (TYPE) i;
+}
+
+TYPE
+foo_1s (vector int v)
+{
+ int i = vec_extract (v, 1);
+ return (TYPE) i;
+}
+
+TYPE
+foo_2s (vector int v)
+{
+ int i = vec_extract (v, 2);
+ return (TYPE) i;
+}
+
+TYPE
+foo_3s (vector int v)
+{
+ int i = vec_extract (v, 3);
+ return (TYPE) i;
+}
+
+TYPE
+foo_0u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 0);
+ return (TYPE) u;
+}
+
+TYPE
+foo_1u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 1);
+ return (TYPE) u;
+}
+
+TYPE
+foo_2u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 2);
+ return (TYPE) u;
+}
+
+TYPE
+foo_3u (vector unsigned int v)
+{
+ unsigned int u = vec_extract (v, 3);
+ return (TYPE) u;
+}
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-3.c b/gcc/testsuite/gcc.target/sparc/overflow-3.c
index 31b326486ee..8cb24f52f7b 100644
--- a/gcc/testsuite/gcc.target/sparc/overflow-3.c
+++ b/gcc/testsuite/gcc.target/sparc/overflow-3.c
@@ -5,40 +5,39 @@
#include <stdbool.h>
#include <stdint.h>
-bool my_uadd_overflow (uint64_t a, uint64_t b, uint64_t *res)
+bool my_uadd_overflow (uint32_t a, uint32_t b, uint32_t *res)
{
return __builtin_add_overflow (a, b, res);
}
-bool my_usub_overflow (uint64_t a, uint64_t b, uint64_t *res)
+bool my_usub_overflow (uint32_t a, uint32_t b, uint32_t *res)
{
return __builtin_sub_overflow (a, b, res);
}
-bool my_uneg_overflow (uint64_t a, uint64_t *res)
+bool my_uneg_overflow (uint32_t a, uint32_t *res)
{
return __builtin_sub_overflow (0, a, res);
}
-bool my_add_overflow (int64_t a, int64_t b, int64_t *res)
+bool my_add_overflow (int32_t a, int32_t b, int32_t *res)
{
return __builtin_add_overflow (a, b, res);
}
-bool my_sub_overflow (int64_t a, int64_t b, int64_t *res)
+bool my_sub_overflow (int32_t a, int32_t b, int32_t *res)
{
return __builtin_sub_overflow (a, b, res);
}
-bool my_neg_overflow (int64_t a, int64_t *res)
+bool my_neg_overflow (int32_t a, int32_t *res)
{
return __builtin_sub_overflow (0, a, res);
}
/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
-/* { dg-final { scan-assembler-times "movlu\t%" 1 } } */
-/* { dg-final { scan-assembler-times "blu" 2 } } */
+/* { dg-final { scan-assembler-times "addx\t%" 3 } } */
/* { dg-final { scan-assembler-times "bvs" 3 } } */
/* { dg-final { scan-assembler-not "cmp\t%" } } */
/* { dg-final { scan-assembler-not "save\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-4.c b/gcc/testsuite/gcc.target/sparc/overflow-4.c
new file mode 100644
index 00000000000..31b326486ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-4.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-require-effective-target lp64 } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool my_uadd_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (uint64_t a, uint64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int64_t a, int64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "movlu\t%" 1 } } */
+/* { dg-final { scan-assembler-times "blu" 2 } } */
+/* { dg-final { scan-assembler-times "bvs" 3 } } */
+/* { dg-final { scan-assembler-not "cmp\t%" } } */
+/* { dg-final { scan-assembler-not "save\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/overflow-5.c b/gcc/testsuite/gcc.target/sparc/overflow-5.c
new file mode 100644
index 00000000000..501ce04f7a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/overflow-5.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O -mvis3" } */
+/* { dg-require-effective-target lp64 } */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool my_uadd_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_usub_overflow (uint64_t a, uint64_t b, uint64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_uneg_overflow (uint64_t a, uint64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+bool my_add_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_add_overflow (a, b, res);
+}
+
+bool my_sub_overflow (int64_t a, int64_t b, int64_t *res)
+{
+ return __builtin_sub_overflow (a, b, res);
+}
+
+bool my_neg_overflow (int64_t a, int64_t *res)
+{
+ return __builtin_sub_overflow (0, a, res);
+}
+
+/* { dg-final { scan-assembler-times "addcc\t%" 2 } } */
+/* { dg-final { scan-assembler-times "subcc\t%" 4 } } */
+/* { dg-final { scan-assembler-times "addxc\t%" 3 } } */
+/* { dg-final { scan-assembler-times "bvs" 3 } } */
+/* { dg-final { scan-assembler-not "cmp\t%" } } */
+/* { dg-final { scan-assembler-not "save\t%" } } */
diff --git a/gcc/testsuite/gfortran.dg/allocate_with_source_14.f03 b/gcc/testsuite/gfortran.dg/allocate_with_source_14.f03
index 36c1245ccdd..fd2db7439fe 100644
--- a/gcc/testsuite/gfortran.dg/allocate_with_source_14.f03
+++ b/gcc/testsuite/gfortran.dg/allocate_with_source_14.f03
@@ -210,5 +210,5 @@ program main
call v%free()
deallocate(av)
end program
-! { dg-final { scan-tree-dump-times "__builtin_malloc" 23 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_malloc" 22 "original" } }
! { dg-final { scan-tree-dump-times "__builtin_free" 29 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/associate_23.f90 b/gcc/testsuite/gfortran.dg/associate_23.f90
new file mode 100644
index 00000000000..b4d58ffd2b7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_23.f90
@@ -0,0 +1,36 @@
+! { dg-do run }
+!
+! Tests the fix for PR64933
+!
+! Contributed by Olivier Marsden <olivier.marsden@ecmwf.int>
+!
+program test_this
+ implicit none
+ character(len = 15) :: char_var, char_var_dim (3)
+ character(len = 80) :: buffer
+
+! Original failing case reported in PR
+ ASSOCIATE(should_work=>char_var)
+ should_work = "test succesful"
+ write (buffer, *) should_work(5:14)
+ END ASSOCIATE
+
+ if (trim (buffer) .ne. " succesful") call abort
+
+! Found to be failing during debugging
+ ASSOCIATE(should_work=>char_var_dim)
+ should_work = ["test SUCCESFUL", "test_SUCCESFUL", "test.SUCCESFUL"]
+ write (buffer, *) should_work(:)(5:14)
+ END ASSOCIATE
+
+ if (trim (buffer) .ne. " SUCCESFUL_SUCCESFUL.SUCCESFUL") call abort
+
+! Found to be failing during debugging
+ ASSOCIATE(should_work=>char_var_dim(1:2))
+ should_work = ["test SUCCESFUL", "test_SUCCESFUL", "test.SUCCESFUL"]
+ write (buffer, *) should_work(:)(5:14)
+ END ASSOCIATE
+
+ if (trim (buffer) .ne. " SUCCESFUL_SUCCESFUL") call abort
+
+end program
diff --git a/gcc/testsuite/gfortran.dg/class_58.f90 b/gcc/testsuite/gfortran.dg/class_58.f90
new file mode 100644
index 00000000000..20b601a2f51
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_58.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+!
+! PR 68440: [OOP] ICE on declaring class variable with wrong attribute
+!
+! Contributed by Gerhard Steinmetz <gerhard.steinmetz.fortran@t-online.de>
+
+subroutine s
+ type t
+ end type
+ class(t), parameter :: x = t() ! { dg-error "cannot have the PARAMETER attribute" }
+ class(t), parameter :: y = x ! { dg-error "cannot have the PARAMETER attribute" }
+ class(t) :: z = x ! { dg-error "must be dummy, allocatable or pointer" }
+end
diff --git a/gcc/testsuite/gfortran.dg/class_59.f90 b/gcc/testsuite/gfortran.dg/class_59.f90
new file mode 100644
index 00000000000..e077ef8dc30
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_59.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+!
+! PR 71894: [OOP] ICE in gfc_add_component_ref, at fortran/class.c:227
+!
+! Contributed by Gerhard Steinmetz <gerhard.steinmetz.fortran@t-online.de>
+
+subroutine s1
+ type t
+ integer :: n
+ end type
+ type(t) :: x
+ class(t) :: y ! { dg-error "must be dummy, allocatable or pointer" }
+ x = y
+end
+
+subroutine s2
+ type t
+ end type
+ class(t) :: x ! { dg-error "must be dummy, allocatable or pointer" }
+ class(t), allocatable :: y
+ select type (y)
+ type is (t)
+ y = x
+ end select
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_exp_1.f90 b/gcc/testsuite/gfortran.dg/dec_exp_1.f90
new file mode 100644
index 00000000000..c8b395aa9ce
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_exp_1.f90
@@ -0,0 +1,35 @@
+! { dg-do run }
+! { dg-options "-fdec" }
+!
+! Test support for providing a default exponent of zero when unspecified in
+! real constants with -fdec.
+!
+
+subroutine asserteq (rexp, ract, msg)
+ real, intent(in) :: rexp, ract
+ character(*), intent(in) :: msg
+ if (rexp .ne. ract) then
+ write (*, '(A,F12.6,F12.6)') msg, rexp, ract
+ call abort()
+ endif
+end subroutine
+
+implicit none
+
+real, parameter :: r1 = 8e0
+real, parameter :: r2 = 8e ! { equivalent to 8e0 }
+real, volatile :: r3, r4
+character(2) :: s
+r3 = 8e ! { equivalent to 8e0 }
+s = '8e'
+
+read (s, *) r4
+
+call asserteq (r1, r2, "[const]")
+call asserteq (r1, r3, "[vol. ]")
+call asserteq (r1, r4, "[read ]")
+
+r4 = 8e + 48e
+call asserteq (56e, r4, "[sum ]")
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_exp_2.f90 b/gcc/testsuite/gfortran.dg/dec_exp_2.f90
new file mode 100644
index 00000000000..9137aabc4b3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_exp_2.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "" }
+!
+! Make sure we still see an error for missing exponents without -fdec.
+!
+
+implicit none
+
+real, parameter :: r1 = 8e ! { dg-error "Missing exponent" }
+real, volatile :: r2
+r2 = 8e ! { dg-error "Missing exponent" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_exp_3.f90 b/gcc/testsuite/gfortran.dg/dec_exp_3.f90
new file mode 100644
index 00000000000..34835a77b32
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_exp_3.f90
@@ -0,0 +1,15 @@
+! { dg-do run "xfail *-*-*" }
+! { dg-options "" }
+!
+! Make sure we still see an error for missing exponents without -fdec.
+!
+
+implicit none
+
+real :: r
+character(2) :: s
+s = '8e'
+
+read (s, *) r ! { XFAIL "Bad real number" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_1.f b/gcc/testsuite/gfortran.dg/dec_parameter_1.f
new file mode 100644
index 00000000000..69ffa53c806
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_1.f
@@ -0,0 +1,64 @@
+ ! { dg-do run }
+ ! { dg-options "-ffixed-form -std=legacy" }
+ !
+ ! Test DEC-style PARAMETER statements without parentheses in
+ ! fixed form.
+ !
+
+ subroutine sub1(t, x, y)
+ implicit real(8) (A-H,O-Z)
+ parameter (pi_1 = 3.141592654d0, f_1 = 3.d08)
+ parameter pi_2 = 3.141592654d0, f_2 = 3.d08
+ ! Note that if the parameter statements above are matched
+ ! incorrectly as assignments, the below specification
+ ! statements will be considered out-of-order and we see
+ ! 'unexpected specification statement'. A PARAMETER
+ ! statement should still be a specification statement.
+
+ real(8), intent(in) :: t
+ real(8), intent(out) :: x, y
+
+ real(8), volatile :: two
+ two = 2.0d0
+ x = two * pi_1 * f_1 * t
+ y = two * pi_2 * f_2 * t
+ z = two * pi_3 * f_3 * t
+ return
+ end subroutine
+
+ subroutine sub2(t, x, y, z)
+ implicit none
+ real(8) :: pi_1, pi_2, f_1, f_2
+ parameter (pi_1 = 3.141592654d0, f_1 = 3.d08)
+ parameter pi_2 = 3.141592654d0, f_2 = 3.d08
+ real(8), parameter :: pi_3 = 3.141592654d0, f_3 = 3.d08
+ ! Ditto sub1
+
+ real(8), intent(in) :: t
+ real(8), intent(out) :: x, y, z
+
+ real(8), volatile :: two
+ two = 2.0d0
+ x = two * pi_1 * f_1 * t
+ y = two * pi_2 * f_2 * t
+ z = two * pi_3 * f_3 * t
+ end subroutine
+
+ implicit none
+ real(8) :: x1, x2, y1, y2, z2
+ real(8), volatile :: t
+ t = 1.5e-6
+
+ call sub1(t, x1, y1)
+ call sub2(t, x2, y2, z2)
+
+ write(*,'(4D18.5)') t, x1, y1
+ write(*,'(4D18.5)') t, x2, y2, z2
+
+ if (x1 .ne. x2 .or. y1 .ne. y2
+ & .or. x1 .ne. y1 .or. x2 .ne. y2
+ & .or. y2 .ne. z2) then
+ call abort()
+ endif
+
+ end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_2.f90 b/gcc/testsuite/gfortran.dg/dec_parameter_2.f90
new file mode 100644
index 00000000000..280f0007f93
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_2.f90
@@ -0,0 +1,63 @@
+! { dg-do run }
+! { dg-options "-ffree-form -std=legacy" }
+!
+! Test DEC-style PARAMETER statements without parentheses in free form.
+!
+
+subroutine sub1(t, x, y)
+ implicit real(8) (A-H,O-Z)
+ parameter (pi_1 = 3.141592654d0, f_1 = 3.d08)
+ parameter pi_2 = 3.141592654d0, f_2 = 3.d08 ! legacy PARAMETER
+ ! Note that if the parameter statements above are matched
+ ! incorrectly as assignments, the below specification
+ ! statements will be considered out-of-order and we see
+ ! 'unexpected specification statement'. A PARAMETER
+ ! statement should still be a specification statement.
+
+ real(8), intent(in) :: t
+ real(8), intent(out) :: x, y
+
+ real(8), volatile :: two
+ two = 2.0d0
+ x = two * pi_1 * f_1 * t
+ y = two * pi_2 * f_2 * t
+ z = two * pi_3 * f_3 * t
+ return
+end subroutine
+
+subroutine sub2(t, x, y, z)
+ implicit none
+ real(8) :: pi_1, pi_2, f_1, f_2
+ parameter (pi_1 = 3.141592654d0, f_1 = 3.d08)
+ parameter pi_2 = 3.141592654d0, f_2 = 3.d08 ! legacy PARAMETER
+ real(8), parameter :: pi_3 = 3.141592654d0, f_3 = 3.d08
+ ! Ditto sub1
+
+ real(8), intent(in) :: t
+ real(8), intent(out) :: x, y, z
+
+ real(8), volatile :: two
+ two = 2.0d0
+ x = two * pi_1 * f_1 * t
+ y = two * pi_2 * f_2 * t
+ z = two * pi_3 * f_3 * t
+end subroutine
+
+implicit none
+real(8) :: x1, x2, y1, y2, z2
+real(8), volatile :: t
+t = 1.5e-6
+
+call sub1(t, x1, y1)
+call sub2(t, x2, y2, z2)
+
+write(*,'(4D18.5)') t, x1, y1
+write(*,'(4D18.5)') t, x2, y2, z2
+
+if (x1 .ne. x2 .or. y1 .ne. y2 &
+ .or. x1 .ne. y1 .or. x2 .ne. y2 &
+ .or. y2 .ne. z2) then
+ call abort()
+endif
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_3.f90 b/gcc/testsuite/gfortran.dg/dec_parameter_3.f90
new file mode 100644
index 00000000000..92f0f61bb66
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_3.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "-ffree-form -std=gnu" }
+!
+! Test warnings for DEC-style PARAMETER statements with std=gnu.
+!
+
+subroutine sub()
+ implicit real(8) (A-Z)
+ parameter pi = 3.1415926535d0 ! { dg-warning "Legacy Extension: PARAMETER" }
+ print *, pi
+end subroutine
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_4.f90 b/gcc/testsuite/gfortran.dg/dec_parameter_4.f90
new file mode 100644
index 00000000000..280d56c424f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_4.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "-ffree-form -std=f95" }
+!
+! Test errors for DEC-style PARAMETER statements with a real standard.
+!
+
+subroutine sub()
+ implicit real(8) (A-Z)
+ parameter pi = 3.1415926535d0 ! { dg-error "Legacy Extension: PARAMETER" }
+ print *, pi
+end subroutine
+
+end
diff --git a/gcc/testsuite/gfortran.dg/elemental_optional_args_6.f90 b/gcc/testsuite/gfortran.dg/elemental_optional_args_6.f90
index ad1c252fb00..2dece646dde 100644
--- a/gcc/testsuite/gfortran.dg/elemental_optional_args_6.f90
+++ b/gcc/testsuite/gfortran.dg/elemental_optional_args_6.f90
@@ -1,4 +1,5 @@
! { dg-do run }
+! { dg-options "-Wpedantic" }
!
! PR fortran/53692
!
diff --git a/gcc/testsuite/gfortran.dg/fmt_l.f90 b/gcc/testsuite/gfortran.dg/fmt_l.f90
index 9dc4f570473..0fd195515fc 100644
--- a/gcc/testsuite/gfortran.dg/fmt_l.f90
+++ b/gcc/testsuite/gfortran.dg/fmt_l.f90
@@ -52,34 +52,34 @@ program test_l
end program test_l
! { dg-output "At line 14 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 15 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 19 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 20 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 24 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 25 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 29 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 30 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 34 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 35 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 39 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 40 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 44 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 45 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 49 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
! { dg-output "At line 50 of file.*" }
-! { dg-output "Fortran runtime warning: Positive width required in format(\n|\r\n|\r)" }
+! { dg-output "Fortran runtime warning: Positive width required with L descriptor(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/gfortran.dg/fmt_l0.f90 b/gcc/testsuite/gfortran.dg/fmt_l0.f90
new file mode 100644
index 00000000000..fab1ffb1ce9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/fmt_l0.f90
@@ -0,0 +1,12 @@
+! { dg-do run }
+! { dg-options "-std=gnu -pedantic" }
+! Test the GNU extension of a L format descriptor without width
+! PR libfortran/54679
+program main
+ implicit none
+ character(len=20) :: str
+ character(len=60) :: format2 = "(2(1x,l0,1x))"
+ write(str,format2)
+end program main
+! { dg-output "At line 9 of file.*" }
+! { dg-output "Fortran runtime warning: Zero width after L descriptor(\n|\r\n|\r)" }
diff --git a/gcc/testsuite/gfortran.dg/fmt_t_9.f b/gcc/testsuite/gfortran.dg/fmt_t_9.f
new file mode 100644
index 00000000000..bfe0361d0e1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/fmt_t_9.f
@@ -0,0 +1,41 @@
+! { dg-options "-ffixed-line-length-none -std=gnu" }
+! { dg-do run }
+! PR78123 Short reads with T edit descriptor not padding correctly
+ PROGRAM tformat
+C
+ INTEGER MXFLTL
+ PARAMETER (MXFLTL = 99999)
+ INTEGER IFLGHT, NFLCYC, IFLTSQ(MXFLTL), IDXBLK, LMAX, LMIN, I
+C
+ OPEN(29, status='scratch')
+ WRITE(29, '(a)') " 1 1 1 TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT 72 122 4"
+ WRITE(29, '(a)') ""
+ WRITE(29, '(a)') " 451 402012011201120112011200120112011201120112011201120111971201120112011201120112011201"
+ WRITE(29, '(a)') " 451 4020 866 866 866 866 866 866 866 866 865 866 865 866 866 866 866 866 866 866 865 866"
+ REWIND(29)
+C The error occurs in the following loop:
+ 10 CONTINUE
+ READ(29,1010 ) IDXBLK, LMAX, LMIN
+1010 FORMAT(8X,I4,T51,2I5) ! wrong if this format is used
+c write(6,fmt='("IDXBLK,LMAX,LMIN=",3I5)')IDXBLK,LMAX,LMIN
+ IF (IDXBLK .EQ. 0) GO TO 20
+ GO TO 10
+C
+ 20 CONTINUE
+ READ(29,1040,END=100) IFLGHT, NFLCYC,
+ & (IFLTSQ(I), I=1,NFLCYC)
+1040 FORMAT(I5,I5,2X,(T13,20I4))
+c write(6,fmt='(2i6)') IFLGHT,NFLCYC
+c write(6,fmt='(20I4)') (IFLTSQ(I), I=1,NFLCYC)
+c write(6,*) "Program is correct"
+ close(29)
+ if (IFLGHT.ne.451) call abort
+ if (NFLCYC.ne.40) call abort
+ stop
+C
+ 100 CONTINUE
+C write(6,*) "End of file encountered (wrong)"
+ close (29)
+ call abort
+ STOP
+ END
diff --git a/gcc/testsuite/gfortran.dg/implicit_class_1.f90 b/gcc/testsuite/gfortran.dg/implicit_class_1.f90
index 2ab90405eb0..380942cfdba 100644
--- a/gcc/testsuite/gfortran.dg/implicit_class_1.f90
+++ b/gcc/testsuite/gfortran.dg/implicit_class_1.f90
@@ -1,4 +1,5 @@
! { dg-do run }
+! { dg-skip-if "" { powerpc-ibm-aix* } { "*" } { "" } }
!
! PR 56500: [OOP] "IMPLICIT CLASS(...)" wrongly rejected
!
diff --git a/gcc/testsuite/gfortran.dg/move_alloc_17.f90 b/gcc/testsuite/gfortran.dg/move_alloc_17.f90
new file mode 100644
index 00000000000..acede0f901b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/move_alloc_17.f90
@@ -0,0 +1,21 @@
+! { dg-do compile }
+!
+! The call to MOVE_ALLOC below caused a seg fault in runtime.
+! This was discussed in:
+! https://groups.google.com/forum/#!topic/comp.lang.fortran/ZVLqXFYDZ0M
+! Richard Maine proposed that the code violated the restrictions on
+! actual arguments in F2003 12.4.1.7 and so the fix asserts that the
+! TO and FROM arguments cannot be the same object or subobjects thereof.
+!
+!
+program test_move_alloc
+ type :: linked_list
+ type(linked_list), allocatable :: link
+ integer :: value
+ end type linked_list
+ type(linked_list) :: test
+
+ allocate(test % link)
+ allocate(test % link % link)
+ call move_alloc(test % link, test % link % link) ! { dg-error "aliasing restrictions" }
+end program test_move_alloc
diff --git a/gcc/testsuite/gfortran.dg/move_alloc_18.f90 b/gcc/testsuite/gfortran.dg/move_alloc_18.f90
new file mode 100644
index 00000000000..bc72d5d1f87
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/move_alloc_18.f90
@@ -0,0 +1,21 @@
+! { dg-do compile }
+!
+! Test that the anti-aliasing restriction does not knock out valid code.
+!
+! Contributed by Andrew Balwin on
+! https://groups.google.com/forum/#!topic/comp.lang.fortran/oiXdl1LPb_s
+!
+ PROGRAM TEST
+ IMPLICIT NONE
+
+ TYPE FOOBAR
+ INTEGER, ALLOCATABLE :: COMP(:)
+ END TYPE
+
+ TYPE (FOOBAR) :: MY_ARRAY(6)
+
+ ALLOCATE (MY_ARRAY(1)%COMP(10))
+
+ CALL MOVE_ALLOC (MY_ARRAY(1)%COMP, MY_ARRAY(2)%COMP)
+
+ END PROGRAM TEST
diff --git a/gcc/testsuite/gfortran.dg/pr67219.f90 b/gcc/testsuite/gfortran.dg/pr67219.f90
new file mode 100644
index 00000000000..26d5f3f5cae
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr67219.f90
@@ -0,0 +1,8 @@
+! { dg-do compile }
+! PR 67149 - this used to throw a spurious error.
+function foo(bar)
+ integer(8) :: foo
+ integer(4), intent(in) :: bar
+ integer(4), parameter :: huge_4 = huge(0_4)
+ foo = (huge_4 - int(bar,kind=8))
+end function
diff --git a/gcc/testsuite/gfortran.dg/pr70937.f90 b/gcc/testsuite/gfortran.dg/pr70937.f90
index 3fb17bd227e..265029b833d 100644
--- a/gcc/testsuite/gfortran.dg/pr70937.f90
+++ b/gcc/testsuite/gfortran.dg/pr70937.f90
@@ -1,4 +1,5 @@
! { dg-do compile }
+! { dg-require-effective-target lto }
! { dg-options "-flto" }
SUBROUTINE dbcsr_test_read_args(narg, args)
CHARACTER(len=*), DIMENSION(:), &
diff --git a/gcc/testsuite/gfortran.dg/proc_ptr_comp_46.f90 b/gcc/testsuite/gfortran.dg/proc_ptr_comp_46.f90
new file mode 100644
index 00000000000..c01b8221210
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/proc_ptr_comp_46.f90
@@ -0,0 +1,29 @@
+! { dg-do compile }
+!
+! PR 77596: [F03] procedure pointer component with implicit interface can point to a function
+!
+! Contributed by toK <t.kondic@leeds.ac.uk>
+
+program xxx
+ implicit none
+
+ type tf
+ procedure(), nopass, pointer :: fp
+ end type tf
+
+ call ass()
+
+contains
+
+ integer function ff(x)
+ integer, intent(in) :: x
+ ff = x + 1
+ end function ff
+
+ subroutine ass()
+ type(tf) :: p
+ p%fp=>ff ! { dg-error "is not a subroutine" }
+ call p%fp(3)
+ end subroutine ass
+
+end
diff --git a/gcc/testsuite/gfortran.dg/select_type_39.f03 b/gcc/testsuite/gfortran.dg/select_type_39.f03
new file mode 100644
index 00000000000..08d619536ab
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/select_type_39.f03
@@ -0,0 +1,20 @@
+! { dg-do run }
+!
+! Tests the fix for PR67564 comment #9.
+!
+! Contributed by Neil Carlson <neil.n.carlson@gmail.com>
+!
+class(*), allocatable :: val(:)
+call get_value (val)
+select type (val)
+type is (character(*))
+ if (size (val) .ne. 2) call abort
+ if (len(val) .ne. 3) call abort
+ if (any (val .ne. ['foo','bar'])) call abort
+end select
+contains
+ subroutine get_value (value)
+ class(*), allocatable, intent(out) :: value(:)
+ allocate(value, source=['foo','bar'])
+ end subroutine
+end
diff --git a/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90 b/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90
new file mode 100644
index 00000000000..6a663e66b5f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90
@@ -0,0 +1,34 @@
+! { dg-do compile }
+! { dg-options "-Wno-argument-mismatch" }
+!
+! No warnings should be output here with -Wno-argument-mismatch.
+!
+
+subroutine s1(x)
+ implicit none
+ integer, intent(in) :: x
+ print *, x
+end subroutine
+
+subroutine s2(x)
+ implicit none
+ integer, intent(in) :: x(1)
+ print *, x
+end subroutine
+
+subroutine s3(x)
+ implicit none
+ integer, intent(in) :: x(2)
+ print *, x
+end subroutine
+
+implicit none
+integer :: x, y(1)
+real :: r
+
+call s1(r)
+call s1(y)
+call s2(x)
+call s3(y)
+
+end
diff --git a/gcc/testsuite/gfortran.dg/warn_conversion_9.f90 b/gcc/testsuite/gfortran.dg/warn_conversion_9.f90
new file mode 100644
index 00000000000..794eeef99b6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/warn_conversion_9.f90
@@ -0,0 +1,7 @@
+! { dg-do compile }
+! { dg-options "-Wconversion" }
+! PR 78221 - used to give a spurious warning
+complex, parameter :: i = (0.,1.)
+complex :: t
+t = (i)
+end
diff --git a/gcc/testsuite/gfortran.dg/where_5.f90 b/gcc/testsuite/gfortran.dg/where_5.f90
new file mode 100644
index 00000000000..5ada63d6a5d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/where_5.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-Wcharacter-truncation" }
+subroutine where_ice (i,j)
+
+ implicit none
+
+ character(8) :: y(10,10,2)
+
+ integer :: i
+ integer :: j
+
+ character(12) :: txt(5)
+ where (txt(1:3) /= '' ) y(1:3,i,j) = txt(1:3) ! { dg-warning "CHARACTER expression will be truncated" }
+
+end subroutine where_ice
diff --git a/gcc/testsuite/gfortran.dg/where_6.f90 b/gcc/testsuite/gfortran.dg/where_6.f90
new file mode 100644
index 00000000000..c7c43db8423
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/where_6.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-Wcharacter-truncation" }
+subroutine where_ice (i,j)
+
+ implicit none
+
+ character(8) :: y(10,10,2)
+
+ integer :: i
+ integer :: j
+
+ character(12) :: txt(5)
+ if (.true.) where (txt(1:3) /= '' ) y(1:3,i,j) = txt(1:3) ! { dg-warning "CHARACTER expression will be truncated" }
+
+end subroutine where_ice
diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp
index 07b8f7d834d..707f63bea24 100644
--- a/gcc/testsuite/lib/scanasm.exp
+++ b/gcc/testsuite/lib/scanasm.exp
@@ -103,6 +103,7 @@ proc hidden-scan-for { symbol } {
set objformat [gcc_target_object_format]
switch $objformat {
+ coff { return "$symbol\[,\d\]*hidden" }
elf { return "hidden\[ \t_\]*$symbol" }
mach-o { return "private_extern\[ \t_\]*_?$symbol" }
default { return "" }
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index d2fe96ebeeb..ce60cce9cae 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -462,9 +462,7 @@ proc check_gc_sections_available { } {
}
# Check if the ld used by gcc supports --gc-sections.
- set gcc_spec [${tool}_target_compile "-dumpspecs" "" "none" ""]
- regsub ".*\n\\*linker:\[ \t\]*\n(\[^ \t\n\]*).*" "$gcc_spec" {\1} linker
- set gcc_ld [lindex [${tool}_target_compile "-print-prog-name=$linker" "" "none" ""] 0]
+ set gcc_ld [lindex [${tool}_target_compile "-print-prog-name=ld" "" "none" ""] 0]
set ld_output [remote_exec host "$gcc_ld" "--help"]
if { [ string first "--gc-sections" $ld_output ] >= 0 } {
set gc_sections_available_saved 1
@@ -533,7 +531,7 @@ proc check_profiling_available { test_what } {
}
if { $test_what == "-fauto-profile" } {
- if { ! ([istarget x86_64-*-linux*] || [istarget i?86-*-linux*]) } {
+ if { !([istarget i?86-*-linux*] || [istarget x86_64-*-linux*]) } {
verbose "autofdo only supported on linux"
return 0
}
@@ -1524,7 +1522,7 @@ proc check_750cl_hw_available { } {
proc check_sse_os_support_available { } {
return [check_cached_effective_target sse_os_support_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} elseif { [istarget i?86-*-solaris2*] } {
# The Solaris 2 kernel doesn't save and restore SSE registers
@@ -1548,7 +1546,7 @@ proc check_sse_os_support_available { } {
proc check_avx_os_support_available { } {
return [check_cached_effective_target avx_os_support_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
# Check that OS has AVX and SSE saving enabled.
@@ -1571,7 +1569,7 @@ proc check_avx_os_support_available { } {
proc check_sse_hw_available { } {
return [check_cached_effective_target sse_hw_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse_hw_available {
@@ -1671,7 +1669,7 @@ proc check_mips_msa_hw_available { } {
proc check_sse2_hw_available { } {
return [check_cached_effective_target sse2_hw_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse2_hw_available {
@@ -1694,7 +1692,7 @@ proc check_sse2_hw_available { } {
proc check_sse4_hw_available { } {
return [check_cached_effective_target sse4_hw_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache sse4_hw_available {
@@ -1717,7 +1715,7 @@ proc check_sse4_hw_available { } {
proc check_avx_hw_available { } {
return [check_cached_effective_target avx_hw_available {
# If this is not the right target then we can skip the test.
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
expr 0
} else {
check_runtime_nocache avx_hw_available {
@@ -2622,8 +2620,7 @@ proc check_effective_target___float128 { } {
return [check_ppc_float128_sw_available]
}
if { [istarget ia64-*-*]
- || [istarget i?86-*-*]
- || [istarget x86_64-*-*] } {
+ || [istarget i?86-*-*] || [istarget x86_64-*-*] } {
return 1
}
return 0
@@ -2779,9 +2776,8 @@ proc check_effective_target_vect_cmdline_needed { } {
set et_vect_cmdline_needed_saved 1
if { [istarget alpha*-*-*]
|| [istarget ia64-*-*]
- || (([istarget x86_64-*-*] || [istarget i?86-*-*])
- && ([check_effective_target_x32]
- || [check_effective_target_lp64]))
+ || (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && ![is-effective-target ia32])
|| ([istarget powerpc*-*-*]
&& ([check_effective_target_powerpc_spe]
|| [check_effective_target_powerpc_altivec]))
@@ -2811,16 +2807,16 @@ proc check_effective_target_vect_int { } {
set et_vect_int_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*]
- && ![istarget powerpc-*-linux*paired*])
- || [istarget spu-*-*]
- || [istarget sparc*-*-*]
- || [istarget alpha*-*-*]
- || [istarget ia64-*-*]
- || [istarget aarch64*-*-*]
- || [check_effective_target_arm32]
- || ([istarget mips*-*-*]
- && ([et-is-effective-target mips_loongson]
- || [et-is-effective-target mips_msa])) } {
+ && ![istarget powerpc-*-linux*paired*])
+ || [istarget spu-*-*]
+ || [istarget sparc*-*-*]
+ || [istarget alpha*-*-*]
+ || [istarget ia64-*-*]
+ || [istarget aarch64*-*-*]
+ || [check_effective_target_arm32]
+ || ([istarget mips*-*-*]
+ && ([et-is-effective-target mips_loongson]
+ || [et-is-effective-target mips_msa])) } {
set et_vect_int_saved($et_index) 1
}
}
@@ -2843,13 +2839,13 @@ proc check_effective_target_vect_intfloat_cvt { } {
} else {
set et_vect_intfloat_cvt_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget powerpc*-*-*]
- && ![istarget powerpc-*-linux*paired*])
- || ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok])
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
- set et_vect_intfloat_cvt_saved($et_index) 1
+ || ([istarget powerpc*-*-*]
+ && ![istarget powerpc-*-linux*paired*])
+ || ([istarget arm*-*-*]
+ && [check_effective_target_arm_neon_ok])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_intfloat_cvt_saved($et_index) 1
}
}
@@ -2885,14 +2881,14 @@ proc check_effective_target_vect_uintfloat_cvt { } {
} else {
set et_vect_uintfloat_cvt_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget powerpc*-*-*]
- && ![istarget powerpc-*-linux*paired*])
- || [istarget aarch64*-*-*]
- || ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok])
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
- set et_vect_uintfloat_cvt_saved($et_index) 1
+ || ([istarget powerpc*-*-*]
+ && ![istarget powerpc-*-linux*paired*])
+ || [istarget aarch64*-*-*]
+ || ([istarget arm*-*-*]
+ && [check_effective_target_arm_neon_ok])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_uintfloat_cvt_saved($et_index) 1
}
}
@@ -2915,13 +2911,13 @@ proc check_effective_target_vect_floatint_cvt { } {
} else {
set et_vect_floatint_cvt_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget powerpc*-*-*]
- && ![istarget powerpc-*-linux*paired*])
- || ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok])
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
- set et_vect_floatint_cvt_saved($et_index) 1
+ || ([istarget powerpc*-*-*]
+ && ![istarget powerpc-*-linux*paired*])
+ || ([istarget arm*-*-*]
+ && [check_effective_target_arm_neon_ok])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_floatint_cvt_saved($et_index) 1
}
}
@@ -2969,14 +2965,13 @@ proc check_effective_target_vect_simd_clones { } {
verbose "check_effective_target_vect_simd_clones: using cached result" 2
} else {
set et_vect_simd_clones_saved($et_index) 0
- if { [istarget i?86-*-*] || [istarget x86_64-*-*] } {
- # On i?86/x86_64 #pragma omp declare simd builds a sse2, avx, avx2
- # and avx512f clone. Only the right clone for the specified arch
- # will be chosen, but still we need to at least be able to assemble
- # avx512f.
- if { [check_effective_target_avx512f] } {
- set et_vect_simd_clones_saved($et_index) 1
- }
+ # On i?86/x86_64 #pragma omp declare simd builds a sse2, avx,
+ # avx2 and avx512f clone. Only the right clone for the
+ # specified arch will be chosen, but still we need to at least
+ # be able to assemble avx512f.
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && [check_effective_target_avx512f]) } {
+ set et_vect_simd_clones_saved($et_index) 1
}
}
@@ -4781,7 +4776,7 @@ proc check_effective_target_vect_shift { } {
} else {
set et_vect_shift_saved($et_index) 0
if { ([istarget powerpc*-*-*]
- && ![istarget powerpc-*-linux*paired*])
+ && ![istarget powerpc-*-linux*paired*])
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget aarch64*-*-*]
@@ -4899,16 +4894,16 @@ proc check_effective_target_vect_float { } {
} else {
set et_vect_float_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || [istarget powerpc*-*-*]
- || [istarget spu-*-*]
- || [istarget mips-sde-elf]
- || [istarget mipsisa64*-*-*]
- || [istarget ia64-*-*]
- || [istarget aarch64*-*-*]
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa])
- || [check_effective_target_arm32] } {
- set et_vect_float_saved($et_index) 1
+ || [istarget powerpc*-*-*]
+ || [istarget spu-*-*]
+ || [istarget mips-sde-elf]
+ || [istarget mipsisa64*-*-*]
+ || [istarget ia64-*-*]
+ || [istarget aarch64*-*-*]
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa])
+ || [check_effective_target_arm32] } {
+ set et_vect_float_saved($et_index) 1
}
}
@@ -4929,22 +4924,18 @@ proc check_effective_target_vect_double { } {
verbose "check_effective_target_vect_double: using cached result" 2
} else {
set et_vect_double_saved($et_index) 0
- if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || [istarget aarch64*-*-*] } {
- if { [check_no_compiler_messages vect_double assembly {
- #ifdef __tune_atom__
- # error No double vectorizer support.
- #endif
- }] } {
- set et_vect_double_saved($et_index) 1
- } else {
- set et_vect_double_saved($et_index) 0
- }
- } elseif { [istarget spu-*-*]
- || ([istarget powerpc*-*-*] && [check_vsx_hw_available])
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
- set et_vect_double_saved($et_index) 1
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && [check_no_compiler_messages vect_double assembly {
+ #ifdef __tune_atom__
+ # error No double vectorizer support.
+ #endif
+ }])
+ || [istarget aarch64*-*-*]
+ || [istarget spu-*-*]
+ || ([istarget powerpc*-*-*] && [check_vsx_hw_available])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_double_saved($et_index) 1
}
}
@@ -4966,8 +4957,8 @@ proc check_effective_target_vect_long_long { } {
} else {
set et_vect_long_long_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
set et_vect_long_long_saved($et_index) 1
}
}
@@ -5296,12 +5287,12 @@ proc check_effective_target_vect_widen_mult_hi_to_si { } {
set et_vect_widen_mult_hi_to_si_saved($et_index) 0
}
if { [istarget powerpc*-*-*]
- || [istarget spu-*-*]
- || [istarget ia64-*-*]
- || [istarget aarch64*-*-*]
- || [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok]) } {
+ || [istarget spu-*-*]
+ || [istarget ia64-*-*]
+ || [istarget aarch64*-*-*]
+ || [istarget i?86-*-*] || [istarget x86_64-*-*]
+ || ([istarget arm*-*-*]
+ && [check_effective_target_arm_neon_ok]) } {
set et_vect_widen_mult_hi_to_si_saved($et_index) 1
}
}
@@ -5351,12 +5342,12 @@ proc check_effective_target_vect_widen_mult_hi_to_si_pattern { } {
} else {
set et_vect_widen_mult_hi_to_si_pattern_saved($et_index) 0
if { [istarget powerpc*-*-*]
- || [istarget spu-*-*]
- || [istarget ia64-*-*]
- || [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok]
- && [check_effective_target_arm_little_endian]) } {
+ || [istarget spu-*-*]
+ || [istarget ia64-*-*]
+ || [istarget i?86-*-*] || [istarget x86_64-*-*]
+ || ([istarget arm*-*-*]
+ && [check_effective_target_arm_neon_ok]
+ && [check_effective_target_arm_little_endian]) } {
set et_vect_widen_mult_hi_to_si_pattern_saved($et_index) 1
}
}
@@ -5523,7 +5514,7 @@ proc check_effective_target_vect_usad_char { } {
verbose "check_effective_target_vect_usad_char: using cached result" 2
} else {
set et_vect_usad_char_saved($et_index) 0
- if { ([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
+ if { [istarget i?86-*-*] || [istarget x86_64-*-*] } {
set et_vect_usad_char_saved($et_index) 1
}
}
@@ -5668,16 +5659,13 @@ proc check_effective_target_vect_hw_misalign { } {
proc check_effective_target_vect_aligned_arrays { } {
set et_vect_aligned_arrays 0
- if { ([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
- if { ([is-effective-target lp64]
- && ( ![check_avx_available]
- || [check_prefer_avx128])) } {
- set et_vect_aligned_arrays 1
- }
- }
- if [istarget spu-*-*] {
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && !([is-effective-target ia32]
+ || ([check_avx_available] && ![check_prefer_avx128])))
+ || [istarget spu-*-*] } {
set et_vect_aligned_arrays 1
}
+
verbose "check_effective_target_vect_aligned_arrays:\
returning $et_vect_aligned_arrays" 2
return $et_vect_aligned_arrays
@@ -5991,7 +5979,7 @@ proc check_effective_target_vect_interleave { } {
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mpaired_single]
|| [et-is-effective-target mips_msa])) } {
- set et_vect_interleave_saved($et_index) 1
+ set et_vect_interleave_saved($et_index) 1
}
}
@@ -6037,14 +6025,11 @@ proc check_effective_target_vect_multiple_sizes { } {
global et_index
set et_vect_multiple_sizes_saved($et_index) 0
- if { ([istarget aarch64*-*-*]
- || ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok])) } {
- set et_vect_multiple_sizes_saved($et_index) 1
- }
- if { ([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
- if { ([check_avx_available] && ![check_prefer_avx128]) } {
+ if { [istarget aarch64*-*-*]
+ || ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok])
+ || (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && ([check_avx_available] && ![check_prefer_avx128])) } {
set et_vect_multiple_sizes_saved($et_index) 1
- }
}
verbose "check_effective_target_vect_multiple_sizes:\
@@ -6107,7 +6092,7 @@ proc check_effective_target_sqrt_insn { } {
verbose "check_effective_target_hw_sqrt: using cached result" 2
} else {
set et_sqrt_insn_saved 0
- if { [istarget x86_64-*-*]
+ if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
|| ([istarget arm*-*-*] && [check_effective_target_arm_vfp_ok]) } {
@@ -6145,8 +6130,8 @@ proc check_effective_target_vect_call_sqrtf { } {
proc check_effective_target_vect_call_lrint { } {
set et_vect_call_lrint 0
- if { ([istarget i?86-*-*] || [istarget x86_64-*-*])
- && [check_effective_target_ilp32] } {
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && [check_effective_target_ilp32]) } {
set et_vect_call_lrint 1
}
@@ -6420,10 +6405,9 @@ proc check_effective_target_section_anchors { } {
# Return 1 if the target supports atomic operations on "int_128" values.
proc check_effective_target_sync_int_128 { } {
- if { ([istarget x86_64-*-*] || [istarget i?86-*-*])
- && ![is-effective-target ia32] } {
- return 1
- } elseif { [istarget spu-*-*] } {
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && ![is-effective-target ia32])
+ || [istarget spu-*-*] } {
return 1
} else {
return 0
@@ -6434,21 +6418,21 @@ proc check_effective_target_sync_int_128 { } {
# and can execute them.
proc check_effective_target_sync_int_128_runtime { } {
- if { ([istarget x86_64-*-*] || [istarget i?86-*-*])
- && ![is-effective-target ia32] } {
- return [check_cached_effective_target sync_int_128_available {
- check_runtime_nocache sync_int_128_available {
- #include "cpuid.h"
- int main ()
- {
- unsigned int eax, ebx, ecx, edx;
- if (__get_cpuid (1, &eax, &ebx, &ecx, &edx))
- return !(ecx & bit_CMPXCHG16B);
- return 1;
- }
- } ""
- }]
- } elseif { [istarget spu-*-*] } {
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && ![is-effective-target ia32]
+ && [check_cached_effective_target sync_int_128_available {
+ check_runtime_nocache sync_int_128_available {
+ #include "cpuid.h"
+ int main ()
+ {
+ unsigned int eax, ebx, ecx, edx;
+ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return !(ecx & bit_CMPXCHG16B);
+ return 1;
+ }
+ } ""
+ }])
+ || [istarget spu-*-*] } {
return 1
} else {
return 0
@@ -6461,7 +6445,7 @@ proc check_effective_target_sync_int_128_runtime { } {
# Note: 32bit s390 targets require -mzarch in dg-options.
proc check_effective_target_sync_long_long { } {
- if { [istarget x86_64-*-*] || [istarget i?86-*-*])
+ if { [istarget i?86-*-*] || [istarget x86_64-*-*])
|| [istarget aarch64*-*-*]
|| [istarget arm*-*-*]
|| [istarget alpha*-*-*]
@@ -6480,46 +6464,43 @@ proc check_effective_target_sync_long_long { } {
# Note: 32bit x86 targets require -march=pentium in dg-options.
proc check_effective_target_sync_long_long_runtime { } {
- if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
- return [check_cached_effective_target sync_long_long_available {
- check_runtime_nocache sync_long_long_available {
- #include "cpuid.h"
- int main ()
- {
- unsigned int eax, ebx, ecx, edx;
- if (__get_cpuid (1, &eax, &ebx, &ecx, &edx))
- return !(edx & bit_CMPXCHG8B);
- return 1;
- }
- } ""
- }]
- } elseif { [istarget aarch64*-*-*] } {
- return 1
- } elseif { [istarget arm*-*-linux-*] } {
- return [check_runtime sync_longlong_runtime {
- #include <stdlib.h>
- int main ()
- {
- long long l1;
-
- if (sizeof (long long) != 8)
- exit (1);
+ if { (([istarget x86_64-*-*] || [istarget i?86-*-*])
+ && [check_cached_effective_target sync_long_long_available {
+ check_runtime_nocache sync_long_long_available {
+ #include "cpuid.h"
+ int main ()
+ {
+ unsigned int eax, ebx, ecx, edx;
+ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return !(edx & bit_CMPXCHG8B);
+ return 1;
+ }
+ } ""
+ }])
+ || [istarget aarch64*-*-*]
+ || ([istarget arm*-*-linux-*]
+ && [check_runtime sync_longlong_runtime {
+ #include <stdlib.h>
+ int main ()
+ {
+ long long l1;
- /* Just check for native; checking for kernel fallback is tricky. */
- asm volatile ("ldrexd r0,r1, [%0]" : : "r" (&l1) : "r0", "r1");
+ if (sizeof (long long) != 8)
+ exit (1);
- exit (0);
- }
- } "" ]
- } elseif { [istarget alpha*-*-*] } {
- return 1
- } elseif { ([istarget sparc*-*-*]
- && [check_effective_target_lp64]
- && [check_effective_target_ultrasparc_hw]) } {
- return 1
- } elseif { [istarget spu-*-*] } {
- return 1
- } elseif { [istarget powerpc*-*-*] && [check_effective_target_lp64] } {
+ /* Just check for native;
+ checking for kernel fallback is tricky. */
+ asm volatile ("ldrexd r0,r1, [%0]"
+ : : "r" (&l1) : "r0", "r1");
+ exit (0);
+ }
+ } "" ])
+ || [istarget alpha*-*-*]
+ || ([istarget sparc*-*-*]
+ && [check_effective_target_lp64]
+ && [check_effective_target_ultrasparc_hw])
+ || [istarget spu-*-*]
+ || ([istarget powerpc*-*-*] && [check_effective_target_lp64]) } {
return 1
} else {
return 0
@@ -6541,18 +6522,15 @@ proc check_effective_target_bswap { } {
|| [istarget m68k-*-*]
|| [istarget powerpc*-*-*]
|| [istarget rs6000-*-*]
- || [istarget s390*-*-*] } {
- set et_bswap_saved 1
- } else {
- if { [istarget arm*-*-*]
+ || [istarget s390*-*-*]
+ || ([istarget arm*-*-*]
&& [check_no_compiler_messages_nocache arm_v6_or_later object {
#if __ARM_ARCH < 6
#error not armv6 or later
#endif
int i;
- } ""] } {
+ } ""]) } {
set et_bswap_saved 1
- }
}
}
@@ -7231,7 +7209,7 @@ proc check_effective_target_avx512f { } {
# Return 1 if avx instructions can be compiled.
proc check_effective_target_avx { } {
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
return [check_no_compiler_messages avx object {
@@ -7897,7 +7875,7 @@ proc check_effective_target_pie_copyreloc { } {
global tool
global GCC_UNDER_TEST
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
@@ -7949,7 +7927,7 @@ proc check_effective_target_got32x_reloc { } {
global tool
global GCC_UNDER_TEST
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
@@ -8000,7 +7978,7 @@ proc check_effective_target_tls_get_addr_via_got { } {
global tool
global GCC_UNDER_TEST
- if { !([istarget x86_64-*-*] || [istarget i?86-*-*]) } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
return 0
}
@@ -8094,3 +8072,55 @@ proc check_effective_target_profile_update_atomic {} {
int main (void) { return 0; }
} "-fprofile-update=atomic -fprofile-generate"]
}
+
+#For versions of ARM architectures that have hardware div insn,
+#disable the divmod transform
+
+proc check_effective_target_arm_divmod_simode { } {
+ return [check_no_compiler_messages arm_divmod assembly {
+ #ifdef __ARM_ARCH_EXT_IDIV__
+ #error has div insn
+ #endif
+ int i;
+ }]
+}
+
+# Return 1 if target supports divmod hardware insn or divmod libcall.
+
+proc check_effective_target_divmod { } {
+ #TODO: Add checks for all targets that have either hardware divmod insn
+ # or define libfunc for divmod.
+ if { [istarget arm*-*-*]
+ || [istarget i?86-*-*] || [istarget x86_64-*-*] } {
+ return 1
+ }
+ return 0
+}
+
+# Return 1 if target supports divmod for SImode. The reason for
+# separating this from check_effective_target_divmod is that
+# some versions of ARM architecture define div instruction
+# only for simode, and for these archs, we do not want to enable
+# divmod transform for simode.
+
+proc check_effective_target_divmod_simode { } {
+ if { [istarget arm*-*-*] } {
+ return [check_effective_target_arm_divmod_simode]
+ }
+
+ return [check_effective_target_divmod]
+}
+
+# Return 1 if store merging optimization is applicable for target.
+# Store merging is not profitable for targets like the avr which
+# can load/store only one byte at a time. Use int size as a proxy
+# for the number of bytes the target can write, and skip for targets
+# with a smallish (< 32) size.
+
+proc check_effective_target_store_merge { } {
+ if { [is-effective-target non_strict_align ] && [is-effective-target int32plus] } {
+ return 1
+ }
+
+ return 0
+}
diff --git a/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm
index 45b6e702481..744a017bef6 100644
--- a/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm
+++ b/gcc/testsuite/obj-c++.dg/lto/trivial-1_0.mm
@@ -1,7 +1,7 @@
/* { dg-lto-do run } */
/* { dg-skip-if "Needs OBJC2 ABI" { "*-*-darwin*" && lp64 } { "*" } { "" } } */
extern "C" {
-extern int printf (char *,...) ;
+extern int printf (const char *,...) ;
extern void abort (void) ;
}
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 8df9b08010f..861834d3663 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -807,15 +807,20 @@ shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
can_guard_call_p. */
join_tgt_in_edge_from_call = find_fallthru_edge (bi_call_bb->succs);
gcc_assert (join_tgt_in_edge_from_call);
- free_dominance_info (CDI_DOMINATORS);
+ /* We don't want to handle PHIs. */
+ if (EDGE_COUNT (join_tgt_in_edge_from_call->dest->preds) > 1)
+ join_tgt_bb = split_edge (join_tgt_in_edge_from_call);
+ else
+ join_tgt_bb = join_tgt_in_edge_from_call->dest;
}
else
- join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
+ {
+ join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
+ join_tgt_bb = join_tgt_in_edge_from_call->dest;
+ }
bi_call_bsi = gsi_for_stmt (bi_call);
- join_tgt_bb = join_tgt_in_edge_from_call->dest;
-
/* Now it is time to insert the first conditional expression
into bi_call_bb and split this bb so that bi_call is
shrink-wrapped. */
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index de5e5757080..6899d2a8736 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -1045,6 +1045,7 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
copy_body_data *id = (copy_body_data *) data;
tree fn = id->src_fn;
tree new_block;
+ bool copied = false;
/* Begin by recognizing trees that we'll completely rewrite for the
inlining context. Our output for these trees is completely
@@ -1241,10 +1242,40 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
*walk_subtrees = 0;
return NULL;
}
+ else if (TREE_CODE (*tp) == COND_EXPR)
+ {
+ tree cond = TREE_OPERAND (*tp, 0);
+ walk_tree (&cond, copy_tree_body_r, data, NULL);
+ tree folded = fold (cond);
+ if (TREE_CODE (folded) == INTEGER_CST)
+ {
+ /* Only copy the taken branch; for a C++ base constructor clone
+ inherited from a virtual base, copying the other branch leads
+ to references to parameters that were optimized away. */
+ tree branch = (integer_nonzerop (folded)
+ ? TREE_OPERAND (*tp, 1)
+ : TREE_OPERAND (*tp, 2));
+ tree type = TREE_TYPE (*tp);
+ if (VOID_TYPE_P (type)
+ || type == TREE_TYPE (branch))
+ {
+ *tp = branch;
+ return copy_tree_body_r (tp, walk_subtrees, data);
+ }
+ }
+ /* Avoid copying the condition twice. */
+ copy_tree_r (tp, walk_subtrees, NULL);
+ TREE_OPERAND (*tp, 0) = cond;
+ walk_tree (&TREE_OPERAND (*tp, 1), copy_tree_body_r, data, NULL);
+ walk_tree (&TREE_OPERAND (*tp, 2), copy_tree_body_r, data, NULL);
+ *walk_subtrees = 0;
+ copied = true;
+ }
/* Here is the "usual case". Copy this tree node, and then
tweak some special cases. */
- copy_tree_r (tp, walk_subtrees, NULL);
+ if (!copied)
+ copy_tree_r (tp, walk_subtrees, NULL);
/* If EXPR has block defined, map it to newly constructed block.
When inlining we want EXPRs without block appear in the block
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index abeee92204e..d18b954a385 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -56,9 +56,9 @@ static GTY(()) tree tree_interval_profiler_fn;
static GTY(()) tree tree_pow2_profiler_fn;
static GTY(()) tree tree_one_value_profiler_fn;
static GTY(()) tree tree_indirect_call_profiler_fn;
-static GTY(()) tree tree_time_profiler_fn;
static GTY(()) tree tree_average_profiler_fn;
static GTY(()) tree tree_ior_profiler_fn;
+static GTY(()) tree tree_time_profiler_counter;
static GTY(()) tree ic_void_ptr_var;
@@ -75,7 +75,7 @@ static GTY(()) tree ptr_void;
static void
init_ic_make_global_vars (void)
{
- tree gcov_type_ptr;
+ tree gcov_type_ptr;
ptr_void = build_pointer_type (void_type_node);
@@ -119,7 +119,7 @@ init_ic_make_global_vars (void)
/* Create the type and function decls for the interface with gcov. */
void
-gimple_init_edge_profiler (void)
+gimple_init_gcov_profiler (void)
{
tree interval_profiler_fn_type;
tree pow2_profiler_fn_type;
@@ -127,7 +127,6 @@ gimple_init_edge_profiler (void)
tree gcov_type_ptr;
tree ic_profiler_fn_type;
tree average_profiler_fn_type;
- tree time_profiler_fn_type;
const char *profiler_fn_name;
const char *fn_name;
@@ -201,17 +200,17 @@ gimple_init_edge_profiler (void)
= tree_cons (get_identifier ("leaf"), NULL,
DECL_ATTRIBUTES (tree_indirect_call_profiler_fn));
- /* void (*) (gcov_type *, gcov_type, void *) */
- time_profiler_fn_type
- = build_function_type_list (void_type_node,
- gcov_type_ptr, NULL_TREE);
- fn_name = concat ("__gcov_time_profiler", fn_suffix, NULL);
- tree_time_profiler_fn = build_fn_decl (fn_name, time_profiler_fn_type);
- free (CONST_CAST (char *, fn_name));
- TREE_NOTHROW (tree_time_profiler_fn) = 1;
- DECL_ATTRIBUTES (tree_time_profiler_fn)
- = tree_cons (get_identifier ("leaf"), NULL,
- DECL_ATTRIBUTES (tree_time_profiler_fn));
+ tree_time_profiler_counter
+ = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier ("__gcov_time_profiler_counter"),
+ get_gcov_type ());
+ TREE_PUBLIC (tree_time_profiler_counter) = 1;
+ DECL_EXTERNAL (tree_time_profiler_counter) = 1;
+ TREE_STATIC (tree_time_profiler_counter) = 1;
+ DECL_ARTIFICIAL (tree_time_profiler_counter) = 1;
+ DECL_INITIAL (tree_time_profiler_counter) = NULL;
+
+ varpool_node::finalize_decl (tree_time_profiler_counter);
/* void (*) (gcov_type *, gcov_type) */
average_profiler_fn_type
@@ -239,7 +238,6 @@ gimple_init_edge_profiler (void)
DECL_ASSEMBLER_NAME (tree_pow2_profiler_fn);
DECL_ASSEMBLER_NAME (tree_one_value_profiler_fn);
DECL_ASSEMBLER_NAME (tree_indirect_call_profiler_fn);
- DECL_ASSEMBLER_NAME (tree_time_profiler_fn);
DECL_ASSEMBLER_NAME (tree_average_profiler_fn);
DECL_ASSEMBLER_NAME (tree_ior_profiler_fn);
}
@@ -426,7 +424,7 @@ gimple_gen_ic_func_profiler (void)
if (c_node->only_called_directly_p ())
return;
- gimple_init_edge_profiler ();
+ gimple_init_gcov_profiler ();
/* Insert code:
@@ -460,16 +458,75 @@ gimple_gen_ic_func_profiler (void)
counter position and GSI is the iterator we place the counter. */
void
-gimple_gen_time_profiler (unsigned tag, unsigned base,
- gimple_stmt_iterator &gsi)
+gimple_gen_time_profiler (unsigned tag, unsigned base)
{
- tree ref_ptr = tree_coverage_counter_addr (tag, base);
- gcall *call;
+ tree type = get_gcov_type ();
+ basic_block cond_bb
+ = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+
+ basic_block update_bb = split_edge (single_succ_edge (cond_bb));
+
+ edge true_edge = single_succ_edge (cond_bb);
+ true_edge->flags = EDGE_TRUE_VALUE;
+ true_edge->probability = PROB_VERY_UNLIKELY;
+ edge e
+ = make_edge (cond_bb, single_succ_edge (update_bb)->dest, EDGE_FALSE_VALUE);
+ e->probability = REG_BR_PROB_BASE - true_edge->probability;
+
+ gimple_stmt_iterator gsi = gsi_start_bb (cond_bb);
+ tree original_ref = tree_coverage_counter_ref (tag, base);
+ tree ref = force_gimple_operand_gsi (&gsi, original_ref, true, NULL_TREE,
+ true, GSI_SAME_STMT);
+ tree one = build_int_cst (type, 1);
- ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
- true, NULL_TREE, true, GSI_SAME_STMT);
- call = gimple_build_call (tree_time_profiler_fn, 1, ref_ptr);
- gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+ /* Emit: if (counters[0] != 0). */
+ gcond *cond = gimple_build_cond (EQ_EXPR, ref, build_int_cst (type, 0),
+ NULL, NULL);
+ gsi_insert_before (&gsi, cond, GSI_NEW_STMT);
+
+ gsi = gsi_start_bb (update_bb);
+
+ /* Emit: counters[0] = ++__gcov_time_profiler_counter. */
+ if (flag_profile_update == PROFILE_UPDATE_ATOMIC)
+ {
+ tree ptr = make_temp_ssa_name (build_pointer_type (type), NULL,
+ "time_profiler_counter_ptr");
+ tree addr = build1 (ADDR_EXPR, TREE_TYPE (ptr),
+ tree_time_profiler_counter);
+ gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr);
+ gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
+ tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32
+ ? BUILT_IN_ATOMIC_ADD_FETCH_8:
+ BUILT_IN_ATOMIC_ADD_FETCH_4);
+ gcall *stmt = gimple_build_call (f, 3, ptr, one,
+ build_int_cst (integer_type_node,
+ MEMMODEL_RELAXED));
+ tree result_type = TREE_TYPE (TREE_TYPE (f));
+ tree tmp = make_temp_ssa_name (result_type, NULL, "time_profile");
+ gimple_set_lhs (stmt, tmp);
+ gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
+ tmp = make_temp_ssa_name (type, NULL, "time_profile");
+ assign = gimple_build_assign (tmp, NOP_EXPR,
+ gimple_call_lhs (stmt));
+ gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
+ assign = gimple_build_assign (original_ref, tmp);
+ gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
+ }
+ else
+ {
+ tree tmp = make_temp_ssa_name (type, NULL, "time_profile");
+ gassign *assign = gimple_build_assign (tmp, tree_time_profiler_counter);
+ gsi_insert_before (&gsi, assign, GSI_NEW_STMT);
+
+ tmp = make_temp_ssa_name (type, NULL, "time_profile");
+ assign = gimple_build_assign (tmp, PLUS_EXPR, gimple_assign_lhs (assign),
+ one);
+ gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
+ assign = gimple_build_assign (original_ref, tmp);
+ gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
+ assign = gimple_build_assign (tree_time_profiler_counter, tmp);
+ gsi_insert_after (&gsi, assign, GSI_NEW_STMT);
+ }
}
/* Output instructions as GIMPLE trees to increment the average histogram
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 26c9f9e894b..ebae6cfa6fe 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -32,12 +32,12 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "alias.h"
#include "fold-const.h"
-
#include "langhooks.h"
#include "dumpfile.h"
#include "tree-eh.h"
#include "tree-dfa.h"
#include "ipa-reference.h"
+#include "varasm.h"
/* Broad overview of how alias analysis on gimple works:
@@ -373,14 +373,18 @@ ptrs_compare_unequal (tree ptr1, tree ptr2)
/* We may not use restrict to optimize pointer comparisons.
See PR71062. So we have to assume that restrict-pointed-to
may be in fact obj1. */
- if (!pi || pi->pt.vars_contains_restrict)
+ if (!pi
+ || pi->pt.vars_contains_restrict
+ || pi->pt.vars_contains_interposable)
return false;
if (VAR_P (obj1)
&& (TREE_STATIC (obj1) || DECL_EXTERNAL (obj1)))
{
varpool_node *node = varpool_node::get (obj1);
/* If obj1 may bind to NULL give up (see below). */
- if (! node || ! node->nonzero_address ())
+ if (! node
+ || ! node->nonzero_address ()
+ || ! decl_binds_to_current_def_p (obj1))
return false;
}
return !pt_solution_includes (&pi->pt, obj1);
@@ -553,7 +557,12 @@ dump_points_to_solution (FILE *file, struct pt_solution *pt)
comma = ", ";
}
if (pt->vars_contains_restrict)
- fprintf (file, "%srestrict", comma);
+ {
+ fprintf (file, "%srestrict", comma);
+ comma = ", ";
+ }
+ if (pt->vars_contains_interposable)
+ fprintf (file, "%sinterposable", comma);
fprintf (file, ")");
}
}
diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
index 27a06fcca2c..810d83c978e 100644
--- a/gcc/tree-ssa-alias.h
+++ b/gcc/tree-ssa-alias.h
@@ -57,6 +57,8 @@ struct GTY(()) pt_solution
/* Nonzero if the vars bitmap includes a anonymous variable used to
represent storage pointed to by a restrict qualified pointer. */
unsigned int vars_contains_restrict : 1;
+ /* Nonzero if the vars bitmap includes an interposable variable. */
+ unsigned int vars_contains_interposable : 1;
/* Set of variables that this pointer may point to. */
bitmap vars;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 463db048cb6..0524e57564f 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "trans-mem.h"
#include "gimple-fold.h"
#include "tree-scalar-evolution.h"
+#include "tree-ssa-loop-niter.h"
/* TODO: Support for predicated code motion. I.e.
@@ -2369,8 +2370,16 @@ fill_always_executed_in_1 (struct loop *loop, sbitmap contains_call)
break;
FOR_EACH_EDGE (e, ei, bb->succs)
- if (!flow_bb_inside_loop_p (loop, e->dest))
- break;
+ {
+ /* If there is an exit from this BB. */
+ if (!flow_bb_inside_loop_p (loop, e->dest))
+ break;
+ /* Or we enter a possibly non-finite loop. */
+ if (flow_loop_nested_p (bb->loop_father,
+ e->dest->loop_father)
+ && ! finite_loop_p (e->dest->loop_father))
+ break;
+ }
if (e)
break;
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 0cea1a8472d..c315da88ce4 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -112,6 +112,9 @@ along with GCC; see the file COPYING3. If not see
#include "params.h"
#include "internal-fn.h"
#include "case-cfn-macros.h"
+#include "optabs-libfuncs.h"
+#include "tree-eh.h"
+#include "targhooks.h"
/* This structure represents one basic block that either computes a
division, or is a common dominator for basic block that compute a
@@ -184,6 +187,9 @@ static struct
/* Number of fp fused multiply-add ops inserted. */
int fmas_inserted;
+
+ /* Number of divmod calls inserted. */
+ int divmod_calls_inserted;
} widen_mul_stats;
/* The instance of "struct occurrence" representing the highest
@@ -3793,6 +3799,213 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
return true;
}
+/* Return true if target has support for divmod. */
+
+static bool
+target_supports_divmod_p (optab divmod_optab, optab div_optab, machine_mode mode)
+{
+ /* If target supports hardware divmod insn, use it for divmod. */
+ if (optab_handler (divmod_optab, mode) != CODE_FOR_nothing)
+ return true;
+
+ /* Check if libfunc for divmod is available. */
+ rtx libfunc = optab_libfunc (divmod_optab, mode);
+ if (libfunc != NULL_RTX)
+ {
+ /* If optab_handler exists for div_optab, perhaps in a wider mode,
+ we don't want to use the libfunc even if it exists for given mode. */
+ for (machine_mode div_mode = mode;
+ div_mode != VOIDmode;
+ div_mode = GET_MODE_WIDER_MODE (div_mode))
+ if (optab_handler (div_optab, div_mode) != CODE_FOR_nothing)
+ return false;
+
+ return targetm.expand_divmod_libfunc != NULL;
+ }
+
+ return false;
+}
+
+/* Check if stmt is candidate for divmod transform. */
+
+static bool
+divmod_candidate_p (gassign *stmt)
+{
+ tree type = TREE_TYPE (gimple_assign_lhs (stmt));
+ enum machine_mode mode = TYPE_MODE (type);
+ optab divmod_optab, div_optab;
+
+ if (TYPE_UNSIGNED (type))
+ {
+ divmod_optab = udivmod_optab;
+ div_optab = udiv_optab;
+ }
+ else
+ {
+ divmod_optab = sdivmod_optab;
+ div_optab = sdiv_optab;
+ }
+
+ tree op1 = gimple_assign_rhs1 (stmt);
+ tree op2 = gimple_assign_rhs2 (stmt);
+
+ /* Disable the transform if either is a constant, since division-by-constant
+ may have specialized expansion. */
+ if (CONSTANT_CLASS_P (op1) || CONSTANT_CLASS_P (op2))
+ return false;
+
+ /* Exclude the case where TYPE_OVERFLOW_TRAPS (type) as that should
+ expand using the [su]divv optabs. */
+ if (TYPE_OVERFLOW_TRAPS (type))
+ return false;
+
+ if (!target_supports_divmod_p (divmod_optab, div_optab, mode))
+ return false;
+
+ return true;
+}
+
+/* This function looks for:
+ t1 = a TRUNC_DIV_EXPR b;
+ t2 = a TRUNC_MOD_EXPR b;
+ and transforms it to the following sequence:
+ complex_tmp = DIVMOD (a, b);
+ t1 = REALPART_EXPR(a);
+ t2 = IMAGPART_EXPR(b);
+ For conditions enabling the transform see divmod_candidate_p().
+
+ The pass has three parts:
+ 1) Find top_stmt which is trunc_div or trunc_mod stmt and dominates all
+ other trunc_div_expr and trunc_mod_expr stmts.
+ 2) Add top_stmt and all trunc_div and trunc_mod stmts dominated by top_stmt
+ to stmts vector.
+ 3) Insert DIVMOD call just before top_stmt and update entries in
+ stmts vector to use return value of DIMOVD (REALEXPR_PART for div,
+ IMAGPART_EXPR for mod). */
+
+static bool
+convert_to_divmod (gassign *stmt)
+{
+ if (stmt_can_throw_internal (stmt)
+ || !divmod_candidate_p (stmt))
+ return false;
+
+ tree op1 = gimple_assign_rhs1 (stmt);
+ tree op2 = gimple_assign_rhs2 (stmt);
+
+ imm_use_iterator use_iter;
+ gimple *use_stmt;
+ auto_vec<gimple *> stmts;
+
+ gimple *top_stmt = stmt;
+ basic_block top_bb = gimple_bb (stmt);
+
+ /* Part 1: Try to set top_stmt to "topmost" stmt that dominates
+ at-least stmt and possibly other trunc_div/trunc_mod stmts
+ having same operands as stmt. */
+
+ FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, op1)
+ {
+ if (is_gimple_assign (use_stmt)
+ && (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
+ || gimple_assign_rhs_code (use_stmt) == TRUNC_MOD_EXPR)
+ && operand_equal_p (op1, gimple_assign_rhs1 (use_stmt), 0)
+ && operand_equal_p (op2, gimple_assign_rhs2 (use_stmt), 0))
+ {
+ if (stmt_can_throw_internal (use_stmt))
+ continue;
+
+ basic_block bb = gimple_bb (use_stmt);
+
+ if (bb == top_bb)
+ {
+ if (gimple_uid (use_stmt) < gimple_uid (top_stmt))
+ top_stmt = use_stmt;
+ }
+ else if (dominated_by_p (CDI_DOMINATORS, top_bb, bb))
+ {
+ top_bb = bb;
+ top_stmt = use_stmt;
+ }
+ }
+ }
+
+ tree top_op1 = gimple_assign_rhs1 (top_stmt);
+ tree top_op2 = gimple_assign_rhs2 (top_stmt);
+
+ stmts.safe_push (top_stmt);
+ bool div_seen = (gimple_assign_rhs_code (top_stmt) == TRUNC_DIV_EXPR);
+
+ /* Part 2: Add all trunc_div/trunc_mod statements domianted by top_bb
+ to stmts vector. The 2nd loop will always add stmt to stmts vector, since
+ gimple_bb (top_stmt) dominates gimple_bb (stmt), so the
+ 2nd loop ends up adding at-least single trunc_mod_expr stmt. */
+
+ FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, top_op1)
+ {
+ if (is_gimple_assign (use_stmt)
+ && (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR
+ || gimple_assign_rhs_code (use_stmt) == TRUNC_MOD_EXPR)
+ && operand_equal_p (top_op1, gimple_assign_rhs1 (use_stmt), 0)
+ && operand_equal_p (top_op2, gimple_assign_rhs2 (use_stmt), 0))
+ {
+ if (use_stmt == top_stmt
+ || stmt_can_throw_internal (use_stmt)
+ || !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), top_bb))
+ continue;
+
+ stmts.safe_push (use_stmt);
+ if (gimple_assign_rhs_code (use_stmt) == TRUNC_DIV_EXPR)
+ div_seen = true;
+ }
+ }
+
+ if (!div_seen)
+ return false;
+
+ /* Part 3: Create libcall to internal fn DIVMOD:
+ divmod_tmp = DIVMOD (op1, op2). */
+
+ gcall *call_stmt = gimple_build_call_internal (IFN_DIVMOD, 2, op1, op2);
+ tree res = make_temp_ssa_name (build_complex_type (TREE_TYPE (op1)),
+ call_stmt, "divmod_tmp");
+ gimple_call_set_lhs (call_stmt, res);
+
+ /* Insert the call before top_stmt. */
+ gimple_stmt_iterator top_stmt_gsi = gsi_for_stmt (top_stmt);
+ gsi_insert_before (&top_stmt_gsi, call_stmt, GSI_SAME_STMT);
+
+ widen_mul_stats.divmod_calls_inserted++;
+
+ /* Update all statements in stmts vector:
+ lhs = op1 TRUNC_DIV_EXPR op2 -> lhs = REALPART_EXPR<divmod_tmp>
+ lhs = op1 TRUNC_MOD_EXPR op2 -> lhs = IMAGPART_EXPR<divmod_tmp>. */
+
+ for (unsigned i = 0; stmts.iterate (i, &use_stmt); ++i)
+ {
+ tree new_rhs;
+
+ switch (gimple_assign_rhs_code (use_stmt))
+ {
+ case TRUNC_DIV_EXPR:
+ new_rhs = fold_build1 (REALPART_EXPR, TREE_TYPE (op1), res);
+ break;
+
+ case TRUNC_MOD_EXPR:
+ new_rhs = fold_build1 (IMAGPART_EXPR, TREE_TYPE (op1), res);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+ gimple_assign_set_rhs_from_tree (&gsi, new_rhs);
+ update_stmt (use_stmt);
+ }
+
+ return true;
+}
/* Find integer multiplications where the operands are extended from
smaller types, and replace the MULT_EXPR with a WIDEN_MULT_EXPR
@@ -3837,6 +4050,8 @@ pass_optimize_widening_mul::execute (function *fun)
bool cfg_changed = false;
memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
+ calculate_dominance_info (CDI_DOMINATORS);
+ renumber_gimple_stmt_uids ();
FOR_EACH_BB_FN (bb, fun)
{
@@ -3870,6 +4085,10 @@ pass_optimize_widening_mul::execute (function *fun)
match_uaddsub_overflow (&gsi, stmt, code);
break;
+ case TRUNC_MOD_EXPR:
+ convert_to_divmod (as_a<gassign *> (stmt));
+ break;
+
default:;
}
}
@@ -3916,6 +4135,8 @@ pass_optimize_widening_mul::execute (function *fun)
widen_mul_stats.maccs_inserted);
statistics_counter_event (fun, "fused multiply-adds inserted",
widen_mul_stats.fmas_inserted);
+ statistics_counter_event (fun, "divmod calls inserted",
+ widen_mul_stats.divmod_calls_inserted);
return cfg_changed ? TODO_cleanup_cfg : 0;
}
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index 3f3b88cfc61..63738d07e2e 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -1474,6 +1474,14 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
else
negate = false;
+ /* If the code negates only iff positive then make sure to not
+ introduce undefined behavior when negating or computing the absolute.
+ ??? We could use range info if present to check for arg1 == INT_MIN. */
+ if (negate
+ && (ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+ && ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1))))
+ return false;
+
result = duplicate_ssa_name (result, NULL);
if (negate)
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 99e1b414070..5dcf6720605 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -924,7 +924,7 @@ eliminate_using_constants (enum tree_code opcode,
tree type = TREE_TYPE (oelast->op);
if (oelast->rank == 0
- && (INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type)))
+ && (ANY_INTEGRAL_TYPE_P (type) || FLOAT_TYPE_P (type)))
{
switch (opcode)
{
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index fb364f1319d..28803826b43 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -39,6 +39,8 @@
#include "tree-dfa.h"
#include "params.h"
#include "gimple-walk.h"
+#include "varasm.h"
+
/* The idea behind this analyzer is to generate set constraints from the
program, then solve the resulting constraints in order to generate the
@@ -5566,7 +5568,7 @@ push_fields_onto_fieldstack (tree type, vec<fieldoff_s> *fieldstack,
&& offset + foff != 0)
{
fieldoff_s e
- = {0, offset + foff, false, false, false, false, NULL_TREE};
+ = {0, offset + foff, false, false, true, false, NULL_TREE};
pair = fieldstack->safe_push (e);
}
@@ -6360,6 +6362,13 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt,
&& fndecl
&& ! auto_var_in_fn_p (vi->decl, fndecl)))
pt->vars_contains_nonlocal = true;
+
+ /* If we have a variable that is interposable record that fact
+ for pointer comparison simplification. */
+ if (VAR_P (vi->decl)
+ && (TREE_STATIC (vi->decl) || DECL_EXTERNAL (vi->decl))
+ && ! decl_binds_to_current_def_p (vi->decl))
+ pt->vars_contains_interposable = true;
}
else if (TREE_CODE (vi->decl) == FUNCTION_DECL
@@ -7592,7 +7601,8 @@ make_pass_build_ealias (gcc::context *ctxt)
/* IPA PTA solutions for ESCAPED. */
struct pt_solution ipa_escaped_pt
- = { true, false, false, false, false, false, false, false, false, NULL };
+ = { true, false, false, false, false,
+ false, false, false, false, false, NULL };
/* Associate node with varinfo DATA. Worker for
cgraph_for_symbol_thunks_and_aliases. */
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index c99fa4069be..220dc302627 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -583,6 +583,7 @@ vect_slp_analyze_node_dependences (slp_instance instance, slp_tree node,
if (!dr_b)
return false;
+ bool dependent = false;
/* If we run into a store of this same instance (we've just
marked those) then delay dependence checking until we run
into the last store because this is where it will have
@@ -599,22 +600,21 @@ vect_slp_analyze_node_dependences (slp_instance instance, slp_tree node,
= STMT_VINFO_DATA_REF (vinfo_for_stmt (store));
ddr_p ddr = initialize_data_dependence_relation
(dr_a, store_dr, vNULL);
- if (vect_slp_analyze_data_ref_dependence (ddr))
- {
- free_dependence_relation (ddr);
- return false;
- }
+ dependent = vect_slp_analyze_data_ref_dependence (ddr);
free_dependence_relation (ddr);
+ if (dependent)
+ break;
}
}
-
- ddr_p ddr = initialize_data_dependence_relation (dr_a, dr_b, vNULL);
- if (vect_slp_analyze_data_ref_dependence (ddr))
+ else
{
+ ddr_p ddr = initialize_data_dependence_relation (dr_a,
+ dr_b, vNULL);
+ dependent = vect_slp_analyze_data_ref_dependence (ddr);
free_dependence_relation (ddr);
- return false;
}
- free_dependence_relation (ddr);
+ if (dependent)
+ return false;
}
}
return true;
@@ -773,10 +773,25 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
base = ref;
while (handled_component_p (base))
base = TREE_OPERAND (base, 0);
+ unsigned int base_alignment;
+ unsigned HOST_WIDE_INT base_bitpos;
+ get_object_alignment_1 (base, &base_alignment, &base_bitpos);
+ /* As data-ref analysis strips the MEM_REF down to its base operand
+ to form DR_BASE_ADDRESS and adds the offset to DR_INIT we have to
+ adjust things to make base_alignment valid as the alignment of
+ DR_BASE_ADDRESS. */
if (TREE_CODE (base) == MEM_REF)
- base = build2 (MEM_REF, TREE_TYPE (base), base_addr,
- build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)), 0));
- unsigned int base_alignment = get_object_alignment (base);
+ {
+ base_bitpos -= mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
+ base_bitpos &= (base_alignment - 1);
+ }
+ if (base_bitpos != 0)
+ base_alignment = base_bitpos & -base_bitpos;
+ /* Also look at the alignment of the base address DR analysis
+ computed. */
+ unsigned int base_addr_alignment = get_pointer_alignment (base_addr);
+ if (base_addr_alignment > base_alignment)
+ base_alignment = base_addr_alignment;
if (base_alignment >= TYPE_ALIGN (TREE_TYPE (vectype)))
DR_VECT_AUX (dr)->base_element_aligned = true;
@@ -798,12 +813,9 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
if (base_alignment < TYPE_ALIGN (vectype))
{
- /* Strip an inner MEM_REF to a bare decl if possible. */
- if (TREE_CODE (base) == MEM_REF
- && integer_zerop (TREE_OPERAND (base, 1))
- && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
- base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
-
+ base = base_addr;
+ if (TREE_CODE (base) == ADDR_EXPR)
+ base = TREE_OPERAND (base, 0);
if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype)))
{
if (dump_enabled_p ())
@@ -816,6 +828,19 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
return true;
}
+ if (DECL_USER_ALIGN (base))
+ {
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_NOTE, vect_location,
+ "not forcing alignment of user-aligned "
+ "variable: ");
+ dump_generic_expr (MSG_NOTE, TDF_SLIM, base);
+ dump_printf (MSG_NOTE, "\n");
+ }
+ return true;
+ }
+
/* Force the alignment of the decl.
NOTE: This is the only change to the code we make during
the analysis phase, before deciding to vectorize the loop. */
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index 9cca9b717a6..1cd9c7221b0 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -1225,6 +1225,27 @@ destroy_loop_vec_info (loop_vec_info loop_vinfo, bool clean_stmts)
swap_ssa_operands (stmt,
gimple_assign_rhs1_ptr (stmt),
gimple_assign_rhs2_ptr (stmt));
+ else if (code == COND_EXPR
+ && CONSTANT_CLASS_P (gimple_assign_rhs2 (stmt)))
+ {
+ tree cond_expr = gimple_assign_rhs1 (stmt);
+ enum tree_code cond_code = TREE_CODE (cond_expr);
+
+ if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
+ {
+ bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr,
+ 0));
+ cond_code = invert_tree_comparison (cond_code,
+ honor_nans);
+ if (cond_code != ERROR_MARK)
+ {
+ TREE_SET_CODE (cond_expr, cond_code);
+ swap_ssa_operands (stmt,
+ gimple_assign_rhs2_ptr (stmt),
+ gimple_assign_rhs3_ptr (stmt));
+ }
+ }
+ }
}
/* Free stmt_vec_info. */
@@ -3006,38 +3027,56 @@ vect_is_simple_reduction (loop_vec_info loop_info, gimple *phi,
&& (code == COND_EXPR
|| !def2 || gimple_nop_p (def2)
|| !flow_bb_inside_loop_p (loop, gimple_bb (def2))
- || (def2 && flow_bb_inside_loop_p (loop, gimple_bb (def2))
- && (is_gimple_assign (def2)
+ || (def2 && flow_bb_inside_loop_p (loop, gimple_bb (def2))
+ && (is_gimple_assign (def2)
|| is_gimple_call (def2)
- || STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def2))
- == vect_induction_def
- || (gimple_code (def2) == GIMPLE_PHI
+ || STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def2))
+ == vect_induction_def
+ || (gimple_code (def2) == GIMPLE_PHI
&& STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def2))
- == vect_internal_def
+ == vect_internal_def
&& !is_loop_header_bb_p (gimple_bb (def2)))))))
{
- if (check_reduction
- && orig_code != MINUS_EXPR)
- {
+ if (check_reduction && orig_code != MINUS_EXPR)
+ {
+ /* Check if we can swap operands (just for simplicity - so that
+ the rest of the code can assume that the reduction variable
+ is always the last (second) argument). */
if (code == COND_EXPR)
{
- /* No current known use where this case would be useful. */
- if (dump_enabled_p ())
- report_vect_op (MSG_NOTE, def_stmt,
- "detected reduction: cannot currently swap "
- "operands for cond_expr");
- return NULL;
+ /* Swap cond_expr by inverting the condition. */
+ tree cond_expr = gimple_assign_rhs1 (def_stmt);
+ enum tree_code invert_code = ERROR_MARK;
+ enum tree_code cond_code = TREE_CODE (cond_expr);
+
+ if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
+ {
+ bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr, 0));
+ invert_code = invert_tree_comparison (cond_code, honor_nans);
+ }
+ if (invert_code != ERROR_MARK)
+ {
+ TREE_SET_CODE (cond_expr, invert_code);
+ swap_ssa_operands (def_stmt,
+ gimple_assign_rhs2_ptr (def_stmt),
+ gimple_assign_rhs3_ptr (def_stmt));
+ }
+ else
+ {
+ if (dump_enabled_p ())
+ report_vect_op (MSG_NOTE, def_stmt,
+ "detected reduction: cannot swap operands "
+ "for cond_expr");
+ return NULL;
+ }
}
+ else
+ swap_ssa_operands (def_stmt, gimple_assign_rhs1_ptr (def_stmt),
+ gimple_assign_rhs2_ptr (def_stmt));
- /* Swap operands (just for simplicity - so that the rest of the code
- can assume that the reduction variable is always the last (second)
- argument). */
- if (dump_enabled_p ())
+ if (dump_enabled_p ())
report_vect_op (MSG_NOTE, def_stmt,
- "detected reduction: need to swap operands: ");
-
- swap_ssa_operands (def_stmt, gimple_assign_rhs1_ptr (def_stmt),
- gimple_assign_rhs2_ptr (def_stmt));
+ "detected reduction: need to swap operands: ");
if (CONSTANT_CLASS_P (gimple_assign_rhs1 (def_stmt)))
LOOP_VINFO_OPERANDS_SWAPPED (loop_info) = true;
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 5a611e42556..8d547681913 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -207,14 +207,20 @@ vect_get_place_in_interleaving_chain (gimple *stmt, gimple *first_stmt)
/* Get the defs for the rhs of STMT (collect them in OPRNDS_INFO), check that
they are of a valid type and that they match the defs of the first stmt of
- the SLP group (stored in OPRNDS_INFO). If there was a fatal error
- return -1, if the error could be corrected by swapping operands of the
- operation return 1, if everything is ok return 0. */
+ the SLP group (stored in OPRNDS_INFO). This function tries to match stmts
+ by swapping operands of STMT when possible. Non-zero *SWAP indicates swap
+ is required for cond_expr stmts. Specifically, *SWAP is 1 if STMT is cond
+ and operands of comparison need to be swapped; *SWAP is 2 if STMT is cond
+ and code of comparison needs to be inverted. If there is any operand swap
+ in this function, *SWAP is set to non-zero value.
+ If there was a fatal error return -1; if the error could be corrected by
+ swapping operands of father node of this one, return 1; if everything is
+ ok return 0. */
-static int
-vect_get_and_check_slp_defs (vec_info *vinfo,
+static int
+vect_get_and_check_slp_defs (vec_info *vinfo, unsigned char *swap,
gimple *stmt, unsigned stmt_num,
- vec<slp_oprnd_info> *oprnds_info)
+ vec<slp_oprnd_info> *oprnds_info)
{
tree oprnd;
unsigned int i, number_of_oprnds;
@@ -237,11 +243,12 @@ vect_get_and_check_slp_defs (vec_info *vinfo,
{
enum tree_code code = gimple_assign_rhs_code (stmt);
number_of_oprnds = gimple_num_ops (stmt) - 1;
+ /* Swap can only be done for cond_expr if asked to, otherwise we
+ could result in different comparison code to the first stmt. */
if (gimple_assign_rhs_code (stmt) == COND_EXPR
&& COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
{
first_op_cond = true;
- commutative = true;
number_of_oprnds++;
}
else
@@ -250,20 +257,24 @@ vect_get_and_check_slp_defs (vec_info *vinfo,
else
return -1;
- bool swapped = false;
+ bool swapped = (*swap != 0);
+ gcc_assert (!swapped || first_op_cond);
for (i = 0; i < number_of_oprnds; i++)
{
again:
if (first_op_cond)
{
- if (i == 0 || i == 1)
- oprnd = TREE_OPERAND (gimple_op (stmt, first_op_idx),
- swapped ? !i : i);
+ /* Map indicating how operands of cond_expr should be swapped. */
+ int maps[3][4] = {{0, 1, 2, 3}, {1, 0, 2, 3}, {0, 1, 3, 2}};
+ int *map = maps[*swap];
+
+ if (i < 2)
+ oprnd = TREE_OPERAND (gimple_op (stmt, first_op_idx), map[i]);
else
- oprnd = gimple_op (stmt, first_op_idx + i - 1);
+ oprnd = gimple_op (stmt, map[i]);
}
else
- oprnd = gimple_op (stmt, first_op_idx + (swapped ? !i : i));
+ oprnd = gimple_op (stmt, first_op_idx + (swapped ? !i : i));
oprnd_info = (*oprnds_info)[i];
@@ -431,9 +442,25 @@ again:
if (first_op_cond)
{
tree cond = gimple_assign_rhs1 (stmt);
- swap_ssa_operands (stmt, &TREE_OPERAND (cond, 0),
- &TREE_OPERAND (cond, 1));
- TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
+ enum tree_code code = TREE_CODE (cond);
+
+ /* Swap. */
+ if (*swap == 1)
+ {
+ swap_ssa_operands (stmt, &TREE_OPERAND (cond, 0),
+ &TREE_OPERAND (cond, 1));
+ TREE_SET_CODE (cond, swap_tree_comparison (code));
+ }
+ /* Invert. */
+ else
+ {
+ swap_ssa_operands (stmt, gimple_assign_rhs2_ptr (stmt),
+ gimple_assign_rhs3_ptr (stmt));
+ bool honor_nans = HONOR_NANS (TREE_OPERAND (cond, 0));
+ code = invert_tree_comparison (TREE_CODE (cond), honor_nans);
+ gcc_assert (code != ERROR_MARK);
+ TREE_SET_CODE (cond, code);
+ }
}
else
swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt),
@@ -446,6 +473,7 @@ again:
}
}
+ *swap = swapped;
return 0;
}
@@ -455,10 +483,17 @@ again:
true if they are, otherwise return false and indicate in *MATCHES
which stmts are not isomorphic to the first one. If MATCHES[0]
is false then this indicates the comparison could not be
- carried out or the stmts will never be vectorized by SLP. */
+ carried out or the stmts will never be vectorized by SLP.
+
+ Note COND_EXPR is possibly ismorphic to another one after swapping its
+ operands. Set SWAP[i] to 1 if stmt I is COND_EXPR and isomorphic to
+ the first stmt by swapping the two operands of comparison; set SWAP[i]
+ to 2 if stmt I is isormorphic to the first stmt by inverting the code
+ of comparison. Take A1 >= B1 ? X1 : Y1 as an exmple, it can be swapped
+ to (B1 <= A1 ? X1 : Y1); or be inverted to (A1 < B1) ? Y1 : X1. */
static bool
-vect_build_slp_tree_1 (vec_info *vinfo,
+vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap,
vec<gimple *> stmts, unsigned int group_size,
unsigned nops, unsigned int *max_nunits,
bool *matches, bool *two_operators)
@@ -482,6 +517,7 @@ vect_build_slp_tree_1 (vec_info *vinfo,
/* For every stmt in NODE find its def stmt/s. */
FOR_EACH_VEC_ELT (stmts, i, stmt)
{
+ swap[i] = 0;
matches[i] = false;
if (dump_enabled_p ())
@@ -782,26 +818,44 @@ vect_build_slp_tree_1 (vec_info *vinfo,
return false;
}
- if (rhs_code == COND_EXPR)
- {
- tree cond_expr = gimple_assign_rhs1 (stmt);
+ if (rhs_code == COND_EXPR)
+ {
+ tree cond_expr = gimple_assign_rhs1 (stmt);
+ enum tree_code cond_code = TREE_CODE (cond_expr);
+ enum tree_code swap_code = ERROR_MARK;
+ enum tree_code invert_code = ERROR_MARK;
if (i == 0)
first_cond_code = TREE_CODE (cond_expr);
- else if (first_cond_code != TREE_CODE (cond_expr))
- {
- if (dump_enabled_p ())
- {
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ else if (TREE_CODE_CLASS (cond_code) == tcc_comparison)
+ {
+ bool honor_nans = HONOR_NANS (TREE_OPERAND (cond_expr, 0));
+ swap_code = swap_tree_comparison (cond_code);
+ invert_code = invert_tree_comparison (cond_code, honor_nans);
+ }
+
+ if (first_cond_code == cond_code)
+ ;
+ /* Isomorphic can be achieved by swapping. */
+ else if (first_cond_code == swap_code)
+ swap[i] = 1;
+ /* Isomorphic can be achieved by inverting. */
+ else if (first_cond_code == invert_code)
+ swap[i] = 2;
+ else
+ {
+ if (dump_enabled_p ())
+ {
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"Build SLP failed: different"
" operation");
- dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
+ dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
stmt, 0);
- }
+ }
/* Mismatch. */
continue;
}
- }
+ }
}
matches[i] = true;
@@ -885,7 +939,8 @@ vect_build_slp_tree (vec_info *vinfo,
return NULL;
bool two_operators = false;
- if (!vect_build_slp_tree_1 (vinfo,
+ unsigned char *swap = XALLOCAVEC (unsigned char, group_size);
+ if (!vect_build_slp_tree_1 (vinfo, swap,
stmts, group_size, nops,
&this_max_nunits, matches, &two_operators))
return NULL;
@@ -905,18 +960,12 @@ vect_build_slp_tree (vec_info *vinfo,
slp_oprnd_info oprnd_info;
FOR_EACH_VEC_ELT (stmts, i, stmt)
{
- switch (vect_get_and_check_slp_defs (vinfo, stmt, i, &oprnds_info))
- {
- case 0:
- break;
- case -1:
- matches[0] = false;
- vect_free_oprnd_info (oprnds_info);
- return NULL;
- case 1:
- matches[i] = false;
- break;
- }
+ int res = vect_get_and_check_slp_defs (vinfo, &swap[i],
+ stmt, i, &oprnds_info);
+ if (res != 0)
+ matches[(res == -1) ? 0 : i] = false;
+ if (!matches[0])
+ break;
}
for (i = 0; i < group_size; ++i)
if (!matches[i])
@@ -1040,7 +1089,8 @@ vect_build_slp_tree (vec_info *vinfo,
operand order already. */
for (j = 0; j < group_size; ++j)
if (!matches[j]
- && STMT_VINFO_NUM_SLP_USES (vinfo_for_stmt (stmts[j])) != 0)
+ && (swap[j] != 0
+ || STMT_VINFO_NUM_SLP_USES (vinfo_for_stmt (stmts[j]))))
{
if (dump_enabled_p ())
{
@@ -1409,10 +1459,30 @@ vect_supported_load_permutation_p (slp_instance slp_instn)
SLP_TREE_LOAD_PERMUTATION (node).release ();
else
{
+ stmt_vec_info group_info
+ = vinfo_for_stmt (SLP_TREE_SCALAR_STMTS (node)[0]);
+ group_info = vinfo_for_stmt (GROUP_FIRST_ELEMENT (group_info));
+ unsigned nunits
+ = TYPE_VECTOR_SUBPARTS (STMT_VINFO_VECTYPE (group_info));
+ unsigned k, maxk = 0;
+ FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (node), j, k)
+ if (k > maxk)
+ maxk = k;
+ /* In BB vectorization we may not actually use a loaded vector
+ accessing elements in excess of GROUP_SIZE. */
+ if (maxk >= (GROUP_SIZE (group_info) & ~(nunits - 1)))
+ {
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "BB vectorization with gaps at the end of "
+ "a load is not supported\n");
+ return false;
+ }
+
/* Verify the permutation can be generated. */
vec<tree> tem;
+ unsigned n_perms;
if (!vect_transform_slp_perm_load (node, tem, NULL,
- 1, slp_instn, true))
+ 1, slp_instn, true, &n_perms))
{
dump_printf_loc (MSG_MISSED_OPTIMIZATION,
vect_location,
@@ -1425,11 +1495,13 @@ vect_supported_load_permutation_p (slp_instance slp_instn)
}
/* For loop vectorization verify we can generate the permutation. */
+ unsigned n_perms;
FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
if (node->load_permutation.exists ()
&& !vect_transform_slp_perm_load
(node, vNULL, NULL,
- SLP_INSTANCE_UNROLLING_FACTOR (slp_instn), slp_instn, true))
+ SLP_INSTANCE_UNROLLING_FACTOR (slp_instn), slp_instn, true,
+ &n_perms))
return false;
return true;
@@ -1498,14 +1570,38 @@ vect_analyze_slp_cost_1 (slp_instance instance, slp_tree node,
stmt = GROUP_FIRST_ELEMENT (stmt_info);
stmt_info = vinfo_for_stmt (stmt);
/* Record the cost for the permutation. */
- record_stmt_cost (body_cost_vec, ncopies_for_cost, vec_perm,
+ unsigned n_perms;
+ vect_transform_slp_perm_load (node, vNULL, NULL,
+ ncopies_for_cost, instance, true,
+ &n_perms);
+ record_stmt_cost (body_cost_vec, n_perms, vec_perm,
stmt_info, 0, vect_body);
- /* And adjust the number of loads performed. */
unsigned nunits
= TYPE_VECTOR_SUBPARTS (STMT_VINFO_VECTYPE (stmt_info));
- ncopies_for_cost
- = (GROUP_SIZE (stmt_info) - GROUP_GAP (stmt_info)
- + nunits - 1) / nunits;
+ /* And adjust the number of loads performed. This handles
+ redundancies as well as loads that are later dead. */
+ auto_sbitmap perm (GROUP_SIZE (stmt_info));
+ bitmap_clear (perm);
+ for (i = 0; i < SLP_TREE_LOAD_PERMUTATION (node).length (); ++i)
+ bitmap_set_bit (perm, SLP_TREE_LOAD_PERMUTATION (node)[i]);
+ ncopies_for_cost = 0;
+ bool load_seen = false;
+ for (i = 0; i < GROUP_SIZE (stmt_info); ++i)
+ {
+ if (i % nunits == 0)
+ {
+ if (load_seen)
+ ncopies_for_cost++;
+ load_seen = false;
+ }
+ if (bitmap_bit_p (perm, i))
+ load_seen = true;
+ }
+ if (load_seen)
+ ncopies_for_cost++;
+ gcc_assert (ncopies_for_cost
+ <= (GROUP_SIZE (stmt_info) - GROUP_GAP (stmt_info)
+ + nunits - 1) / nunits);
ncopies_for_cost *= SLP_INSTANCE_UNROLLING_FACTOR (instance);
}
/* Record the cost for the vector loads. */
@@ -3352,7 +3448,8 @@ vect_create_mask_and_perm (gimple *stmt,
bool
vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
gimple_stmt_iterator *gsi, int vf,
- slp_instance slp_node_instance, bool analyze_only)
+ slp_instance slp_node_instance, bool analyze_only,
+ unsigned *n_perms)
{
gimple *stmt = SLP_TREE_SCALAR_STMTS (node)[0];
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
@@ -3407,6 +3504,7 @@ vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
int first_vec_index = -1;
int second_vec_index = -1;
bool noop_p = true;
+ *n_perms = 0;
for (int j = 0; j < unroll_factor; j++)
{
@@ -3463,6 +3561,9 @@ vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
return false;
}
+ if (! noop_p)
+ ++*n_perms;
+
if (!analyze_only)
{
tree mask_vec = NULL_TREE;
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 1d17156b0b6..b0b131d9245 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -1770,6 +1770,11 @@ get_group_load_store_type (gimple *stmt, tree vectype, bool slp,
" non-consecutive accesses\n");
return false;
}
+ /* If the access is aligned an overrun is fine. */
+ if (overrun_p
+ && aligned_access_p
+ (STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt))))
+ overrun_p = false;
if (overrun_p && !can_overrun_p)
{
if (dump_enabled_p ())
@@ -1789,6 +1794,10 @@ get_group_load_store_type (gimple *stmt, tree vectype, bool slp,
/* If there is a gap at the end of the group then these optimizations
would access excess elements in the last iteration. */
bool would_overrun_p = (gap != 0);
+ /* If the access is aligned an overrun is fine. */
+ if (would_overrun_p
+ && aligned_access_p (STMT_VINFO_DATA_REF (stmt_info)))
+ would_overrun_p = false;
if (!STMT_VINFO_STRIDED_P (stmt_info)
&& (can_overrun_p || !would_overrun_p)
&& compare_step_with_zero (stmt) > 0)
@@ -2423,6 +2432,116 @@ vectorizable_mask_load_store (gimple *stmt, gimple_stmt_iterator *gsi,
return true;
}
+/* Check and perform vectorization of BUILT_IN_BSWAP{16,32,64}. */
+
+static bool
+vectorizable_bswap (gimple *stmt, gimple_stmt_iterator *gsi,
+ gimple **vec_stmt, slp_tree slp_node,
+ tree vectype_in, enum vect_def_type *dt)
+{
+ tree op, vectype;
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
+ unsigned ncopies, nunits;
+
+ op = gimple_call_arg (stmt, 0);
+ vectype = STMT_VINFO_VECTYPE (stmt_info);
+ nunits = TYPE_VECTOR_SUBPARTS (vectype);
+
+ /* Multiple types in SLP are handled by creating the appropriate number of
+ vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
+ case of SLP. */
+ if (slp_node)
+ ncopies = 1;
+ else
+ ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits;
+
+ gcc_assert (ncopies >= 1);
+
+ tree char_vectype = get_same_sized_vectype (char_type_node, vectype_in);
+ if (! char_vectype)
+ return false;
+
+ unsigned char *elts
+ = XALLOCAVEC (unsigned char, TYPE_VECTOR_SUBPARTS (char_vectype));
+ unsigned char *elt = elts;
+ unsigned word_bytes = TYPE_VECTOR_SUBPARTS (char_vectype) / nunits;
+ for (unsigned i = 0; i < nunits; ++i)
+ for (unsigned j = 0; j < word_bytes; ++j)
+ *elt++ = (i + 1) * word_bytes - j - 1;
+
+ if (! can_vec_perm_p (TYPE_MODE (char_vectype), false, elts))
+ return false;
+
+ if (! vec_stmt)
+ {
+ STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_NOTE, vect_location, "=== vectorizable_bswap ==="
+ "\n");
+ if (! PURE_SLP_STMT (stmt_info))
+ {
+ add_stmt_cost (stmt_info->vinfo->target_cost_data,
+ 1, vector_stmt, stmt_info, 0, vect_prologue);
+ add_stmt_cost (stmt_info->vinfo->target_cost_data,
+ ncopies, vec_perm, stmt_info, 0, vect_body);
+ }
+ return true;
+ }
+
+ tree *telts = XALLOCAVEC (tree, TYPE_VECTOR_SUBPARTS (char_vectype));
+ for (unsigned i = 0; i < TYPE_VECTOR_SUBPARTS (char_vectype); ++i)
+ telts[i] = build_int_cst (char_type_node, elts[i]);
+ tree bswap_vconst = build_vector (char_vectype, telts);
+
+ /* Transform. */
+ vec<tree> vec_oprnds = vNULL;
+ gimple *new_stmt = NULL;
+ stmt_vec_info prev_stmt_info = NULL;
+ for (unsigned j = 0; j < ncopies; j++)
+ {
+ /* Handle uses. */
+ if (j == 0)
+ vect_get_vec_defs (op, NULL, stmt, &vec_oprnds, NULL, slp_node, -1);
+ else
+ vect_get_vec_defs_for_stmt_copy (dt, &vec_oprnds, NULL);
+
+ /* Arguments are ready. create the new vector stmt. */
+ unsigned i;
+ tree vop;
+ FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
+ {
+ tree tem = make_ssa_name (char_vectype);
+ new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
+ char_vectype, vop));
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ tree tem2 = make_ssa_name (char_vectype);
+ new_stmt = gimple_build_assign (tem2, VEC_PERM_EXPR,
+ tem, tem, bswap_vconst);
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ tem = make_ssa_name (vectype);
+ new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
+ vectype, tem2));
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ if (slp_node)
+ SLP_TREE_VEC_STMTS (slp_node).quick_push (new_stmt);
+ }
+
+ if (slp_node)
+ continue;
+
+ if (j == 0)
+ STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
+ else
+ STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
+
+ prev_stmt_info = vinfo_for_stmt (new_stmt);
+ }
+
+ vec_oprnds.release ();
+ return true;
+}
+
/* Return true if vector types VECTYPE_IN and VECTYPE_OUT have
integer elements and if we can narrow VECTYPE_IN to VECTYPE_OUT
in a single step. On success, store the binary pack code in
@@ -2649,6 +2768,12 @@ vectorizable_call (gimple *gs, gimple_stmt_iterator *gsi, gimple **vec_stmt,
{ 0, 1, 2, ... vf - 1 } vector. */
gcc_assert (nargs == 0);
}
+ else if (modifier == NONE
+ && (gimple_call_builtin_p (stmt, BUILT_IN_BSWAP16)
+ || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
+ || gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)))
+ return vectorizable_bswap (stmt, gsi, vec_stmt, slp_node,
+ vectype_in, dt);
else
{
if (dump_enabled_p ())
@@ -6548,18 +6673,6 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
if (slp && SLP_TREE_LOAD_PERMUTATION (slp_node).exists ())
slp_perm = true;
- /* ??? The following is overly pessimistic (as well as the loop
- case above) in the case we can statically determine the excess
- elements loaded are within the bounds of a decl that is accessed.
- Likewise for BB vectorizations using masked loads is a possibility. */
- if (bb_vinfo && slp_perm && group_size % nunits != 0)
- {
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "BB vectorization with gaps at the end of a load "
- "is not supported\n");
- return false;
- }
-
/* Invalidate assumptions made by dependence analysis when vectorization
on the unrolled body effectively re-orders stmts. */
if (!PURE_SLP_STMT (stmt_info)
@@ -6978,8 +7091,11 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
}
}
if (slp_perm)
- vect_transform_slp_perm_load (slp_node, dr_chain, gsi, vf,
- slp_node_instance, false);
+ {
+ unsigned n_perms;
+ vect_transform_slp_perm_load (slp_node, dr_chain, gsi, vf,
+ slp_node_instance, false, &n_perms);
+ }
return true;
}
@@ -7497,8 +7613,10 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
if (slp_perm)
{
+ unsigned n_perms;
if (!vect_transform_slp_perm_load (slp_node, dr_chain, gsi, vf,
- slp_node_instance, false))
+ slp_node_instance, false,
+ &n_perms))
{
dr_chain.release ();
return false;
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 386654862b4..2a7cdfe27a5 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -1166,7 +1166,7 @@ extern int vect_get_known_peeling_cost (loop_vec_info, int, int *,
extern void vect_free_slp_instance (slp_instance);
extern bool vect_transform_slp_perm_load (slp_tree, vec<tree> ,
gimple_stmt_iterator *, int,
- slp_instance, bool);
+ slp_instance, bool, unsigned *);
extern bool vect_slp_analyze_operations (vec<slp_instance> slp_instances,
void *);
extern bool vect_schedule_slp (vec_info *);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index fcdb3417bb3..68fe2acb997 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -10650,18 +10650,17 @@ public:
}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
- void push_value_range (const_tree var, value_range *vr);
- value_range *pop_value_range (const_tree var);
+ void push_value_range (tree var, value_range *vr);
+ value_range *pop_value_range (tree var);
value_range *try_find_new_range (tree op, tree_code code, tree limit);
/* Cond_stack holds the old VR. */
- auto_vec<std::pair <const_tree, value_range*> > stack;
+ auto_vec<std::pair <tree, value_range*> > stack;
bitmap need_eh_cleanup;
auto_vec<gimple *> stmts_to_fixup;
auto_vec<gimple *> stmts_to_remove;
};
-
/* Find new range for OP such that (OP CODE LIMIT) is true. */
value_range *
@@ -10679,6 +10678,10 @@ evrp_dom_walker::try_find_new_range (tree op, tree_code code, tree limit)
PUSH old value in the stack with the old VR. */
if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
{
+ if (old_vr->type == vr.type
+ && vrp_operand_equal_p (old_vr->min, vr.min)
+ && vrp_operand_equal_p (old_vr->max, vr.max))
+ return NULL;
value_range *new_vr = vrp_value_range_pool.allocate ();
*new_vr = vr;
return new_vr;
@@ -10696,7 +10699,10 @@ evrp_dom_walker::before_dom_children (basic_block bb)
edge_iterator ei;
edge e;
- push_value_range (NULL_TREE, NULL);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Visiting BB%d\n", bb->index);
+
+ stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
edge pred_e = NULL;
FOR_EACH_EDGE (e, ei, bb->preds)
@@ -10723,6 +10729,11 @@ evrp_dom_walker::before_dom_children (basic_block bb)
&& (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
|| POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Visiting controlling predicate ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
/* Entering a new scope. Try to see if we can find a VR
here. */
tree op1 = gimple_cond_rhs (stmt);
@@ -10778,6 +10789,11 @@ evrp_dom_walker::before_dom_children (basic_block bb)
continue;
value_range vr_result = VR_INITIALIZER;
bool interesting = stmt_interesting_for_vrp (phi);
+ if (interesting && dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Visiting PHI node ");
+ print_gimple_stmt (dump_file, phi, 0, 0);
+ }
if (!has_unvisited_preds
&& interesting)
extract_range_from_phi_node (phi, &vr_result);
@@ -10814,6 +10830,12 @@ evrp_dom_walker::before_dom_children (basic_block bb)
bool was_noreturn = (is_gimple_call (stmt)
&& gimple_call_noreturn_p (stmt));
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Visiting stmt ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
if (gcond *cond = dyn_cast <gcond *> (stmt))
{
vrp_visit_cond_stmt (cond, &taken_edge);
@@ -10825,6 +10847,7 @@ evrp_dom_walker::before_dom_children (basic_block bb)
gimple_cond_make_false (cond);
else
gcc_unreachable ();
+ update_stmt (stmt);
}
}
else if (stmt_interesting_for_vrp (stmt))
@@ -10873,6 +10896,55 @@ evrp_dom_walker::before_dom_children (basic_block bb)
else
set_defs_to_varying (stmt);
+ /* See if we can derive a range for any of STMT's operands. */
+ tree op;
+ ssa_op_iter i;
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE)
+ {
+ tree value;
+ enum tree_code comp_code;
+
+ /* If OP is used in such a way that we can infer a value
+ range for it, and we don't find a previous assertion for
+ it, create a new assertion location node for OP. */
+ if (infer_value_range (stmt, op, &comp_code, &value))
+ {
+ /* If we are able to infer a nonzero value range for OP,
+ then walk backwards through the use-def chain to see if OP
+ was set via a typecast.
+ If so, then we can also infer a nonzero value range
+ for the operand of the NOP_EXPR. */
+ if (comp_code == NE_EXPR && integer_zerop (value))
+ {
+ tree t = op;
+ gimple *def_stmt = SSA_NAME_DEF_STMT (t);
+ while (is_gimple_assign (def_stmt)
+ && CONVERT_EXPR_CODE_P
+ (gimple_assign_rhs_code (def_stmt))
+ && TREE_CODE
+ (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
+ && POINTER_TYPE_P
+ (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
+ {
+ t = gimple_assign_rhs1 (def_stmt);
+ def_stmt = SSA_NAME_DEF_STMT (t);
+
+ /* Add VR when (T COMP_CODE value) condition is
+ true. */
+ value_range *op_range
+ = try_find_new_range (t, comp_code, value);
+ if (op_range)
+ push_value_range (t, op_range);
+ }
+ }
+ /* Add VR when (OP COMP_CODE value) condition is true. */
+ value_range *op_range = try_find_new_range (op,
+ comp_code, value);
+ if (op_range)
+ push_value_range (op, op_range);
+ }
+ }
+
/* Try folding stmts with the VR discovered. */
bool did_replace
= replace_uses_in (stmt, op_with_constant_singleton_value_range);
@@ -10938,42 +11010,44 @@ evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
gcc_checking_assert (!stack.is_empty ());
while (stack.last ().first != NULL_TREE)
pop_value_range (stack.last ().first);
- pop_value_range (stack.last ().first);
+ stack.pop ();
}
/* Push the Value Range of VAR to the stack and update it with new VR. */
void
-evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
+evrp_dom_walker::push_value_range (tree var, value_range *vr)
{
- if (vr != NULL)
+ if (SSA_NAME_VERSION (var) >= num_vr_values)
+ return;
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
- unsigned ver = SSA_NAME_VERSION (var);
- gcc_checking_assert (vr_value);
- stack.safe_push (std::make_pair (var, vr_value[ver]));
-
- if (ver < num_vr_values)
- vr_value[ver] = vr;
+ fprintf (dump_file, "pushing new range for ");
+ print_generic_expr (dump_file, var, 0);
+ fprintf (dump_file, ": ");
+ dump_value_range (dump_file, vr);
+ fprintf (dump_file, "\n");
}
- else
- stack.safe_push (std::make_pair (var, vr));
+ stack.safe_push (std::make_pair (var, get_value_range (var)));
+ vr_value[SSA_NAME_VERSION (var)] = vr;
}
/* Pop the Value Range from the vrp_stack and update VAR with it. */
value_range *
-evrp_dom_walker::pop_value_range (const_tree var)
+evrp_dom_walker::pop_value_range (tree var)
{
value_range *vr = stack.last ().second;
- if (vr != NULL)
+ gcc_checking_assert (var == stack.last ().first);
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
- unsigned ver = SSA_NAME_VERSION (var);
- gcc_checking_assert (var == stack.last ().first);
- gcc_checking_assert (vr_value);
-
- if (ver < num_vr_values)
- vr_value[ver] = vr;
+ fprintf (dump_file, "popping range for ");
+ print_generic_expr (dump_file, var, 0);
+ fprintf (dump_file, ", restoring ");
+ dump_value_range (dump_file, vr);
+ fprintf (dump_file, "\n");
}
+ vr_value[SSA_NAME_VERSION (var)] = vr;
stack.pop ();
return vr;
}
diff --git a/gcc/tree.c b/gcc/tree.c
index 56cc653c875..c155d56d2c5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -6497,6 +6497,21 @@ set_type_quals (tree type, int type_quals)
TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
}
+/* Returns true iff CAND and BASE have equivalent language-specific
+ qualifiers. */
+
+bool
+check_lang_type (const_tree cand, const_tree base)
+{
+ if (lang_hooks.types.type_hash_eq == NULL)
+ return true;
+ /* type_hash_eq currently only applies to these types. */
+ if (TREE_CODE (cand) != FUNCTION_TYPE
+ && TREE_CODE (cand) != METHOD_TYPE)
+ return true;
+ return lang_hooks.types.type_hash_eq (cand, base);
+}
+
/* Returns true iff unqualified CAND and BASE are equivalent. */
bool
@@ -6517,7 +6532,8 @@ bool
check_qualified_type (const_tree cand, const_tree base, int type_quals)
{
return (TYPE_QUALS (cand) == type_quals
- && check_base_type (cand, base));
+ && check_base_type (cand, base)
+ && check_lang_type (cand, base));
}
/* Returns true iff CAND is equivalent to BASE with ALIGN. */
@@ -6532,7 +6548,8 @@ check_aligned_type (const_tree cand, const_tree base, unsigned int align)
/* Check alignment. */
&& TYPE_ALIGN (cand) == align
&& attribute_list_equal (TYPE_ATTRIBUTES (cand),
- TYPE_ATTRIBUTES (base)));
+ TYPE_ATTRIBUTES (base))
+ && check_lang_type (cand, base));
}
/* This function checks to see if TYPE matches the size one of the built-in
@@ -13272,12 +13289,10 @@ verify_type_variant (const_tree t, tree tv)
verify_variant_match (TYPE_SIZE);
if (TREE_CODE (TYPE_SIZE_UNIT (t)) != PLACEHOLDER_EXPR
&& TREE_CODE (TYPE_SIZE_UNIT (tv)) != PLACEHOLDER_EXPR
- && TYPE_SIZE_UNIT (t) != TYPE_SIZE_UNIT (tv)
- /* FIXME: ideally we should compare pointer equality, but java FE
- produce variants where size is INTEGER_CST of different type (int
- wrt size_type) during libjava biuld. */
- && !operand_equal_p (TYPE_SIZE_UNIT (t), TYPE_SIZE_UNIT (tv), 0))
+ && TYPE_SIZE_UNIT (t) != TYPE_SIZE_UNIT (tv))
{
+ gcc_assert (!operand_equal_p (TYPE_SIZE_UNIT (t),
+ TYPE_SIZE_UNIT (tv), 0));
error ("type variant has different TYPE_SIZE_UNIT");
debug_tree (tv);
error ("type variant's TYPE_SIZE_UNIT");
diff --git a/gcc/tree.h b/gcc/tree.h
index c494f23c90d..6a98b6ee0b6 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1757,6 +1757,10 @@ extern void protected_set_expr_location (tree, location_t);
/* True if BLOCK has the same ranges as its BLOCK_SUPERCONTEXT. */
#define BLOCK_SAME_RANGE(NODE) (BLOCK_CHECK (NODE)->base.u.bits.nameless_flag)
+/* True if BLOCK appears in cold section. */
+#define BLOCK_IN_COLD_SECTION_P(NODE) \
+ (BLOCK_CHECK (NODE)->base.u.bits.atomic_flag)
+
/* An index number for this block. These values are not guaranteed to
be unique across functions -- whether or not they are depends on
the debugging output format in use. */
@@ -4210,6 +4214,11 @@ extern tree merge_dllimport_decl_attributes (tree, tree);
/* Handle a "dllimport" or "dllexport" attribute. */
extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+/* Returns true iff CAND and BASE have equivalent language-specific
+ qualifiers. */
+
+extern bool check_lang_type (const_tree cand, const_tree base);
+
/* Returns true iff unqualified CAND and BASE are equivalent. */
extern bool check_base_type (const_tree cand, const_tree base);
diff --git a/gcc/value-prof.h b/gcc/value-prof.h
index 07e2b3b5840..02220acb206 100644
--- a/gcc/value-prof.h
+++ b/gcc/value-prof.h
@@ -96,15 +96,14 @@ bool check_ic_target (gcall *, struct cgraph_node *);
/* In tree-profile.c. */
-extern void gimple_init_edge_profiler (void);
+extern void gimple_init_gcov_profiler (void);
extern void gimple_gen_edge_profiler (int, edge);
extern void gimple_gen_interval_profiler (histogram_value, unsigned, unsigned);
extern void gimple_gen_pow2_profiler (histogram_value, unsigned, unsigned);
extern void gimple_gen_one_value_profiler (histogram_value, unsigned, unsigned);
extern void gimple_gen_ic_profiler (histogram_value, unsigned, unsigned);
extern void gimple_gen_ic_func_profiler (void);
-extern void gimple_gen_time_profiler (unsigned, unsigned,
- gimple_stmt_iterator &);
+extern void gimple_gen_time_profiler (unsigned, unsigned);
extern void gimple_gen_average_profiler (histogram_value, unsigned, unsigned);
extern void gimple_gen_ior_profiler (histogram_value, unsigned, unsigned);
extern void stream_out_histogram_value (struct output_block *, histogram_value);
diff --git a/include/ChangeLog b/include/ChangeLog
index 5054b7e912a..d029f722ae9 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ * demangle.h (enum demangle_component_type): Add
+ DEMANGLE_COMPONENT_NOEXCEPT, DEMANGLE_COMPONENT_THROW_SPEC.
+
2016-10-17 Jakub Jelinek <jakub@redhat.com>
* dwarf2.h (enum dwarf_calling_convention): Add new DWARF5
diff --git a/include/demangle.h b/include/demangle.h
index 1d7cadf4b71..7a03c204aac 100644
--- a/include/demangle.h
+++ b/include/demangle.h
@@ -449,7 +449,9 @@ enum demangle_component_type
/* A transaction-safe function type. */
DEMANGLE_COMPONENT_TRANSACTION_SAFE,
/* A cloned function. */
- DEMANGLE_COMPONENT_CLONE
+ DEMANGLE_COMPONENT_CLONE,
+ DEMANGLE_COMPONENT_NOEXCEPT,
+ DEMANGLE_COMPONENT_THROW_SPEC
};
/* Types which are only used internally. */
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 9083bdab980..a298a2fcef6 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,7 @@
+2016-11-08 Richard Earnshaw <rearnsha@arm.com>
+
+ * lex.c (search_line_fast): New implementation for AArch64.
+
2016-10-25 David Malcolm <dmalcolm@redhat.com>
* files.c (destroy_cpp_file): Free file->path.
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 6f65fa152fc..cea88488f36 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -752,6 +752,101 @@ search_line_fast (const uchar *s, const uchar *end ATTRIBUTE_UNUSED)
}
}
+#elif defined (__ARM_NEON) && defined (__ARM_64BIT_STATE)
+#include "arm_neon.h"
+
+/* This doesn't have to be the exact page size, but no system may use
+ a size smaller than this. ARMv8 requires a minimum page size of
+ 4k. The impact of being conservative here is a small number of
+ cases will take the slightly slower entry path into the main
+ loop. */
+
+#define AARCH64_MIN_PAGE_SIZE 4096
+
+static const uchar *
+search_line_fast (const uchar *s, const uchar *end ATTRIBUTE_UNUSED)
+{
+ const uint8x16_t repl_nl = vdupq_n_u8 ('\n');
+ const uint8x16_t repl_cr = vdupq_n_u8 ('\r');
+ const uint8x16_t repl_bs = vdupq_n_u8 ('\\');
+ const uint8x16_t repl_qm = vdupq_n_u8 ('?');
+ const uint8x16_t xmask = (uint8x16_t) vdupq_n_u64 (0x8040201008040201ULL);
+
+#ifdef __AARCH64EB
+ const int16x8_t shift = {8, 8, 8, 8, 0, 0, 0, 0};
+#else
+ const int16x8_t shift = {0, 0, 0, 0, 8, 8, 8, 8};
+#endif
+
+ unsigned int found;
+ const uint8_t *p;
+ uint8x16_t data;
+ uint8x16_t t;
+ uint16x8_t m;
+ uint8x16_t u, v, w;
+
+ /* Align the source pointer. */
+ p = (const uint8_t *)((uintptr_t)s & -16);
+
+ /* Assuming random string start positions, with a 4k page size we'll take
+ the slow path about 0.37% of the time. */
+ if (__builtin_expect ((AARCH64_MIN_PAGE_SIZE
+ - (((uintptr_t) s) & (AARCH64_MIN_PAGE_SIZE - 1)))
+ < 16, 0))
+ {
+ /* Slow path: the string starts near a possible page boundary. */
+ uint32_t misalign, mask;
+
+ misalign = (uintptr_t)s & 15;
+ mask = (-1u << misalign) & 0xffff;
+ data = vld1q_u8 (p);
+ t = vceqq_u8 (data, repl_nl);
+ u = vceqq_u8 (data, repl_cr);
+ v = vorrq_u8 (t, vceqq_u8 (data, repl_bs));
+ w = vorrq_u8 (u, vceqq_u8 (data, repl_qm));
+ t = vorrq_u8 (v, w);
+ t = vandq_u8 (t, xmask);
+ m = vpaddlq_u8 (t);
+ m = vshlq_u16 (m, shift);
+ found = vaddvq_u16 (m);
+ found &= mask;
+ if (found)
+ return (const uchar*)p + __builtin_ctz (found);
+ }
+ else
+ {
+ data = vld1q_u8 ((const uint8_t *) s);
+ t = vceqq_u8 (data, repl_nl);
+ u = vceqq_u8 (data, repl_cr);
+ v = vorrq_u8 (t, vceqq_u8 (data, repl_bs));
+ w = vorrq_u8 (u, vceqq_u8 (data, repl_qm));
+ t = vorrq_u8 (v, w);
+ if (__builtin_expect (vpaddd_u64 ((uint64x2_t)t), 0))
+ goto done;
+ }
+
+ do
+ {
+ p += 16;
+ data = vld1q_u8 (p);
+ t = vceqq_u8 (data, repl_nl);
+ u = vceqq_u8 (data, repl_cr);
+ v = vorrq_u8 (t, vceqq_u8 (data, repl_bs));
+ w = vorrq_u8 (u, vceqq_u8 (data, repl_qm));
+ t = vorrq_u8 (v, w);
+ } while (!vpaddd_u64 ((uint64x2_t)t));
+
+done:
+ /* Now that we've found the terminating substring, work out precisely where
+ we need to stop. */
+ t = vandq_u8 (t, xmask);
+ m = vpaddlq_u8 (t);
+ m = vshlq_u16 (m, shift);
+ found = vaddvq_u16 (m);
+ return (((((uintptr_t) p) < (uintptr_t) s) ? s : (const uchar *)p)
+ + __builtin_ctz (found));
+}
+
#elif defined (__ARM_NEON)
#include "arm_neon.h"
diff --git a/libcpp/po/ChangeLog b/libcpp/po/ChangeLog
index 331f0053620..3858bd51915 100644
--- a/libcpp/po/ChangeLog
+++ b/libcpp/po/ChangeLog
@@ -1,3 +1,7 @@
+2016-10-29 Joseph Myers <joseph@codesourcery.com>
+
+ * eo.po: Update.
+
2016-08-19 Joseph Myers <joseph@codesourcery.com>
* cpplib.pot: Regenerate.
diff --git a/libcpp/po/eo.po b/libcpp/po/eo.po
index c9d947030ad..3b063910a65 100644
--- a/libcpp/po/eo.po
+++ b/libcpp/po/eo.po
@@ -5,17 +5,18 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: cpplib 6.1-b20160131\n"
+"Project-Id-Version: cpplib 6.1.0\n"
"Report-Msgid-Bugs-To: http://gcc.gnu.org/bugs.html\n"
"POT-Creation-Date: 2016-04-21 15:24+0000\n"
-"PO-Revision-Date: 2016-02-12 13:14-0300\n"
+"PO-Revision-Date: 2016-10-28 21:47-0300\n"
"Last-Translator: Felipe Castro <fefcas@gmail.com>\n"
"Language-Team: Esperanto <translation-team-eo@lists.sourceforge.net>\n"
"Language: eo\n"
+"X-Bugs: Report translation errors to the Language-Team address.\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.6.10\n"
+"X-Generator: Poedit 1.5.4\n"
#: charset.c:674
#, c-format
@@ -272,7 +273,7 @@ msgstr "\"%s\" post # ne estas pozitiva entjero"
#: directives.c:1061
#, c-format
msgid "file \"%s\" linemarker ignored due to incorrect nesting"
-msgstr ""
+msgstr "linimarkilo de dosiero \"%s\" estis preteratentata pro malkorekta nesto"
#: directives.c:1120 directives.c:1122 directives.c:1124 directives.c:1710
#, c-format
@@ -433,10 +434,8 @@ msgid "invalid prefix \"0b\" for floating constant"
msgstr "malvalida prefikso \"0b\" por glitkoma konstanto"
#: expr.c:555
-#, fuzzy
-#| msgid "use of C++11 hexadecimal floating constant"
msgid "use of C++1z hexadecimal floating constant"
-msgstr "uzo de deksesuma glitkoma konstanto de C++11"
+msgstr "uzo de deksesuma glitkoma konstanto de C++1z"
#: expr.c:558
msgid "use of C99 hexadecimal floating constant"
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 116c87b92c6..e3a81f6b026 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,22 @@
+2016-11-03 Martin Liska <mliska@suse.cz>
+
+ * libgcov-profiler.c (__gcov_time_profiler): Remove.
+ (__gcov_time_profiler_atomic): Likewise.
+
+2016-11-03 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ PR libgcc/78067
+ * libgcc2.c (__floatdisf, __floatdidf): Avoid undefined results from
+ count_leading_zeros.
+
+2016-11-02 Uros Bizjak <ubizjak@gmail.com>
+
+ * Makefile.in (LIB2_DIVMOD_FUNCS): Add _divmoddi4.
+ * libgcc2.c (__divmoddi4): New function.
+ * libgcc2.h (__divmoddi4): Declare.
+ * libgcc-std.ver.in (GCC_7.0.0): New. Add __PFX_divmoddi4
+ and __PFX_divmodti4.
+
2016-10-24 Florian Weimer <fweimer@redhat.com>
PR libgcc/78064
@@ -5,7 +24,7 @@
2016-10-19 John David Anglin <danglin@gcc.gnu.org>
- * config/pa/pa64-hpux-lib.h: New file.
+ * config/pa/pa64-hpux-lib.h: New file.
(EH_FRAME_SECTION_NAME): Rename to __LIBGCC_EH_FRAME_SECTION_NAME__.
(DTORS_SECTION_ASM_OP): Rename to __LIBGCC_DTORS_SECTION_ASM_OP__.
* config.host (tm_file): Add pa/pa64-hpux-lib.h to tm_file on
@@ -358,7 +377,7 @@
2016-06-23 Jakub Sejdak <jakub.sejdak@phoesys.com>
- * config.host: Add suport for arm*-*-phoenix* targets.
+ * config.host: Add suport for arm*-*-phoenix* targets.
2016-06-21 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index 873cad04b78..ae69611f2bf 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -255,10 +255,6 @@ LIB2FUNCS_ST = _eprintf __gcc_bcmp
# List of functions not to build from libgcc2.c.
LIB2FUNCS_EXCLUDE =
-# These might cause a divide overflow trap and so are compiled with
-# unwinder info.
-LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4
-
# List of extra C and assembler files to add to static and shared libgcc2.
# Assembler files should have names ending in `.S'.
LIB2ADD =
@@ -455,7 +451,8 @@ endif
# These might cause a divide overflow trap and so are compiled with
# unwinder info.
-LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4
+LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _divmoddi4 \
+ _udivdi3 _umoddi3 _udivmoddi4 _udiv_w_sdiv
# Remove any objects from lib2funcs and LIB2_DIVMOD_FUNCS that are
# defined as optimized assembly code in LIB1ASMFUNCS or as C code
diff --git a/libgcc/libgcc-std.ver.in b/libgcc/libgcc-std.ver.in
index c8ca62fbe05..a35d4b3013a 100644
--- a/libgcc/libgcc-std.ver.in
+++ b/libgcc/libgcc-std.ver.in
@@ -1938,3 +1938,9 @@ GCC_4.7.0 {
%inherit GCC_4.8.0 GCC_4.7.0
GCC_4.8.0 {
}
+
+%inherit GCC_7.0.0 GCC_4.8.0
+GCC_7.0.0 {
+ __PFX__divmoddi4
+ __PFX__divmodti4
+}
diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
index 9fb150b2dd5..97b9237ea2b 100644
--- a/libgcc/libgcc2.c
+++ b/libgcc/libgcc2.c
@@ -680,7 +680,8 @@ __udiv_w_sdiv (UWtype *rp __attribute__ ((__unused__)),
#endif
#if (defined (L_udivdi3) || defined (L_divdi3) || \
- defined (L_umoddi3) || defined (L_moddi3))
+ defined (L_umoddi3) || defined (L_moddi3) || \
+ defined (L_divmoddi4))
#define L_udivmoddi4
#endif
@@ -937,7 +938,8 @@ __parityDI2 (UDWtype x)
#ifdef TARGET_HAS_NO_HW_DIVIDE
#if (defined (L_udivdi3) || defined (L_divdi3) || \
- defined (L_umoddi3) || defined (L_moddi3))
+ defined (L_umoddi3) || defined (L_moddi3) || \
+ defined (L_divmoddi4))
static inline __attribute__ ((__always_inline__))
#endif
UDWtype
@@ -1004,7 +1006,8 @@ __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
#else
#if (defined (L_udivdi3) || defined (L_divdi3) || \
- defined (L_umoddi3) || defined (L_moddi3))
+ defined (L_umoddi3) || defined (L_moddi3) || \
+ defined (L_divmoddi4))
static inline __attribute__ ((__always_inline__))
#endif
UDWtype
@@ -1269,6 +1272,34 @@ __moddi3 (DWtype u, DWtype v)
}
#endif
+#ifdef L_divmoddi4
+DWtype
+__divmoddi4 (DWtype u, DWtype v, DWtype *rp)
+{
+ Wtype c1 = 0, c2 = 0;
+ DWunion uu = {.ll = u};
+ DWunion vv = {.ll = v};
+ DWtype w;
+ DWtype r;
+
+ if (uu.s.high < 0)
+ c1 = ~c1, c2 = ~c2,
+ uu.ll = -uu.ll;
+ if (vv.s.high < 0)
+ c1 = ~c1,
+ vv.ll = -vv.ll;
+
+ w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype*)&r);
+ if (c1)
+ w = -w;
+ if (c2)
+ r = -r;
+
+ *rp = r;
+ return w;
+}
+#endif
+
#ifdef L_umoddi3
UDWtype
__umoddi3 (UDWtype u, UDWtype v)
@@ -1643,6 +1674,11 @@ FUNC (DWtype u)
hi = -(UWtype) hi;
UWtype count, shift;
+#if !defined (COUNT_LEADING_ZEROS_0) || COUNT_LEADING_ZEROS_0 != W_TYPE_SIZE
+ if (hi == 0)
+ count = W_TYPE_SIZE;
+ else
+#endif
count_leading_zeros (count, hi);
/* No leading bits means u == minimum. */
diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h
index c46fb77a6ec..15f970515f8 100644
--- a/libgcc/libgcc2.h
+++ b/libgcc/libgcc2.h
@@ -281,6 +281,7 @@ typedef int shift_count_type __attribute__((mode (__libgcc_shift_count__)));
#define __ashrdi3 __NDW(ashr,3)
#define __cmpdi2 __NDW(cmp,2)
#define __ucmpdi2 __NDW(ucmp,2)
+#define __divmoddi4 __NDW(divmod,4)
#define __udivmoddi4 __NDW(udivmod,4)
#define __fixunstfDI __NDW(fixunstf,)
#define __fixtfdi __NDW(fixtf,)
@@ -376,10 +377,12 @@ extern DWtype __divdi3 (DWtype, DWtype);
extern UDWtype __udivdi3 (UDWtype, UDWtype);
extern UDWtype __umoddi3 (UDWtype, UDWtype);
extern DWtype __moddi3 (DWtype, DWtype);
+extern DWtype __divmoddi4 (DWtype, DWtype, DWtype *);
/* __udivmoddi4 is static inline when building other libgcc2 portions. */
#if (!defined (L_udivdi3) && !defined (L_divdi3) && \
- !defined (L_umoddi3) && !defined (L_moddi3))
+ !defined (L_umoddi3) && !defined (L_moddi3) && \
+ !defined (L_divmoddi4))
extern UDWtype __udivmoddi4 (UDWtype, UDWtype, UDWtype *);
#endif
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index 38ed5f113e7..4f0a40675a2 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -342,30 +342,9 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
#ifdef L_gcov_time_profiler
/* Counter for first visit of each function. */
-static gcov_type function_counter;
+gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN;
-/* Sets corresponding COUNTERS if there is no value. */
-
-void
-__gcov_time_profiler (gcov_type* counters)
-{
- if (!counters[0])
- counters[0] = ++function_counter;
-}
-
-#if GCOV_SUPPORTS_ATOMIC
-/* Sets corresponding COUNTERS if there is no value.
- Function is thread-safe. */
-
-void
-__gcov_time_profiler_atomic (gcov_type* counters)
-{
- if (!counters[0])
- counters[0] = __atomic_add_fetch (&function_counter, 1, __ATOMIC_RELAXED);
-}
#endif
-#endif
-
#ifdef L_gcov_average_profiler
/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 107372340ed..d50ef47b475 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,23 @@
+2016-11-03 Fritz Reese <fritzoreese@gmail.com>
+
+ * io/io.h (IOPARM_DT_DEFAULT_EXP): New flag bit.
+ * io/list_read.c (parse_real, read_real): Allow omission of exponent
+ with IOPARM_DT_DEFAULT_EXP.
+ * io/read.c (read_f): Ditto.
+
+2016-10-31 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR libgfortran/54679
+ * io/format.c (parse_format_list): Adjust checks for FMT_L to
+ treat a zero width as an extension, giving warnings or error
+ as appropriate. Improve messages.
+
+2016-10-30 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR fortran/78123
+ * io/transfer.c (formatted_transfer_scalar_read): Clear seen_eor
+ only if we have tabbed to left of current position.
+
2016-10-26 Fritz Reese <fritzoreese@gmail.com>
* libgfortran.h (IOPARM_OPEN_HAS_READONLY, IOPARM_OPEN_HAS_SHARE,
diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c
index 31bc642910a..8a1859749e1 100644
--- a/libgfortran/io/format.c
+++ b/libgfortran/io/format.c
@@ -870,19 +870,25 @@ parse_format_list (st_parameter_dt *dtp, bool *seen_dd)
t = format_lex (fmt);
if (t != FMT_POSINT)
{
- if (notification_std(GFC_STD_GNU) == NOTIFICATION_ERROR)
+ if (t == FMT_ZERO)
{
- fmt->error = posint_required;
- goto finished;
+ if (notification_std(GFC_STD_GNU) == NOTIFICATION_ERROR)
+ {
+ fmt->error = "Extension: Zero width after L descriptor";
+ goto finished;
+ }
+ else
+ notify_std (&dtp->common, GFC_STD_GNU,
+ "Zero width after L descriptor");
}
else
{
fmt->saved_token = t;
- fmt->value = 1; /* Default width */
- notify_std (&dtp->common, GFC_STD_GNU, posint_required);
+ notify_std (&dtp->common, GFC_STD_GNU,
+ "Positive width required with L descriptor");
}
+ fmt->value = 1; /* Default width */
}
-
get_fnode (fmt, &head, &tail, FMT_L);
tail->u.n = fmt->value;
tail->repeat = repeat;
diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h
index 7a548497af9..cd0a26f6aa0 100644
--- a/libgfortran/io/io.h
+++ b/libgfortran/io/io.h
@@ -443,6 +443,7 @@ st_parameter_inquire;
#define IOPARM_DT_HAS_SIGN (1 << 24)
#define IOPARM_DT_HAS_F2003 (1 << 25)
#define IOPARM_DT_HAS_UDTIO (1 << 26)
+#define IOPARM_DT_DEFAULT_EXP (1 << 27)
/* Internal use bit. */
#define IOPARM_DT_IONML_SET (1u << 31)
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index f258c9d9249..a35beb88a00 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -1374,7 +1374,16 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
exp2:
if (!isdigit (c))
- goto bad_exponent;
+ {
+ /* Extension: allow default exponent of 0 when omitted. */
+ if (dtp->common.flags & IOPARM_DT_DEFAULT_EXP)
+ {
+ push_char (dtp, '0');
+ goto done;
+ }
+ else
+ goto bad_exponent;
+ }
push_char (dtp, c);
@@ -1816,7 +1825,16 @@ read_real (st_parameter_dt *dtp, void * dest, int length)
exp2:
if (!isdigit (c))
- goto bad_exponent;
+ {
+ /* Extension: allow default exponent of 0 when omitted. */
+ if (dtp->common.flags & IOPARM_DT_DEFAULT_EXP)
+ {
+ push_char (dtp, '0');
+ goto done;
+ }
+ else
+ goto bad_exponent;
+ }
push_char (dtp, c);
diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c
index 23b6f644429..508b3a04fb0 100644
--- a/libgfortran/io/read.c
+++ b/libgfortran/io/read.c
@@ -1087,7 +1087,13 @@ exponent:
the d parameter before explict conversion takes place. */
if (w == 0)
- goto bad_float;
+ {
+ /* Extension: allow default exponent of 0 when omitted. */
+ if (dtp->common.flags & IOPARM_DT_DEFAULT_EXP)
+ goto done;
+ else
+ goto bad_float;
+ }
if (dtp->u.p.blank_status == BLANK_UNSPECIFIED)
{
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index b8eb5eda20f..583036292f9 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -1579,7 +1579,8 @@ formatted_transfer_scalar_read (st_parameter_dt *dtp, bt type, void *p, int kind
dtp->u.p.current_unit->bytes_left -= dtp->u.p.sf_seen_eor;
dtp->u.p.skips -= dtp->u.p.sf_seen_eor;
bytes_used = pos;
- dtp->u.p.sf_seen_eor = 0;
+ if (dtp->u.p.pending_spaces == 0)
+ dtp->u.p.sf_seen_eor = 0;
}
if (dtp->u.p.skips < 0)
{
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 2e46ecd514f..edf193a5d40 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -105,7 +105,7 @@ toolexeclib_LTLIBRARIES = libgo-llgo.la
toolexeclib_LIBRARIES = libgobegin-llgo.a
else
toolexeclib_LTLIBRARIES = libgo.la
-toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a
+toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
endif
toolexeclibgo_DATA = \
@@ -428,7 +428,6 @@ endif
endif
runtime_files = \
- runtime/go-append.c \
runtime/go-assert.c \
runtime/go-breakpoint.c \
runtime/go-caller.c \
@@ -436,12 +435,10 @@ runtime_files = \
runtime/go-cdiv.c \
runtime/go-cgo.c \
runtime/go-construct-map.c \
- runtime/go-copy.c \
runtime/go-defer.c \
runtime/go-deferred-recover.c \
runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-make-slice.c \
runtime/go-matherr.c \
runtime/go-memclr.c \
runtime/go-memcmp.c \
@@ -482,7 +479,7 @@ runtime_files = \
runtime/parfor.c \
runtime/print.c \
runtime/proc.c \
- runtime/runtime.c \
+ runtime/runtime_c.c \
runtime/signal_unix.c \
runtime/thread.c \
$(runtime_thread_files) \
@@ -575,6 +572,16 @@ s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
$(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
$(STAMP) $@
+runtime.inc: s-runtime-inc; @true
+s-runtime-inc: runtime.lo Makefile
+ rm -f runtime.inc.tmp2
+ grep -v "#define _" runtime.inc.tmp | grep -v "#define c[01] " > runtime.inc.tmp2
+ for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
+ grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
+ done
+ $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
+ $(STAMP) $@
+
noinst_DATA = zstdpkglist.go
# Generate the list of go std packages that were included in libgo
@@ -584,7 +591,7 @@ s-zstdpkglist: Makefile
echo 'package main' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
- echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | grep -v _c | sed 's/\.lo/\": true,/' | sed 's/^/\t\"/' | sort -u >> zstdpkglist.go.tmp
echo '}' >> zstdpkglist.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
@@ -595,12 +602,6 @@ else
syscall_epoll_file =
endif
-extra_go_files_syscall = \
- libcalls.go \
- sysinfo.go \
- syscall_arch.go \
- $(syscall_epoll_file)
-
libcalls.go: s-libcalls; @true
s-libcalls: libcalls-list go/syscall/mksyscall.awk $(srcdir)/go/syscall/*.go
rm -f libcalls.go.tmp
@@ -681,175 +682,178 @@ else
syscall_lib_clone_lo =
endif
+PACKAGES = \
+ archive/tar \
+ archive/zip \
+ bufio \
+ bytes \
+ compress/bzip2 \
+ compress/flate \
+ compress/gzip \
+ compress/lzw \
+ compress/zlib \
+ container/heap \
+ container/list \
+ container/ring \
+ context \
+ crypto \
+ crypto/aes \
+ crypto/cipher \
+ crypto/des \
+ crypto/dsa \
+ crypto/ecdsa \
+ crypto/elliptic \
+ crypto/hmac \
+ crypto/md5 \
+ crypto/rand \
+ crypto/rc4 \
+ crypto/rsa \
+ crypto/sha1 \
+ crypto/sha256 \
+ crypto/sha512 \
+ crypto/subtle \
+ crypto/tls \
+ crypto/x509 \
+ crypto/x509/pkix \
+ database/sql \
+ database/sql/driver \
+ debug/dwarf \
+ debug/elf \
+ debug/gosym \
+ debug/macho \
+ debug/pe \
+ debug/plan9obj \
+ encoding \
+ encoding/ascii85 \
+ encoding/asn1 \
+ encoding/base32 \
+ encoding/base64 \
+ encoding/binary \
+ encoding/csv \
+ encoding/gob \
+ encoding/hex \
+ encoding/json \
+ encoding/pem \
+ encoding/xml \
+ errors \
+ exp/proxy \
+ exp/terminal \
+ expvar \
+ flag \
+ fmt \
+ go/ast \
+ go/build \
+ go/constant \
+ go/doc \
+ go/format \
+ go/importer \
+ go/internal/gccgoimporter \
+ go/internal/gcimporter \
+ go/parser \
+ go/printer \
+ go/scanner \
+ go/token \
+ go/types \
+ golang_org/x/net/http2/hpack \
+ golang_org/x/net/lex/httplex \
+ hash \
+ hash/adler32 \
+ hash/crc32 \
+ hash/crc64 \
+ hash/fnv \
+ html \
+ html/template \
+ image \
+ image/color \
+ image/color/palette \
+ image/draw \
+ image/gif \
+ image/internal/imageutil \
+ image/jpeg \
+ image/png \
+ index/suffixarray \
+ internal/nettrace \
+ internal/race \
+ internal/singleflight \
+ internal/syscall/unix \
+ internal/testenv \
+ internal/trace \
+ io \
+ io/ioutil \
+ log \
+ log/syslog \
+ math \
+ math/big \
+ math/cmplx \
+ math/rand \
+ mime \
+ mime/multipart \
+ mime/quotedprintable \
+ net \
+ net/http \
+ net/http/cgi \
+ net/http/cookiejar \
+ net/http/fcgi \
+ net/http/httptest \
+ net/http/httptrace \
+ net/http/httputil \
+ net/http/internal \
+ net/http/pprof \
+ net/internal/socktest \
+ net/mail \
+ net/rpc \
+ net/rpc/jsonrpc \
+ net/smtp \
+ net/textproto \
+ net/url \
+ old/regexp \
+ old/template \
+ os \
+ os/exec \
+ os/signal \
+ os/user \
+ path \
+ path/filepath \
+ reflect \
+ regexp \
+ regexp/syntax \
+ runtime \
+ runtime/debug \
+ runtime/internal/atomic \
+ runtime/internal/sys \
+ runtime/pprof \
+ sort \
+ strconv \
+ strings \
+ sync \
+ sync/atomic \
+ syscall \
+ testing \
+ testing/iotest \
+ testing/quick \
+ text/scanner \
+ text/tabwriter \
+ text/template \
+ text/template/parse \
+ time \
+ unicode \
+ unicode/utf16 \
+ unicode/utf8
+
libgo_go_objs = \
- bufio.lo \
- bytes.lo \
+ $(addsuffix .lo,$(PACKAGES)) \
bytes/index.lo \
- context.lo \
- crypto.lo \
- encoding.lo \
- errors.lo \
- expvar.lo \
- flag.lo \
- fmt.lo \
- hash.lo \
- html.lo \
- image.lo \
- io.lo \
- log.lo \
- math.lo \
- mime.lo \
- net.lo \
- os.lo \
- path.lo \
- reflect-go.lo \
reflect/makefunc_ffi_c.lo \
- regexp.lo \
- runtime-go.lo \
- sort.lo \
- strconv.lo \
- strings.lo \
strings/index.lo \
- sync.lo \
- syscall.lo \
$(syscall_lib_clone_lo) \
syscall/errno.lo \
syscall/signame.lo \
syscall/wait.lo \
- testing.lo \
- time-go.lo \
- unicode.lo \
- archive/tar.lo \
- archive/zip.lo \
- compress/bzip2.lo \
- compress/flate.lo \
- compress/gzip.lo \
- compress/lzw.lo \
- compress/zlib.lo \
- container/heap.lo \
- container/list.lo \
- container/ring.lo \
- crypto/aes.lo \
- crypto/cipher.lo \
- crypto/des.lo \
- crypto/dsa.lo \
- crypto/ecdsa.lo \
- crypto/elliptic.lo \
- crypto/hmac.lo \
- crypto/md5.lo \
- crypto/rand.lo \
- crypto/rc4.lo \
- crypto/rsa.lo \
- crypto/sha1.lo \
- crypto/sha256.lo \
- crypto/sha512.lo \
- crypto/subtle.lo \
- crypto/tls.lo \
- crypto/x509.lo \
- crypto/x509/pkix.lo \
- database/sql.lo \
- database/sql/driver.lo \
- debug/dwarf.lo \
- debug/elf.lo \
- debug/gosym.lo \
- debug/macho.lo \
- debug/pe.lo \
- debug/plan9obj.lo \
- encoding/ascii85.lo \
- encoding/asn1.lo \
- encoding/base32.lo \
- encoding/base64.lo \
- encoding/binary.lo \
- encoding/csv.lo \
- encoding/gob.lo \
- encoding/hex.lo \
- encoding/json.lo \
- encoding/pem.lo \
- encoding/xml.lo \
- exp/proxy.lo \
- exp/terminal.lo \
- html/template.lo \
- go/ast.lo \
- go/build.lo \
- go/constant.lo \
- go/doc.lo \
- go/format.lo \
- go/importer.lo \
- go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo \
- go/parser.lo \
- go/printer.lo \
- go/scanner.lo \
- go/token.lo \
- go/types.lo \
- golang_org/x/net/http2/hpack.lo \
- golang_org/x/net/lex/httplex.lo \
$(golang_org_x_net_route_lo) \
- hash/adler32.lo \
- hash/crc32.lo \
- hash/crc64.lo \
- hash/fnv.lo \
- net/http/cgi.lo \
- net/http/cookiejar.lo \
- net/http/fcgi.lo \
- net/http/httptest.lo \
- net/http/httptrace.lo \
- net/http/httputil.lo \
- net/http/internal.lo \
- net/http/pprof.lo \
- image/color.lo \
- image/color/palette.lo \
- image/draw.lo \
- image/gif.lo \
- image/internal/imageutil.lo \
- image/jpeg.lo \
- image/png.lo \
- index/suffixarray.lo \
- internal/nettrace.lo \
- internal/race.lo \
- internal/singleflight.lo \
- internal/syscall/unix.lo \
- internal/testenv.lo \
- internal/trace.lo \
- io/ioutil.lo \
- log/syslog.lo \
log/syslog/syslog_c.lo \
- math/big.lo \
- math/cmplx.lo \
- math/rand.lo \
- mime/multipart.lo \
- mime/quotedprintable.lo \
- net/http.lo \
- net/internal/socktest.lo \
- net/mail.lo \
- net/rpc.lo \
- net/smtp.lo \
- net/textproto.lo \
- net/url.lo \
- old/regexp.lo \
- old/template.lo \
- os/exec.lo \
$(os_lib_inotify_lo) \
- os/signal.lo \
- os/user.lo \
- path/filepath.lo \
- regexp/syntax.lo \
- net/rpc/jsonrpc.lo \
- runtime/debug.lo \
- runtime/pprof.lo \
- runtime/internal/atomic.lo \
runtime/internal/atomic_c.lo \
- runtime/internal/sys.lo \
- sync/atomic.lo \
- sync/atomic_c.lo \
- text/scanner.lo \
- text/tabwriter.lo \
- text/template.lo \
- text/template/parse.lo \
- testing/iotest.lo \
- testing/quick.lo \
- unicode/utf16.lo \
- unicode/utf8.lo
+ sync/atomic_c.lo
libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
@@ -881,9 +885,6 @@ libgolibbegin_a_SOURCES = \
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
-libnetgo_a_SOURCES =
-libnetgo_a_LIBADD = netgo.o
-
# Make sure runtime.inc is built before compiling any .c file.
$(libgo_la_OBJECTS): runtime.inc
$(libgo_llgo_la_OBJECTS): runtime.inc
@@ -906,8 +907,8 @@ GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
# Build the dependencies for a Go package.
BUILDDEPS = \
$(MKDIR_P) $(@D); \
- dir=`echo $@ | sed -e 's/.lo.dep$$//' -e 's/-go//'`; \
- files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst -go,,$(subst .lo.dep,,$@))))" $(matchargs_$(subst /,_,$(subst -go,,$(subst .lo.dep,,$@))))`; \
+ dir=`echo $@ | sed -e 's/.lo.dep$$//'`; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst .lo.dep,,$@)))" $(matchargs_$(subst /,_,$(subst .lo.dep,,$@)))`; \
$(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $$files > $@.tmp; \
if ! cmp $@.tmp $@ >/dev/null 2>/dev/null; then \
rm -f `echo $@ | sed -e 's/\.dep$$//'`; \
@@ -918,20 +919,13 @@ BUILDDEPS = \
BUILDPACKAGE = \
$(MKDIR_P) $(@D); \
files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
- $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
+ $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
-# Build deps for netgo.o.
-BUILDNETGODEPS = \
- $(MKDIR_P) $(@D); \
- files=`$(SHELL) $(srcdir)/match.sh --nocgo --tag=netgo --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/net`; \
- $(SHELL) $(srcdir)/godeps.sh netgo.o $$files > $@.tmp; \
- mv -f $@.tmp $@
-
-# Build netgo.o.
-BUILDNETGO = \
- $(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
- $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp; \
+ $(SHELL) $(srcdir)/mvifdiff.sh $@.tmp `echo $@ | sed -e 's/s-gox/gox/'`
GOTESTFLAGS =
GOBENCH =
@@ -1006,1856 +1000,139 @@ else
CHECK_DEPS += libgo.la libgobegin.a
endif
-@go_include@ bufio.lo.dep
-bufio.lo.dep: $(srcdir)/go/bufio/*.go
- $(BUILDDEPS)
-bufio.lo:
- $(BUILDPACKAGE)
-bufio/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bufio/check
-
-@go_include@ bytes.lo.dep
-bytes.lo.dep: $(srcdir)/go/bytes/*.go
- $(BUILDDEPS)
-bytes.lo:
- $(BUILDPACKAGE)
-bytes/index.lo: go/bytes/indexbyte.c runtime.inc
- @$(MKDIR_P) bytes
- $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
-bytes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bytes/check
-
-@go_include@ context.lo.dep
-context.lo.dep: $(srcdir)/go/context/*.go
- $(BUILDDEPS)
-context.lo:
- $(BUILDPACKAGE)
-context/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: context/check
-
-@go_include@ crypto.lo.dep
-crypto.lo.dep: $(srcdir)/go/crypto/*.go
- $(BUILDDEPS)
-crypto.lo:
- $(BUILDPACKAGE)
-crypto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/check
-
-@go_include@ encoding.lo.dep
-encoding.lo.dep: $(srcdir)/go/encoding/*.go
- $(BUILDDEPS)
-encoding.lo:
- $(BUILDPACKAGE)
-encoding/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/check
-
-@go_include@ errors.lo.dep
-errors.lo.dep: $(srcdir)/go/errors/*.go
- $(BUILDDEPS)
-errors.lo:
- $(BUILDPACKAGE)
-errors/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: errors/check
-
-@go_include@ expvar.lo.dep
-expvar.lo.dep: $(srcdir)/go/expvar/*.go
- $(BUILDDEPS)
-expvar.lo:
- $(BUILDPACKAGE)
-expvar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: expvar/check
-
-@go_include@ flag.lo.dep
-flag.lo.dep: $(srcdir)/go/flag/*.go
- $(BUILDDEPS)
-flag.lo:
- $(BUILDPACKAGE)
-flag/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: flag/check
-
-@go_include@ fmt.lo.dep
-fmt.lo.dep: $(srcdir)/go/fmt/*.go
- $(BUILDDEPS)
-fmt.lo:
- $(BUILDPACKAGE)
-fmt/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: fmt/check
-
-@go_include@ hash.lo.dep
-hash.lo.dep: $(srcdir)/go/hash/*.go
- $(BUILDDEPS)
-hash.lo:
- $(BUILDPACKAGE)
-hash/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/check
-
-@go_include@ html.lo.dep
-html.lo.dep: $(srcdir)/go/html/*.go
- $(BUILDDEPS)
-html.lo:
- $(BUILDPACKAGE)
-html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/check
-
-@go_include@ image.lo.dep
-image.lo.dep: $(srcdir)/go/image/*.go
- $(BUILDDEPS)
-image.lo:
- $(BUILDPACKAGE)
-image/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/check
-
-@go_include@ io.lo.dep
-io.lo.dep: $(srcdir)/go/io/*.go
- $(BUILDDEPS)
-io.lo:
- $(BUILDPACKAGE)
-io/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/check
-
-@go_include@ log.lo.dep
-log.lo.dep: $(srcdir)/go/log/*.go
- $(BUILDDEPS)
-log.lo:
- $(BUILDPACKAGE)
-log/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/check
-
-@go_include@ math.lo.dep
-math.lo.dep: $(srcdir)/go/math/*.go
- $(BUILDDEPS)
-math.lo:
- $(MKDIR_P) $(@D)
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) $(MATH_FLAG) -I . -c -fgo-pkgpath=math -o $@ $$files
-math/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/check
-
-@go_include@ mime.lo.dep
-mime.lo.dep: $(srcdir)/go/mime/*.go
- $(BUILDDEPS)
-mime.lo:
- $(BUILDPACKAGE)
-mime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/check
-
-@go_include@ net.lo.dep
-net.lo.dep: $(srcdir)/go/net/*.go
- $(BUILDDEPS)
-net.lo:
- $(BUILDPACKAGE)
-net/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/check
-
-@go_include@ netgo.o.dep
-netgo.o.dep: $(srcdir)/go/net/*.go
- $(BUILDNETGODEPS)
-netgo.o: netgo.o.dep
- $(BUILDNETGO)
-
-if LIBGO_IS_SOLARIS
-if HAVE_STAT_TIMESPEC
-matchargs_os = --tag=solaristag
-else
-matchargs_os =
-endif
-else
-matchargs_os =
-endif
-
-@go_include@ os.lo.dep
-os.lo.dep: $(srcdir)/go/os/*.go
- $(BUILDDEPS)
-os.lo:
- $(BUILDPACKAGE)
-os/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/check
-
-@go_include@ path.lo.dep
-path.lo.dep: $(srcdir)/go/path/*.go
- $(BUILDDEPS)
-path.lo:
- $(BUILDPACKAGE)
-path/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/check
-
-@go_include@ reflect-go.lo.dep
-reflect-go.lo.dep: $(srcdir)/go/reflect/*.go
- $(BUILDDEPS)
-reflect-go.lo:
- $(BUILDPACKAGE)
-reflect/check: $(CHECK_DEPS)
- @$(CHECK)
-reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
- @$(MKDIR_P) reflect
- $(LTCOMPILE) -c -o $@ $<
-.PHONY: reflect/check
-
-@go_include@ regexp.lo.dep
-regexp.lo.dep: $(srcdir)/go/regexp/*.go
- $(BUILDDEPS)
-regexp.lo:
- $(BUILDPACKAGE)
-regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/check
-
+# PACKAGE_template defines the rules for each package.
+# For example, for the package bufio, it produces:
+#
+# @go_include@ bufio.lo.dep
+# bufio.lo.dep: $(srcdir)/go/bufio/*.go
+# $(BUILDDEPS)
+# bufio.lo:
+# $(BUILDPACKAGE)
+# bufio/check: $(CHECK_DEPS)
+# @$(CHECK)
+# .PHONY: bufio/check
+#
+# This is invoked with $(1) set to a package, which is a directory name,
+# such as "bufio" or "archive/tar".
+define PACKAGE_template
+@go_include@ $(1).lo.dep
+$(1).lo.dep: $(srcdir)/go/$(1)/*.go
+ $$(BUILDDEPS)
+$(1).lo:
+ $$(BUILDPACKAGE)
+$(1)/check: $$(CHECK_DEPS)
+ @$$(CHECK)
+.PHONY: $(1)/check
+$(1).gox: $(1).s-gox; @true
+$(1).s-gox: $(1).lo
+ $$(BUILDGOX)
+ $$(STAMP) $$@
+endef
+
+# This line expands PACKAGE_template once for each package name listed
+# in $(PACKAGES).
+$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
+
+# Pass -ffp-contract=off, or 386-specific options, when building the
+# math package. MATH_FLAG is defined in configure.ac.
+math_lo_GOCFLAGS = $(MATH_FLAG)
+
+# Add the generated file runtime_sysinfo.go to the runtime package.
extra_go_files_runtime = runtime_sysinfo.go
+runtime.lo.dep: $(extra_go_files_runtime)
-@go_include@ runtime-go.lo.dep
-runtime-go.lo.dep: $(srcdir)/go/runtime/*.go $(extra_go_files_runtime)
- $(BUILDDEPS)
-runtime_go_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
-runtime-go.lo:
- $(BUILDPACKAGE)
-runtime.inc: s-runtime-inc; @true
-s-runtime-inc: runtime-go.lo Makefile
- rm -f runtime.inc.tmp2
- grep -v "#define _" runtime.inc.tmp | grep -v "#define c0 " | grep -v "#define c1 " > runtime.inc.tmp2
- for pattern in '_G[a-z]' '_P[a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
- grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
- done
- $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
- $(STAMP) $@
+# Add generated files to the syscall package.
+extra_go_files_syscall = \
+ libcalls.go \
+ sysinfo.go \
+ syscall_arch.go \
+ $(syscall_epoll_file)
+syscall.lo.dep: $(extra_go_files_syscall)
+
+# Pass -fgo-compiling-runtime when compiling the runtime package.
+runtime_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
runtime_check_GOCFLAGS = -fgo-compiling-runtime
-runtime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/check
-
-@go_include@ sort.lo.dep
-sort.lo.dep: $(srcdir)/go/sort/*.go
- $(BUILDDEPS)
-sort.lo:
- $(BUILDPACKAGE)
-sort/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sort/check
-
-@go_include@ strconv.lo.dep
-strconv.lo.dep: $(srcdir)/go/strconv/*.go
- $(BUILDDEPS)
-strconv.lo:
- $(BUILDPACKAGE)
-strconv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strconv/check
-
-@go_include@ strings.lo.dep
-strings.lo.dep: $(srcdir)/go/strings/*.go
- $(BUILDDEPS)
-strings.lo:
- $(BUILDPACKAGE)
-strings/index.lo: go/strings/indexbyte.c runtime.inc
- @$(MKDIR_P) strings
- $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c
-strings/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strings/check
-
-@go_include@ sync.lo.dep
-sync.lo.dep: $(srcdir)/go/sync/*.go
- $(BUILDDEPS)
-sync.lo:
- $(BUILDPACKAGE)
-sync/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/check
-
-@go_include@ testing.lo.dep
-testing.lo.dep: $(srcdir)/go/testing/*.go
- $(BUILDDEPS)
-testing.lo:
- $(BUILDPACKAGE)
-testing/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/check
-
-@go_include@ time-go.lo.dep
-time-go.lo.dep: $(srcdir)/go/time/*.go
- $(BUILDDEPS)
-time-go.lo:
- $(BUILDPACKAGE)
-time/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: time/check
-
-@go_include@ unicode.lo.dep
-unicode.lo.dep: $(srcdir)/go/unicode/*.go
- $(BUILDDEPS)
-unicode.lo:
- $(BUILDPACKAGE)
-unicode/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/check
-
-@go_include@ archive/tar.lo.dep
-archive/tar.lo.dep: $(srcdir)/go/archive/tar/*.go
- $(BUILDDEPS)
-archive/tar.lo:
- $(BUILDPACKAGE)
-archive/tar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/tar/check
-
-@go_include@ archive/zip.lo.dep
-archive/zip.lo.dep: $(srcdir)/go/archive/zip/*.go
- $(BUILDDEPS)
-archive/zip.lo:
- $(BUILDPACKAGE)
-archive/zip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/zip/check
-
-@go_include@ compress/bzip2.lo.dep
-compress/bzip2.lo.dep: $(srcdir)/go/compress/bzip2/*.go
- $(BUILDDEPS)
-compress/bzip2.lo:
- $(BUILDPACKAGE)
-compress/bzip2/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/bzip2/check
-
-@go_include@ compress/flate.lo.dep
-compress/flate.lo.dep: $(srcdir)/go/compress/flate/*.go
- $(BUILDDEPS)
-compress/flate.lo:
- $(BUILDPACKAGE)
-compress/flate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/flate/check
-
-@go_include@ compress/gzip.lo.dep
-compress/gzip.lo.dep: $(srcdir)/go/compress/gzip/*.go
- $(BUILDDEPS)
-compress/gzip.lo:
- $(BUILDPACKAGE)
-compress/gzip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/gzip/check
-
-@go_include@ compress/lzw.lo.dep
-compress/lzw.lo.dep: $(srcdir)/go/compress/lzw/*.go
- $(BUILDDEPS)
-compress/lzw.lo:
- $(BUILDPACKAGE)
-compress/lzw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/lzw/check
-
-@go_include@ compress/zlib.lo.dep
-compress/zlib.lo.dep: $(srcdir)/go/compress/zlib/*.go
- $(BUILDDEPS)
-compress/zlib.lo:
- $(BUILDPACKAGE)
-compress/zlib/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/zlib/check
-
-@go_include@ container/heap.lo.dep
-container/heap.lo.dep: $(srcdir)/go/container/heap/*.go
- $(BUILDDEPS)
-container/heap.lo:
- $(BUILDPACKAGE)
-container/heap/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/heap/check
-
-@go_include@ container/list.lo.dep
-container/list.lo.dep: $(srcdir)/go/container/list/*.go
- $(BUILDDEPS)
-container/list.lo:
- $(BUILDPACKAGE)
-container/list/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/list/check
-
-@go_include@ container/ring.lo.dep
-container/ring.lo.dep: $(srcdir)/go/container/ring/*.go
- $(BUILDDEPS)
-container/ring.lo:
- $(BUILDPACKAGE)
-container/ring/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/ring/check
-
-@go_include@ crypto/aes.lo.dep
-crypto/aes.lo.dep: $(srcdir)/go/crypto/aes/*.go
- $(BUILDDEPS)
-crypto/aes.lo:
- $(BUILDPACKAGE)
-crypto/aes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/aes/check
-
-@go_include@ crypto/cipher.lo.dep
-crypto/cipher.lo.dep: $(srcdir)/go/crypto/cipher/*.go
- $(BUILDDEPS)
-crypto/cipher.lo:
- $(BUILDPACKAGE)
-crypto/cipher/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/cipher/check
-
-@go_include@ crypto/des.lo.dep
-crypto/des.lo.dep: $(srcdir)/go/crypto/des/*.go
- $(BUILDDEPS)
-crypto/des.lo:
- $(BUILDPACKAGE)
-crypto/des/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/des/check
-
-@go_include@ crypto/dsa.lo.dep
-crypto/dsa.lo.dep: $(srcdir)/go/crypto/dsa/*.go
- $(BUILDDEPS)
-crypto/dsa.lo:
- $(BUILDPACKAGE)
-crypto/dsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/dsa/check
-
-@go_include@ crypto/ecdsa.lo.dep
-crypto/ecdsa.lo.dep: $(srcdir)/go/crypto/ecdsa/*.go
- $(BUILDDEPS)
-crypto/ecdsa.lo:
- $(BUILDPACKAGE)
-crypto/ecdsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/ecdsa/check
-
-@go_include@ crypto/elliptic.lo.dep
-crypto/elliptic.lo.dep: $(srcdir)/go/crypto/elliptic/*.go
- $(BUILDDEPS)
-crypto/elliptic.lo:
- $(BUILDPACKAGE)
-crypto/elliptic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/elliptic/check
-
-@go_include@ crypto/hmac.lo.dep
-crypto/hmac.lo.dep: $(srcdir)/go/crypto/hmac/*.go
- $(BUILDDEPS)
-crypto/hmac.lo:
- $(BUILDPACKAGE)
-crypto/hmac/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/hmac/check
-
-@go_include@ crypto/md5.lo.dep
-crypto/md5.lo.dep: $(srcdir)/go/crypto/md5/*.go
- $(BUILDDEPS)
-crypto/md5.lo:
- $(BUILDPACKAGE)
-crypto/md5/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/md5/check
-
-@go_include@ crypto/rand.lo.dep
-crypto/rand.lo.dep: $(srcdir)/go/crypto/rand/*.go
- $(BUILDDEPS)
-crypto/rand.lo:
- $(BUILDPACKAGE)
-crypto/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rand/check
-
-@go_include@ crypto/rc4.lo.dep
-crypto/rc4.lo.dep: $(srcdir)/go/crypto/rc4/*.go
- $(BUILDDEPS)
-crypto/rc4.lo:
- $(BUILDPACKAGE)
-crypto/rc4/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rc4/check
-
-@go_include@ crypto/rsa.lo.dep
-crypto/rsa.lo.dep: $(srcdir)/go/crypto/rsa/*.go
- $(BUILDDEPS)
-crypto/rsa.lo:
- $(BUILDPACKAGE)
-crypto/rsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rsa/check
-
-@go_include@ crypto/sha1.lo.dep
-crypto/sha1.lo.dep: $(srcdir)/go/crypto/sha1/*.go
- $(BUILDDEPS)
-crypto/sha1.lo:
- $(BUILDPACKAGE)
-crypto/sha1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha1/check
-
-@go_include@ crypto/sha256.lo.dep
-crypto/sha256.lo.dep: $(srcdir)/go/crypto/sha256/*.go
- $(BUILDDEPS)
-crypto/sha256.lo:
- $(BUILDPACKAGE)
-crypto/sha256/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha256/check
-
-@go_include@ crypto/sha512.lo.dep
-crypto/sha512.lo.dep: $(srcdir)/go/crypto/sha512/*.go
- $(BUILDDEPS)
-crypto/sha512.lo:
- $(BUILDPACKAGE)
-crypto/sha512/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha512/check
-
-@go_include@ crypto/subtle.lo.dep
-crypto/subtle.lo.dep: $(srcdir)/go/crypto/subtle/*.go
- $(BUILDDEPS)
-crypto/subtle.lo:
- $(BUILDPACKAGE)
-crypto/subtle/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/subtle/check
-
-@go_include@ crypto/tls.lo.dep
-crypto/tls.lo.dep: $(srcdir)/go/crypto/tls/*.go
- $(BUILDDEPS)
-crypto/tls.lo:
- $(BUILDPACKAGE)
-crypto/tls/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/tls/check
-
-@go_include@ crypto/x509.lo.dep
-crypto/x509.lo.dep: $(srcdir)/go/crypto/x509/*.go
- $(BUILDDEPS)
-crypto/x509.lo:
- $(BUILDPACKAGE)
-crypto/x509/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/check
-
-@go_include@ crypto/x509/pkix.lo.dep
-crypto/x509/pkix.lo.dep: $(srcdir)/go/crypto/x509/pkix/*.go
- $(BUILDDEPS)
-crypto/x509/pkix.lo:
- $(BUILDPACKAGE)
-crypto/x509/pkix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/pkix/check
-
-@go_include@ database/sql.lo.dep
-database/sql.lo.dep: $(srcdir)/go/database/sql/*.go
- $(BUILDDEPS)
-database/sql.lo:
- $(BUILDPACKAGE)
-database/sql/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/check
-
-@go_include@ database/sql/driver.lo.dep
-database/sql/driver.lo.dep: $(srcdir)/go/database/sql/driver/*.go
- $(BUILDDEPS)
-database/sql/driver.lo:
- $(BUILDPACKAGE)
-database/sql/driver/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/driver/check
-
-@go_include@ debug/dwarf.lo.dep
-debug/dwarf.lo.dep: $(srcdir)/go/debug/dwarf/*.go
- $(BUILDDEPS)
-debug/dwarf.lo:
- $(BUILDPACKAGE)
-debug/dwarf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/dwarf/check
-
-@go_include@ debug/elf.lo.dep
-debug/elf.lo.dep: $(srcdir)/go/debug/elf/*.go
- $(BUILDDEPS)
-debug/elf.lo:
- $(BUILDPACKAGE)
-debug/elf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/elf/check
-
-@go_include@ debug/gosym.lo.dep
-debug/gosym.lo.dep: $(srcdir)/go/debug/gosym/*.go
- $(BUILDDEPS)
-debug/gosym.lo:
- $(BUILDPACKAGE)
-debug/gosym/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/gosym/check
-
-@go_include@ debug/macho.lo.dep
-debug/macho.lo.dep: $(srcdir)/go/debug/macho/*.go
- $(BUILDDEPS)
-debug/macho.lo:
- $(BUILDPACKAGE)
-debug/macho/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/macho/check
-
-@go_include@ debug/pe.lo.dep
-debug/pe.lo.dep: $(srcdir)/go/debug/pe/*.go
- $(BUILDDEPS)
-debug/pe.lo:
- $(BUILDPACKAGE)
-debug/pe/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/pe/check
-
-@go_include@ debug/plan9obj.lo.dep
-debug/plan9obj.lo.dep: $(srcdir)/go/debug/plan9obj/*.go
- $(BUILDDEPS)
-debug/plan9obj.lo:
- $(BUILDPACKAGE)
-debug/plan9obj/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/plan9obj/check
-
-@go_include@ encoding/asn1.lo.dep
-encoding/asn1.lo.dep: $(srcdir)/go/encoding/asn1/*.go
- $(BUILDDEPS)
-encoding/asn1.lo:
- $(BUILDPACKAGE)
-encoding/asn1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/asn1/check
-
-@go_include@ encoding/ascii85.lo.dep
-encoding/ascii85.lo.dep: $(srcdir)/go/encoding/ascii85/*.go
- $(BUILDDEPS)
-encoding/ascii85.lo:
- $(BUILDPACKAGE)
-encoding/ascii85/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/ascii85/check
-
-@go_include@ encoding/base32.lo.dep
-encoding/base32.lo.dep: $(srcdir)/go/encoding/base32/*.go
- $(BUILDDEPS)
-encoding/base32.lo:
- $(BUILDPACKAGE)
-encoding/base32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base32/check
-
-@go_include@ encoding/base64.lo.dep
-encoding/base64.lo.dep: $(srcdir)/go/encoding/base64/*.go
- $(BUILDDEPS)
-encoding/base64.lo:
- $(BUILDPACKAGE)
-encoding/base64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base64/check
-
-@go_include@ encoding/binary.lo.dep
-encoding/binary.lo.dep: $(srcdir)/go/encoding/binary/*.go
- $(BUILDDEPS)
-encoding/binary.lo:
- $(BUILDPACKAGE)
-encoding/binary/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/binary/check
-
-@go_include@ encoding/csv.lo.dep
-encoding/csv.lo.dep: $(srcdir)/go/encoding/csv/*.go
- $(BUILDDEPS)
-encoding/csv.lo:
- $(BUILDPACKAGE)
-encoding/csv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/csv/check
-
-@go_include@ encoding/gob.lo.dep
-encoding/gob.lo.dep: $(srcdir)/go/encoding/gob/*.go
- $(BUILDDEPS)
-encoding/gob.lo:
- $(BUILDPACKAGE)
-encoding/gob/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/gob/check
-
-@go_include@ encoding/hex.lo.dep
-encoding/hex.lo.dep: $(srcdir)/go/encoding/hex/*.go
- $(BUILDDEPS)
-encoding/hex.lo:
- $(BUILDPACKAGE)
-encoding/hex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/hex/check
-
-@go_include@ encoding/json.lo.dep
-encoding/json.lo.dep: $(srcdir)/go/encoding/json/*.go
- $(BUILDDEPS)
-encoding/json.lo:
- $(BUILDPACKAGE)
-encoding/json/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/json/check
-
-@go_include@ encoding/pem.lo.dep
-encoding/pem.lo.dep: $(srcdir)/go/encoding/pem/*.go
- $(BUILDDEPS)
-encoding/pem.lo:
- $(BUILDPACKAGE)
-encoding/pem/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/pem/check
-
-@go_include@ encoding/xml.lo.dep
-encoding/xml.lo.dep: $(srcdir)/go/encoding/xml/*.go
- $(BUILDDEPS)
-encoding/xml.lo:
- $(BUILDPACKAGE)
-encoding/xml/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/xml/check
-
-@go_include@ exp/proxy.lo.dep
-exp/proxy.lo.dep: $(srcdir)/go/exp/proxy/*.go
- $(BUILDDEPS)
-exp/proxy.lo:
- $(BUILDPACKAGE)
-exp/proxy/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/proxy/check
-
-@go_include@ exp/terminal.lo.dep
-exp/terminal.lo.dep: $(srcdir)/go/exp/terminal/*.go
- $(BUILDDEPS)
-exp/terminal.lo:
- $(BUILDPACKAGE)
-exp/terminal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/terminal/check
-
-@go_include@ html/template.lo.dep
-html/template.lo.dep: $(srcdir)/go/html/template/*.go
- $(BUILDDEPS)
-html/template.lo:
- $(BUILDPACKAGE)
-html/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/template/check
-
-@go_include@ go/ast.lo.dep
-go/ast.lo.dep: $(srcdir)/go/go/ast/*.go
- $(BUILDDEPS)
-go/ast.lo:
- $(BUILDPACKAGE)
-go/ast/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/ast/check
-
-@go_include@ go/build.lo.dep
-go/build.lo.dep: $(srcdir)/go/go/build/*.go
- $(BUILDDEPS)
-go/build.lo:
- $(BUILDPACKAGE)
-go/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/build/check
-
-@go_include@ go/constant.lo.dep
-go/constant.lo.dep: $(srcdir)/go/go/constant/*.go
- $(BUILDDEPS)
-go/constant.lo:
- $(BUILDPACKAGE)
-go/constant/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/constant/check
-
-@go_include@ go/doc.lo.dep
-go/doc.lo.dep: $(srcdir)/go/go/doc/*.go
- $(BUILDDEPS)
-go/doc.lo:
- $(BUILDPACKAGE)
-go/doc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/doc/check
-
-@go_include@ go/format.lo.dep
-go/format.lo.dep: $(srcdir)/go/go/format/*.go
- $(BUILDDEPS)
-go/format.lo:
- $(BUILDPACKAGE)
-go/format/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/format/check
-
-@go_include@ go/importer.lo.dep
-go/importer.lo.dep: $(srcdir)/go/go/importer/*.go
- $(BUILDDEPS)
-go/importer.lo:
- $(BUILDPACKAGE)
-go/importer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/importer/check
-
-@go_include@ go/parser.lo.dep
-go/parser.lo.dep: $(srcdir)/go/go/parser/*.go
- $(BUILDDEPS)
-go/parser.lo:
- $(BUILDPACKAGE)
-go/parser/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/parser/check
-
-@go_include@ go/printer.lo.dep
-go/printer.lo.dep: $(srcdir)/go/go/printer/*.go
- $(BUILDDEPS)
-go/printer.lo:
- $(BUILDPACKAGE)
-go/printer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/printer/check
-
-@go_include@ go/scanner.lo.dep
-go/scanner.lo.dep: $(srcdir)/go/go/scanner/*.go
- $(BUILDDEPS)
-go/scanner.lo:
- $(BUILDPACKAGE)
-go/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/scanner/check
-
-@go_include@ go/token.lo.dep
-go/token.lo.dep: $(srcdir)/go/go/token/*.go
- $(BUILDDEPS)
-go/token.lo:
- $(BUILDPACKAGE)
-go/token/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/token/check
-
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(srcdir)/go/go/types/*.go
- $(BUILDDEPS)
-go/types.lo:
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
-@go_include@ go/internal/gcimporter.lo.dep
-go/internal/gcimporter.lo.dep: $(srcdir)/go/go/internal/gcimporter/*.go
- $(BUILDDEPS)
-go/internal/gcimporter.lo:
- $(BUILDPACKAGE)
-go/internal/gcimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gcimporter/check
-
-@go_include@ go/internal/gccgoimporter.lo.dep
-go/internal/gccgoimporter.lo.dep: $(srcdir)/go/go/internal/gccgoimporter/*.go
- $(BUILDDEPS)
-go/internal/gccgoimporter.lo:
- $(BUILDPACKAGE)
-go/internal/gccgoimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gccgoimporter/check
-
-@go_include@ golang_org/x/net/http2/hpack.lo.dep
-golang_org/x/net/http2/hpack.lo.dep: $(srcdir)/go/golang_org/x/net/http2/hpack/*.go
- $(BUILDDEPS)
-golang_org/x/net/http2/hpack.lo:
- $(BUILDPACKAGE)
-golang_org/x/net/http2/hpack/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: golang_org/x/net/http2/hpack/check
-
-@go_include@ golang_org/x/net/lex/httplex.lo.dep
-golang_org/x/net/lex/httplex.lo.dep: $(srcdir)/go/golang_org/x/net/lex/httplex/*.go
- $(BUILDDEPS)
-golang_org/x/net/lex/httplex.lo:
- $(BUILDPACKAGE)
-golang_org/x/net/lex/httplex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: golang_org/x/net/lex/httplex/check
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime
-if LIBGO_IS_BSD
+# At least for now, we need -static-libgo for this test, because
+# otherwise we can't get the line numbers.
+# Also use -fno-inline to get better results from the memory profiler.
+runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
-golang_org_x_net_route_lo = \
- golang_org/x/net/route/route.lo
-golang_org_x_net_route_check = \
- golang_org/x/net/route/check
+extra_go_files_runtime_internal_sys = version.go
+runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
-@go_include@ golang_org/x/net/route.lo.dep
-golang_org/x/net/route.lo.dep: $(srcdir)/go/golang_org/x/net/route/*.go
- $(BUILDDEPS)
-golang_org/x/net/route.lo:
- $(BUILDPACKAGE)
-golang_org/x/net/route/check: $(CHECK_DEPS)
- @$(CHECK)
+# FIXME: The following C files may as well move to the runtime
+# directory and be treated like other C files.
-endif
+# Use C code to speed up {bytes,strings}.IndexByte and friends.
+bytes/index.lo: go/bytes/indexbyte.c runtime.inc
+ @$(MKDIR_P) bytes
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/bytes/indexbyte.c
+strings/index.lo: go/strings/indexbyte.c runtime.inc
+ @$(MKDIR_P) strings
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/strings/indexbyte.c
-.PHONY: golang_org/x/net/route/check
-
-@go_include@ hash/adler32.lo.dep
-hash/adler32.lo.dep: $(srcdir)/go/hash/adler32/*.go
- $(BUILDDEPS)
-hash/adler32.lo:
- $(BUILDPACKAGE)
-hash/adler32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/adler32/check
-
-@go_include@ hash/crc32.lo.dep
-hash/crc32.lo.dep: $(srcdir)/go/hash/crc32/*.go
- $(BUILDDEPS)
-hash/crc32.lo:
- $(BUILDPACKAGE)
-hash/crc32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc32/check
-
-@go_include@ hash/crc64.lo.dep
-hash/crc64.lo.dep: $(srcdir)/go/hash/crc64/*.go
- $(BUILDDEPS)
-hash/crc64.lo:
- $(BUILDPACKAGE)
-hash/crc64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc64/check
-
-@go_include@ hash/fnv.lo.dep
-hash/fnv.lo.dep: $(srcdir)/go/hash/fnv/*.go
- $(BUILDDEPS)
-hash/fnv.lo:
- $(BUILDPACKAGE)
-hash/fnv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/fnv/check
-
-@go_include@ image/color.lo.dep
-image/color.lo.dep: $(srcdir)/go/image/color/*.go
- $(BUILDDEPS)
-image/color.lo:
- $(BUILDPACKAGE)
-image/color/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/check
-
-@go_include@ image/color/palette.lo.dep
-image/color/palette.lo.dep: $(srcdir)/go/image/color/palette/*.go
- $(BUILDDEPS)
-image/color/palette.lo:
- $(BUILDPACKAGE)
-image/color/palette/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/palette/check
-
-@go_include@ image/draw.lo.dep
-image/draw.lo.dep: $(srcdir)/go/image/draw/*.go
- $(BUILDDEPS)
-image/draw.lo:
- $(BUILDPACKAGE)
-image/draw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/draw/check
-
-@go_include@ image/gif.lo.dep
-image/gif.lo.dep: $(srcdir)/go/image/gif/*.go
- $(BUILDDEPS)
-image/gif.lo:
- $(BUILDPACKAGE)
-image/gif/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/gif/check
-
-@go_include@ image/internal/imageutil.lo.dep
-image/internal/imageutil.lo.dep: $(srcdir)/go/image/internal/imageutil/*.go
- $(BUILDDEPS)
-image/internal/imageutil.lo:
- $(BUILDPACKAGE)
-image/internal/imageutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/internal/imageutil/check
-
-@go_include@ image/jpeg.lo.dep
-image/jpeg.lo.dep: $(srcdir)/go/image/jpeg/*.go
- $(BUILDDEPS)
-image/jpeg.lo:
- $(BUILDPACKAGE)
-image/jpeg/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/jpeg/check
-
-@go_include@ image/png.lo.dep
-image/png.lo.dep: $(srcdir)/go/image/png/*.go
- $(BUILDDEPS)
-image/png.lo:
- $(BUILDPACKAGE)
-image/png/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/png/check
-
-@go_include@ index/suffixarray.lo.dep
-index/suffixarray.lo.dep: $(srcdir)/go/index/suffixarray/*.go
- $(BUILDDEPS)
-index/suffixarray.lo:
- $(BUILDPACKAGE)
-index/suffixarray/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: index/suffixarray/check
-
-@go_include@ internal/nettrace.lo.dep
-internal/nettrace.lo.dep: $(srcdir)/go/internal/nettrace/*.go
- $(BUILDDEPS)
-internal/nettrace.lo:
- $(BUILDPACKAGE)
-internal/nettrace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/nettrace/check
-
-@go_include@ internal/race.lo.dep
-internal/race.lo.dep: $(srcdir)/go/internal/race/*.go
- $(BUILDDEPS)
-internal/race.lo:
- $(BUILDPACKAGE)
-internal/race/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/race/check
-
-@go_include@ internal/singleflight.lo.dep
-internal/singleflight.lo.dep: $(srcdir)/go/internal/singleflight/*.go
- $(BUILDDEPS)
-internal/singleflight.lo:
- $(BUILDPACKAGE)
-internal/singleflight/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/singleflight/check
-
-@go_include@ internal/syscall/unix.lo.dep
-internal/syscall/unix.lo.dep: $(srcdir)/go/internal/syscall/unix/*.go
- $(BUILDDEPS)
-internal/syscall/unix.lo:
- $(BUILDPACKAGE)
-internal/syscall/unix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/syscall/unix/check
-
-@go_include@ internal/testenv.lo.dep
-internal/testenv.lo.dep: $(srcdir)/go/internal/testenv/*.go
- $(BUILDDEPS)
-internal/testenv.lo:
- $(BUILDPACKAGE)
-internal/testenv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/testenv/check
-
-@go_include@ internal/trace.lo.dep
-internal/trace.lo.dep: $(srcdir)/go/internal/trace/*.go
- $(BUILDDEPS)
-internal/trace.lo:
- $(BUILDPACKAGE)
-internal/trace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/trace/check
-
-@go_include@ io/ioutil.lo.dep
-io/ioutil.lo.dep: $(srcdir)/go/io/ioutil/*.go
- $(BUILDDEPS)
-io/ioutil.lo:
- $(BUILDPACKAGE)
-io/ioutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/ioutil/check
-
-@go_include@ log/syslog.lo.dep
-log/syslog.lo.dep: $(srcdir)/go/log/syslog/*.go
- $(BUILDDEPS)
-log/syslog.lo:
- $(BUILDPACKAGE)
-log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc log/syslog.lo
+# Use a C function with a fixed number of arguments to call a C
+# varargs function.
+log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc
@$(MKDIR_P) log/syslog
$(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c
-log/syslog/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/syslog/check
-
-@go_include@ math/big.lo.dep
-math/big.lo.dep: $(srcdir)/go/math/big/*.go
- $(BUILDDEPS)
-math/big.lo:
- $(BUILDPACKAGE)
-math/big/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/big/check
-
-@go_include@ math/cmplx.lo.dep
-math/cmplx.lo.dep: $(srcdir)/go/math/cmplx/*.go
- $(BUILDDEPS)
-math/cmplx.lo:
- $(BUILDPACKAGE)
-math/cmplx/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/cmplx/check
-
-@go_include@ math/rand.lo.dep
-math/rand.lo.dep: $(srcdir)/go/math/rand/*.go
- $(BUILDDEPS)
-math/rand.lo:
- $(BUILDPACKAGE)
-math/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/rand/check
-
-@go_include@ mime/multipart.lo.dep
-mime/multipart.lo.dep: $(srcdir)/go/mime/multipart/*.go
- $(BUILDDEPS)
-mime/multipart.lo:
- $(BUILDPACKAGE)
-mime/multipart/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/multipart/check
-
-@go_include@ mime/quotedprintable.lo.dep
-mime/quotedprintable.lo.dep: $(srcdir)/go/mime/quotedprintable/*.go
- $(BUILDDEPS)
-mime/quotedprintable.lo:
- $(BUILDPACKAGE)
-mime/quotedprintable/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/quotedprintable/check
-
-@go_include@ net/http.lo.dep
-net/http.lo.dep: $(srcdir)/go/net/http/*.go
- $(BUILDDEPS)
-net/http.lo:
- $(BUILDPACKAGE)
-net/http/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/check
-
-@go_include@ net/mail.lo.dep
-net/mail.lo.dep: $(srcdir)/go/net/mail/*.go
- $(BUILDDEPS)
-net/mail.lo:
- $(BUILDPACKAGE)
-net/mail/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/mail/check
-
-@go_include@ net/rpc.lo.dep
-net/rpc.lo.dep: $(srcdir)/go/net/rpc/*.go
- $(BUILDDEPS)
-net/rpc.lo:
- $(BUILDPACKAGE)
-net/rpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/check
-
-@go_include@ net/smtp.lo.dep
-net/smtp.lo.dep: $(srcdir)/go/net/smtp/*.go
- $(BUILDDEPS)
-net/smtp.lo:
- $(BUILDPACKAGE)
-net/smtp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/smtp/check
-
-@go_include@ net/url.lo.dep
-net/url.lo.dep: $(srcdir)/go/net/url/*.go
- $(BUILDDEPS)
-net/url.lo:
- $(BUILDPACKAGE)
-net/url/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/url/check
-
-@go_include@ net/textproto.lo.dep
-net/textproto.lo.dep: $(srcdir)/go/net/textproto/*.go
- $(BUILDDEPS)
-net/textproto.lo:
- $(BUILDPACKAGE)
-net/textproto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/textproto/check
-
-@go_include@ net/http/cgi.lo.dep
-net/http/cgi.lo.dep: $(srcdir)/go/net/http/cgi/*.go
- $(BUILDDEPS)
-net/http/cgi.lo:
- $(BUILDPACKAGE)
-net/http/cgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cgi/check
-
-@go_include@ net/http/cookiejar.lo.dep
-net/http/cookiejar.lo.dep: $(srcdir)/go/net/http/cookiejar/*.go
- $(BUILDDEPS)
-net/http/cookiejar.lo:
- $(BUILDPACKAGE)
-net/http/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cookiejar/check
-
-@go_include@ net/http/fcgi.lo.dep
-net/http/fcgi.lo.dep: $(srcdir)/go/net/http/fcgi/*.go
- $(BUILDDEPS)
-net/http/fcgi.lo:
- $(BUILDPACKAGE)
-net/http/fcgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/fcgi/check
-
-@go_include@ net/http/httptest.lo.dep
-net/http/httptest.lo.dep: $(srcdir)/go/net/http/httptest/*.go
- $(BUILDDEPS)
-net/http/httptest.lo:
- $(BUILDPACKAGE)
-net/http/httptest/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptest/check
-
-@go_include@ net/http/httptrace.lo.dep
-net/http/httptrace.lo.dep: $(srcdir)/go/net/http/httptrace/*.go
- $(BUILDDEPS)
-net/http/httptrace.lo:
- $(BUILDPACKAGE)
-net/http/httptrace/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptrace/check
-
-@go_include@ net/http/httputil.lo.dep
-net/http/httputil.lo.dep: $(srcdir)/go/net/http/httputil/*.go
- $(BUILDDEPS)
-net/http/httputil.lo:
- $(BUILDPACKAGE)
-net/http/httputil/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httputil/check
-
-@go_include@ net/http/internal.lo.dep
-net/http/internal.lo.dep: $(srcdir)/go/net/http/internal/*.go
- $(BUILDDEPS)
-net/http/internal.lo:
- $(BUILDPACKAGE)
-net/http/internal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/internal/check
-
-@go_include@ net/http/pprof.lo.dep
-net/http/pprof.lo.dep: $(srcdir)/go/net/http/pprof/*.go
- $(BUILDDEPS)
-net/http/pprof.lo:
- $(BUILDPACKAGE)
-net/http/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/pprof/check
-
-@go_include@ net/internal/socktest.lo.dep
-net/internal/socktest.lo.dep: $(srcdir)/go/net/internal/socktest/*.go
- $(BUILDDEPS)
-net/internal/socktest.lo:
- $(BUILDPACKAGE)
-net/internal/socktest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/internal/socktest/check
-
-@go_include@ net/rpc/jsonrpc.lo.dep
-net/rpc/jsonrpc.lo.dep: $(srcdir)/go/net/rpc/jsonrpc/*.go
- $(BUILDDEPS)
-net/rpc/jsonrpc.lo:
- $(BUILDPACKAGE)
-net/rpc/jsonrpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/jsonrpc/check
-
-@go_include@ old/regexp.lo.dep
-old/regexp.lo.dep: $(srcdir)/go/old/regexp/*.go
- $(BUILDDEPS)
-old/regexp.lo:
- $(BUILDPACKAGE)
-old/regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/regexp/check
-
-@go_include@ old/template.lo.dep
-old/template.lo.dep: $(srcdir)/go/old/template/*.go
- $(BUILDDEPS)
-old/template.lo:
- $(BUILDPACKAGE)
-old/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/template/check
-
-@go_include@ os/exec.lo.dep
-os/exec.lo.dep: $(srcdir)/go/os/exec/*.go
- $(BUILDDEPS)
-os/exec.lo:
- $(BUILDPACKAGE)
-os/exec/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/exec/check
-
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(srcdir)/go/os/signal/*.go
- $(BUILDDEPS)
-os/signal.lo:
- $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/signal/check
-
-@go_include@ os/user.lo.dep
-os/user.lo.dep: $(srcdir)/go/os/user/*.go
- $(BUILDDEPS)
-os/user.lo:
- $(BUILDPACKAGE)
-os/user/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/user/check
-
-@go_include@ path/filepath.lo.dep
-path/filepath.lo.dep: $(srcdir)/go/path/filepath/*.go
- $(BUILDDEPS)
-path/filepath.lo:
- $(BUILDPACKAGE)
-path/filepath/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/filepath/check
-
-@go_include@ regexp/syntax.lo.dep
-regexp/syntax.lo.dep: $(srcdir)/go/regexp/syntax/*.go
- $(BUILDDEPS)
-regexp/syntax.lo:
- $(BUILDPACKAGE)
-regexp/syntax/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/syntax/check
-
-@go_include@ runtime/debug.lo.dep
-runtime/debug.lo.dep: $(srcdir)/go/runtime/debug/*.go
- $(BUILDDEPS)
-runtime/debug.lo:
- $(BUILDPACKAGE)
-runtime/debug/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/debug/check
-
-@go_include@ runtime/pprof.lo.dep
-runtime/pprof.lo.dep: $(srcdir)/go/runtime/pprof/*.go
- $(BUILDDEPS)
-runtime/pprof.lo:
- $(BUILDPACKAGE)
-runtime/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/pprof/check
-# At least for now, we need -static-libgo for this test, because
-# otherwise we can't get the line numbers.
-# Also use -fno-inline to get better results from the memory profiler.
-runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
-
-@go_include@ runtime/internal/atomic.lo.dep
-runtime/internal/atomic.lo.dep: $(srcdir)/go/runtime/internal/atomic/*.go
- $(BUILDDEPS)
-runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
-runtime/internal/atomic.lo:
- $(BUILDPACKAGE)
-runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc runtime/internal/atomic.lo
- $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
-runtime/internal/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/internal/atomic/check
-extra_go_files_runtime_internal_sys = version.go
+# The interface to libffi from the reflect package is written in C.
+reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
+ @$(MKDIR_P) reflect
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/reflect/makefunc_ffi_c.c
-@go_include@ runtime/internal/sys.lo.dep
-runtime/internal/sys.lo.dep: $(srcdir)/go/runtime/internal/sys/*.go
- $(BUILDDEPS)
-runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
-runtime/internal/sys.lo:
- $(BUILDPACKAGE)
-runtime/internal/sys/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/internal/sys/check
-
-@go_include@ sync/atomic.lo.dep
-sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go
- $(BUILDDEPS)
-sync/atomic.lo:
- $(BUILDPACKAGE)
-sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc sync/atomic.lo
+# The atomic functions are written in C.
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) runtime/internal
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
+sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) sync
$(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c
-sync/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/atomic/check
-
-@go_include@ text/scanner.lo.dep
-text/scanner.lo.dep: $(srcdir)/go/text/scanner/*.go
- $(BUILDDEPS)
-text/scanner.lo:
- $(BUILDPACKAGE)
-text/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/scanner/check
-
-@go_include@ text/tabwriter.lo.dep
-text/tabwriter.lo.dep: $(srcdir)/go/text/tabwriter/*.go
- $(BUILDDEPS)
-text/tabwriter.lo:
- $(BUILDPACKAGE)
-text/tabwriter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/tabwriter/check
-
-@go_include@ text/template.lo.dep
-text/template.lo.dep: $(srcdir)/go/text/template/*.go
- $(BUILDDEPS)
-text/template.lo:
- $(BUILDPACKAGE)
-text/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/check
-
-@go_include@ text/template/parse.lo.dep
-text/template/parse.lo.dep: $(srcdir)/go/text/template/parse/*.go
- $(BUILDDEPS)
-text/template/parse.lo:
- $(BUILDPACKAGE)
-text/template/parse/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/parse/check
-
-@go_include@ testing/iotest.lo.dep
-testing/iotest.lo.dep: $(srcdir)/go/testing/iotest/*.go
- $(BUILDDEPS)
-testing/iotest.lo:
- $(BUILDPACKAGE)
-testing/iotest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/iotest/check
-
-@go_include@ testing/quick.lo.dep
-testing/quick.lo.dep: $(srcdir)/go/testing/quick/*.go
- $(BUILDDEPS)
-testing/quick.lo:
- $(BUILDPACKAGE)
-testing/quick/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/quick/check
-
-@go_include@ unicode/utf16.lo.dep
-unicode/utf16.lo.dep: $(srcdir)/go/unicode/utf16/*.go
- $(BUILDDEPS)
-unicode/utf16.lo:
- $(BUILDPACKAGE)
-unicode/utf16/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf16/check
-
-@go_include@ unicode/utf8.lo.dep
-unicode/utf8.lo.dep: $(srcdir)/go/unicode/utf8/*.go
- $(BUILDDEPS)
-unicode/utf8.lo:
- $(BUILDPACKAGE)
-unicode/utf8/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf8/check
-
-@go_include@ syscall.lo.dep
-syscall.lo.dep: $(srcdir)/go/syscall/*.go $(extra_go_files_syscall)
- $(BUILDDEPS)
-syscall.lo:
- $(BUILDPACKAGE)
+
+# A few syscall functions are written in C.
syscall/clone_linux.lo: go/syscall/clone_linux.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/clone_linux.c
syscall/errno.lo: go/syscall/errno.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/errno.c
syscall/signame.lo: go/syscall/signame.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/signame.c
syscall/wait.lo: go/syscall/wait.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: syscall/check
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
-# How to build a .gox file from a .lo file.
-BUILDGOX = \
- f=`echo $< | sed -e 's/.lo$$/.o/'`; \
- $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
-
-bufio.gox: bufio.lo
- $(BUILDGOX)
-bytes.gox: bytes.lo
- $(BUILDGOX)
-context.gox: context.lo
- $(BUILDGOX)
-crypto.gox: crypto.lo
- $(BUILDGOX)
-encoding.gox: encoding.lo
- $(BUILDGOX)
-errors.gox: errors.lo
- $(BUILDGOX)
-expvar.gox: expvar.lo
- $(BUILDGOX)
-flag.gox: flag.lo
- $(BUILDGOX)
-fmt.gox: fmt.lo
- $(BUILDGOX)
-hash.gox: hash.lo
- $(BUILDGOX)
-html.gox: html.lo
- $(BUILDGOX)
-image.gox: image.lo
- $(BUILDGOX)
-io.gox: io.lo
- $(BUILDGOX)
-log.gox: log.lo
- $(BUILDGOX)
-math.gox: math.lo
- $(BUILDGOX)
-mime.gox: mime.lo
- $(BUILDGOX)
-net.gox: net.lo
- $(BUILDGOX)
-os.gox: os.lo
- $(BUILDGOX)
-path.gox: path.lo
- $(BUILDGOX)
-reflect.gox: reflect-go.lo
- $(BUILDGOX)
-regexp.gox: regexp.lo
- $(BUILDGOX)
-runtime.gox: runtime-go.lo
- $(BUILDGOX)
-sort.gox: sort.lo
- $(BUILDGOX)
-strconv.gox: strconv.lo
- $(BUILDGOX)
-strings.gox: strings.lo
- $(BUILDGOX)
-sync.gox: sync.lo
- $(BUILDGOX)
-syscall.gox: syscall.lo
- $(BUILDGOX)
-testing.gox: testing.lo
- $(BUILDGOX)
-time.gox: time-go.lo
- $(BUILDGOX)
-unicode.gox: unicode.lo
- $(BUILDGOX)
-
-archive/tar.gox: archive/tar.lo
- $(BUILDGOX)
-archive/zip.gox: archive/zip.lo
- $(BUILDGOX)
-
-compress/bzip2.gox: compress/bzip2.lo
- $(BUILDGOX)
-compress/flate.gox: compress/flate.lo
- $(BUILDGOX)
-compress/gzip.gox: compress/gzip.lo
- $(BUILDGOX)
-compress/lzw.gox: compress/lzw.lo
- $(BUILDGOX)
-compress/zlib.gox: compress/zlib.lo
- $(BUILDGOX)
-
-container/heap.gox: container/heap.lo
- $(BUILDGOX)
-container/list.gox: container/list.lo
- $(BUILDGOX)
-container/ring.gox: container/ring.lo
- $(BUILDGOX)
-
-crypto/aes.gox: crypto/aes.lo
- $(BUILDGOX)
-crypto/cipher.gox: crypto/cipher.lo
- $(BUILDGOX)
-crypto/des.gox: crypto/des.lo
- $(BUILDGOX)
-crypto/dsa.gox: crypto/dsa.lo
- $(BUILDGOX)
-crypto/ecdsa.gox: crypto/ecdsa.lo
- $(BUILDGOX)
-crypto/elliptic.gox: crypto/elliptic.lo
- $(BUILDGOX)
-crypto/hmac.gox: crypto/hmac.lo
- $(BUILDGOX)
-crypto/md5.gox: crypto/md5.lo
- $(BUILDGOX)
-crypto/rand.gox: crypto/rand.lo
- $(BUILDGOX)
-crypto/rc4.gox: crypto/rc4.lo
- $(BUILDGOX)
-crypto/rsa.gox: crypto/rsa.lo
- $(BUILDGOX)
-crypto/sha1.gox: crypto/sha1.lo
- $(BUILDGOX)
-crypto/sha256.gox: crypto/sha256.lo
- $(BUILDGOX)
-crypto/sha512.gox: crypto/sha512.lo
- $(BUILDGOX)
-crypto/subtle.gox: crypto/subtle.lo
- $(BUILDGOX)
-crypto/tls.gox: crypto/tls.lo
- $(BUILDGOX)
-crypto/x509.gox: crypto/x509.lo
- $(BUILDGOX)
-
-crypto/x509/pkix.gox: crypto/x509/pkix.lo
- $(BUILDGOX)
-
-database/sql.gox: database/sql.lo
- $(BUILDGOX)
-
-database/sql/driver.gox: database/sql/driver.lo
- $(BUILDGOX)
-
-debug/dwarf.gox: debug/dwarf.lo
- $(BUILDGOX)
-debug/elf.gox: debug/elf.lo
- $(BUILDGOX)
-debug/gosym.gox: debug/gosym.lo
- $(BUILDGOX)
-debug/macho.gox: debug/macho.lo
- $(BUILDGOX)
-debug/pe.gox: debug/pe.lo
- $(BUILDGOX)
-debug/plan9obj.gox: debug/plan9obj.lo
- $(BUILDGOX)
-
-encoding/ascii85.gox: encoding/ascii85.lo
- $(BUILDGOX)
-encoding/asn1.gox: encoding/asn1.lo
- $(BUILDGOX)
-encoding/base32.gox: encoding/base32.lo
- $(BUILDGOX)
-encoding/base64.gox: encoding/base64.lo
- $(BUILDGOX)
-encoding/binary.gox: encoding/binary.lo
- $(BUILDGOX)
-encoding/csv.gox: encoding/csv.lo
- $(BUILDGOX)
-encoding/gob.gox: encoding/gob.lo
- $(BUILDGOX)
-encoding/hex.gox: encoding/hex.lo
- $(BUILDGOX)
-encoding/json.gox: encoding/json.lo
- $(BUILDGOX)
-encoding/pem.gox: encoding/pem.lo
- $(BUILDGOX)
-encoding/xml.gox: encoding/xml.lo
- $(BUILDGOX)
-
-exp/proxy.gox: exp/proxy.lo
- $(BUILDGOX)
-exp/terminal.gox: exp/terminal.lo
- $(BUILDGOX)
-
-html/template.gox: html/template.lo
- $(BUILDGOX)
-
-go/ast.gox: go/ast.lo
- $(BUILDGOX)
-go/build.gox: go/build.lo
- $(BUILDGOX)
-go/constant.gox: go/constant.lo
- $(BUILDGOX)
-go/doc.gox: go/doc.lo
- $(BUILDGOX)
-go/format.gox: go/format.lo
- $(BUILDGOX)
-go/importer.gox: go/importer.lo
- $(BUILDGOX)
-go/parser.gox: go/parser.lo
- $(BUILDGOX)
-go/printer.gox: go/printer.lo
- $(BUILDGOX)
-go/scanner.gox: go/scanner.lo
- $(BUILDGOX)
-go/token.gox: go/token.lo
- $(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
-
-go/internal/gcimporter.gox: go/internal/gcimporter.lo
- $(BUILDGOX)
-go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo
- $(BUILDGOX)
-
-golang_org/x/net/http2/hpack.gox: golang_org/x/net/http2/hpack.lo
- $(BUILDGOX)
-
-golang_org/x/net/lex/httplex.gox: golang_org/x/net/lex/httplex.lo
- $(BUILDGOX)
+# Solaris 12 changed the type of fields in struct stat.
+# Use a build tag, based on a configure check, to cope.
+if LIBGO_IS_SOLARIS
+if HAVE_STAT_TIMESPEC
+matchargs_os = --tag=solaristag
+else
+matchargs_os =
+endif
+else
+matchargs_os =
+endif
if LIBGO_IS_BSD
-golang_org/x/net/route.gox: golang_org/x/net/route.lo
- $(BUILDGOX)
-endif
-hash/adler32.gox: hash/adler32.lo
- $(BUILDGOX)
-hash/crc32.gox: hash/crc32.lo
- $(BUILDGOX)
-hash/crc64.gox: hash/crc64.lo
- $(BUILDGOX)
-hash/fnv.gox: hash/fnv.lo
- $(BUILDGOX)
-
-image/color.gox: image/color.lo
- $(BUILDGOX)
-image/draw.gox: image/draw.lo
- $(BUILDGOX)
-image/gif.gox: image/gif.lo
- $(BUILDGOX)
-image/internal/imageutil.gox: image/internal/imageutil.lo
- $(BUILDGOX)
-image/jpeg.gox: image/jpeg.lo
- $(BUILDGOX)
-image/png.gox: image/png.lo
- $(BUILDGOX)
-
-image/color/palette.gox: image/color/palette.lo
- $(BUILDGOX)
-
-index/suffixarray.gox: index/suffixarray.lo
- $(BUILDGOX)
-
-internal/nettrace.gox: internal/nettrace.lo
- $(BUILDGOX)
-internal/race.gox: internal/race.lo
- $(BUILDGOX)
-internal/singleflight.gox: internal/singleflight.lo
- $(BUILDGOX)
-internal/syscall/unix.gox: internal/syscall/unix.lo
- $(BUILDGOX)
-internal/testenv.gox: internal/testenv.lo
- $(BUILDGOX)
-internal/trace.gox: internal/trace.lo
- $(BUILDGOX)
-
-io/ioutil.gox: io/ioutil.lo
- $(BUILDGOX)
-
-log/syslog.gox: log/syslog.lo
- $(BUILDGOX)
-
-math/big.gox: math/big.lo
- $(BUILDGOX)
-math/cmplx.gox: math/cmplx.lo
- $(BUILDGOX)
-math/rand.gox: math/rand.lo
- $(BUILDGOX)
-
-mime/multipart.gox: mime/multipart.lo
- $(BUILDGOX)
-mime/quotedprintable.gox: mime/quotedprintable.lo
- $(BUILDGOX)
-
-net/http.gox: net/http.lo
- $(BUILDGOX)
-net/mail.gox: net/mail.lo
- $(BUILDGOX)
-net/rpc.gox: net/rpc.lo
- $(BUILDGOX)
-net/smtp.gox: net/smtp.lo
- $(BUILDGOX)
-net/textproto.gox: net/textproto.lo
- $(BUILDGOX)
-net/url.gox: net/url.lo
- $(BUILDGOX)
-
-net/http/cgi.gox: net/http/cgi.lo
- $(BUILDGOX)
-net/http/cookiejar.gox: net/http/cookiejar.lo
- $(BUILDGOX)
-net/http/fcgi.gox: net/http/fcgi.lo
- $(BUILDGOX)
-net/http/httptest.gox: net/http/httptest.lo
- $(BUILDGOX)
-net/http/httptrace.gox: net/http/httptrace.lo
- $(BUILDGOX)
-net/http/httputil.gox: net/http/httputil.lo
- $(BUILDGOX)
-net/http/pprof.gox: net/http/pprof.lo
- $(BUILDGOX)
-
-net/http/internal.gox: net/http/internal.lo
- $(BUILDGOX)
-
-net/internal/socktest.gox: net/internal/socktest.lo
- $(BUILDGOX)
-
-net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
- $(BUILDGOX)
-
-old/regexp.gox: old/regexp.lo
- $(BUILDGOX)
-old/template.gox: old/template.lo
- $(BUILDGOX)
-
-os/exec.gox: os/exec.lo
- $(BUILDGOX)
-os/signal.gox: os/signal.lo
- $(BUILDGOX)
-os/user.gox: os/user.lo
- $(BUILDGOX)
-
-path/filepath.gox: path/filepath.lo
- $(BUILDGOX)
-
-regexp/syntax.gox: regexp/syntax.lo
- $(BUILDGOX)
-
-runtime/debug.gox: runtime/debug.lo
- $(BUILDGOX)
-runtime/pprof.gox: runtime/pprof.lo
- $(BUILDGOX)
-runtime/internal/atomic.gox: runtime/internal/atomic.lo
- $(BUILDGOX)
-runtime/internal/sys.gox: runtime/internal/sys.lo
- $(BUILDGOX)
-
-sync/atomic.gox: sync/atomic.lo
- $(BUILDGOX)
-
-text/scanner.gox: text/scanner.lo
- $(BUILDGOX)
-text/tabwriter.gox: text/tabwriter.lo
- $(BUILDGOX)
-text/template.gox: text/template.lo
- $(BUILDGOX)
-text/template/parse.gox: text/template/parse.lo
- $(BUILDGOX)
-
-testing/iotest.gox: testing/iotest.lo
- $(BUILDGOX)
-testing/quick.gox: testing/quick.lo
- $(BUILDGOX)
-
-unicode/utf16.gox: unicode/utf16.lo
- $(BUILDGOX)
-unicode/utf8.gox: unicode/utf8.lo
- $(BUILDGOX)
+# Build golang_org/x/net/route only on BSD systems.
+
+$(eval $(call PACKAGE_template,golang_org/x/net/route)
+
+golang_org_x_net_route_lo = \
+ golang_org/x/net/route/route.lo
+golang_org_x_net_route_check = \
+ golang_org/x/net/route/check
+
+endif
TEST_PACKAGES = \
bufio/check \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 25b5a7be8eb..908e66042a5 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -163,61 +163,14 @@ libgolibbegin_a_AR = $(AR) $(ARFLAGS)
libgolibbegin_a_LIBADD =
am_libgolibbegin_a_OBJECTS = libgolibbegin_a-go-libmain.$(OBJEXT)
libgolibbegin_a_OBJECTS = $(am_libgolibbegin_a_OBJECTS)
-libnetgo_a_AR = $(AR) $(ARFLAGS)
-libnetgo_a_DEPENDENCIES = netgo.o
-am_libnetgo_a_OBJECTS =
-libnetgo_a_OBJECTS = $(am_libnetgo_a_OBJECTS)
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
@LIBGO_IS_LINUX_TRUE@am__DEPENDENCIES_1 = syscall/clone_linux.lo
-am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo context.lo \
- crypto.lo encoding.lo errors.lo expvar.lo flag.lo fmt.lo \
- hash.lo html.lo image.lo io.lo log.lo math.lo mime.lo net.lo \
- os.lo path.lo reflect-go.lo reflect/makefunc_ffi_c.lo \
- regexp.lo runtime-go.lo sort.lo strconv.lo strings.lo \
- strings/index.lo sync.lo syscall.lo $(am__DEPENDENCIES_1) \
- syscall/errno.lo syscall/signame.lo syscall/wait.lo testing.lo \
- time-go.lo unicode.lo archive/tar.lo archive/zip.lo \
- compress/bzip2.lo compress/flate.lo compress/gzip.lo \
- compress/lzw.lo compress/zlib.lo container/heap.lo \
- container/list.lo container/ring.lo crypto/aes.lo \
- crypto/cipher.lo crypto/des.lo crypto/dsa.lo crypto/ecdsa.lo \
- crypto/elliptic.lo crypto/hmac.lo crypto/md5.lo crypto/rand.lo \
- crypto/rc4.lo crypto/rsa.lo crypto/sha1.lo crypto/sha256.lo \
- crypto/sha512.lo crypto/subtle.lo crypto/tls.lo crypto/x509.lo \
- crypto/x509/pkix.lo database/sql.lo database/sql/driver.lo \
- debug/dwarf.lo debug/elf.lo debug/gosym.lo debug/macho.lo \
- debug/pe.lo debug/plan9obj.lo encoding/ascii85.lo \
- encoding/asn1.lo encoding/base32.lo encoding/base64.lo \
- encoding/binary.lo encoding/csv.lo encoding/gob.lo \
- encoding/hex.lo encoding/json.lo encoding/pem.lo \
- encoding/xml.lo exp/proxy.lo exp/terminal.lo html/template.lo \
- go/ast.lo go/build.lo go/constant.lo go/doc.lo go/format.lo \
- go/importer.lo go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo go/parser.lo go/printer.lo \
- go/scanner.lo go/token.lo go/types.lo \
- golang_org/x/net/http2/hpack.lo \
- golang_org/x/net/lex/httplex.lo $(golang_org_x_net_route_lo) \
- hash/adler32.lo hash/crc32.lo hash/crc64.lo hash/fnv.lo \
- net/http/cgi.lo net/http/cookiejar.lo net/http/fcgi.lo \
- net/http/httptest.lo net/http/httptrace.lo \
- net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \
- image/color.lo image/color/palette.lo image/draw.lo \
- image/gif.lo image/internal/imageutil.lo image/jpeg.lo \
- image/png.lo index/suffixarray.lo internal/nettrace.lo \
- internal/race.lo internal/singleflight.lo \
- internal/syscall/unix.lo internal/testenv.lo internal/trace.lo \
- io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \
- math/cmplx.lo math/rand.lo mime/multipart.lo \
- mime/quotedprintable.lo net/http.lo net/internal/socktest.lo \
- net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
- old/regexp.lo old/template.lo os/exec.lo os/signal.lo \
- os/user.lo path/filepath.lo regexp/syntax.lo \
- net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
- runtime/internal/atomic.lo runtime/internal/atomic_c.lo \
- runtime/internal/sys.lo sync/atomic.lo sync/atomic_c.lo \
- text/scanner.lo text/tabwriter.lo text/template.lo \
- text/template/parse.lo testing/iotest.lo testing/quick.lo \
- unicode/utf16.lo unicode/utf8.lo
+am__DEPENDENCIES_2 = $(addsuffix .lo,$(PACKAGES)) bytes/index.lo \
+ reflect/makefunc_ffi_c.lo strings/index.lo \
+ $(am__DEPENDENCIES_1) syscall/errno.lo syscall/signame.lo \
+ syscall/wait.lo $(golang_org_x_net_route_lo) \
+ log/syslog/syslog_c.lo runtime/internal/atomic_c.lo \
+ sync/atomic_c.lo
am__DEPENDENCIES_3 =
am__DEPENDENCIES_4 = $(am__DEPENDENCIES_2) \
../libbacktrace/libbacktrace.la $(am__DEPENDENCIES_3) \
@@ -237,23 +190,22 @@ libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_4)
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
@LIBGO_IS_LINUX_TRUE@am__objects_4 = getncpu-linux.lo
-am__objects_5 = go-append.lo go-assert.lo go-breakpoint.lo \
- go-caller.lo go-callers.lo go-cdiv.lo go-cgo.lo \
- go-construct-map.lo go-copy.lo go-defer.lo \
- go-deferred-recover.lo go-ffi.lo go-fieldtrack.lo \
- go-make-slice.lo go-matherr.lo go-memclr.lo go-memcmp.lo \
- go-memequal.lo go-memmove.lo go-nanotime.lo go-now.lo \
- go-new.lo go-nosys.lo go-panic.lo go-recover.lo \
- go-reflect-call.lo go-runtime-error.lo go-setenv.lo \
- go-signal.lo go-strslice.lo go-type-complex.lo \
- go-type-float.lo go-type-identity.lo go-type-string.lo \
- go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \
- go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \
- env_posix.lo heapdump.lo mcache.lo mcentral.lo \
- $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
- panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
- thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
- runtime1.lo sigqueue.lo $(am__objects_4)
+am__objects_5 = go-assert.lo go-breakpoint.lo go-caller.lo \
+ go-callers.lo go-cdiv.lo go-cgo.lo go-construct-map.lo \
+ go-defer.lo go-deferred-recover.lo go-ffi.lo go-fieldtrack.lo \
+ go-matherr.lo go-memclr.lo go-memcmp.lo go-memequal.lo \
+ go-memmove.lo go-nanotime.lo go-now.lo go-new.lo go-nosys.lo \
+ go-panic.lo go-recover.lo go-reflect-call.lo \
+ go-runtime-error.lo go-setenv.lo go-signal.lo go-strslice.lo \
+ go-type-complex.lo go-type-float.lo go-type-identity.lo \
+ go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
+ go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
+ go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \
+ mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \
+ msize.lo panic.lo parfor.lo print.lo proc.lo runtime_c.lo \
+ signal_unix.lo thread.lo $(am__objects_2) yield.lo \
+ $(am__objects_3) malloc.lo runtime1.lo sigqueue.lo \
+ $(am__objects_4)
am_libgo_llgo_la_OBJECTS = $(am__objects_5)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -281,8 +233,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libgobegin_llgo_a_SOURCES) $(libgobegin_a_SOURCES) \
- $(libgolibbegin_a_SOURCES) $(libnetgo_a_SOURCES) \
- $(libgo_llgo_la_SOURCES) $(libgo_la_SOURCES)
+ $(libgolibbegin_a_SOURCES) $(libgo_llgo_la_SOURCES) \
+ $(libgo_la_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -566,7 +518,7 @@ AM_MAKEFLAGS = \
FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@GOC_IS_LLGO_FALSE@toolexeclib_LTLIBRARIES = libgo.la
@GOC_IS_LLGO_TRUE@toolexeclib_LTLIBRARIES = libgo-llgo.la
-@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a libnetgo.a
+@GOC_IS_LLGO_FALSE@toolexeclib_LIBRARIES = libgobegin.a libgolibbegin.a
@GOC_IS_LLGO_TRUE@toolexeclib_LIBRARIES = libgobegin-llgo.a
toolexeclibgo_DATA = \
bufio.gox \
@@ -824,7 +776,6 @@ toolexeclibgounicode_DATA = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@LIBGO_IS_LINUX_TRUE@runtime_getncpu_file = runtime/getncpu-linux.c
runtime_files = \
- runtime/go-append.c \
runtime/go-assert.c \
runtime/go-breakpoint.c \
runtime/go-caller.c \
@@ -832,12 +783,10 @@ runtime_files = \
runtime/go-cdiv.c \
runtime/go-cgo.c \
runtime/go-construct-map.c \
- runtime/go-copy.c \
runtime/go-defer.c \
runtime/go-deferred-recover.c \
runtime/go-ffi.c \
runtime/go-fieldtrack.c \
- runtime/go-make-slice.c \
runtime/go-matherr.c \
runtime/go-memclr.c \
runtime/go-memcmp.c \
@@ -878,7 +827,7 @@ runtime_files = \
runtime/parfor.c \
runtime/print.c \
runtime/proc.c \
- runtime/runtime.c \
+ runtime/runtime_c.c \
runtime/signal_unix.c \
runtime/thread.c \
$(runtime_thread_files) \
@@ -892,187 +841,184 @@ runtime_files = \
noinst_DATA = zstdpkglist.go
@LIBGO_IS_LINUX_FALSE@syscall_epoll_file =
@LIBGO_IS_LINUX_TRUE@syscall_epoll_file = epoll.go
-extra_go_files_syscall = \
- libcalls.go \
- sysinfo.go \
- syscall_arch.go \
- $(syscall_epoll_file)
-
SYSINFO_FLAGS = \
$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(OSCFLAGS) -O
@LIBGO_IS_LINUX_FALSE@syscall_lib_clone_lo =
@LIBGO_IS_LINUX_TRUE@syscall_lib_clone_lo = syscall/clone_linux.lo
+PACKAGES = \
+ archive/tar \
+ archive/zip \
+ bufio \
+ bytes \
+ compress/bzip2 \
+ compress/flate \
+ compress/gzip \
+ compress/lzw \
+ compress/zlib \
+ container/heap \
+ container/list \
+ container/ring \
+ context \
+ crypto \
+ crypto/aes \
+ crypto/cipher \
+ crypto/des \
+ crypto/dsa \
+ crypto/ecdsa \
+ crypto/elliptic \
+ crypto/hmac \
+ crypto/md5 \
+ crypto/rand \
+ crypto/rc4 \
+ crypto/rsa \
+ crypto/sha1 \
+ crypto/sha256 \
+ crypto/sha512 \
+ crypto/subtle \
+ crypto/tls \
+ crypto/x509 \
+ crypto/x509/pkix \
+ database/sql \
+ database/sql/driver \
+ debug/dwarf \
+ debug/elf \
+ debug/gosym \
+ debug/macho \
+ debug/pe \
+ debug/plan9obj \
+ encoding \
+ encoding/ascii85 \
+ encoding/asn1 \
+ encoding/base32 \
+ encoding/base64 \
+ encoding/binary \
+ encoding/csv \
+ encoding/gob \
+ encoding/hex \
+ encoding/json \
+ encoding/pem \
+ encoding/xml \
+ errors \
+ exp/proxy \
+ exp/terminal \
+ expvar \
+ flag \
+ fmt \
+ go/ast \
+ go/build \
+ go/constant \
+ go/doc \
+ go/format \
+ go/importer \
+ go/internal/gccgoimporter \
+ go/internal/gcimporter \
+ go/parser \
+ go/printer \
+ go/scanner \
+ go/token \
+ go/types \
+ golang_org/x/net/http2/hpack \
+ golang_org/x/net/lex/httplex \
+ hash \
+ hash/adler32 \
+ hash/crc32 \
+ hash/crc64 \
+ hash/fnv \
+ html \
+ html/template \
+ image \
+ image/color \
+ image/color/palette \
+ image/draw \
+ image/gif \
+ image/internal/imageutil \
+ image/jpeg \
+ image/png \
+ index/suffixarray \
+ internal/nettrace \
+ internal/race \
+ internal/singleflight \
+ internal/syscall/unix \
+ internal/testenv \
+ internal/trace \
+ io \
+ io/ioutil \
+ log \
+ log/syslog \
+ math \
+ math/big \
+ math/cmplx \
+ math/rand \
+ mime \
+ mime/multipart \
+ mime/quotedprintable \
+ net \
+ net/http \
+ net/http/cgi \
+ net/http/cookiejar \
+ net/http/fcgi \
+ net/http/httptest \
+ net/http/httptrace \
+ net/http/httputil \
+ net/http/internal \
+ net/http/pprof \
+ net/internal/socktest \
+ net/mail \
+ net/rpc \
+ net/rpc/jsonrpc \
+ net/smtp \
+ net/textproto \
+ net/url \
+ old/regexp \
+ old/template \
+ os \
+ os/exec \
+ os/signal \
+ os/user \
+ path \
+ path/filepath \
+ reflect \
+ regexp \
+ regexp/syntax \
+ runtime \
+ runtime/debug \
+ runtime/internal/atomic \
+ runtime/internal/sys \
+ runtime/pprof \
+ sort \
+ strconv \
+ strings \
+ sync \
+ sync/atomic \
+ syscall \
+ testing \
+ testing/iotest \
+ testing/quick \
+ text/scanner \
+ text/tabwriter \
+ text/template \
+ text/template/parse \
+ time \
+ unicode \
+ unicode/utf16 \
+ unicode/utf8
+
libgo_go_objs = \
- bufio.lo \
- bytes.lo \
+ $(addsuffix .lo,$(PACKAGES)) \
bytes/index.lo \
- context.lo \
- crypto.lo \
- encoding.lo \
- errors.lo \
- expvar.lo \
- flag.lo \
- fmt.lo \
- hash.lo \
- html.lo \
- image.lo \
- io.lo \
- log.lo \
- math.lo \
- mime.lo \
- net.lo \
- os.lo \
- path.lo \
- reflect-go.lo \
reflect/makefunc_ffi_c.lo \
- regexp.lo \
- runtime-go.lo \
- sort.lo \
- strconv.lo \
- strings.lo \
strings/index.lo \
- sync.lo \
- syscall.lo \
$(syscall_lib_clone_lo) \
syscall/errno.lo \
syscall/signame.lo \
syscall/wait.lo \
- testing.lo \
- time-go.lo \
- unicode.lo \
- archive/tar.lo \
- archive/zip.lo \
- compress/bzip2.lo \
- compress/flate.lo \
- compress/gzip.lo \
- compress/lzw.lo \
- compress/zlib.lo \
- container/heap.lo \
- container/list.lo \
- container/ring.lo \
- crypto/aes.lo \
- crypto/cipher.lo \
- crypto/des.lo \
- crypto/dsa.lo \
- crypto/ecdsa.lo \
- crypto/elliptic.lo \
- crypto/hmac.lo \
- crypto/md5.lo \
- crypto/rand.lo \
- crypto/rc4.lo \
- crypto/rsa.lo \
- crypto/sha1.lo \
- crypto/sha256.lo \
- crypto/sha512.lo \
- crypto/subtle.lo \
- crypto/tls.lo \
- crypto/x509.lo \
- crypto/x509/pkix.lo \
- database/sql.lo \
- database/sql/driver.lo \
- debug/dwarf.lo \
- debug/elf.lo \
- debug/gosym.lo \
- debug/macho.lo \
- debug/pe.lo \
- debug/plan9obj.lo \
- encoding/ascii85.lo \
- encoding/asn1.lo \
- encoding/base32.lo \
- encoding/base64.lo \
- encoding/binary.lo \
- encoding/csv.lo \
- encoding/gob.lo \
- encoding/hex.lo \
- encoding/json.lo \
- encoding/pem.lo \
- encoding/xml.lo \
- exp/proxy.lo \
- exp/terminal.lo \
- html/template.lo \
- go/ast.lo \
- go/build.lo \
- go/constant.lo \
- go/doc.lo \
- go/format.lo \
- go/importer.lo \
- go/internal/gcimporter.lo \
- go/internal/gccgoimporter.lo \
- go/parser.lo \
- go/printer.lo \
- go/scanner.lo \
- go/token.lo \
- go/types.lo \
- golang_org/x/net/http2/hpack.lo \
- golang_org/x/net/lex/httplex.lo \
$(golang_org_x_net_route_lo) \
- hash/adler32.lo \
- hash/crc32.lo \
- hash/crc64.lo \
- hash/fnv.lo \
- net/http/cgi.lo \
- net/http/cookiejar.lo \
- net/http/fcgi.lo \
- net/http/httptest.lo \
- net/http/httptrace.lo \
- net/http/httputil.lo \
- net/http/internal.lo \
- net/http/pprof.lo \
- image/color.lo \
- image/color/palette.lo \
- image/draw.lo \
- image/gif.lo \
- image/internal/imageutil.lo \
- image/jpeg.lo \
- image/png.lo \
- index/suffixarray.lo \
- internal/nettrace.lo \
- internal/race.lo \
- internal/singleflight.lo \
- internal/syscall/unix.lo \
- internal/testenv.lo \
- internal/trace.lo \
- io/ioutil.lo \
- log/syslog.lo \
log/syslog/syslog_c.lo \
- math/big.lo \
- math/cmplx.lo \
- math/rand.lo \
- mime/multipart.lo \
- mime/quotedprintable.lo \
- net/http.lo \
- net/internal/socktest.lo \
- net/mail.lo \
- net/rpc.lo \
- net/smtp.lo \
- net/textproto.lo \
- net/url.lo \
- old/regexp.lo \
- old/template.lo \
- os/exec.lo \
$(os_lib_inotify_lo) \
- os/signal.lo \
- os/user.lo \
- path/filepath.lo \
- regexp/syntax.lo \
- net/rpc/jsonrpc.lo \
- runtime/debug.lo \
- runtime/pprof.lo \
- runtime/internal/atomic.lo \
runtime/internal/atomic_c.lo \
- runtime/internal/sys.lo \
- sync/atomic.lo \
- sync/atomic_c.lo \
- text/scanner.lo \
- text/tabwriter.lo \
- text/template.lo \
- text/template/parse.lo \
- testing/iotest.lo \
- testing/quick.lo \
- unicode/utf16.lo \
- unicode/utf8.lo
+ sync/atomic_c.lo
libgo_ldflags = \
-version-info $(libtool_VERSION) $(PTHREAD_CFLAGS) $(AM_LDFLAGS)
@@ -1101,8 +1047,6 @@ libgolibbegin_a_SOURCES = \
runtime/go-libmain.c
libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -fPIC
-libnetgo_a_SOURCES =
-libnetgo_a_LIBADD = netgo.o
LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
AM_GOCFLAGS = $(STRINGOPS_FLAG) $(GO_SPLIT_STACK)
GOCOMPILE = $(GOC) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_GOCFLAGS) $(GOCFLAGS)
@@ -1116,8 +1060,8 @@ GOLINK = $(LIBTOOL) --tag GO --mode-link $(GOC) \
# Build the dependencies for a Go package.
BUILDDEPS = \
$(MKDIR_P) $(@D); \
- dir=`echo $@ | sed -e 's/.lo.dep$$//' -e 's/-go//'`; \
- files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst -go,,$(subst .lo.dep,,$@))))" $(matchargs_$(subst /,_,$(subst -go,,$(subst .lo.dep,,$@))))`; \
+ dir=`echo $@ | sed -e 's/.lo.dep$$//'`; \
+ files=`$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/$$dir --extrafiles="$(extra_go_files_$(subst /,_,$(subst .lo.dep,,$@)))" $(matchargs_$(subst /,_,$(subst .lo.dep,,$@)))`; \
$(SHELL) $(srcdir)/godeps.sh `echo $@ | sed -e 's/.dep$$//'` $$files > $@.tmp; \
if ! cmp $@.tmp $@ >/dev/null 2>/dev/null; then \
rm -f `echo $@ | sed -e 's/\.dep$$//'`; \
@@ -1129,22 +1073,14 @@ BUILDDEPS = \
BUILDPACKAGE = \
$(MKDIR_P) $(@D); \
files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
- $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//' -e 's/-go$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
-
-
-# Build deps for netgo.o.
-BUILDNETGODEPS = \
- $(MKDIR_P) $(@D); \
- files=`$(SHELL) $(srcdir)/match.sh --nocgo --tag=netgo --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/net`; \
- $(SHELL) $(srcdir)/godeps.sh netgo.o $$files > $@.tmp; \
- mv -f $@.tmp $@
+ $(LTGOCOMPILE) -I . -c -fgo-pkgpath=`echo $@ | sed -e 's/.lo$$//'` $($(subst -,_,$(subst .,_,$(subst /,_,$@)))_GOCFLAGS) -o $@ $$files
-# Build netgo.o.
-BUILDNETGO = \
- $(MKDIR_P) $(@D); \
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g' -e 's/[^ ]*\.dep//'`; \
- $(GOCOMPILE) -I . -c -fPIC -fgo-pkgpath=net -o $@ $$files
+# How to build a .gox file from a .lo file.
+BUILDGOX = \
+ f=`echo $< | sed -e 's/.lo$$/.o/'`; \
+ $(OBJCOPY) -j .go_export $$f $@.tmp; \
+ $(SHELL) $(srcdir)/mvifdiff.sh $@.tmp `echo $@ | sed -e 's/s-gox/gox/'`
GOTESTFLAGS =
GOBENCH =
@@ -1199,30 +1135,46 @@ CHECK_DEPS = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \
$(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \
$(toolexeclibgounicode_DATA) $(am__append_1) $(am__append_2)
-@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
-@HAVE_STAT_TIMESPEC_TRUE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = --tag=solaristag
-@LIBGO_IS_SOLARIS_FALSE@matchargs_os =
+
+# Pass -ffp-contract=off, or 386-specific options, when building the
+# math package. MATH_FLAG is defined in configure.ac.
+math_lo_GOCFLAGS = $(MATH_FLAG)
+
+# Add the generated file runtime_sysinfo.go to the runtime package.
extra_go_files_runtime = runtime_sysinfo.go
-runtime_go_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
-runtime_check_GOCFLAGS = -fgo-compiling-runtime
-@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_lo = \
-@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/route.lo
-@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_check = \
-@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/check
+# Add generated files to the syscall package.
+extra_go_files_syscall = \
+ libcalls.go \
+ sysinfo.go \
+ syscall_arch.go \
+ $(syscall_epoll_file)
+
+
+# Pass -fgo-compiling-runtime when compiling the runtime package.
+runtime_lo_GOCFLAGS = -fgo-c-header=runtime.inc.tmp -fgo-compiling-runtime
+runtime_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_atomic_lo_check_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
+runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime
# At least for now, we need -static-libgo for this test, because
# otherwise we can't get the line numbers.
# Also use -fno-inline to get better results from the memory profiler.
runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline
-runtime_internal_atomic_lo_GOCFLAGS = -fgo-compiling-runtime
extra_go_files_runtime_internal_sys = version.go
-runtime_internal_sys_lo_GOCFLAGS = -fgo-compiling-runtime
+@HAVE_STAT_TIMESPEC_FALSE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os =
-# How to build a .gox file from a .lo file.
-BUILDGOX = \
- f=`echo $< | sed -e 's/.lo$$/.o/'`; \
- $(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
+# Solaris 12 changed the type of fields in struct stat.
+# Use a build tag, based on a configure check, to cope.
+@HAVE_STAT_TIMESPEC_TRUE@@LIBGO_IS_SOLARIS_TRUE@matchargs_os = --tag=solaristag
+@LIBGO_IS_SOLARIS_FALSE@matchargs_os =
+@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_lo = \
+@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/route.lo
+
+@LIBGO_IS_BSD_TRUE@golang_org_x_net_route_check = \
+@LIBGO_IS_BSD_TRUE@ golang_org/x/net/route/check
TEST_PACKAGES = \
bufio/check \
@@ -1466,10 +1418,6 @@ libgolibbegin.a: $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_DEPENDENCIES) $(EX
-rm -f libgolibbegin.a
$(libgolibbegin_a_AR) libgolibbegin.a $(libgolibbegin_a_OBJECTS) $(libgolibbegin_a_LIBADD)
$(RANLIB) libgolibbegin.a
-libnetgo.a: $(libnetgo_a_OBJECTS) $(libnetgo_a_DEPENDENCIES) $(EXTRA_libnetgo_a_DEPENDENCIES)
- -rm -f libnetgo.a
- $(libnetgo_a_AR) libnetgo.a $(libnetgo_a_OBJECTS) $(libnetgo_a_LIBADD)
- $(RANLIB) libnetgo.a
install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
@@ -1519,7 +1467,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-none.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-solaris.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-append.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-breakpoint.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
@@ -1527,12 +1474,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cdiv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-defer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-ffi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-make-slice.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-matherr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memclr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memcmp.Plo@am__quote@
@@ -1578,8 +1523,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtems-task-variable-add.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/runtime_c.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signal_unix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sigqueue.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-linux.Plo@am__quote@
@@ -1650,13 +1595,6 @@ libgolibbegin_a-go-libmain.obj: runtime/go-libmain.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -c -o libgolibbegin_a-go-libmain.obj `if test -f 'runtime/go-libmain.c'; then $(CYGPATH_W) 'runtime/go-libmain.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-libmain.c'; fi`
-go-append.lo: runtime/go-append.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-append.c' object='go-append.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
-
go-assert.lo: runtime/go-assert.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert.lo -MD -MP -MF $(DEPDIR)/go-assert.Tpo -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-assert.Tpo $(DEPDIR)/go-assert.Plo
@@ -1706,13 +1644,6 @@ go-construct-map.lo: runtime/go-construct-map.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
-go-copy.lo: runtime/go-copy.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-copy.lo -MD -MP -MF $(DEPDIR)/go-copy.Tpo -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-copy.Tpo $(DEPDIR)/go-copy.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-copy.c' object='go-copy.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
-
go-defer.lo: runtime/go-defer.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-defer.lo -MD -MP -MF $(DEPDIR)/go-defer.Tpo -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-defer.Tpo $(DEPDIR)/go-defer.Plo
@@ -1741,13 +1672,6 @@ go-fieldtrack.lo: runtime/go-fieldtrack.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
-go-make-slice.lo: runtime/go-make-slice.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-make-slice.lo -MD -MP -MF $(DEPDIR)/go-make-slice.Tpo -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-make-slice.Tpo $(DEPDIR)/go-make-slice.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-make-slice.c' object='go-make-slice.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
-
go-matherr.lo: runtime/go-matherr.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-matherr.lo -MD -MP -MF $(DEPDIR)/go-matherr.Tpo -c -o go-matherr.lo `test -f 'runtime/go-matherr.c' || echo '$(srcdir)/'`runtime/go-matherr.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-matherr.Tpo $(DEPDIR)/go-matherr.Plo
@@ -2035,12 +1959,12 @@ proc.lo: runtime/proc.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc.lo `test -f 'runtime/proc.c' || echo '$(srcdir)/'`runtime/proc.c
-runtime.lo: runtime/runtime.c
-@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT runtime.lo -MD -MP -MF $(DEPDIR)/runtime.Tpo -c -o runtime.lo `test -f 'runtime/runtime.c' || echo '$(srcdir)/'`runtime/runtime.c
-@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/runtime.Tpo $(DEPDIR)/runtime.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/runtime.c' object='runtime.lo' libtool=yes @AMDEPBACKSLASH@
+runtime_c.lo: runtime/runtime_c.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT runtime_c.lo -MD -MP -MF $(DEPDIR)/runtime_c.Tpo -c -o runtime_c.lo `test -f 'runtime/runtime_c.c' || echo '$(srcdir)/'`runtime/runtime_c.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/runtime_c.Tpo $(DEPDIR)/runtime_c.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/runtime_c.c' object='runtime_c.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o runtime.lo `test -f 'runtime/runtime.c' || echo '$(srcdir)/'`runtime/runtime.c
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o runtime_c.lo `test -f 'runtime/runtime_c.c' || echo '$(srcdir)/'`runtime/runtime_c.c
signal_unix.lo: runtime/signal_unix.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT signal_unix.lo -MD -MP -MF $(DEPDIR)/signal_unix.Tpo -c -o signal_unix.lo `test -f 'runtime/signal_unix.c' || echo '$(srcdir)/'`runtime/signal_unix.c
@@ -3321,6 +3245,16 @@ s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
$(SHELL) $(srcdir)/mvifdiff.sh tmp-runtime_sysinfo.go runtime_sysinfo.go
$(STAMP) $@
+runtime.inc: s-runtime-inc; @true
+s-runtime-inc: runtime.lo Makefile
+ rm -f runtime.inc.tmp2
+ grep -v "#define _" runtime.inc.tmp | grep -v "#define c[01] " > runtime.inc.tmp2
+ for pattern in '_[GP][a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
+ grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
+ done
+ $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
+ $(STAMP) $@
+
# Generate the list of go std packages that were included in libgo
zstdpkglist.go: s-zstdpkglist; @true
s-zstdpkglist: Makefile
@@ -3328,7 +3262,7 @@ s-zstdpkglist: Makefile
echo 'package main' > zstdpkglist.go.tmp
echo "" >> zstdpkglist.go.tmp
echo 'var stdpkg = map[string]bool{' >> zstdpkglist.go.tmp
- echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | sed 's/\.lo/\": true,/' | sed 's/-go//' | grep -v _c | sed 's/^/\t\"/' | sort | uniq >> zstdpkglist.go.tmp
+ echo $(libgo_go_objs) 'unsafe.lo' 'runtime/cgo.lo' | sed 's/\.lo /\": true,\n/g' | grep -v _c | sed 's/\.lo/\": true,/' | sed 's/^/\t\"/' | sort -u >> zstdpkglist.go.tmp
echo '}' >> zstdpkglist.go.tmp
$(SHELL) $(srcdir)/mvifdiff.sh zstdpkglist.go.tmp zstdpkglist.go
$(STAMP) $@
@@ -3410,1818 +3344,89 @@ $(libgobegin_a_OBJECTS): runtime.inc
$(libgobegin_llgo_a_OBJECTS): runtime.inc
$(libgolibbegin_a_OBJECTS): runtime.inc
-@go_include@ bufio.lo.dep
-bufio.lo.dep: $(srcdir)/go/bufio/*.go
- $(BUILDDEPS)
-bufio.lo:
- $(BUILDPACKAGE)
-bufio/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bufio/check
-
-@go_include@ bytes.lo.dep
-bytes.lo.dep: $(srcdir)/go/bytes/*.go
- $(BUILDDEPS)
-bytes.lo:
- $(BUILDPACKAGE)
+# PACKAGE_template defines the rules for each package.
+# For example, for the package bufio, it produces:
+#
+# @go_include@ bufio.lo.dep
+# bufio.lo.dep: $(srcdir)/go/bufio/*.go
+# $(BUILDDEPS)
+# bufio.lo:
+# $(BUILDPACKAGE)
+# bufio/check: $(CHECK_DEPS)
+# @$(CHECK)
+# .PHONY: bufio/check
+#
+# This is invoked with $(1) set to a package, which is a directory name,
+# such as "bufio" or "archive/tar".
+define PACKAGE_template
+@go_include@ $(1).lo.dep
+$(1).lo.dep: $(srcdir)/go/$(1)/*.go
+ $$(BUILDDEPS)
+$(1).lo:
+ $$(BUILDPACKAGE)
+$(1)/check: $$(CHECK_DEPS)
+ @$$(CHECK)
+.PHONY: $(1)/check
+$(1).gox: $(1).s-gox; @true
+$(1).s-gox: $(1).lo
+ $$(BUILDGOX)
+ $$(STAMP) $$@
+endef
+
+# This line expands PACKAGE_template once for each package name listed
+# in $(PACKAGES).
+$(foreach package,$(PACKAGES),$(eval $(call PACKAGE_template,$(package))))
+runtime.lo.dep: $(extra_go_files_runtime)
+syscall.lo.dep: $(extra_go_files_syscall)
+runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys)
+
+# FIXME: The following C files may as well move to the runtime
+# directory and be treated like other C files.
+
+# Use C code to speed up {bytes,strings}.IndexByte and friends.
bytes/index.lo: go/bytes/indexbyte.c runtime.inc
@$(MKDIR_P) bytes
- $(LTCOMPILE) -c -o bytes/index.lo $(srcdir)/go/bytes/indexbyte.c
-bytes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: bytes/check
-
-@go_include@ context.lo.dep
-context.lo.dep: $(srcdir)/go/context/*.go
- $(BUILDDEPS)
-context.lo:
- $(BUILDPACKAGE)
-context/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: context/check
-
-@go_include@ crypto.lo.dep
-crypto.lo.dep: $(srcdir)/go/crypto/*.go
- $(BUILDDEPS)
-crypto.lo:
- $(BUILDPACKAGE)
-crypto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/check
-
-@go_include@ encoding.lo.dep
-encoding.lo.dep: $(srcdir)/go/encoding/*.go
- $(BUILDDEPS)
-encoding.lo:
- $(BUILDPACKAGE)
-encoding/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/check
-
-@go_include@ errors.lo.dep
-errors.lo.dep: $(srcdir)/go/errors/*.go
- $(BUILDDEPS)
-errors.lo:
- $(BUILDPACKAGE)
-errors/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: errors/check
-
-@go_include@ expvar.lo.dep
-expvar.lo.dep: $(srcdir)/go/expvar/*.go
- $(BUILDDEPS)
-expvar.lo:
- $(BUILDPACKAGE)
-expvar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: expvar/check
-
-@go_include@ flag.lo.dep
-flag.lo.dep: $(srcdir)/go/flag/*.go
- $(BUILDDEPS)
-flag.lo:
- $(BUILDPACKAGE)
-flag/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: flag/check
-
-@go_include@ fmt.lo.dep
-fmt.lo.dep: $(srcdir)/go/fmt/*.go
- $(BUILDDEPS)
-fmt.lo:
- $(BUILDPACKAGE)
-fmt/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: fmt/check
-
-@go_include@ hash.lo.dep
-hash.lo.dep: $(srcdir)/go/hash/*.go
- $(BUILDDEPS)
-hash.lo:
- $(BUILDPACKAGE)
-hash/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/check
-
-@go_include@ html.lo.dep
-html.lo.dep: $(srcdir)/go/html/*.go
- $(BUILDDEPS)
-html.lo:
- $(BUILDPACKAGE)
-html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/check
-
-@go_include@ image.lo.dep
-image.lo.dep: $(srcdir)/go/image/*.go
- $(BUILDDEPS)
-image.lo:
- $(BUILDPACKAGE)
-image/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/check
-
-@go_include@ io.lo.dep
-io.lo.dep: $(srcdir)/go/io/*.go
- $(BUILDDEPS)
-io.lo:
- $(BUILDPACKAGE)
-io/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/check
-
-@go_include@ log.lo.dep
-log.lo.dep: $(srcdir)/go/log/*.go
- $(BUILDDEPS)
-log.lo:
- $(BUILDPACKAGE)
-log/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/check
-
-@go_include@ math.lo.dep
-math.lo.dep: $(srcdir)/go/math/*.go
- $(BUILDDEPS)
-math.lo:
- $(MKDIR_P) $(@D)
- files=`echo $^ | sed -e 's/[^ ]*\.gox//g'`; \
- $(LTGOCOMPILE) $(MATH_FLAG) -I . -c -fgo-pkgpath=math -o $@ $$files
-math/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/check
-
-@go_include@ mime.lo.dep
-mime.lo.dep: $(srcdir)/go/mime/*.go
- $(BUILDDEPS)
-mime.lo:
- $(BUILDPACKAGE)
-mime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/check
-
-@go_include@ net.lo.dep
-net.lo.dep: $(srcdir)/go/net/*.go
- $(BUILDDEPS)
-net.lo:
- $(BUILDPACKAGE)
-net/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/check
-
-@go_include@ netgo.o.dep
-netgo.o.dep: $(srcdir)/go/net/*.go
- $(BUILDNETGODEPS)
-netgo.o: netgo.o.dep
- $(BUILDNETGO)
-
-@go_include@ os.lo.dep
-os.lo.dep: $(srcdir)/go/os/*.go
- $(BUILDDEPS)
-os.lo:
- $(BUILDPACKAGE)
-os/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/check
-
-@go_include@ path.lo.dep
-path.lo.dep: $(srcdir)/go/path/*.go
- $(BUILDDEPS)
-path.lo:
- $(BUILDPACKAGE)
-path/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/check
-
-@go_include@ reflect-go.lo.dep
-reflect-go.lo.dep: $(srcdir)/go/reflect/*.go
- $(BUILDDEPS)
-reflect-go.lo:
- $(BUILDPACKAGE)
-reflect/check: $(CHECK_DEPS)
- @$(CHECK)
-reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
- @$(MKDIR_P) reflect
- $(LTCOMPILE) -c -o $@ $<
-.PHONY: reflect/check
-
-@go_include@ regexp.lo.dep
-regexp.lo.dep: $(srcdir)/go/regexp/*.go
- $(BUILDDEPS)
-regexp.lo:
- $(BUILDPACKAGE)
-regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/check
-
-@go_include@ runtime-go.lo.dep
-runtime-go.lo.dep: $(srcdir)/go/runtime/*.go $(extra_go_files_runtime)
- $(BUILDDEPS)
-runtime-go.lo:
- $(BUILDPACKAGE)
-runtime.inc: s-runtime-inc; @true
-s-runtime-inc: runtime-go.lo Makefile
- rm -f runtime.inc.tmp2
- grep -v "#define _" runtime.inc.tmp | grep -v "#define c0 " | grep -v "#define c1 " > runtime.inc.tmp2
- for pattern in '_G[a-z]' '_P[a-z]' _Max _Lock _Sig _Trace _MHeap _Num; do \
- grep "#define $$pattern" runtime.inc.tmp >> runtime.inc.tmp2; \
- done
- $(SHELL) $(srcdir)/mvifdiff.sh runtime.inc.tmp2 runtime.inc
- $(STAMP) $@
-runtime/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/check
-
-@go_include@ sort.lo.dep
-sort.lo.dep: $(srcdir)/go/sort/*.go
- $(BUILDDEPS)
-sort.lo:
- $(BUILDPACKAGE)
-sort/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sort/check
-
-@go_include@ strconv.lo.dep
-strconv.lo.dep: $(srcdir)/go/strconv/*.go
- $(BUILDDEPS)
-strconv.lo:
- $(BUILDPACKAGE)
-strconv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strconv/check
-
-@go_include@ strings.lo.dep
-strings.lo.dep: $(srcdir)/go/strings/*.go
- $(BUILDDEPS)
-strings.lo:
- $(BUILDPACKAGE)
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/bytes/indexbyte.c
strings/index.lo: go/strings/indexbyte.c runtime.inc
@$(MKDIR_P) strings
- $(LTCOMPILE) -c -o strings/index.lo $(srcdir)/go/strings/indexbyte.c
-strings/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: strings/check
-
-@go_include@ sync.lo.dep
-sync.lo.dep: $(srcdir)/go/sync/*.go
- $(BUILDDEPS)
-sync.lo:
- $(BUILDPACKAGE)
-sync/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/check
-
-@go_include@ testing.lo.dep
-testing.lo.dep: $(srcdir)/go/testing/*.go
- $(BUILDDEPS)
-testing.lo:
- $(BUILDPACKAGE)
-testing/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/check
-
-@go_include@ time-go.lo.dep
-time-go.lo.dep: $(srcdir)/go/time/*.go
- $(BUILDDEPS)
-time-go.lo:
- $(BUILDPACKAGE)
-time/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: time/check
-
-@go_include@ unicode.lo.dep
-unicode.lo.dep: $(srcdir)/go/unicode/*.go
- $(BUILDDEPS)
-unicode.lo:
- $(BUILDPACKAGE)
-unicode/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/check
-
-@go_include@ archive/tar.lo.dep
-archive/tar.lo.dep: $(srcdir)/go/archive/tar/*.go
- $(BUILDDEPS)
-archive/tar.lo:
- $(BUILDPACKAGE)
-archive/tar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/tar/check
-
-@go_include@ archive/zip.lo.dep
-archive/zip.lo.dep: $(srcdir)/go/archive/zip/*.go
- $(BUILDDEPS)
-archive/zip.lo:
- $(BUILDPACKAGE)
-archive/zip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: archive/zip/check
-
-@go_include@ compress/bzip2.lo.dep
-compress/bzip2.lo.dep: $(srcdir)/go/compress/bzip2/*.go
- $(BUILDDEPS)
-compress/bzip2.lo:
- $(BUILDPACKAGE)
-compress/bzip2/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/bzip2/check
-
-@go_include@ compress/flate.lo.dep
-compress/flate.lo.dep: $(srcdir)/go/compress/flate/*.go
- $(BUILDDEPS)
-compress/flate.lo:
- $(BUILDPACKAGE)
-compress/flate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/flate/check
-
-@go_include@ compress/gzip.lo.dep
-compress/gzip.lo.dep: $(srcdir)/go/compress/gzip/*.go
- $(BUILDDEPS)
-compress/gzip.lo:
- $(BUILDPACKAGE)
-compress/gzip/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/gzip/check
-
-@go_include@ compress/lzw.lo.dep
-compress/lzw.lo.dep: $(srcdir)/go/compress/lzw/*.go
- $(BUILDDEPS)
-compress/lzw.lo:
- $(BUILDPACKAGE)
-compress/lzw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/lzw/check
-
-@go_include@ compress/zlib.lo.dep
-compress/zlib.lo.dep: $(srcdir)/go/compress/zlib/*.go
- $(BUILDDEPS)
-compress/zlib.lo:
- $(BUILDPACKAGE)
-compress/zlib/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: compress/zlib/check
-
-@go_include@ container/heap.lo.dep
-container/heap.lo.dep: $(srcdir)/go/container/heap/*.go
- $(BUILDDEPS)
-container/heap.lo:
- $(BUILDPACKAGE)
-container/heap/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/heap/check
-
-@go_include@ container/list.lo.dep
-container/list.lo.dep: $(srcdir)/go/container/list/*.go
- $(BUILDDEPS)
-container/list.lo:
- $(BUILDPACKAGE)
-container/list/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/list/check
-
-@go_include@ container/ring.lo.dep
-container/ring.lo.dep: $(srcdir)/go/container/ring/*.go
- $(BUILDDEPS)
-container/ring.lo:
- $(BUILDPACKAGE)
-container/ring/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: container/ring/check
-
-@go_include@ crypto/aes.lo.dep
-crypto/aes.lo.dep: $(srcdir)/go/crypto/aes/*.go
- $(BUILDDEPS)
-crypto/aes.lo:
- $(BUILDPACKAGE)
-crypto/aes/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/aes/check
-
-@go_include@ crypto/cipher.lo.dep
-crypto/cipher.lo.dep: $(srcdir)/go/crypto/cipher/*.go
- $(BUILDDEPS)
-crypto/cipher.lo:
- $(BUILDPACKAGE)
-crypto/cipher/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/cipher/check
-
-@go_include@ crypto/des.lo.dep
-crypto/des.lo.dep: $(srcdir)/go/crypto/des/*.go
- $(BUILDDEPS)
-crypto/des.lo:
- $(BUILDPACKAGE)
-crypto/des/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/des/check
-
-@go_include@ crypto/dsa.lo.dep
-crypto/dsa.lo.dep: $(srcdir)/go/crypto/dsa/*.go
- $(BUILDDEPS)
-crypto/dsa.lo:
- $(BUILDPACKAGE)
-crypto/dsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/dsa/check
-
-@go_include@ crypto/ecdsa.lo.dep
-crypto/ecdsa.lo.dep: $(srcdir)/go/crypto/ecdsa/*.go
- $(BUILDDEPS)
-crypto/ecdsa.lo:
- $(BUILDPACKAGE)
-crypto/ecdsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/ecdsa/check
-
-@go_include@ crypto/elliptic.lo.dep
-crypto/elliptic.lo.dep: $(srcdir)/go/crypto/elliptic/*.go
- $(BUILDDEPS)
-crypto/elliptic.lo:
- $(BUILDPACKAGE)
-crypto/elliptic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/elliptic/check
-
-@go_include@ crypto/hmac.lo.dep
-crypto/hmac.lo.dep: $(srcdir)/go/crypto/hmac/*.go
- $(BUILDDEPS)
-crypto/hmac.lo:
- $(BUILDPACKAGE)
-crypto/hmac/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/hmac/check
-
-@go_include@ crypto/md5.lo.dep
-crypto/md5.lo.dep: $(srcdir)/go/crypto/md5/*.go
- $(BUILDDEPS)
-crypto/md5.lo:
- $(BUILDPACKAGE)
-crypto/md5/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/md5/check
-
-@go_include@ crypto/rand.lo.dep
-crypto/rand.lo.dep: $(srcdir)/go/crypto/rand/*.go
- $(BUILDDEPS)
-crypto/rand.lo:
- $(BUILDPACKAGE)
-crypto/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rand/check
-
-@go_include@ crypto/rc4.lo.dep
-crypto/rc4.lo.dep: $(srcdir)/go/crypto/rc4/*.go
- $(BUILDDEPS)
-crypto/rc4.lo:
- $(BUILDPACKAGE)
-crypto/rc4/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rc4/check
-
-@go_include@ crypto/rsa.lo.dep
-crypto/rsa.lo.dep: $(srcdir)/go/crypto/rsa/*.go
- $(BUILDDEPS)
-crypto/rsa.lo:
- $(BUILDPACKAGE)
-crypto/rsa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/rsa/check
-
-@go_include@ crypto/sha1.lo.dep
-crypto/sha1.lo.dep: $(srcdir)/go/crypto/sha1/*.go
- $(BUILDDEPS)
-crypto/sha1.lo:
- $(BUILDPACKAGE)
-crypto/sha1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha1/check
-
-@go_include@ crypto/sha256.lo.dep
-crypto/sha256.lo.dep: $(srcdir)/go/crypto/sha256/*.go
- $(BUILDDEPS)
-crypto/sha256.lo:
- $(BUILDPACKAGE)
-crypto/sha256/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha256/check
-
-@go_include@ crypto/sha512.lo.dep
-crypto/sha512.lo.dep: $(srcdir)/go/crypto/sha512/*.go
- $(BUILDDEPS)
-crypto/sha512.lo:
- $(BUILDPACKAGE)
-crypto/sha512/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/sha512/check
-
-@go_include@ crypto/subtle.lo.dep
-crypto/subtle.lo.dep: $(srcdir)/go/crypto/subtle/*.go
- $(BUILDDEPS)
-crypto/subtle.lo:
- $(BUILDPACKAGE)
-crypto/subtle/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/subtle/check
-
-@go_include@ crypto/tls.lo.dep
-crypto/tls.lo.dep: $(srcdir)/go/crypto/tls/*.go
- $(BUILDDEPS)
-crypto/tls.lo:
- $(BUILDPACKAGE)
-crypto/tls/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/tls/check
-
-@go_include@ crypto/x509.lo.dep
-crypto/x509.lo.dep: $(srcdir)/go/crypto/x509/*.go
- $(BUILDDEPS)
-crypto/x509.lo:
- $(BUILDPACKAGE)
-crypto/x509/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/check
-
-@go_include@ crypto/x509/pkix.lo.dep
-crypto/x509/pkix.lo.dep: $(srcdir)/go/crypto/x509/pkix/*.go
- $(BUILDDEPS)
-crypto/x509/pkix.lo:
- $(BUILDPACKAGE)
-crypto/x509/pkix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: crypto/x509/pkix/check
-
-@go_include@ database/sql.lo.dep
-database/sql.lo.dep: $(srcdir)/go/database/sql/*.go
- $(BUILDDEPS)
-database/sql.lo:
- $(BUILDPACKAGE)
-database/sql/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/check
-
-@go_include@ database/sql/driver.lo.dep
-database/sql/driver.lo.dep: $(srcdir)/go/database/sql/driver/*.go
- $(BUILDDEPS)
-database/sql/driver.lo:
- $(BUILDPACKAGE)
-database/sql/driver/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: database/sql/driver/check
-
-@go_include@ debug/dwarf.lo.dep
-debug/dwarf.lo.dep: $(srcdir)/go/debug/dwarf/*.go
- $(BUILDDEPS)
-debug/dwarf.lo:
- $(BUILDPACKAGE)
-debug/dwarf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/dwarf/check
-
-@go_include@ debug/elf.lo.dep
-debug/elf.lo.dep: $(srcdir)/go/debug/elf/*.go
- $(BUILDDEPS)
-debug/elf.lo:
- $(BUILDPACKAGE)
-debug/elf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/elf/check
-
-@go_include@ debug/gosym.lo.dep
-debug/gosym.lo.dep: $(srcdir)/go/debug/gosym/*.go
- $(BUILDDEPS)
-debug/gosym.lo:
- $(BUILDPACKAGE)
-debug/gosym/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/gosym/check
-
-@go_include@ debug/macho.lo.dep
-debug/macho.lo.dep: $(srcdir)/go/debug/macho/*.go
- $(BUILDDEPS)
-debug/macho.lo:
- $(BUILDPACKAGE)
-debug/macho/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/macho/check
-
-@go_include@ debug/pe.lo.dep
-debug/pe.lo.dep: $(srcdir)/go/debug/pe/*.go
- $(BUILDDEPS)
-debug/pe.lo:
- $(BUILDPACKAGE)
-debug/pe/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/pe/check
-
-@go_include@ debug/plan9obj.lo.dep
-debug/plan9obj.lo.dep: $(srcdir)/go/debug/plan9obj/*.go
- $(BUILDDEPS)
-debug/plan9obj.lo:
- $(BUILDPACKAGE)
-debug/plan9obj/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: debug/plan9obj/check
-
-@go_include@ encoding/asn1.lo.dep
-encoding/asn1.lo.dep: $(srcdir)/go/encoding/asn1/*.go
- $(BUILDDEPS)
-encoding/asn1.lo:
- $(BUILDPACKAGE)
-encoding/asn1/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/asn1/check
-
-@go_include@ encoding/ascii85.lo.dep
-encoding/ascii85.lo.dep: $(srcdir)/go/encoding/ascii85/*.go
- $(BUILDDEPS)
-encoding/ascii85.lo:
- $(BUILDPACKAGE)
-encoding/ascii85/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/ascii85/check
-
-@go_include@ encoding/base32.lo.dep
-encoding/base32.lo.dep: $(srcdir)/go/encoding/base32/*.go
- $(BUILDDEPS)
-encoding/base32.lo:
- $(BUILDPACKAGE)
-encoding/base32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base32/check
-
-@go_include@ encoding/base64.lo.dep
-encoding/base64.lo.dep: $(srcdir)/go/encoding/base64/*.go
- $(BUILDDEPS)
-encoding/base64.lo:
- $(BUILDPACKAGE)
-encoding/base64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/base64/check
-
-@go_include@ encoding/binary.lo.dep
-encoding/binary.lo.dep: $(srcdir)/go/encoding/binary/*.go
- $(BUILDDEPS)
-encoding/binary.lo:
- $(BUILDPACKAGE)
-encoding/binary/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/binary/check
-
-@go_include@ encoding/csv.lo.dep
-encoding/csv.lo.dep: $(srcdir)/go/encoding/csv/*.go
- $(BUILDDEPS)
-encoding/csv.lo:
- $(BUILDPACKAGE)
-encoding/csv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/csv/check
-
-@go_include@ encoding/gob.lo.dep
-encoding/gob.lo.dep: $(srcdir)/go/encoding/gob/*.go
- $(BUILDDEPS)
-encoding/gob.lo:
- $(BUILDPACKAGE)
-encoding/gob/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/gob/check
-
-@go_include@ encoding/hex.lo.dep
-encoding/hex.lo.dep: $(srcdir)/go/encoding/hex/*.go
- $(BUILDDEPS)
-encoding/hex.lo:
- $(BUILDPACKAGE)
-encoding/hex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/hex/check
-
-@go_include@ encoding/json.lo.dep
-encoding/json.lo.dep: $(srcdir)/go/encoding/json/*.go
- $(BUILDDEPS)
-encoding/json.lo:
- $(BUILDPACKAGE)
-encoding/json/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/json/check
-
-@go_include@ encoding/pem.lo.dep
-encoding/pem.lo.dep: $(srcdir)/go/encoding/pem/*.go
- $(BUILDDEPS)
-encoding/pem.lo:
- $(BUILDPACKAGE)
-encoding/pem/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/pem/check
-
-@go_include@ encoding/xml.lo.dep
-encoding/xml.lo.dep: $(srcdir)/go/encoding/xml/*.go
- $(BUILDDEPS)
-encoding/xml.lo:
- $(BUILDPACKAGE)
-encoding/xml/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: encoding/xml/check
-
-@go_include@ exp/proxy.lo.dep
-exp/proxy.lo.dep: $(srcdir)/go/exp/proxy/*.go
- $(BUILDDEPS)
-exp/proxy.lo:
- $(BUILDPACKAGE)
-exp/proxy/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/proxy/check
-
-@go_include@ exp/terminal.lo.dep
-exp/terminal.lo.dep: $(srcdir)/go/exp/terminal/*.go
- $(BUILDDEPS)
-exp/terminal.lo:
- $(BUILDPACKAGE)
-exp/terminal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/terminal/check
-
-@go_include@ html/template.lo.dep
-html/template.lo.dep: $(srcdir)/go/html/template/*.go
- $(BUILDDEPS)
-html/template.lo:
- $(BUILDPACKAGE)
-html/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: html/template/check
-
-@go_include@ go/ast.lo.dep
-go/ast.lo.dep: $(srcdir)/go/go/ast/*.go
- $(BUILDDEPS)
-go/ast.lo:
- $(BUILDPACKAGE)
-go/ast/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/ast/check
-
-@go_include@ go/build.lo.dep
-go/build.lo.dep: $(srcdir)/go/go/build/*.go
- $(BUILDDEPS)
-go/build.lo:
- $(BUILDPACKAGE)
-go/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/build/check
-
-@go_include@ go/constant.lo.dep
-go/constant.lo.dep: $(srcdir)/go/go/constant/*.go
- $(BUILDDEPS)
-go/constant.lo:
- $(BUILDPACKAGE)
-go/constant/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/constant/check
-
-@go_include@ go/doc.lo.dep
-go/doc.lo.dep: $(srcdir)/go/go/doc/*.go
- $(BUILDDEPS)
-go/doc.lo:
- $(BUILDPACKAGE)
-go/doc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/doc/check
-
-@go_include@ go/format.lo.dep
-go/format.lo.dep: $(srcdir)/go/go/format/*.go
- $(BUILDDEPS)
-go/format.lo:
- $(BUILDPACKAGE)
-go/format/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/format/check
-
-@go_include@ go/importer.lo.dep
-go/importer.lo.dep: $(srcdir)/go/go/importer/*.go
- $(BUILDDEPS)
-go/importer.lo:
- $(BUILDPACKAGE)
-go/importer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/importer/check
-
-@go_include@ go/parser.lo.dep
-go/parser.lo.dep: $(srcdir)/go/go/parser/*.go
- $(BUILDDEPS)
-go/parser.lo:
- $(BUILDPACKAGE)
-go/parser/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/parser/check
-
-@go_include@ go/printer.lo.dep
-go/printer.lo.dep: $(srcdir)/go/go/printer/*.go
- $(BUILDDEPS)
-go/printer.lo:
- $(BUILDPACKAGE)
-go/printer/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/printer/check
-
-@go_include@ go/scanner.lo.dep
-go/scanner.lo.dep: $(srcdir)/go/go/scanner/*.go
- $(BUILDDEPS)
-go/scanner.lo:
- $(BUILDPACKAGE)
-go/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/scanner/check
-
-@go_include@ go/token.lo.dep
-go/token.lo.dep: $(srcdir)/go/go/token/*.go
- $(BUILDDEPS)
-go/token.lo:
- $(BUILDPACKAGE)
-go/token/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/token/check
-
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(srcdir)/go/go/types/*.go
- $(BUILDDEPS)
-go/types.lo:
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
-@go_include@ go/internal/gcimporter.lo.dep
-go/internal/gcimporter.lo.dep: $(srcdir)/go/go/internal/gcimporter/*.go
- $(BUILDDEPS)
-go/internal/gcimporter.lo:
- $(BUILDPACKAGE)
-go/internal/gcimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gcimporter/check
-
-@go_include@ go/internal/gccgoimporter.lo.dep
-go/internal/gccgoimporter.lo.dep: $(srcdir)/go/go/internal/gccgoimporter/*.go
- $(BUILDDEPS)
-go/internal/gccgoimporter.lo:
- $(BUILDPACKAGE)
-go/internal/gccgoimporter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/internal/gccgoimporter/check
-
-@go_include@ golang_org/x/net/http2/hpack.lo.dep
-golang_org/x/net/http2/hpack.lo.dep: $(srcdir)/go/golang_org/x/net/http2/hpack/*.go
- $(BUILDDEPS)
-golang_org/x/net/http2/hpack.lo:
- $(BUILDPACKAGE)
-golang_org/x/net/http2/hpack/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: golang_org/x/net/http2/hpack/check
-
-@go_include@ golang_org/x/net/lex/httplex.lo.dep
-golang_org/x/net/lex/httplex.lo.dep: $(srcdir)/go/golang_org/x/net/lex/httplex/*.go
- $(BUILDDEPS)
-golang_org/x/net/lex/httplex.lo:
- $(BUILDPACKAGE)
-golang_org/x/net/lex/httplex/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: golang_org/x/net/lex/httplex/check
-
-@LIBGO_IS_BSD_TRUE@@go_include@ golang_org/x/net/route.lo.dep
-@LIBGO_IS_BSD_TRUE@golang_org/x/net/route.lo.dep: $(srcdir)/go/golang_org/x/net/route/*.go
-@LIBGO_IS_BSD_TRUE@ $(BUILDDEPS)
-@LIBGO_IS_BSD_TRUE@golang_org/x/net/route.lo:
-@LIBGO_IS_BSD_TRUE@ $(BUILDPACKAGE)
-@LIBGO_IS_BSD_TRUE@golang_org/x/net/route/check: $(CHECK_DEPS)
-@LIBGO_IS_BSD_TRUE@ @$(CHECK)
-
-.PHONY: golang_org/x/net/route/check
-
-@go_include@ hash/adler32.lo.dep
-hash/adler32.lo.dep: $(srcdir)/go/hash/adler32/*.go
- $(BUILDDEPS)
-hash/adler32.lo:
- $(BUILDPACKAGE)
-hash/adler32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/adler32/check
-
-@go_include@ hash/crc32.lo.dep
-hash/crc32.lo.dep: $(srcdir)/go/hash/crc32/*.go
- $(BUILDDEPS)
-hash/crc32.lo:
- $(BUILDPACKAGE)
-hash/crc32/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc32/check
-
-@go_include@ hash/crc64.lo.dep
-hash/crc64.lo.dep: $(srcdir)/go/hash/crc64/*.go
- $(BUILDDEPS)
-hash/crc64.lo:
- $(BUILDPACKAGE)
-hash/crc64/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/crc64/check
-
-@go_include@ hash/fnv.lo.dep
-hash/fnv.lo.dep: $(srcdir)/go/hash/fnv/*.go
- $(BUILDDEPS)
-hash/fnv.lo:
- $(BUILDPACKAGE)
-hash/fnv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: hash/fnv/check
-
-@go_include@ image/color.lo.dep
-image/color.lo.dep: $(srcdir)/go/image/color/*.go
- $(BUILDDEPS)
-image/color.lo:
- $(BUILDPACKAGE)
-image/color/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/check
-
-@go_include@ image/color/palette.lo.dep
-image/color/palette.lo.dep: $(srcdir)/go/image/color/palette/*.go
- $(BUILDDEPS)
-image/color/palette.lo:
- $(BUILDPACKAGE)
-image/color/palette/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/color/palette/check
-
-@go_include@ image/draw.lo.dep
-image/draw.lo.dep: $(srcdir)/go/image/draw/*.go
- $(BUILDDEPS)
-image/draw.lo:
- $(BUILDPACKAGE)
-image/draw/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/draw/check
-
-@go_include@ image/gif.lo.dep
-image/gif.lo.dep: $(srcdir)/go/image/gif/*.go
- $(BUILDDEPS)
-image/gif.lo:
- $(BUILDPACKAGE)
-image/gif/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/gif/check
-
-@go_include@ image/internal/imageutil.lo.dep
-image/internal/imageutil.lo.dep: $(srcdir)/go/image/internal/imageutil/*.go
- $(BUILDDEPS)
-image/internal/imageutil.lo:
- $(BUILDPACKAGE)
-image/internal/imageutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/internal/imageutil/check
-
-@go_include@ image/jpeg.lo.dep
-image/jpeg.lo.dep: $(srcdir)/go/image/jpeg/*.go
- $(BUILDDEPS)
-image/jpeg.lo:
- $(BUILDPACKAGE)
-image/jpeg/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/jpeg/check
-
-@go_include@ image/png.lo.dep
-image/png.lo.dep: $(srcdir)/go/image/png/*.go
- $(BUILDDEPS)
-image/png.lo:
- $(BUILDPACKAGE)
-image/png/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: image/png/check
-
-@go_include@ index/suffixarray.lo.dep
-index/suffixarray.lo.dep: $(srcdir)/go/index/suffixarray/*.go
- $(BUILDDEPS)
-index/suffixarray.lo:
- $(BUILDPACKAGE)
-index/suffixarray/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: index/suffixarray/check
-
-@go_include@ internal/nettrace.lo.dep
-internal/nettrace.lo.dep: $(srcdir)/go/internal/nettrace/*.go
- $(BUILDDEPS)
-internal/nettrace.lo:
- $(BUILDPACKAGE)
-internal/nettrace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/nettrace/check
-
-@go_include@ internal/race.lo.dep
-internal/race.lo.dep: $(srcdir)/go/internal/race/*.go
- $(BUILDDEPS)
-internal/race.lo:
- $(BUILDPACKAGE)
-internal/race/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/race/check
-
-@go_include@ internal/singleflight.lo.dep
-internal/singleflight.lo.dep: $(srcdir)/go/internal/singleflight/*.go
- $(BUILDDEPS)
-internal/singleflight.lo:
- $(BUILDPACKAGE)
-internal/singleflight/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/singleflight/check
-
-@go_include@ internal/syscall/unix.lo.dep
-internal/syscall/unix.lo.dep: $(srcdir)/go/internal/syscall/unix/*.go
- $(BUILDDEPS)
-internal/syscall/unix.lo:
- $(BUILDPACKAGE)
-internal/syscall/unix/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/syscall/unix/check
-
-@go_include@ internal/testenv.lo.dep
-internal/testenv.lo.dep: $(srcdir)/go/internal/testenv/*.go
- $(BUILDDEPS)
-internal/testenv.lo:
- $(BUILDPACKAGE)
-internal/testenv/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/testenv/check
-
-@go_include@ internal/trace.lo.dep
-internal/trace.lo.dep: $(srcdir)/go/internal/trace/*.go
- $(BUILDDEPS)
-internal/trace.lo:
- $(BUILDPACKAGE)
-internal/trace/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: internal/trace/check
-
-@go_include@ io/ioutil.lo.dep
-io/ioutil.lo.dep: $(srcdir)/go/io/ioutil/*.go
- $(BUILDDEPS)
-io/ioutil.lo:
- $(BUILDPACKAGE)
-io/ioutil/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: io/ioutil/check
-
-@go_include@ log/syslog.lo.dep
-log/syslog.lo.dep: $(srcdir)/go/log/syslog/*.go
- $(BUILDDEPS)
-log/syslog.lo:
- $(BUILDPACKAGE)
-log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc log/syslog.lo
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/strings/indexbyte.c
+
+# Use a C function with a fixed number of arguments to call a C
+# varargs function.
+log/syslog/syslog_c.lo: go/log/syslog/syslog_c.c runtime.inc
@$(MKDIR_P) log/syslog
$(LTCOMPILE) -c -o $@ $(srcdir)/go/log/syslog/syslog_c.c
-log/syslog/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: log/syslog/check
-
-@go_include@ math/big.lo.dep
-math/big.lo.dep: $(srcdir)/go/math/big/*.go
- $(BUILDDEPS)
-math/big.lo:
- $(BUILDPACKAGE)
-math/big/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/big/check
-
-@go_include@ math/cmplx.lo.dep
-math/cmplx.lo.dep: $(srcdir)/go/math/cmplx/*.go
- $(BUILDDEPS)
-math/cmplx.lo:
- $(BUILDPACKAGE)
-math/cmplx/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/cmplx/check
-
-@go_include@ math/rand.lo.dep
-math/rand.lo.dep: $(srcdir)/go/math/rand/*.go
- $(BUILDDEPS)
-math/rand.lo:
- $(BUILDPACKAGE)
-math/rand/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: math/rand/check
-
-@go_include@ mime/multipart.lo.dep
-mime/multipart.lo.dep: $(srcdir)/go/mime/multipart/*.go
- $(BUILDDEPS)
-mime/multipart.lo:
- $(BUILDPACKAGE)
-mime/multipart/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/multipart/check
-
-@go_include@ mime/quotedprintable.lo.dep
-mime/quotedprintable.lo.dep: $(srcdir)/go/mime/quotedprintable/*.go
- $(BUILDDEPS)
-mime/quotedprintable.lo:
- $(BUILDPACKAGE)
-mime/quotedprintable/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: mime/quotedprintable/check
-
-@go_include@ net/http.lo.dep
-net/http.lo.dep: $(srcdir)/go/net/http/*.go
- $(BUILDDEPS)
-net/http.lo:
- $(BUILDPACKAGE)
-net/http/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/check
-
-@go_include@ net/mail.lo.dep
-net/mail.lo.dep: $(srcdir)/go/net/mail/*.go
- $(BUILDDEPS)
-net/mail.lo:
- $(BUILDPACKAGE)
-net/mail/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/mail/check
-
-@go_include@ net/rpc.lo.dep
-net/rpc.lo.dep: $(srcdir)/go/net/rpc/*.go
- $(BUILDDEPS)
-net/rpc.lo:
- $(BUILDPACKAGE)
-net/rpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/check
-
-@go_include@ net/smtp.lo.dep
-net/smtp.lo.dep: $(srcdir)/go/net/smtp/*.go
- $(BUILDDEPS)
-net/smtp.lo:
- $(BUILDPACKAGE)
-net/smtp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/smtp/check
-
-@go_include@ net/url.lo.dep
-net/url.lo.dep: $(srcdir)/go/net/url/*.go
- $(BUILDDEPS)
-net/url.lo:
- $(BUILDPACKAGE)
-net/url/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/url/check
-
-@go_include@ net/textproto.lo.dep
-net/textproto.lo.dep: $(srcdir)/go/net/textproto/*.go
- $(BUILDDEPS)
-net/textproto.lo:
- $(BUILDPACKAGE)
-net/textproto/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/textproto/check
-
-@go_include@ net/http/cgi.lo.dep
-net/http/cgi.lo.dep: $(srcdir)/go/net/http/cgi/*.go
- $(BUILDDEPS)
-net/http/cgi.lo:
- $(BUILDPACKAGE)
-net/http/cgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cgi/check
-
-@go_include@ net/http/cookiejar.lo.dep
-net/http/cookiejar.lo.dep: $(srcdir)/go/net/http/cookiejar/*.go
- $(BUILDDEPS)
-net/http/cookiejar.lo:
- $(BUILDPACKAGE)
-net/http/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/cookiejar/check
-
-@go_include@ net/http/fcgi.lo.dep
-net/http/fcgi.lo.dep: $(srcdir)/go/net/http/fcgi/*.go
- $(BUILDDEPS)
-net/http/fcgi.lo:
- $(BUILDPACKAGE)
-net/http/fcgi/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/fcgi/check
-
-@go_include@ net/http/httptest.lo.dep
-net/http/httptest.lo.dep: $(srcdir)/go/net/http/httptest/*.go
- $(BUILDDEPS)
-net/http/httptest.lo:
- $(BUILDPACKAGE)
-net/http/httptest/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptest/check
-
-@go_include@ net/http/httptrace.lo.dep
-net/http/httptrace.lo.dep: $(srcdir)/go/net/http/httptrace/*.go
- $(BUILDDEPS)
-net/http/httptrace.lo:
- $(BUILDPACKAGE)
-net/http/httptrace/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httptrace/check
-
-@go_include@ net/http/httputil.lo.dep
-net/http/httputil.lo.dep: $(srcdir)/go/net/http/httputil/*.go
- $(BUILDDEPS)
-net/http/httputil.lo:
- $(BUILDPACKAGE)
-net/http/httputil/check: $(check_deps)
- @$(CHECK)
-.PHONY: net/http/httputil/check
-
-@go_include@ net/http/internal.lo.dep
-net/http/internal.lo.dep: $(srcdir)/go/net/http/internal/*.go
- $(BUILDDEPS)
-net/http/internal.lo:
- $(BUILDPACKAGE)
-net/http/internal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/internal/check
-
-@go_include@ net/http/pprof.lo.dep
-net/http/pprof.lo.dep: $(srcdir)/go/net/http/pprof/*.go
- $(BUILDDEPS)
-net/http/pprof.lo:
- $(BUILDPACKAGE)
-net/http/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/http/pprof/check
-
-@go_include@ net/internal/socktest.lo.dep
-net/internal/socktest.lo.dep: $(srcdir)/go/net/internal/socktest/*.go
- $(BUILDDEPS)
-net/internal/socktest.lo:
- $(BUILDPACKAGE)
-net/internal/socktest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/internal/socktest/check
-
-@go_include@ net/rpc/jsonrpc.lo.dep
-net/rpc/jsonrpc.lo.dep: $(srcdir)/go/net/rpc/jsonrpc/*.go
- $(BUILDDEPS)
-net/rpc/jsonrpc.lo:
- $(BUILDPACKAGE)
-net/rpc/jsonrpc/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: net/rpc/jsonrpc/check
-
-@go_include@ old/regexp.lo.dep
-old/regexp.lo.dep: $(srcdir)/go/old/regexp/*.go
- $(BUILDDEPS)
-old/regexp.lo:
- $(BUILDPACKAGE)
-old/regexp/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/regexp/check
-
-@go_include@ old/template.lo.dep
-old/template.lo.dep: $(srcdir)/go/old/template/*.go
- $(BUILDDEPS)
-old/template.lo:
- $(BUILDPACKAGE)
-old/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/template/check
-
-@go_include@ os/exec.lo.dep
-os/exec.lo.dep: $(srcdir)/go/os/exec/*.go
- $(BUILDDEPS)
-os/exec.lo:
- $(BUILDPACKAGE)
-os/exec/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/exec/check
-
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(srcdir)/go/os/signal/*.go
- $(BUILDDEPS)
-os/signal.lo:
- $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/signal/check
-
-@go_include@ os/user.lo.dep
-os/user.lo.dep: $(srcdir)/go/os/user/*.go
- $(BUILDDEPS)
-os/user.lo:
- $(BUILDPACKAGE)
-os/user/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: os/user/check
-
-@go_include@ path/filepath.lo.dep
-path/filepath.lo.dep: $(srcdir)/go/path/filepath/*.go
- $(BUILDDEPS)
-path/filepath.lo:
- $(BUILDPACKAGE)
-path/filepath/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: path/filepath/check
-
-@go_include@ regexp/syntax.lo.dep
-regexp/syntax.lo.dep: $(srcdir)/go/regexp/syntax/*.go
- $(BUILDDEPS)
-regexp/syntax.lo:
- $(BUILDPACKAGE)
-regexp/syntax/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: regexp/syntax/check
-
-@go_include@ runtime/debug.lo.dep
-runtime/debug.lo.dep: $(srcdir)/go/runtime/debug/*.go
- $(BUILDDEPS)
-runtime/debug.lo:
- $(BUILDPACKAGE)
-runtime/debug/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/debug/check
-
-@go_include@ runtime/pprof.lo.dep
-runtime/pprof.lo.dep: $(srcdir)/go/runtime/pprof/*.go
- $(BUILDDEPS)
-runtime/pprof.lo:
- $(BUILDPACKAGE)
-runtime/pprof/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/pprof/check
-
-@go_include@ runtime/internal/atomic.lo.dep
-runtime/internal/atomic.lo.dep: $(srcdir)/go/runtime/internal/atomic/*.go
- $(BUILDDEPS)
-runtime/internal/atomic.lo:
- $(BUILDPACKAGE)
-runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc runtime/internal/atomic.lo
+
+# The interface to libffi from the reflect package is written in C.
+reflect/makefunc_ffi_c.lo: go/reflect/makefunc_ffi_c.c runtime.inc
+ @$(MKDIR_P) reflect
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/reflect/makefunc_ffi_c.c
+
+# The atomic functions are written in C.
+runtime/internal/atomic_c.lo: go/runtime/internal/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) runtime/internal
$(LTCOMPILE) -c -o $@ $(srcdir)/go/runtime/internal/atomic/atomic.c
-runtime/internal/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/internal/atomic/check
-
-@go_include@ runtime/internal/sys.lo.dep
-runtime/internal/sys.lo.dep: $(srcdir)/go/runtime/internal/sys/*.go
- $(BUILDDEPS)
-runtime/internal/sys.lo:
- $(BUILDPACKAGE)
-runtime/internal/sys/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: runtime/internal/sys/check
-
-@go_include@ sync/atomic.lo.dep
-sync/atomic.lo.dep: $(srcdir)/go/sync/atomic/*.go
- $(BUILDDEPS)
-sync/atomic.lo:
- $(BUILDPACKAGE)
-sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc sync/atomic.lo
+sync/atomic_c.lo: go/sync/atomic/atomic.c runtime.inc
+ @$(MKDIR_P) sync
$(LTCOMPILE) -c -o $@ $(srcdir)/go/sync/atomic/atomic.c
-sync/atomic/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: sync/atomic/check
-
-@go_include@ text/scanner.lo.dep
-text/scanner.lo.dep: $(srcdir)/go/text/scanner/*.go
- $(BUILDDEPS)
-text/scanner.lo:
- $(BUILDPACKAGE)
-text/scanner/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/scanner/check
-
-@go_include@ text/tabwriter.lo.dep
-text/tabwriter.lo.dep: $(srcdir)/go/text/tabwriter/*.go
- $(BUILDDEPS)
-text/tabwriter.lo:
- $(BUILDPACKAGE)
-text/tabwriter/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/tabwriter/check
-
-@go_include@ text/template.lo.dep
-text/template.lo.dep: $(srcdir)/go/text/template/*.go
- $(BUILDDEPS)
-text/template.lo:
- $(BUILDPACKAGE)
-text/template/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/check
-
-@go_include@ text/template/parse.lo.dep
-text/template/parse.lo.dep: $(srcdir)/go/text/template/parse/*.go
- $(BUILDDEPS)
-text/template/parse.lo:
- $(BUILDPACKAGE)
-text/template/parse/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: text/template/parse/check
-
-@go_include@ testing/iotest.lo.dep
-testing/iotest.lo.dep: $(srcdir)/go/testing/iotest/*.go
- $(BUILDDEPS)
-testing/iotest.lo:
- $(BUILDPACKAGE)
-testing/iotest/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/iotest/check
-
-@go_include@ testing/quick.lo.dep
-testing/quick.lo.dep: $(srcdir)/go/testing/quick/*.go
- $(BUILDDEPS)
-testing/quick.lo:
- $(BUILDPACKAGE)
-testing/quick/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: testing/quick/check
-
-@go_include@ unicode/utf16.lo.dep
-unicode/utf16.lo.dep: $(srcdir)/go/unicode/utf16/*.go
- $(BUILDDEPS)
-unicode/utf16.lo:
- $(BUILDPACKAGE)
-unicode/utf16/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf16/check
-
-@go_include@ unicode/utf8.lo.dep
-unicode/utf8.lo.dep: $(srcdir)/go/unicode/utf8/*.go
- $(BUILDDEPS)
-unicode/utf8.lo:
- $(BUILDPACKAGE)
-unicode/utf8/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: unicode/utf8/check
-
-@go_include@ syscall.lo.dep
-syscall.lo.dep: $(srcdir)/go/syscall/*.go $(extra_go_files_syscall)
- $(BUILDDEPS)
-syscall.lo:
- $(BUILDPACKAGE)
+
+# A few syscall functions are written in C.
syscall/clone_linux.lo: go/syscall/clone_linux.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/clone_linux.c
syscall/errno.lo: go/syscall/errno.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/errno.c
syscall/signame.lo: go/syscall/signame.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/signame.c
syscall/wait.lo: go/syscall/wait.c runtime.inc
@$(MKDIR_P) syscall
- $(LTCOMPILE) -c -o $@ $<
-syscall/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: syscall/check
-
-bufio.gox: bufio.lo
- $(BUILDGOX)
-bytes.gox: bytes.lo
- $(BUILDGOX)
-context.gox: context.lo
- $(BUILDGOX)
-crypto.gox: crypto.lo
- $(BUILDGOX)
-encoding.gox: encoding.lo
- $(BUILDGOX)
-errors.gox: errors.lo
- $(BUILDGOX)
-expvar.gox: expvar.lo
- $(BUILDGOX)
-flag.gox: flag.lo
- $(BUILDGOX)
-fmt.gox: fmt.lo
- $(BUILDGOX)
-hash.gox: hash.lo
- $(BUILDGOX)
-html.gox: html.lo
- $(BUILDGOX)
-image.gox: image.lo
- $(BUILDGOX)
-io.gox: io.lo
- $(BUILDGOX)
-log.gox: log.lo
- $(BUILDGOX)
-math.gox: math.lo
- $(BUILDGOX)
-mime.gox: mime.lo
- $(BUILDGOX)
-net.gox: net.lo
- $(BUILDGOX)
-os.gox: os.lo
- $(BUILDGOX)
-path.gox: path.lo
- $(BUILDGOX)
-reflect.gox: reflect-go.lo
- $(BUILDGOX)
-regexp.gox: regexp.lo
- $(BUILDGOX)
-runtime.gox: runtime-go.lo
- $(BUILDGOX)
-sort.gox: sort.lo
- $(BUILDGOX)
-strconv.gox: strconv.lo
- $(BUILDGOX)
-strings.gox: strings.lo
- $(BUILDGOX)
-sync.gox: sync.lo
- $(BUILDGOX)
-syscall.gox: syscall.lo
- $(BUILDGOX)
-testing.gox: testing.lo
- $(BUILDGOX)
-time.gox: time-go.lo
- $(BUILDGOX)
-unicode.gox: unicode.lo
- $(BUILDGOX)
-
-archive/tar.gox: archive/tar.lo
- $(BUILDGOX)
-archive/zip.gox: archive/zip.lo
- $(BUILDGOX)
-
-compress/bzip2.gox: compress/bzip2.lo
- $(BUILDGOX)
-compress/flate.gox: compress/flate.lo
- $(BUILDGOX)
-compress/gzip.gox: compress/gzip.lo
- $(BUILDGOX)
-compress/lzw.gox: compress/lzw.lo
- $(BUILDGOX)
-compress/zlib.gox: compress/zlib.lo
- $(BUILDGOX)
-
-container/heap.gox: container/heap.lo
- $(BUILDGOX)
-container/list.gox: container/list.lo
- $(BUILDGOX)
-container/ring.gox: container/ring.lo
- $(BUILDGOX)
-
-crypto/aes.gox: crypto/aes.lo
- $(BUILDGOX)
-crypto/cipher.gox: crypto/cipher.lo
- $(BUILDGOX)
-crypto/des.gox: crypto/des.lo
- $(BUILDGOX)
-crypto/dsa.gox: crypto/dsa.lo
- $(BUILDGOX)
-crypto/ecdsa.gox: crypto/ecdsa.lo
- $(BUILDGOX)
-crypto/elliptic.gox: crypto/elliptic.lo
- $(BUILDGOX)
-crypto/hmac.gox: crypto/hmac.lo
- $(BUILDGOX)
-crypto/md5.gox: crypto/md5.lo
- $(BUILDGOX)
-crypto/rand.gox: crypto/rand.lo
- $(BUILDGOX)
-crypto/rc4.gox: crypto/rc4.lo
- $(BUILDGOX)
-crypto/rsa.gox: crypto/rsa.lo
- $(BUILDGOX)
-crypto/sha1.gox: crypto/sha1.lo
- $(BUILDGOX)
-crypto/sha256.gox: crypto/sha256.lo
- $(BUILDGOX)
-crypto/sha512.gox: crypto/sha512.lo
- $(BUILDGOX)
-crypto/subtle.gox: crypto/subtle.lo
- $(BUILDGOX)
-crypto/tls.gox: crypto/tls.lo
- $(BUILDGOX)
-crypto/x509.gox: crypto/x509.lo
- $(BUILDGOX)
-
-crypto/x509/pkix.gox: crypto/x509/pkix.lo
- $(BUILDGOX)
-
-database/sql.gox: database/sql.lo
- $(BUILDGOX)
-
-database/sql/driver.gox: database/sql/driver.lo
- $(BUILDGOX)
-
-debug/dwarf.gox: debug/dwarf.lo
- $(BUILDGOX)
-debug/elf.gox: debug/elf.lo
- $(BUILDGOX)
-debug/gosym.gox: debug/gosym.lo
- $(BUILDGOX)
-debug/macho.gox: debug/macho.lo
- $(BUILDGOX)
-debug/pe.gox: debug/pe.lo
- $(BUILDGOX)
-debug/plan9obj.gox: debug/plan9obj.lo
- $(BUILDGOX)
-
-encoding/ascii85.gox: encoding/ascii85.lo
- $(BUILDGOX)
-encoding/asn1.gox: encoding/asn1.lo
- $(BUILDGOX)
-encoding/base32.gox: encoding/base32.lo
- $(BUILDGOX)
-encoding/base64.gox: encoding/base64.lo
- $(BUILDGOX)
-encoding/binary.gox: encoding/binary.lo
- $(BUILDGOX)
-encoding/csv.gox: encoding/csv.lo
- $(BUILDGOX)
-encoding/gob.gox: encoding/gob.lo
- $(BUILDGOX)
-encoding/hex.gox: encoding/hex.lo
- $(BUILDGOX)
-encoding/json.gox: encoding/json.lo
- $(BUILDGOX)
-encoding/pem.gox: encoding/pem.lo
- $(BUILDGOX)
-encoding/xml.gox: encoding/xml.lo
- $(BUILDGOX)
-
-exp/proxy.gox: exp/proxy.lo
- $(BUILDGOX)
-exp/terminal.gox: exp/terminal.lo
- $(BUILDGOX)
-
-html/template.gox: html/template.lo
- $(BUILDGOX)
-
-go/ast.gox: go/ast.lo
- $(BUILDGOX)
-go/build.gox: go/build.lo
- $(BUILDGOX)
-go/constant.gox: go/constant.lo
- $(BUILDGOX)
-go/doc.gox: go/doc.lo
- $(BUILDGOX)
-go/format.gox: go/format.lo
- $(BUILDGOX)
-go/importer.gox: go/importer.lo
- $(BUILDGOX)
-go/parser.gox: go/parser.lo
- $(BUILDGOX)
-go/printer.gox: go/printer.lo
- $(BUILDGOX)
-go/scanner.gox: go/scanner.lo
- $(BUILDGOX)
-go/token.gox: go/token.lo
- $(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
-
-go/internal/gcimporter.gox: go/internal/gcimporter.lo
- $(BUILDGOX)
-go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo
- $(BUILDGOX)
-
-golang_org/x/net/http2/hpack.gox: golang_org/x/net/http2/hpack.lo
- $(BUILDGOX)
-
-golang_org/x/net/lex/httplex.gox: golang_org/x/net/lex/httplex.lo
- $(BUILDGOX)
-
-@LIBGO_IS_BSD_TRUE@golang_org/x/net/route.gox: golang_org/x/net/route.lo
-@LIBGO_IS_BSD_TRUE@ $(BUILDGOX)
-
-hash/adler32.gox: hash/adler32.lo
- $(BUILDGOX)
-hash/crc32.gox: hash/crc32.lo
- $(BUILDGOX)
-hash/crc64.gox: hash/crc64.lo
- $(BUILDGOX)
-hash/fnv.gox: hash/fnv.lo
- $(BUILDGOX)
-
-image/color.gox: image/color.lo
- $(BUILDGOX)
-image/draw.gox: image/draw.lo
- $(BUILDGOX)
-image/gif.gox: image/gif.lo
- $(BUILDGOX)
-image/internal/imageutil.gox: image/internal/imageutil.lo
- $(BUILDGOX)
-image/jpeg.gox: image/jpeg.lo
- $(BUILDGOX)
-image/png.gox: image/png.lo
- $(BUILDGOX)
-
-image/color/palette.gox: image/color/palette.lo
- $(BUILDGOX)
-
-index/suffixarray.gox: index/suffixarray.lo
- $(BUILDGOX)
-
-internal/nettrace.gox: internal/nettrace.lo
- $(BUILDGOX)
-internal/race.gox: internal/race.lo
- $(BUILDGOX)
-internal/singleflight.gox: internal/singleflight.lo
- $(BUILDGOX)
-internal/syscall/unix.gox: internal/syscall/unix.lo
- $(BUILDGOX)
-internal/testenv.gox: internal/testenv.lo
- $(BUILDGOX)
-internal/trace.gox: internal/trace.lo
- $(BUILDGOX)
-
-io/ioutil.gox: io/ioutil.lo
- $(BUILDGOX)
-
-log/syslog.gox: log/syslog.lo
- $(BUILDGOX)
-
-math/big.gox: math/big.lo
- $(BUILDGOX)
-math/cmplx.gox: math/cmplx.lo
- $(BUILDGOX)
-math/rand.gox: math/rand.lo
- $(BUILDGOX)
-
-mime/multipart.gox: mime/multipart.lo
- $(BUILDGOX)
-mime/quotedprintable.gox: mime/quotedprintable.lo
- $(BUILDGOX)
-
-net/http.gox: net/http.lo
- $(BUILDGOX)
-net/mail.gox: net/mail.lo
- $(BUILDGOX)
-net/rpc.gox: net/rpc.lo
- $(BUILDGOX)
-net/smtp.gox: net/smtp.lo
- $(BUILDGOX)
-net/textproto.gox: net/textproto.lo
- $(BUILDGOX)
-net/url.gox: net/url.lo
- $(BUILDGOX)
-
-net/http/cgi.gox: net/http/cgi.lo
- $(BUILDGOX)
-net/http/cookiejar.gox: net/http/cookiejar.lo
- $(BUILDGOX)
-net/http/fcgi.gox: net/http/fcgi.lo
- $(BUILDGOX)
-net/http/httptest.gox: net/http/httptest.lo
- $(BUILDGOX)
-net/http/httptrace.gox: net/http/httptrace.lo
- $(BUILDGOX)
-net/http/httputil.gox: net/http/httputil.lo
- $(BUILDGOX)
-net/http/pprof.gox: net/http/pprof.lo
- $(BUILDGOX)
-
-net/http/internal.gox: net/http/internal.lo
- $(BUILDGOX)
-
-net/internal/socktest.gox: net/internal/socktest.lo
- $(BUILDGOX)
-
-net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
- $(BUILDGOX)
-
-old/regexp.gox: old/regexp.lo
- $(BUILDGOX)
-old/template.gox: old/template.lo
- $(BUILDGOX)
-
-os/exec.gox: os/exec.lo
- $(BUILDGOX)
-os/signal.gox: os/signal.lo
- $(BUILDGOX)
-os/user.gox: os/user.lo
- $(BUILDGOX)
-
-path/filepath.gox: path/filepath.lo
- $(BUILDGOX)
-
-regexp/syntax.gox: regexp/syntax.lo
- $(BUILDGOX)
-
-runtime/debug.gox: runtime/debug.lo
- $(BUILDGOX)
-runtime/pprof.gox: runtime/pprof.lo
- $(BUILDGOX)
-runtime/internal/atomic.gox: runtime/internal/atomic.lo
- $(BUILDGOX)
-runtime/internal/sys.gox: runtime/internal/sys.lo
- $(BUILDGOX)
-
-sync/atomic.gox: sync/atomic.lo
- $(BUILDGOX)
-
-text/scanner.gox: text/scanner.lo
- $(BUILDGOX)
-text/tabwriter.gox: text/tabwriter.lo
- $(BUILDGOX)
-text/template.gox: text/template.lo
- $(BUILDGOX)
-text/template/parse.gox: text/template/parse.lo
- $(BUILDGOX)
-
-testing/iotest.gox: testing/iotest.lo
- $(BUILDGOX)
-testing/quick.gox: testing/quick.lo
- $(BUILDGOX)
-
-unicode/utf16.gox: unicode/utf16.lo
- $(BUILDGOX)
-unicode/utf8.gox: unicode/utf8.lo
- $(BUILDGOX)
+ $(LTCOMPILE) -c -o $@ $(srcdir)/go/syscall/wait.c
+
+# Build golang_org/x/net/route only on BSD systems.
+
+@LIBGO_IS_BSD_TRUE@$(eval $(call PACKAGE_template,golang_org/x/net/route)
check: check-tail
check-recursive: check-head
diff --git a/libgo/configure b/libgo/configure
index 3c866f7f21a..7a9df58c216 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -13677,7 +13677,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
GOARCH=ia64
GOARCH_FAMILY=IA64
GOARCH_CACHELINESIZE=16384
- GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PHYSPAGESIZE=65536
;;
m68k*-*-*)
GOARCH=m68k
diff --git a/libgo/configure.ac b/libgo/configure.ac
index 2951392ed16..ed2edd3b69c 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -254,7 +254,7 @@ GOARCH_HUGEPAGESIZE="1 << 21"
GOARCH=ia64
GOARCH_FAMILY=IA64
GOARCH_CACHELINESIZE=16384
- GOARCH_PHYSPAGESIZE=8192
+ GOARCH_PHYSPAGESIZE=65536
;;
m68k*-*-*)
GOARCH=m68k
diff --git a/libgo/go/runtime/lfstack_32bit.go b/libgo/go/runtime/lfstack_32bit.go
index 6a992000084..bc53b13c414 100644
--- a/libgo/go/runtime/lfstack_32bit.go
+++ b/libgo/go/runtime/lfstack_32bit.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le mipso32 mipsn32 s390 sparc
+// +build 386 arm nacl armbe m68k mips mipsle mips64p32 mips64p32le mipso32 mipsn32 ppc s390 sparc
package runtime
diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go
new file mode 100644
index 00000000000..4548a5b2321
--- /dev/null
+++ b/libgo/go/runtime/slice.go
@@ -0,0 +1,212 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname makeslice runtime.makeslice
+//go:linkname growslice runtime.growslice
+//go:linkname slicecopy runtime.slicecopy
+//go:linkname slicestringcopy runtime.slicestringcopy
+
+type slice struct {
+ array unsafe.Pointer
+ len int
+ cap int
+}
+
+// maxElems is a lookup table containing the maximum capacity for a slice.
+// The index is the size of the slice element.
+var maxElems = [...]uintptr{
+ ^uintptr(0),
+ _MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4,
+ _MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8,
+ _MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12,
+ _MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16,
+ _MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20,
+ _MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24,
+ _MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28,
+ _MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32,
+}
+
+// maxSliceCap returns the maximum capacity for a slice.
+func maxSliceCap(elemsize uintptr) uintptr {
+ if elemsize < uintptr(len(maxElems)) {
+ return maxElems[elemsize]
+ }
+ return _MaxMem / elemsize
+}
+
+// TODO: take uintptrs instead of int64s?
+func makeslice(et *_type, len64, cap64 int64) slice {
+ // NOTE: The len > maxElements check here is not strictly necessary,
+ // but it produces a 'len out of range' error instead of a 'cap out of range' error
+ // when someone does make([]T, bignumber). 'cap out of range' is true too,
+ // but since the cap is only being supplied implicitly, saying len is clearer.
+ // See issue 4085.
+ maxElements := maxSliceCap(et.size)
+ len := int(len64)
+ if len64 < 0 || int64(len) != len64 || uintptr(len) > maxElements {
+ panic(errorString("makeslice: len out of range"))
+ }
+
+ cap := int(cap64)
+ if cap < len || int64(cap) != cap64 || uintptr(cap) > maxElements {
+ panic(errorString("makeslice: cap out of range"))
+ }
+
+ // gccgo's current garbage collector requires using newarray,
+ // not mallocgc here. This can change back to mallocgc when
+ // we port the garbage collector.
+ p := newarray(et, cap)
+ return slice{p, len, cap}
+}
+
+// growslice handles slice growth during append.
+// It is passed the slice element type, the old slice, and the desired new minimum capacity,
+// and it returns a new slice with at least that capacity, with the old data
+// copied into it.
+// The new slice's length is set to the requested capacity.
+func growslice(et *_type, old slice, cap int) slice {
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&et))
+ racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
+ }
+ if msanenabled {
+ msanread(old.array, uintptr(old.len*int(et.size)))
+ }
+
+ if et.size == 0 {
+ if cap < old.cap {
+ panic(errorString("growslice: cap out of range"))
+ }
+ // append should not create a slice with nil pointer but non-zero len.
+ // We assume that append doesn't need to preserve old.array in this case.
+ return slice{unsafe.Pointer(&zerobase), cap, cap}
+ }
+
+ newcap := old.cap
+ doublecap := newcap + newcap
+ if cap > doublecap {
+ newcap = cap
+ } else {
+ if old.len < 1024 {
+ newcap = doublecap
+ } else {
+ for newcap < cap {
+ newcap += newcap / 4
+ }
+ }
+ }
+
+ var lenmem, capmem uintptr
+ const ptrSize = unsafe.Sizeof((*byte)(nil))
+ switch et.size {
+ case 1:
+ lenmem = uintptr(old.len)
+ capmem = roundupsize(uintptr(newcap))
+ newcap = int(capmem)
+ case ptrSize:
+ lenmem = uintptr(old.len) * ptrSize
+ capmem = roundupsize(uintptr(newcap) * ptrSize)
+ newcap = int(capmem / ptrSize)
+ default:
+ lenmem = uintptr(old.len) * et.size
+ capmem = roundupsize(uintptr(newcap) * et.size)
+ newcap = int(capmem / et.size)
+ }
+
+ if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) {
+ panic(errorString("growslice: cap out of range"))
+ }
+
+ var p unsafe.Pointer
+ if et.kind&kindNoPointers != 0 {
+ // gccgo's current GC requires newarray, not mallocgc.
+ p = newarray(et, newcap)
+ memmove(p, old.array, lenmem)
+ // The call to memclr is not needed for gccgo since
+ // the newarray function will zero the memory.
+ // Calling memclr is also wrong since we allocated
+ // newcap*et.size bytes, which is not the same as capmem.
+ // memclr(add(p, lenmem), capmem-lenmem)
+ } else {
+ // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
+ // gccgo's current GC requires newarray, not mallocgc.
+ p = newarray(et, newcap)
+ if !writeBarrier.enabled {
+ memmove(p, old.array, lenmem)
+ } else {
+ for i := uintptr(0); i < lenmem; i += et.size {
+ typedmemmove(et, add(p, i), add(old.array, i))
+ }
+ }
+ }
+
+ return slice{p, cap, newcap}
+}
+
+func slicecopy(to, fm slice, width uintptr) int {
+ if fm.len == 0 || to.len == 0 {
+ return 0
+ }
+
+ n := fm.len
+ if to.len < n {
+ n = to.len
+ }
+
+ if width == 0 {
+ return n
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&to))
+ pc := funcPC(slicecopy)
+ racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
+ racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
+ }
+ if msanenabled {
+ msanwrite(to.array, uintptr(n*int(width)))
+ msanread(fm.array, uintptr(n*int(width)))
+ }
+
+ size := uintptr(n) * width
+ if size == 1 { // common case worth about 2x to do here
+ // TODO: is this still worth it with new memmove impl?
+ *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
+ } else {
+ memmove(to.array, fm.array, size)
+ }
+ return n
+}
+
+func slicestringcopy(to []byte, fm string) int {
+ if len(fm) == 0 || len(to) == 0 {
+ return 0
+ }
+
+ n := len(fm)
+ if len(to) < n {
+ n = len(to)
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&to))
+ pc := funcPC(slicestringcopy)
+ racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
+ }
+ if msanenabled {
+ msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
+ }
+
+ memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
+ return n
+}
diff --git a/libgo/go/runtime/string.go b/libgo/go/runtime/string.go
index 5df3aa3904d..bf5791e06ff 100644
--- a/libgo/go/runtime/string.go
+++ b/libgo/go/runtime/string.go
@@ -444,3 +444,20 @@ func gostringw(strw *uint16) string {
b[n2] = 0 // for luck
return s[:n2]
}
+
+// These two functions are called by code generated by cgo -gccgo.
+
+//go:linkname __go_byte_array_to_string __go_byte_array_to_string
+func __go_byte_array_to_string(p unsafe.Pointer, l int) string {
+ if l == 0 {
+ return ""
+ }
+ s, c := rawstringtmp(nil, l)
+ memmove(unsafe.Pointer(&c[0]), p, uintptr(l))
+ return s
+}
+
+//go:linkname __go_string_to_byte_array __go_string_to_byte_array
+func __go_string_to_byte_array(s string) []byte {
+ return stringtoslicebyte(nil, s)
+}
diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go
index 5924ee63dc7..755933de713 100644
--- a/libgo/go/runtime/stubs.go
+++ b/libgo/go/runtime/stubs.go
@@ -253,11 +253,18 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
memmove(dst, src, typ.size)
}
-// Here for gccgo unless and until we port slice.go.
-type slice struct {
- array unsafe.Pointer
- len int
- cap int
+// Temporary for gccgo until we port mbarrier.go.
+//go:linkname typedslicecopy runtime.typedslicecopy
+func typedslicecopy(typ *_type, dst, src slice) int {
+ n := dst.len
+ if n > src.len {
+ n = src.len
+ }
+ if n == 0 {
+ return 0
+ }
+ memmove(dst.array, src.array, uintptr(n)*typ.size)
+ return n
}
// Here for gccgo until we port malloc.go.
@@ -474,3 +481,11 @@ func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
func writebarrierptr(dst *uintptr, src uintptr) {
*dst = src
}
+
+// Temporary for gccgo until we port malloc.go
+var zerobase uintptr
+
+//go:linkname getZerobase runtime.getZerobase
+func getZerobase() *uintptr {
+ return &zerobase
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index b7ebb372967..c9665ea04b5 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -939,8 +939,11 @@ func TestLoadFixed(t *testing.T) {
// but Go and most other systems use "east is positive".
// So GMT+1 corresponds to -3600 in the Go zone, not +3600.
name, offset := Now().In(loc).Zone()
- if name != "GMT+1" || offset != -1*60*60 {
- t.Errorf("Now().In(loc).Zone() = %q, %d, want %q, %d", name, offset, "GMT+1", -1*60*60)
+ // The zone abbreviation is "-01" since tzdata-2016g, and "GMT+1"
+ // on earlier versions; we accept both. (Issue #17276).
+ if !(name == "GMT+1" || name == "-01") || offset != -1*60*60 {
+ t.Errorf("Now().In(loc).Zone() = %q, %d, want %q or %q, %d",
+ name, offset, "GMT+1", "-01", -1*60*60)
}
}
diff --git a/libgo/mkrsysinfo.sh b/libgo/mkrsysinfo.sh
index ffbbcea39a6..32799d6251b 100755
--- a/libgo/mkrsysinfo.sh
+++ b/libgo/mkrsysinfo.sh
@@ -78,7 +78,7 @@ if grep '^const _epoll_data_offset ' ${OUT} >/dev/null 2>&1; then
fi
fi
# Make sure EPOLLET is positive.
-if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go; then
+if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go > /dev/null 2>&1; then
echo "const _EPOLLETpos = _EPOLLET" >> ${OUT}
else
echo "const _EPOLLETpos = 0x80000000" >> ${OUT}
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index 3640476a434..ec2224db2b4 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -188,7 +188,7 @@ grep '^const _EPOLL' gen-sysinfo.go |
grep -v EPOLLET |
sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
# Make sure EPOLLET is positive.
-if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go; then
+if grep '^const _EPOLLET = [0-9]' gen-sysinfo.go >/dev/null 2>&1; then
grep '^const _EPOLLET ' gen-sysinfo.go |
sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
else
@@ -268,7 +268,7 @@ fi
# is not empty, the structure or type is renamed to $2.
upcase_fields () {
name="$1"
- def=`grep "^type $name" gen-sysinfo.go`
+ def=`grep "^type $name " gen-sysinfo.go`
fields=`echo $def | sed -e 's/^[^{]*{\(.*\)}$/\1/'`
prefix=`echo $def | sed -e 's/{.*//'`
if test "$2" != ""; then
diff --git a/libgo/runtime/go-append.c b/libgo/runtime/go-append.c
deleted file mode 100644
index 1b2d49e53c1..00000000000
--- a/libgo/runtime/go-append.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* go-append.c -- the go builtin append function.
-
- Copyright 2010 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include "runtime.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-/* We should be OK if we don't split the stack here, since the only
- libc functions we call are memcpy and memmove. If we don't do
- this, we will always split the stack, because of memcpy and
- memmove. */
-extern struct __go_open_array
-__go_append (struct __go_open_array, void *, uintptr_t, uintptr_t)
- __attribute__ ((no_split_stack));
-
-struct __go_open_array
-__go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
- uintptr_t element_size)
-{
- uintptr_t ucount;
- intgo count;
-
- if (bvalues == NULL || bcount == 0)
- return a;
-
- ucount = (uintptr_t) a.__count + bcount;
- count = (intgo) ucount;
- if ((uintptr_t) count != ucount || count <= a.__count)
- runtime_panicstring ("append: slice overflow");
-
- if (count > a.__capacity)
- {
- intgo m;
- uintptr capmem;
- void *n;
-
- m = a.__capacity;
- if (m + m < count)
- m = count;
- else
- {
- do
- {
- if (a.__count < 1024)
- m += m;
- else
- m += m / 4;
- }
- while (m < count);
- }
-
- if (element_size > 0 && (uintptr) m > MaxMem / element_size)
- runtime_panicstring ("growslice: cap out of range");
-
- capmem = runtime_roundupsize (m * element_size);
-
- n = __go_alloc (capmem);
- __builtin_memcpy (n, a.__values, a.__count * element_size);
-
- a.__values = n;
- a.__capacity = m;
- }
-
- __builtin_memmove ((char *) a.__values + a.__count * element_size,
- bvalues, bcount * element_size);
- a.__count = count;
- return a;
-}
diff --git a/libgo/runtime/go-copy.c b/libgo/runtime/go-copy.c
deleted file mode 100644
index 05e16acbf1c..00000000000
--- a/libgo/runtime/go-copy.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/* go-append.c -- the go builtin copy function.
-
- Copyright 2010 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stddef.h>
-#include <stdint.h>
-
-/* We should be OK if we don't split the stack here, since we are just
- calling memmove which shouldn't need much stack. If we don't do
- this we will always split the stack, because of memmove. */
-
-extern void
-__go_copy (void *, void *, uintptr_t)
- __attribute__ ((no_split_stack));
-
-void
-__go_copy (void *a, void *b, uintptr_t len)
-{
- __builtin_memmove (a, b, len);
-}
diff --git a/libgo/runtime/go-make-slice.c b/libgo/runtime/go-make-slice.c
deleted file mode 100644
index ccd07e5ac51..00000000000
--- a/libgo/runtime/go-make-slice.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/* go-make-slice.c -- make a slice.
-
- Copyright 2011 The Go Authors. All rights reserved.
- Use of this source code is governed by a BSD-style
- license that can be found in the LICENSE file. */
-
-#include <stdint.h>
-
-#include "runtime.h"
-#include "go-alloc.h"
-#include "go-assert.h"
-#include "go-panic.h"
-#include "go-type.h"
-#include "array.h"
-#include "arch.h"
-#include "malloc.h"
-
-/* Dummy word to use as base pointer for make([]T, 0).
- Since you cannot take the address of such a slice,
- you can't tell that they all have the same base pointer. */
-uintptr runtime_zerobase;
-
-struct __go_open_array
-__go_make_slice2 (const struct __go_type_descriptor *td, uintptr_t len,
- uintptr_t cap)
-{
- const struct __go_slice_type* std;
- intgo ilen;
- intgo icap;
- uintptr_t size;
- struct __go_open_array ret;
-
- __go_assert ((td->__code & GO_CODE_MASK) == GO_SLICE);
- std = (const struct __go_slice_type *) td;
-
- ilen = (intgo) len;
- if (ilen < 0
- || (uintptr_t) ilen != len
- || (std->__element_type->__size > 0
- && len > MaxMem / std->__element_type->__size))
- runtime_panicstring ("makeslice: len out of range");
-
- icap = (intgo) cap;
- if (cap < len
- || (uintptr_t) icap != cap
- || (std->__element_type->__size > 0
- && cap > MaxMem / std->__element_type->__size))
- runtime_panicstring ("makeslice: cap out of range");
-
- ret.__count = ilen;
- ret.__capacity = icap;
-
- size = cap * std->__element_type->__size;
-
- if (size == 0)
- ret.__values = &runtime_zerobase;
- else if ((std->__element_type->__code & GO_NO_POINTERS) != 0)
- ret.__values =
- runtime_mallocgc (size,
- (uintptr) std->__element_type | TypeInfo_Array,
- FlagNoScan);
- else
- ret.__values =
- runtime_mallocgc (size,
- (uintptr) std->__element_type | TypeInfo_Array,
- 0);
-
- return ret;
-}
-
-struct __go_open_array
-__go_make_slice1 (const struct __go_type_descriptor *td, uintptr_t len)
-{
- return __go_make_slice2 (td, len, len);
-}
-
-struct __go_open_array
-__go_make_slice2_big (const struct __go_type_descriptor *td, uint64_t len,
- uint64_t cap)
-{
- uintptr_t slen;
- uintptr_t scap;
-
- slen = (uintptr_t) len;
- if ((uint64_t) slen != len)
- runtime_panicstring ("makeslice: len out of range");
-
- scap = (uintptr_t) cap;
- if ((uint64_t) scap != cap)
- runtime_panicstring ("makeslice: cap out of range");
-
- return __go_make_slice2 (td, slen, scap);
-}
-
-struct __go_open_array
-__go_make_slice1_big (const struct __go_type_descriptor *td, uint64_t len)
-{
- return __go_make_slice2_big (td, len, len);
-}
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index 1fd44614227..5cbdc4632fb 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -81,7 +81,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
// All 0-length allocations use this pointer.
// The language does not require the allocations to
// have distinct values.
- return &runtime_zerobase;
+ return runtime_getZerobase();
}
g = runtime_g();
@@ -881,7 +881,7 @@ func new(typ *Type) (ret *uint8) {
}
static void*
-cnew(const Type *typ, intgo n, int32 objtyp)
+runtime_docnew(const Type *typ, intgo n, int32 objtyp)
{
if((objtyp&(PtrSize-1)) != objtyp)
runtime_throw("runtime: invalid objtyp");
@@ -894,13 +894,13 @@ cnew(const Type *typ, intgo n, int32 objtyp)
void*
runtime_cnew(const Type *typ)
{
- return cnew(typ, 1, TypeInfo_SingleObject);
+ return runtime_docnew(typ, 1, TypeInfo_SingleObject);
}
void*
runtime_cnewarray(const Type *typ, intgo n)
{
- return cnew(typ, n, TypeInfo_Array);
+ return runtime_docnew(typ, n, TypeInfo_Array);
}
func GC() {
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index 8be0df4c17d..501f1b41ace 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -234,7 +234,8 @@ enum
/*
* external data
*/
-extern uintptr runtime_zerobase;
+extern uintptr* runtime_getZerobase(void)
+ __asm__(GOSYM_PREFIX "runtime.getZerobase");
extern G** runtime_allg;
extern uintptr runtime_allglen;
extern G* runtime_lastg;
diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime_c.c
index 16be0891aea..16be0891aea 100644
--- a/libgo/runtime/runtime.c
+++ b/libgo/runtime/runtime_c.c
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 50865d1ca79..a7a52f82f0c 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,16 @@
+2016-11-02 Cesar Philippidis <cesar@codesourcery.com>
+ Nathan Sidwell <nathan@acm.org>
+
+ * plugin/plugin-nvptx.c (nvptx_exec): Interrogate board attributes
+ to determine default geometry.
+ * testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c: Set gang
+ dimension.
+
+2016-11-01 Jakub Jelinek <jakub@redhat.com>
+
+ * hashtab.h: Use standard GPLv3 with runtime exception
+ boilerplate.
+
2016-10-27 Aldy Hernandez <aldyh@redhat.com>
* oacc-init.c (goacc_new_thread): Use sizeof of the appropriate
diff --git a/libgomp/hashtab.h b/libgomp/hashtab.h
index ff439a9ea9e..13a0259f58d 100644
--- a/libgomp/hashtab.h
+++ b/libgomp/hashtab.h
@@ -2,19 +2,27 @@
Copyright (C) 1999-2016 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@cygnus.com>.
-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 of the License, 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, write to the Free Software
-Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ This file is part of the GNU Offloading and Multi Processing Library
+ (libgomp).
+
+ Libgomp 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 3, or (at your option)
+ any later version.
+
+ Libgomp 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
/* The hash table code copied from include/hashtab.[hc] and adjusted,
so that the hash table entries are in the flexible array at the end
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index cfd7b58b845..ca33c51db5a 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -46,6 +46,7 @@
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
+#include <errno.h>
static const char *
cuda_error (CUresult r)
@@ -970,9 +971,88 @@ nvptx_exec (void (*fn), size_t mapnum, void **hostaddrs, void **devaddrs,
if (seen_zero)
{
+ /* See if the user provided GOMP_OPENACC_DIM environment
+ variable to specify runtime defaults. */
+ static int default_dims[GOMP_DIM_MAX];
+
+ pthread_mutex_lock (&ptx_dev_lock);
+ if (!default_dims[0])
+ {
+ /* We only read the environment variable once. You can't
+ change it in the middle of execution. The syntax is
+ the same as for the -fopenacc-dim compilation option. */
+ const char *env_var = getenv ("GOMP_OPENACC_DIM");
+ if (env_var)
+ {
+ const char *pos = env_var;
+
+ for (i = 0; *pos && i != GOMP_DIM_MAX; i++)
+ {
+ if (i && *pos++ != ':')
+ break;
+ if (*pos != ':')
+ {
+ const char *eptr;
+
+ errno = 0;
+ long val = strtol (pos, (char **)&eptr, 10);
+ if (errno || val < 0 || (unsigned)val != val)
+ break;
+ default_dims[i] = (int)val;
+ pos = eptr;
+ }
+ }
+ }
+
+ int warp_size, block_size, dev_size, cpu_size;
+ CUdevice dev = nvptx_thread()->ptx_dev->dev;
+ /* 32 is the default for known hardware. */
+ int gang = 0, worker = 32, vector = 32;
+ CUdevice_attribute cu_tpb, cu_ws, cu_mpc, cu_tpm;
+
+ cu_tpb = CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK;
+ cu_ws = CU_DEVICE_ATTRIBUTE_WARP_SIZE;
+ cu_mpc = CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT;
+ cu_tpm = CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR;
+
+ if (cuDeviceGetAttribute (&block_size, cu_tpb, dev) == CUDA_SUCCESS
+ && cuDeviceGetAttribute (&warp_size, cu_ws, dev) == CUDA_SUCCESS
+ && cuDeviceGetAttribute (&dev_size, cu_mpc, dev) == CUDA_SUCCESS
+ && cuDeviceGetAttribute (&cpu_size, cu_tpm, dev) == CUDA_SUCCESS)
+ {
+ GOMP_PLUGIN_debug (0, " warp_size=%d, block_size=%d,"
+ " dev_size=%d, cpu_size=%d\n",
+ warp_size, block_size, dev_size, cpu_size);
+ gang = (cpu_size / block_size) * dev_size;
+ worker = block_size / warp_size;
+ vector = warp_size;
+ }
+
+ /* There is no upper bound on the gang size. The best size
+ matches the hardware configuration. Logical gangs are
+ scheduled onto physical hardware. To maximize usage, we
+ should guess a large number. */
+ if (default_dims[GOMP_DIM_GANG] < 1)
+ default_dims[GOMP_DIM_GANG] = gang ? gang : 1024;
+ /* The worker size must not exceed the hardware. */
+ if (default_dims[GOMP_DIM_WORKER] < 1
+ || (default_dims[GOMP_DIM_WORKER] > worker && gang))
+ default_dims[GOMP_DIM_WORKER] = worker;
+ /* The vector size must exactly match the hardware. */
+ if (default_dims[GOMP_DIM_VECTOR] < 1
+ || (default_dims[GOMP_DIM_VECTOR] != vector && gang))
+ default_dims[GOMP_DIM_VECTOR] = vector;
+
+ GOMP_PLUGIN_debug (0, " default dimensions [%d,%d,%d]\n",
+ default_dims[GOMP_DIM_GANG],
+ default_dims[GOMP_DIM_WORKER],
+ default_dims[GOMP_DIM_VECTOR]);
+ }
+ pthread_mutex_unlock (&ptx_dev_lock);
+
for (i = 0; i != GOMP_DIM_MAX; i++)
- if (!dims[i])
- dims[i] = /* TODO */ 32;
+ if (!dims[i])
+ dims[i] = default_dims[i];
}
/* This reserves a chunk of a pre-allocated page of memory mapped on both
@@ -992,8 +1072,8 @@ nvptx_exec (void (*fn), size_t mapnum, void **hostaddrs, void **devaddrs,
mapnum * sizeof (void *));
GOMP_PLUGIN_debug (0, " %s: kernel %s: launch"
" gangs=%u, workers=%u, vectors=%u\n",
- __FUNCTION__, targ_fn->launch->fn,
- dims[0], dims[1], dims[2]);
+ __FUNCTION__, targ_fn->launch->fn, dims[GOMP_DIM_GANG],
+ dims[GOMP_DIM_WORKER], dims[GOMP_DIM_VECTOR]);
// OpenACC CUDA
//
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c
index 8a755b88038..3ca9388d405 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-auto-1.c
@@ -2,6 +2,8 @@
not optimized away at -O0, and then confuses the target assembler.
{ dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+/* { dg-additional-options "-fopenacc-dim=32" } */
+
#include <stdio.h>
#include <openacc.h>
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 5934bc1fa8a..727ffd39007 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,33 @@
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ * cp-demangle.c (is_fnqual_component_type): New.
+ (d_encoding, d_print_comp_inner, d_print_mod_list): Use it.
+ (FNQUAL_COMPONENT_CASE): New.
+ (d_make_comp, has_return_type, d_print_comp_inner)
+ (d_print_function_type): Use it.
+ (next_is_type_qual): New.
+ (d_cv_qualifiers, d_print_mod): Handle noexcept and throw-spec.
+
+2016-11-02 Mark Wielaard <mjw@redhat.com>
+
+ * cplus-dem.c (demangle_signature): Move fall through comment.
+ (demangle_fund_type): Add fall through comment between 'G' and 'I'.
+ * hashtab.c (iterative_hash): Add fall through comments.
+ * regex.c (regex_compile): Add Fall through comment after '+'/'?'.
+ (byte_re_match_2_internal): Add Fall through comment after jump_n.
+ Change "Note fall through" to "Fall through".
+ (common_op_match_null_string_p): Return false after set_number_at
+ instead of fall through.
+
+2016-11-01 Jason Merrill <jason@redhat.com>
+
+ * cp-demangle.c (d_ctor_dtor_name): Handle inheriting constructor.
+
+2016-10-31 Mark Wielaard <mjw@redhat.com>
+
+ * cplus-dem.c (ada_demangle): Initialize demangled to NULL and
+ XDELETEVEC demangled when unknown.
+
2016-09-19 Andrew Stubbs <ams@codesourcery.com>
* pex-win32.c (argv_to_cmdline): Quote zero-length parameters.
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index a843dc38f98..e239155c442 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -436,6 +436,8 @@ static struct demangle_component *d_operator_name (struct d_info *);
static struct demangle_component *d_special_name (struct d_info *);
+static struct demangle_component *d_parmlist (struct d_info *);
+
static int d_call_offset (struct d_info *, int);
static struct demangle_component *d_ctor_dtor_name (struct d_info *);
@@ -559,6 +561,32 @@ static int d_demangle_callback (const char *, int,
demangle_callbackref, void *);
static char *d_demangle (const char *, int, size_t *);
+/* True iff TYPE is a demangling component representing a
+ function-type-qualifier. */
+
+static int
+is_fnqual_component_type (enum demangle_component_type type)
+{
+ return (type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || type == DEMANGLE_COMPONENT_CONST_THIS
+ || type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ || type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
+ || type == DEMANGLE_COMPONENT_NOEXCEPT
+ || type == DEMANGLE_COMPONENT_THROW_SPEC
+ || type == DEMANGLE_COMPONENT_REFERENCE_THIS);
+}
+
+#define FNQUAL_COMPONENT_CASE \
+ case DEMANGLE_COMPONENT_RESTRICT_THIS: \
+ case DEMANGLE_COMPONENT_VOLATILE_THIS: \
+ case DEMANGLE_COMPONENT_CONST_THIS: \
+ case DEMANGLE_COMPONENT_REFERENCE_THIS: \
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: \
+ case DEMANGLE_COMPONENT_TRANSACTION_SAFE: \
+ case DEMANGLE_COMPONENT_NOEXCEPT: \
+ case DEMANGLE_COMPONENT_THROW_SPEC
+
#ifdef CP_DEMANGLE_DEBUG
static void
@@ -984,14 +1012,9 @@ d_make_comp (struct d_info *di, enum demangle_component_type type,
case DEMANGLE_COMPONENT_RESTRICT:
case DEMANGLE_COMPONENT_VOLATILE:
case DEMANGLE_COMPONENT_CONST:
- case DEMANGLE_COMPONENT_RESTRICT_THIS:
- case DEMANGLE_COMPONENT_VOLATILE_THIS:
- case DEMANGLE_COMPONENT_CONST_THIS:
- case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
- case DEMANGLE_COMPONENT_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ FNQUAL_COMPONENT_CASE:
break;
/* Other types should not be seen here. */
@@ -1225,12 +1248,7 @@ has_return_type (struct demangle_component *dc)
return 0;
case DEMANGLE_COMPONENT_TEMPLATE:
return ! is_ctor_dtor_or_conversion (d_left (dc));
- case DEMANGLE_COMPONENT_RESTRICT_THIS:
- case DEMANGLE_COMPONENT_VOLATILE_THIS:
- case DEMANGLE_COMPONENT_CONST_THIS:
- case DEMANGLE_COMPONENT_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ FNQUAL_COMPONENT_CASE:
return has_return_type (d_left (dc));
}
}
@@ -1287,13 +1305,12 @@ d_encoding (struct d_info *di, int top_level)
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS
- || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
- there may be CV-qualifiers on its right argument which
+ there may be function-qualifiers on its right argument which
really apply here; this happens when parsing a class
which is local to a function. */
if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
@@ -1301,12 +1318,7 @@ d_encoding (struct d_info *di, int top_level)
struct demangle_component *dcr;
dcr = d_right (dc);
- while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
- || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dcr->type == DEMANGLE_COMPONENT_CONST_THIS
- || dcr->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
- || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
- || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ while (is_fnqual_component_type (dcr->type))
dcr = d_left (dcr);
dc->u.s_binary.right = dcr;
}
@@ -2168,6 +2180,13 @@ d_ctor_dtor_name (struct d_info *di)
case 'C':
{
enum gnu_v3_ctor_kinds kind;
+ int inheriting = 0;
+
+ if (d_peek_next_char (di) == 'I')
+ {
+ inheriting = 1;
+ d_advance (di, 1);
+ }
switch (d_peek_next_char (di))
{
@@ -2189,7 +2208,12 @@ d_ctor_dtor_name (struct d_info *di)
default:
return NULL;
}
+
d_advance (di, 2);
+
+ if (inheriting)
+ cplus_demangle_type (di);
+
return d_make_ctor (di, kind, di->last_name);
}
@@ -2227,6 +2251,24 @@ d_ctor_dtor_name (struct d_info *di)
}
}
+/* True iff we're looking at an order-insensitive type-qualifier, including
+ function-type-qualifiers. */
+
+static int
+next_is_type_qual (struct d_info *di)
+{
+ char peek = d_peek_char (di);
+ if (peek == 'r' || peek == 'V' || peek == 'K')
+ return 1;
+ if (peek == 'D')
+ {
+ peek = d_peek_next_char (di);
+ if (peek == 'x' || peek == 'o' || peek == 'O' || peek == 'w')
+ return 1;
+ }
+ return 0;
+}
+
/* <type> ::= <builtin-type>
::= <function-type>
::= <class-enum-type>
@@ -2312,9 +2354,7 @@ cplus_demangle_type (struct d_info *di)
__vector, and it treats it as order-sensitive when mangling
names. */
- peek = d_peek_char (di);
- if (peek == 'r' || peek == 'V' || peek == 'K'
- || (peek == 'D' && d_peek_next_char (di) == 'x'))
+ if (next_is_type_qual (di))
{
struct demangle_component **pret;
@@ -2349,6 +2389,7 @@ cplus_demangle_type (struct d_info *di)
can_subst = 1;
+ peek = d_peek_char (di);
switch (peek)
{
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
@@ -2636,10 +2677,10 @@ d_cv_qualifiers (struct d_info *di,
pstart = pret;
peek = d_peek_char (di);
- while (peek == 'r' || peek == 'V' || peek == 'K'
- || (peek == 'D' && d_peek_next_char (di) == 'x'))
+ while (next_is_type_qual (di))
{
enum demangle_component_type t;
+ struct demangle_component *right = NULL;
d_advance (di, 1);
if (peek == 'r')
@@ -2665,12 +2706,41 @@ d_cv_qualifiers (struct d_info *di,
}
else
{
- t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
- di->expansion += sizeof "transaction_safe";
- d_advance (di, 1);
+ peek = d_next_char (di);
+ if (peek == 'x')
+ {
+ t = DEMANGLE_COMPONENT_TRANSACTION_SAFE;
+ di->expansion += sizeof "transaction_safe";
+ }
+ else if (peek == 'o'
+ || peek == 'O')
+ {
+ t = DEMANGLE_COMPONENT_NOEXCEPT;
+ di->expansion += sizeof "noexcept";
+ if (peek == 'O')
+ {
+ right = d_expression (di);
+ if (right == NULL)
+ return NULL;
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ }
+ }
+ else if (peek == 'w')
+ {
+ t = DEMANGLE_COMPONENT_THROW_SPEC;
+ di->expansion += sizeof "throw";
+ right = d_parmlist (di);
+ if (right == NULL)
+ return NULL;
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ }
+ else
+ return NULL;
}
- *pret = d_make_comp (di, t, NULL, NULL);
+ *pret = d_make_comp (di, t, NULL, right);
if (*pret == NULL)
return NULL;
pret = &d_left (*pret);
@@ -3961,6 +4031,8 @@ d_count_templates_scopes (int *num_templates, int *num_scopes,
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ case DEMANGLE_COMPONENT_NOEXCEPT:
+ case DEMANGLE_COMPONENT_THROW_SPEC:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
@@ -4575,12 +4647,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
adpm[i].templates = dpi->templates;
++i;
- if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
- && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
- && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
- && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
- && typed_name->type != DEMANGLE_COMPONENT_TRANSACTION_SAFE
- && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
+ if (!is_fnqual_component_type (typed_name->type))
break;
typed_name = d_left (typed_name);
@@ -4617,13 +4684,7 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
d_print_error (dpi);
return;
}
- while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
- || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || local_name->type == DEMANGLE_COMPONENT_CONST_THIS
- || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
- || local_name->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
- || (local_name->type
- == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
+ while (is_fnqual_component_type (local_name->type))
{
if (i >= sizeof adpm / sizeof adpm[0])
{
@@ -4948,16 +5009,11 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
}
/* Fall through. */
- case DEMANGLE_COMPONENT_RESTRICT_THIS:
- case DEMANGLE_COMPONENT_VOLATILE_THIS:
- case DEMANGLE_COMPONENT_CONST_THIS:
- case DEMANGLE_COMPONENT_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
- case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ FNQUAL_COMPONENT_CASE:
modifier:
{
/* We keep a list of modifiers on the stack. */
@@ -5662,13 +5718,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
if (mods->printed
|| (! suffix
- && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
- || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
- || mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
- || mods->mod->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
- || (mods->mod->type
- == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
+ && (is_fnqual_component_type (mods->mod->type))))
{
d_print_mod_list (dpi, options, mods->next, suffix);
return;
@@ -5721,12 +5771,7 @@ d_print_mod_list (struct d_print_info *dpi, int options,
dc = dc->u.s_unary_num.sub;
}
- while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
- || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dc->type == DEMANGLE_COMPONENT_CONST_THIS
- || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
- || dc->type == DEMANGLE_COMPONENT_TRANSACTION_SAFE
- || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ while (is_fnqual_component_type (dc->type))
dc = d_left (dc);
d_print_comp (dpi, options, dc);
@@ -5765,6 +5810,24 @@ d_print_mod (struct d_print_info *dpi, int options,
case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
d_append_string (dpi, " transaction_safe");
return;
+ case DEMANGLE_COMPONENT_NOEXCEPT:
+ d_append_string (dpi, " noexcept");
+ if (d_right (mod))
+ {
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, options, d_right (mod));
+ d_append_char (dpi, ')');
+ }
+ return;
+ case DEMANGLE_COMPONENT_THROW_SPEC:
+ d_append_string (dpi, " throw");
+ if (d_right (mod))
+ {
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, options, d_right (mod));
+ d_append_char (dpi, ')');
+ }
+ return;
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
d_append_char (dpi, ' ');
d_print_comp (dpi, options, d_right (mod));
@@ -5852,12 +5915,7 @@ d_print_function_type (struct d_print_info *dpi, int options,
need_space = 1;
need_paren = 1;
break;
- case DEMANGLE_COMPONENT_RESTRICT_THIS:
- case DEMANGLE_COMPONENT_VOLATILE_THIS:
- case DEMANGLE_COMPONENT_CONST_THIS:
- case DEMANGLE_COMPONENT_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+ FNQUAL_COMPONENT_CASE:
break;
default:
break;
@@ -6399,7 +6457,6 @@ is_ctor_or_dtor (const char *mangled,
case DEMANGLE_COMPONENT_CONST_THIS:
case DEMANGLE_COMPONENT_REFERENCE_THIS:
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
- case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
default:
dc = NULL;
break;
diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
index f95405062c9..c955bfbe1e7 100644
--- a/libiberty/cplus-dem.c
+++ b/libiberty/cplus-dem.c
@@ -911,7 +911,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
int len0;
const char* p;
char *d;
- char *demangled;
+ char *demangled = NULL;
/* Discard leading _ada_, which is used for library level subprograms. */
if (strncmp (mangled, "_ada_", 5) == 0)
@@ -1156,6 +1156,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
return demangled;
unknown:
+ XDELETEVEC (demangled);
len0 = strlen (mangled);
demangled = XNEWVEC (char, len0 + 3);
@@ -1656,9 +1657,7 @@ demangle_signature (struct work_stuff *work,
(*mangled)++;
break;
}
- else
- /* fall through */
- {;}
+ /* fall through */
default:
if (AUTO_DEMANGLING || GNU_DEMANGLING)
@@ -4023,6 +4022,7 @@ demangle_fund_type (struct work_stuff *work,
success = 0;
break;
}
+ /* fall through */
case 'I':
(*mangled)++;
if (**mangled == '_')
diff --git a/libiberty/hashtab.c b/libiberty/hashtab.c
index 04607ea6a01..99381b17fd6 100644
--- a/libiberty/hashtab.c
+++ b/libiberty/hashtab.c
@@ -962,17 +962,17 @@ iterative_hash (const PTR k_in /* the key */,
c += length;
switch(len) /* all the case statements fall through */
{
- case 11: c+=((hashval_t)k[10]<<24);
- case 10: c+=((hashval_t)k[9]<<16);
- case 9 : c+=((hashval_t)k[8]<<8);
+ case 11: c+=((hashval_t)k[10]<<24); /* fall through */
+ case 10: c+=((hashval_t)k[9]<<16); /* fall through */
+ case 9 : c+=((hashval_t)k[8]<<8); /* fall through */
/* the first byte of c is reserved for the length */
- case 8 : b+=((hashval_t)k[7]<<24);
- case 7 : b+=((hashval_t)k[6]<<16);
- case 6 : b+=((hashval_t)k[5]<<8);
- case 5 : b+=k[4];
- case 4 : a+=((hashval_t)k[3]<<24);
- case 3 : a+=((hashval_t)k[2]<<16);
- case 2 : a+=((hashval_t)k[1]<<8);
+ case 8 : b+=((hashval_t)k[7]<<24); /* fall through */
+ case 7 : b+=((hashval_t)k[6]<<16); /* fall through */
+ case 6 : b+=((hashval_t)k[5]<<8); /* fall through */
+ case 5 : b+=k[4]; /* fall through */
+ case 4 : a+=((hashval_t)k[3]<<24); /* fall through */
+ case 3 : a+=((hashval_t)k[2]<<16); /* fall through */
+ case 2 : a+=((hashval_t)k[1]<<8); /* fall through */
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
diff --git a/libiberty/regex.c b/libiberty/regex.c
index 9ffc3f47f00..6854e3b41a0 100644
--- a/libiberty/regex.c
+++ b/libiberty/regex.c
@@ -2493,6 +2493,7 @@ PREFIX(regex_compile) (const char *ARG_PREFIX(pattern),
if ((syntax & RE_BK_PLUS_QM)
|| (syntax & RE_LIMITED_OPS))
goto normal_char;
+ /* Fall through. */
handle_plus:
case '*':
/* If there is no previous pattern... */
@@ -6697,6 +6698,7 @@ byte_re_match_2_internal (struct re_pattern_buffer *bufp,
{
case jump_n:
is_a_jump_n = true;
+ /* Fall through. */
case pop_failure_jump:
case maybe_pop_jump:
case jump:
@@ -7125,7 +7127,7 @@ byte_re_match_2_internal (struct re_pattern_buffer *bufp,
DEBUG_PRINT1 (" Match => jump.\n");
goto unconditional_jump;
}
- /* Note fall through. */
+ /* Fall through. */
/* The end of a simple repeat has a pop_failure_jump back to
@@ -7150,7 +7152,7 @@ byte_re_match_2_internal (struct re_pattern_buffer *bufp,
dummy_low_reg, dummy_high_reg,
reg_dummy, reg_dummy, reg_info_dummy);
}
- /* Note fall through. */
+ /* Fall through. */
unconditional_jump:
#ifdef _LIBC
@@ -7453,6 +7455,7 @@ byte_re_match_2_internal (struct re_pattern_buffer *bufp,
{
case jump_n:
is_a_jump_n = true;
+ /* Fall through. */
case maybe_pop_jump:
case pop_failure_jump:
case jump:
@@ -7718,6 +7721,7 @@ PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end,
case set_number_at:
p1 += 2 * OFFSET_ADDRESS_SIZE;
+ return false;
default:
/* All other opcodes mean we cannot match the empty string. */
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index a5a658a7095..5badc3e5849 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4592,3 +4592,17 @@ __t2m05B500000000000000000_
__10%0__S4_0T0T0
%0<>::%0(%0<>)
+
+# Inheriting constructor
+_ZN1DCI11BEi
+D::B(int)
+
+# exception-specification (C++17)
+_Z1fIvJiELb0EEvPDOT1_EFT_DpT0_E
+void f<void, int, false>(void (*)(int) noexcept(false))
+
+_Z1fIvJiELb0EEvPDoFT_DpT0_E
+void f<void, int, false>(void (*)(int) noexcept)
+
+_Z1fIvJiELb0EEvPDwiEFT_DpT0_E
+void f<void, int, false>(void (*)(int) throw(int))
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index 0a5282e3e9d..dad373eb967 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,57 @@
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * asan/asan_globals.cc (RegisterGlobal): Do not call
+ CheckODRViolationViaPoisoning.
+ (CheckODRViolationViaPoisoning): Remove.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * sanitizer_common/sanitizer_stacktrace.cc (GetCanonicFrame): Assume we
+ compiled code with GCC when extracting the caller PC for ARM if no
+ valid frame pointer is available.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ PR sanitizer/63958
+ Reapply:
+ 2014-10-14 David S. Miller <davem@davemloft.net>
+
+ * sanitizer_common/sanitizer_platform_limits_linux.cc (time_t):
+ Define at __kernel_time_t, as needed for sparc.
+ (struct __old_kernel_stat): Don't check if __sparc__ is defined.
+ * libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+ (__sanitizer): Define struct___old_kernel_stat_sz,
+ struct_kernel_stat_sz, and struct_kernel_stat64_sz for sparc.
+ (__sanitizer_ipc_perm): Adjust for sparc targets.
+ (__sanitizer_shmid_ds): Likewsie.
+ (__sanitizer_sigaction): Likewise.
+ (IOC_SIZE): Likewsie.
+
+2016-11-09 Maxim Ostapenko <m.ostapenko@samsung.com>
+
+ * All source files: Merge from upstream 285547.
+ * configure.tgt (SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS): New
+ variable.
+ * configure.ac (SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS): Handle it.
+ * asan/Makefile.am (asan_files): Add new files.
+ * asan/Makefile.in: Regenerate.
+ * ubsan/Makefile.in: Likewise.
+ * lsan/Makefile.in: Likewise.
+ * tsan/Makefile.am (tsan_files): Add new files.
+ * tsan/Makefile.in: Regenerate.
+ * sanitizer_common/Makefile.am (sanitizer_common_files): Add new files.
+ (EXTRA_libsanitizer_common_la_SOURCES): Define.
+ (libsanitizer_common_la_LIBADD): Likewise.
+ (libsanitizer_common_la_DEPENDENCIES): Likewise.
+ * sanitizer_common/Makefile.in: Regenerate.
+ * interception/Makefile.in: Likewise.
+ * libbacktace/Makefile.in: Likewise.
+ * Makefile.in: Likewise.
+ * configure: Likewise.
+ * merge.sh: Handle builtins/assembly.h merging.
+ * builtins/assembly.h: New file.
+ * asan/libtool-version: Bump the libasan SONAME.
+
2016-09-21 Jakub Jelinek <jakub@redhat.com>
PR sanitizer/77567
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index dfd606aa0c6..21c2f390e97 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-253555
+285547
The first line of this file holds the svn revision number of the
last merge done from the master library sources.
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index 1278900c0d4..28ba4b8e46a 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -210,6 +210,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am
index bd3cd735a98..bfd28c0388e 100644
--- a/libsanitizer/asan/Makefile.am
+++ b/libsanitizer/asan/Makefile.am
@@ -19,6 +19,8 @@ asan_files = \
asan_activation.cc \
asan_allocator.cc \
asan_debugging.cc \
+ asan_descriptions.cc \
+ asan_errors.cc \
asan_fake_stack.cc \
asan_flags.cc \
asan_globals.cc \
@@ -28,6 +30,7 @@ asan_files = \
asan_malloc_linux.cc \
asan_malloc_mac.cc \
asan_malloc_win.cc \
+ asan_memory_profile.cc \
asan_new_delete.cc \
asan_poisoning.cc \
asan_posix.cc \
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index 229c7b400d1..2d9f4a7b815 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -112,9 +112,10 @@ libasan_la_DEPENDENCIES = \
$(top_builddir)/lsan/libsanitizer_lsan.la $(am__append_2) \
$(am__append_3) $(am__DEPENDENCIES_1)
am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \
- asan_fake_stack.lo asan_flags.lo asan_globals.lo \
- asan_interceptors.lo asan_linux.lo asan_mac.lo \
- asan_malloc_linux.lo asan_malloc_mac.lo asan_malloc_win.lo \
+ asan_descriptions.lo asan_errors.lo asan_fake_stack.lo \
+ asan_flags.lo asan_globals.lo asan_interceptors.lo \
+ asan_linux.lo asan_mac.lo asan_malloc_linux.lo \
+ asan_malloc_mac.lo asan_malloc_win.lo asan_memory_profile.lo \
asan_new_delete.lo asan_poisoning.lo asan_posix.lo \
asan_report.lo asan_rtl.lo asan_stack.lo asan_stats.lo \
asan_suppressions.lo asan_thread.lo asan_win.lo \
@@ -219,6 +220,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -308,6 +310,8 @@ asan_files = \
asan_activation.cc \
asan_allocator.cc \
asan_debugging.cc \
+ asan_descriptions.cc \
+ asan_errors.cc \
asan_fake_stack.cc \
asan_flags.cc \
asan_globals.cc \
@@ -317,6 +321,7 @@ asan_files = \
asan_malloc_linux.cc \
asan_malloc_mac.cc \
asan_malloc_win.cc \
+ asan_memory_profile.cc \
asan_new_delete.cc \
asan_poisoning.cc \
asan_posix.cc \
@@ -454,6 +459,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_activation.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_debugging.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_descriptions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_errors.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_fake_stack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@
@@ -463,6 +470,7 @@ distclean-compile:
@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_memory_profile.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@
diff --git a/libsanitizer/asan/asan_activation.cc b/libsanitizer/asan/asan_activation.cc
index 58867956086..ecd767c5985 100644
--- a/libsanitizer/asan/asan_activation.cc
+++ b/libsanitizer/asan/asan_activation.cc
@@ -45,6 +45,7 @@ static struct AsanDeactivatedFlags {
FlagParser parser;
RegisterActivationFlags(&parser, &f, &cf);
+ cf.SetDefaults();
// Copy the current activation flags.
allocator_options.CopyTo(&f, &cf);
cf.malloc_context_size = malloc_context_size;
@@ -59,12 +60,7 @@ static struct AsanDeactivatedFlags {
parser.ParseString(env);
}
- // Override from getprop asan.options.
- char buf[100];
- GetExtraActivationFlags(buf, sizeof(buf));
- parser.ParseString(buf);
-
- SetVerbosity(cf.verbosity);
+ InitializeCommonFlags(&cf);
if (Verbosity()) ReportUnrecognizedFlags();
diff --git a/libsanitizer/asan/asan_allocator.cc b/libsanitizer/asan/asan_allocator.cc
index 187c405e118..d3ddb904d58 100644
--- a/libsanitizer/asan/asan_allocator.cc
+++ b/libsanitizer/asan/asan_allocator.cc
@@ -221,7 +221,7 @@ void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
struct Allocator {
static const uptr kMaxAllowedMallocSize =
- FIRST_32_SECOND_64(3UL << 30, 1UL << 40);
+ FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
@@ -264,9 +264,43 @@ struct Allocator {
SharedInitCode(options);
}
+ void RePoisonChunk(uptr chunk) {
+ // This could a user-facing chunk (with redzones), or some internal
+ // housekeeping chunk, like TransferBatch. Start by assuming the former.
+ AsanChunk *ac = GetAsanChunk((void *)chunk);
+ uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac);
+ uptr beg = ac->Beg();
+ uptr end = ac->Beg() + ac->UsedSize(true);
+ uptr chunk_end = chunk + allocated_size;
+ if (chunk < beg && beg < end && end <= chunk_end) {
+ // Looks like a valid AsanChunk. Or maybe not. Be conservative and only
+ // poison the redzones.
+ PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
+ uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
+ FastPoisonShadowPartialRightRedzone(
+ end_aligned_down, end - end_aligned_down,
+ chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
+ } else {
+ // This can not be an AsanChunk. Poison everything. It may be reused as
+ // AsanChunk later.
+ PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
+ }
+ }
+
void ReInitialize(const AllocatorOptions &options) {
allocator.SetMayReturnNull(options.may_return_null);
SharedInitCode(options);
+
+ // Poison all existing allocation's redzones.
+ if (CanPoisonMemory()) {
+ allocator.ForceLock();
+ allocator.ForEachChunk(
+ [](uptr chunk, void *alloc) {
+ ((Allocator *)alloc)->RePoisonChunk(chunk);
+ },
+ this);
+ allocator.ForceUnlock();
+ }
}
void GetOptions(AllocatorOptions *options) const {
@@ -354,7 +388,7 @@ struct Allocator {
if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
(void*)size);
- return allocator.ReturnNullOrDie();
+ return allocator.ReturnNullOrDieOnBadRequest();
}
AsanThread *t = GetCurrentThread();
@@ -371,8 +405,7 @@ struct Allocator {
allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
}
- if (!allocated)
- return allocator.ReturnNullOrDie();
+ if (!allocated) return allocator.ReturnNullOrDieOnOOM();
if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
// Heap poisoning is enabled, but the allocator provides an unpoisoned
@@ -455,29 +488,28 @@ struct Allocator {
return res;
}
- void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+ // Set quarantine flag if chunk is allocated, issue ASan error report on
+ // available and quarantined chunks. Return true on success, false otherwise.
+ bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr,
BufferedStackTrace *stack) {
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
- if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
- CHUNK_QUARANTINE, memory_order_acquire))
+ if (!atomic_compare_exchange_strong((atomic_uint8_t *)m, &old_chunk_state,
+ CHUNK_QUARANTINE,
+ memory_order_acquire)) {
ReportInvalidFree(ptr, old_chunk_state, stack);
+ // It's not safe to push a chunk in quarantine on invalid free.
+ return false;
+ }
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
+ return true;
}
// Expects the chunk to already be marked as quarantined by using
- // AtomicallySetQuarantineFlag.
+ // AtomicallySetQuarantineFlagIfAllocated.
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
AllocType alloc_type) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
-
- if (m->alloc_type != alloc_type) {
- if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
- ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
- (AllocType)alloc_type);
- }
- }
-
CHECK_GE(m->alloc_tid, 0);
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
CHECK_EQ(m->free_tid, kInvalidTid);
@@ -514,13 +546,24 @@ struct Allocator {
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+
+ ASAN_FREE_HOOK(ptr);
+ // Must mark the chunk as quarantined before any changes to its metadata.
+ // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
+ if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
+
+ if (m->alloc_type != alloc_type) {
+ if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) {
+ ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type,
+ (AllocType)alloc_type);
+ }
+ }
+
if (delete_size && flags()->new_delete_type_mismatch &&
delete_size != m->UsedSize()) {
ReportNewDeleteSizeMismatch(p, delete_size, stack);
}
- ASAN_FREE_HOOK(ptr);
- // Must mark the chunk as quarantined before any changes to its metadata.
- AtomicallySetQuarantineFlag(m, ptr, stack);
+
QuarantineChunk(m, ptr, stack, alloc_type);
}
@@ -551,7 +594,7 @@ struct Allocator {
void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
- return allocator.ReturnNullOrDie();
+ return allocator.ReturnNullOrDieOnBadRequest();
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
// If the memory comes from the secondary allocator no need to clear it
// as it comes directly from mmap.
@@ -642,6 +685,8 @@ struct Allocator {
fallback_mutex.Unlock();
allocator.ForceUnlock();
}
+
+ void ReleaseToOS() { allocator.ReleaseToOS(); }
};
static Allocator instance(LINKER_INITIALIZED);
@@ -653,11 +698,17 @@ static AsanAllocator &get_allocator() {
bool AsanChunkView::IsValid() {
return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
}
+bool AsanChunkView::IsAllocated() {
+ return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED;
+}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
+AllocType AsanChunkView::GetAllocType() {
+ return (AllocType)chunk_->alloc_type;
+}
static StackTrace GetStackTraceFromId(u32 id) {
CHECK(id);
@@ -666,16 +717,22 @@ static StackTrace GetStackTraceFromId(u32 id) {
return res;
}
+u32 AsanChunkView::GetAllocStackId() { return chunk_->alloc_context_id; }
+u32 AsanChunkView::GetFreeStackId() { return chunk_->free_context_id; }
+
StackTrace AsanChunkView::GetAllocStack() {
- return GetStackTraceFromId(chunk_->alloc_context_id);
+ return GetStackTraceFromId(GetAllocStackId());
}
StackTrace AsanChunkView::GetFreeStack() {
- return GetStackTraceFromId(chunk_->free_context_id);
+ return GetStackTraceFromId(GetFreeStackId());
}
+void ReleaseToOS() { instance.ReleaseToOS(); }
+
void InitializeAllocator(const AllocatorOptions &options) {
instance.Initialize(options);
+ SetAllocatorReleaseToOSCallback(ReleaseToOS);
}
void ReInitializeAllocator(const AllocatorOptions &options) {
@@ -689,6 +746,9 @@ void GetAllocatorOptions(AllocatorOptions *options) {
AsanChunkView FindHeapChunkByAddress(uptr addr) {
return instance.FindHeapChunkByAddress(addr);
}
+AsanChunkView FindHeapChunkByAllocBeg(uptr addr) {
+ return AsanChunkView(instance.GetAsanChunk(reinterpret_cast<void*>(addr)));
+}
void AsanThreadLocalMallocStorage::CommitBack() {
instance.CommitBack(this);
@@ -752,7 +812,7 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
-uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
+uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
if (!ptr) return 0;
uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
if (flags()->check_malloc_usable_size && (usable_size == 0)) {
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index 921131ab4e9..7eeddadd547 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -47,16 +47,20 @@ void GetAllocatorOptions(AllocatorOptions *options);
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid(); // Checks if AsanChunkView points to a valid allocated
- // or quarantined chunk.
- uptr Beg(); // First byte of user memory.
- uptr End(); // Last byte of user memory.
- uptr UsedSize(); // Size requested by the user.
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ bool IsAllocated(); // Checks if the memory is currently allocated.
+ 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();
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
+ u32 GetAllocStackId();
+ u32 GetFreeStackId();
StackTrace GetAllocStack();
StackTrace GetFreeStack();
+ AllocType GetAllocType();
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
@@ -85,6 +89,7 @@ class AsanChunkView {
};
AsanChunkView FindHeapChunkByAddress(uptr address);
+AsanChunkView FindHeapChunkByAllocBeg(uptr address);
// List of AsanChunks with total size.
class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
@@ -112,18 +117,36 @@ struct AsanMapUnmapCallback {
# if defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
+typedef DefaultSizeClassMap SizeClassMap;
+# elif defined(__aarch64__) && SANITIZER_ANDROID
+const uptr kAllocatorSpace = 0x3000000000ULL;
+const uptr kAllocatorSize = 0x2000000000ULL; // 128G.
+typedef VeryCompactSizeClassMap SizeClassMap;
# elif defined(__aarch64__)
-// AArch64/SANITIZIER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA
+// AArch64/SANITIZER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA
// so no need to different values for different VMA.
const uptr kAllocatorSpace = 0x10000000000ULL;
const uptr kAllocatorSize = 0x10000000000ULL; // 3T.
+typedef DefaultSizeClassMap SizeClassMap;
+# elif SANITIZER_WINDOWS
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize = 0x8000000000ULL; // 500G
+typedef DefaultSizeClassMap SizeClassMap;
# else
const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
-# endif
typedef DefaultSizeClassMap SizeClassMap;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
- SizeClassMap, AsanMapUnmapCallback> PrimaryAllocator;
+# endif
+struct AP64 { // Allocator64 parameters. Deliberately using a short name.
+ static const uptr kSpaceBeg = kAllocatorSpace;
+ static const uptr kSpaceSize = kAllocatorSize;
+ static const uptr kMetadataSize = 0;
+ typedef __asan::SizeClassMap SizeClassMap;
+ typedef AsanMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+
+typedef SizeClassAllocator64<AP64> PrimaryAllocator;
#else // Fallback to SizeClassAllocator32.
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
@@ -169,7 +192,7 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
BufferedStackTrace *stack);
-uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
+uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
void asan_mz_force_lock();
diff --git a/libsanitizer/asan/asan_debugging.cc b/libsanitizer/asan/asan_debugging.cc
index 6e33a9d4c51..1c8d0df8f6e 100644
--- a/libsanitizer/asan/asan_debugging.cc
+++ b/libsanitizer/asan/asan_debugging.cc
@@ -12,74 +12,39 @@
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
+#include "asan_descriptions.h"
#include "asan_flags.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_report.h"
#include "asan_thread.h"
-namespace __asan {
-
-void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
- descr->name[0] = 0;
- descr->region_address = 0;
- descr->region_size = 0;
- descr->region_kind = "stack";
+namespace {
+using namespace __asan;
- AsanThread::StackFrameAccess access;
- if (!t->GetStackFrameAccessByAddr(addr, &access))
- return;
+static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset,
+ char *name, uptr name_size,
+ uptr &region_address, uptr &region_size) {
InternalMmapVector<StackVarDescr> vars(16);
- if (!ParseFrameDescription(access.frame_descr, &vars)) {
+ if (!ParseFrameDescription(frame_descr, &vars)) {
return;
}
for (uptr i = 0; i < vars.size(); i++) {
- if (access.offset <= vars[i].beg + vars[i].size) {
- internal_strncat(descr->name, vars[i].name_pos,
- Min(descr->name_size, vars[i].name_len));
- descr->region_address = addr - (access.offset - vars[i].beg);
- descr->region_size = vars[i].size;
+ if (offset <= vars[i].beg + vars[i].size) {
+ // We use name_len + 1 because strlcpy will guarantee a \0 at the end, so
+ // if we're limiting the copy due to name_len, we add 1 to ensure we copy
+ // the whole name and then terminate with '\0'.
+ internal_strlcpy(name, vars[i].name_pos,
+ Min(name_size, vars[i].name_len + 1));
+ region_address = addr - (offset - vars[i].beg);
+ region_size = vars[i].size;
return;
}
}
}
-void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
- AsanChunkView chunk = FindHeapChunkByAddress(addr);
-
- descr->name[0] = 0;
- descr->region_address = 0;
- descr->region_size = 0;
-
- if (!chunk.IsValid()) {
- descr->region_kind = "heap-invalid";
- return;
- }
-
- descr->region_address = chunk.Beg();
- descr->region_size = chunk.UsedSize();
- descr->region_kind = "heap";
-}
-
-void AsanLocateAddress(uptr addr, AddressDescription *descr) {
- if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
- return;
- }
- if (GetInfoForAddressIfGlobal(addr, descr)) {
- return;
- }
- asanThreadRegistry().Lock();
- AsanThread *thread = FindThreadByStackAddress(addr);
- asanThreadRegistry().Unlock();
- if (thread) {
- GetInfoForStackVar(addr, descr, thread);
- return;
- }
- GetInfoForHeapAddress(addr, descr);
-}
-
-static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
+uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
bool alloc_stack) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
if (!chunk.IsValid()) return 0;
@@ -106,18 +71,58 @@ static uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id,
return 0;
}
-} // namespace __asan
-
-using namespace __asan;
+} // namespace
SANITIZER_INTERFACE_ATTRIBUTE
const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
- uptr *region_address, uptr *region_size) {
- AddressDescription descr = { name, name_size, 0, 0, nullptr };
- AsanLocateAddress(addr, &descr);
- if (region_address) *region_address = descr.region_address;
- if (region_size) *region_size = descr.region_size;
- return descr.region_kind;
+ uptr *region_address_ptr,
+ uptr *region_size_ptr) {
+ AddressDescription descr(addr);
+ uptr region_address = 0;
+ uptr region_size = 0;
+ const char *region_kind = nullptr;
+ if (name && name_size > 0) name[0] = 0;
+
+ if (auto shadow = descr.AsShadow()) {
+ // region_{address,size} are already 0
+ switch (shadow->kind) {
+ case kShadowKindLow:
+ region_kind = "low shadow";
+ break;
+ case kShadowKindGap:
+ region_kind = "shadow gap";
+ break;
+ case kShadowKindHigh:
+ region_kind = "high shadow";
+ break;
+ }
+ } else if (auto heap = descr.AsHeap()) {
+ region_kind = "heap";
+ region_address = heap->chunk_access.chunk_begin;
+ region_size = heap->chunk_access.chunk_size;
+ } else if (auto stack = descr.AsStack()) {
+ region_kind = "stack";
+ if (!stack->frame_descr) {
+ // region_{address,size} are already 0
+ } else {
+ FindInfoForStackVar(addr, stack->frame_descr, stack->offset, name,
+ name_size, region_address, region_size);
+ }
+ } else if (auto global = descr.AsGlobal()) {
+ region_kind = "global";
+ auto &g = global->globals[0];
+ internal_strlcpy(name, g.name, name_size);
+ region_address = g.beg;
+ region_size = g.size;
+ } else {
+ // region_{address,size} are already 0
+ region_kind = "heap-invalid";
+ }
+
+ CHECK(region_kind);
+ if (region_address_ptr) *region_address_ptr = region_address;
+ if (region_size_ptr) *region_size_ptr = region_size;
+ return region_kind;
}
SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/libsanitizer/asan/asan_descriptions.cc b/libsanitizer/asan/asan_descriptions.cc
new file mode 100644
index 00000000000..35d1619f2d9
--- /dev/null
+++ b/libsanitizer/asan/asan_descriptions.cc
@@ -0,0 +1,484 @@
+//===-- asan_descriptions.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.
+//
+// ASan functions for getting information about an address and/or printing it.
+//===----------------------------------------------------------------------===//
+
+#include "asan_descriptions.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+// Return " (thread_name) " or an empty string if the name is empty.
+const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
+ uptr buff_len) {
+ const char *name = t->name;
+ if (name[0] == '\0') return "";
+ buff[0] = 0;
+ internal_strncat(buff, " (", 3);
+ internal_strncat(buff, name, buff_len - 4);
+ internal_strncat(buff, ")", 2);
+ return buff;
+}
+
+const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) {
+ if (tid == kInvalidTid) return "";
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *t = GetThreadContextByTidLocked(tid);
+ return ThreadNameWithParenthesis(t, buff, buff_len);
+}
+
+void DescribeThread(AsanThreadContext *context) {
+ CHECK(context);
+ asanThreadRegistry().CheckLocked();
+ // No need to announce the main thread.
+ if (context->tid == 0 || context->announced) {
+ return;
+ }
+ context->announced = true;
+ char tname[128];
+ InternalScopedString str(1024);
+ str.append("Thread T%d%s", context->tid,
+ ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
+ if (context->parent_tid == kInvalidTid) {
+ str.append(" created by unknown thread\n");
+ Printf("%s", str.data());
+ return;
+ }
+ str.append(
+ " created by T%d%s here:\n", context->parent_tid,
+ ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
+ Printf("%s", str.data());
+ StackDepotGet(context->stack_id).Print();
+ // Recursively described parent thread if needed.
+ if (flags()->print_full_thread_history) {
+ AsanThreadContext *parent_context =
+ GetThreadContextByTidLocked(context->parent_tid);
+ DescribeThread(parent_context);
+ }
+}
+
+// Shadow descriptions
+static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
+ CHECK(!AddrIsInMem(addr));
+ if (AddrIsInShadowGap(addr)) {
+ *shadow_kind = kShadowKindGap;
+ } else if (AddrIsInHighShadow(addr)) {
+ *shadow_kind = kShadowKindHigh;
+ } else if (AddrIsInLowShadow(addr)) {
+ *shadow_kind = kShadowKindLow;
+ } else {
+ CHECK(0 && "Address is not in memory and not in shadow?");
+ return false;
+ }
+ return true;
+}
+
+bool DescribeAddressIfShadow(uptr addr) {
+ ShadowAddressDescription descr;
+ if (!GetShadowAddressInformation(addr, &descr)) return false;
+ descr.Print();
+ return true;
+}
+
+bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr) {
+ if (AddrIsInMem(addr)) return false;
+ ShadowKind shadow_kind;
+ if (!GetShadowKind(addr, &shadow_kind)) return false;
+ if (shadow_kind != kShadowKindGap) descr->shadow_byte = *(u8 *)addr;
+ descr->addr = addr;
+ descr->kind = shadow_kind;
+ return true;
+}
+
+// Heap descriptions
+static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
+ AsanChunkView chunk, uptr addr,
+ uptr access_size) {
+ descr->bad_addr = addr;
+ if (chunk.AddrIsAtLeft(addr, access_size, &descr->offset)) {
+ descr->access_type = kAccessTypeLeft;
+ } else if (chunk.AddrIsAtRight(addr, access_size, &descr->offset)) {
+ descr->access_type = kAccessTypeRight;
+ if (descr->offset < 0) {
+ descr->bad_addr -= descr->offset;
+ descr->offset = 0;
+ }
+ } else if (chunk.AddrIsInside(addr, access_size, &descr->offset)) {
+ descr->access_type = kAccessTypeInside;
+ } else {
+ descr->access_type = kAccessTypeUnknown;
+ }
+ descr->chunk_begin = chunk.Beg();
+ descr->chunk_size = chunk.UsedSize();
+ descr->alloc_type = chunk.GetAllocType();
+}
+
+static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
+ Decorator d;
+ InternalScopedString str(4096);
+ str.append("%s", d.Location());
+ switch (descr.access_type) {
+ case kAccessTypeLeft:
+ str.append("%p is located %zd bytes to the left of",
+ (void *)descr.bad_addr, descr.offset);
+ break;
+ case kAccessTypeRight:
+ str.append("%p is located %zd bytes to the right of",
+ (void *)descr.bad_addr, descr.offset);
+ break;
+ case kAccessTypeInside:
+ str.append("%p is located %zd bytes inside of", (void *)descr.bad_addr,
+ descr.offset);
+ break;
+ case kAccessTypeUnknown:
+ str.append(
+ "%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void *)descr.bad_addr);
+ }
+ str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
+ (void *)descr.chunk_begin,
+ (void *)(descr.chunk_begin + descr.chunk_size));
+ str.append("%s", d.EndLocation());
+ Printf("%s", str.data());
+}
+
+bool GetHeapAddressInformation(uptr addr, uptr access_size,
+ HeapAddressDescription *descr) {
+ AsanChunkView chunk = FindHeapChunkByAddress(addr);
+ if (!chunk.IsValid()) {
+ return false;
+ }
+ descr->addr = addr;
+ GetAccessToHeapChunkInformation(&descr->chunk_access, chunk, addr,
+ access_size);
+ CHECK_NE(chunk.AllocTid(), kInvalidTid);
+ descr->alloc_tid = chunk.AllocTid();
+ descr->alloc_stack_id = chunk.GetAllocStackId();
+ descr->free_tid = chunk.FreeTid();
+ if (descr->free_tid != kInvalidTid)
+ descr->free_stack_id = chunk.GetFreeStackId();
+ return true;
+}
+
+static StackTrace GetStackTraceFromId(u32 id) {
+ CHECK(id);
+ StackTrace res = StackDepotGet(id);
+ CHECK(res.trace);
+ return res;
+}
+
+bool DescribeAddressIfHeap(uptr addr, uptr access_size) {
+ HeapAddressDescription descr;
+ if (!GetHeapAddressInformation(addr, access_size, &descr)) {
+ Printf(
+ "AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return false;
+ }
+ descr.Print();
+ return true;
+}
+
+// Stack descriptions
+bool GetStackAddressInformation(uptr addr, uptr access_size,
+ StackAddressDescription *descr) {
+ AsanThread *t = FindThreadByStackAddress(addr);
+ if (!t) return false;
+
+ descr->addr = addr;
+ descr->tid = t->tid();
+ // Try to fetch precise stack frame for this access.
+ AsanThread::StackFrameAccess access;
+ if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+ descr->frame_descr = nullptr;
+ return true;
+ }
+
+ descr->offset = access.offset;
+ descr->access_size = access_size;
+ descr->frame_pc = access.frame_pc;
+ descr->frame_descr = access.frame_descr;
+
+#if SANITIZER_PPC64V1
+ // On PowerPC64 ELFv1, the address of a function actually points to a
+ // three-doubleword data structure with the first field containing
+ // the address of the function's code.
+ descr->frame_pc = *reinterpret_cast<uptr *>(descr->frame_pc);
+#endif
+ descr->frame_pc += 16;
+
+ return true;
+}
+
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+ uptr access_size, uptr prev_var_end,
+ uptr next_var_beg) {
+ uptr var_end = var.beg + var.size;
+ uptr addr_end = addr + access_size;
+ const char *pos_descr = nullptr;
+ // If the variable [var.beg, var_end) is the nearest variable to the
+ // current memory access, indicate it in the log.
+ if (addr >= var.beg) {
+ if (addr_end <= var_end)
+ pos_descr = "is inside"; // May happen if this is a use-after-return.
+ else if (addr < var_end)
+ pos_descr = "partially overflows";
+ else if (addr_end <= next_var_beg &&
+ next_var_beg - addr_end >= addr - var_end)
+ pos_descr = "overflows";
+ } else {
+ if (addr_end > var.beg)
+ pos_descr = "partially underflows";
+ else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
+ pos_descr = "underflows";
+ }
+ InternalScopedString str(1024);
+ str.append(" [%zd, %zd)", var.beg, var_end);
+ // Render variable name.
+ str.append(" '");
+ for (uptr i = 0; i < var.name_len; ++i) {
+ str.append("%c", var.name_pos[i]);
+ }
+ str.append("'");
+ if (pos_descr) {
+ Decorator d;
+ // FIXME: we may want to also print the size of the access here,
+ // but in case of accesses generated by memset it may be confusing.
+ str.append("%s <== Memory access at offset %zd %s this variable%s\n",
+ d.Location(), addr, pos_descr, d.EndLocation());
+ } else {
+ str.append("\n");
+ }
+ Printf("%s", str.data());
+}
+
+bool DescribeAddressIfStack(uptr addr, uptr access_size) {
+ StackAddressDescription descr;
+ if (!GetStackAddressInformation(addr, access_size, &descr)) return false;
+ descr.Print();
+ return true;
+}
+
+// Global descriptions
+static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
+ const __asan_global &g) {
+ InternalScopedString str(4096);
+ Decorator d;
+ str.append("%s", d.Location());
+ if (addr < g.beg) {
+ str.append("%p is located %zd bytes to the left", (void *)addr,
+ g.beg - addr);
+ } else if (addr + access_size > g.beg + g.size) {
+ if (addr < g.beg + g.size) addr = g.beg + g.size;
+ str.append("%p is located %zd bytes to the right", (void *)addr,
+ addr - (g.beg + g.size));
+ } else {
+ // Can it happen?
+ str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
+ }
+ str.append(" of global variable '%s' defined in '",
+ MaybeDemangleGlobalName(g.name));
+ PrintGlobalLocation(&str, g);
+ str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
+ str.append("%s", d.EndLocation());
+ PrintGlobalNameIfASCII(&str, g);
+ Printf("%s", str.data());
+}
+
+bool GetGlobalAddressInformation(uptr addr, uptr access_size,
+ GlobalAddressDescription *descr) {
+ descr->addr = addr;
+ int globals_num = GetGlobalsForAddress(addr, descr->globals, descr->reg_sites,
+ ARRAY_SIZE(descr->globals));
+ descr->size = globals_num;
+ descr->access_size = access_size;
+ return globals_num != 0;
+}
+
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size,
+ const char *bug_type) {
+ GlobalAddressDescription descr;
+ if (!GetGlobalAddressInformation(addr, access_size, &descr)) return false;
+
+ descr.Print(bug_type);
+ return true;
+}
+
+void ShadowAddressDescription::Print() const {
+ Printf("Address %p is located in the %s area.\n", addr, ShadowNames[kind]);
+}
+
+void GlobalAddressDescription::Print(const char *bug_type) const {
+ for (int i = 0; i < size; i++) {
+ DescribeAddressRelativeToGlobal(addr, access_size, globals[i]);
+ if (bug_type &&
+ 0 == internal_strcmp(bug_type, "initialization-order-fiasco") &&
+ reg_sites[i]) {
+ Printf(" registered at:\n");
+ StackDepotGet(reg_sites[i]).Print();
+ }
+ }
+}
+
+void StackAddressDescription::Print() const {
+ Decorator d;
+ char tname[128];
+ Printf("%s", d.Location());
+ Printf("Address %p is located in stack of thread T%d%s", addr, tid,
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
+
+ if (!frame_descr) {
+ Printf("%s\n", d.EndLocation());
+ return;
+ }
+ Printf(" at offset %zu in frame%s\n", offset, d.EndLocation());
+
+ // Now we print the frame where the alloca has happened.
+ // We print this frame as a stack trace with one element.
+ // The symbolizer may print more than one frame if inlining was involved.
+ // The frame numbers may be different than those in the stack trace printed
+ // previously. That's unfortunate, but I have no better solution,
+ // especially given that the alloca may be from entirely different place
+ // (e.g. use-after-scope, or different thread's stack).
+ Printf("%s", d.EndLocation());
+ StackTrace alloca_stack(&frame_pc, 1);
+ alloca_stack.Print();
+
+ InternalMmapVector<StackVarDescr> vars(16);
+ if (!ParseFrameDescription(frame_descr, &vars)) {
+ Printf(
+ "AddressSanitizer can't parse the stack frame "
+ "descriptor: |%s|\n",
+ frame_descr);
+ // 'addr' is a stack address, so return true even if we can't parse frame
+ return;
+ }
+ uptr n_objects = vars.size();
+ // Report the number of stack objects.
+ 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 prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
+ uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
+ PrintAccessAndVarIntersection(vars[i], offset, access_size, prev_var_end,
+ next_var_beg);
+ }
+ Printf(
+ "HINT: this may be a false positive if your program uses "
+ "some custom stack unwind mechanism or swapcontext\n");
+ if (SANITIZER_WINDOWS)
+ Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
+ else
+ Printf(" (longjmp and C++ exceptions *are* supported)\n");
+
+ DescribeThread(GetThreadContextByTidLocked(tid));
+}
+
+void HeapAddressDescription::Print() const {
+ PrintHeapChunkAccess(addr, chunk_access);
+
+ asanThreadRegistry().CheckLocked();
+ AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid);
+ StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id);
+
+ char tname[128];
+ Decorator d;
+ AsanThreadContext *free_thread = nullptr;
+ if (free_tid != kInvalidTid) {
+ free_thread = GetThreadContextByTidLocked(free_tid);
+ Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
+ free_thread->tid,
+ ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ StackTrace free_stack = GetStackTraceFromId(free_stack_id);
+ free_stack.Print();
+ Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(),
+ alloc_thread->tid,
+ ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ } else {
+ Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
+ alloc_thread->tid,
+ ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
+ d.EndAllocation());
+ }
+ alloc_stack.Print();
+ DescribeThread(GetCurrentThread());
+ if (free_thread) DescribeThread(free_thread);
+ DescribeThread(alloc_thread);
+}
+
+AddressDescription::AddressDescription(uptr addr, uptr access_size,
+ bool shouldLockThreadRegistry) {
+ if (GetShadowAddressInformation(addr, &data.shadow)) {
+ data.kind = kAddressKindShadow;
+ return;
+ }
+ if (GetHeapAddressInformation(addr, access_size, &data.heap)) {
+ data.kind = kAddressKindHeap;
+ return;
+ }
+
+ bool isStackMemory = false;
+ if (shouldLockThreadRegistry) {
+ ThreadRegistryLock l(&asanThreadRegistry());
+ isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack);
+ } else {
+ isStackMemory = GetStackAddressInformation(addr, access_size, &data.stack);
+ }
+ if (isStackMemory) {
+ data.kind = kAddressKindStack;
+ return;
+ }
+
+ if (GetGlobalAddressInformation(addr, access_size, &data.global)) {
+ data.kind = kAddressKindGlobal;
+ return;
+ }
+ data.kind = kAddressKindWild;
+ addr = 0;
+}
+
+void PrintAddressDescription(uptr addr, uptr access_size,
+ const char *bug_type) {
+ ShadowAddressDescription shadow_descr;
+ if (GetShadowAddressInformation(addr, &shadow_descr)) {
+ shadow_descr.Print();
+ return;
+ }
+
+ GlobalAddressDescription global_descr;
+ if (GetGlobalAddressInformation(addr, access_size, &global_descr)) {
+ global_descr.Print(bug_type);
+ return;
+ }
+
+ StackAddressDescription stack_descr;
+ if (GetStackAddressInformation(addr, access_size, &stack_descr)) {
+ stack_descr.Print();
+ return;
+ }
+
+ HeapAddressDescription heap_descr;
+ if (GetHeapAddressInformation(addr, access_size, &heap_descr)) {
+ heap_descr.Print();
+ return;
+ }
+
+ // We exhausted our possibilities. Bail out.
+ Printf(
+ "AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+}
+} // namespace __asan
diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
new file mode 100644
index 00000000000..584b9ba6491
--- /dev/null
+++ b/libsanitizer/asan/asan_descriptions.h
@@ -0,0 +1,251 @@
+//===-- asan_descriptions.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_descriptions.cc.
+// TODO(filcab): Most struct definitions should move to the interface headers.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_DESCRIPTIONS_H
+#define ASAN_DESCRIPTIONS_H
+
+#include "asan_allocator.h"
+#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_report_decorator.h"
+
+namespace __asan {
+
+void DescribeThread(AsanThreadContext *context);
+static inline void DescribeThread(AsanThread *t) {
+ if (t) DescribeThread(t->context());
+}
+const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
+ uptr buff_len);
+const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len);
+
+class Decorator : public __sanitizer::SanitizerCommonDecorator {
+ public:
+ Decorator() : SanitizerCommonDecorator() {}
+ const char *Access() { return Blue(); }
+ const char *EndAccess() { return Default(); }
+ const char *Location() { return Green(); }
+ const char *EndLocation() { return Default(); }
+ const char *Allocation() { return Magenta(); }
+ const char *EndAllocation() { return Default(); }
+
+ const char *ShadowByte(u8 byte) {
+ switch (byte) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ return Red();
+ case kAsanHeapFreeMagic:
+ return Magenta();
+ case kAsanStackLeftRedzoneMagic:
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ return Red();
+ case kAsanStackAfterReturnMagic:
+ return Magenta();
+ case kAsanInitializationOrderMagic:
+ return Cyan();
+ case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ return Blue();
+ case kAsanStackUseAfterScopeMagic:
+ return Magenta();
+ case kAsanGlobalRedzoneMagic:
+ return Red();
+ case kAsanInternalHeapMagic:
+ return Yellow();
+ case kAsanIntraObjectRedzone:
+ return Yellow();
+ default:
+ return Default();
+ }
+ }
+ const char *EndShadowByte() { return Default(); }
+ const char *MemoryByte() { return Magenta(); }
+ const char *EndMemoryByte() { return Default(); }
+};
+
+enum ShadowKind : u8 {
+ kShadowKindLow,
+ kShadowKindGap,
+ kShadowKindHigh,
+};
+static const char *const ShadowNames[] = {"low shadow", "shadow gap",
+ "high shadow"};
+
+struct ShadowAddressDescription {
+ uptr addr;
+ ShadowKind kind;
+ u8 shadow_byte;
+
+ void Print() const;
+};
+
+bool GetShadowAddressInformation(uptr addr, ShadowAddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr);
+
+enum AccessType {
+ kAccessTypeLeft,
+ kAccessTypeRight,
+ kAccessTypeInside,
+ kAccessTypeUnknown, // This means we have an AddressSanitizer bug!
+};
+
+struct ChunkAccess {
+ uptr bad_addr;
+ sptr offset;
+ uptr chunk_begin;
+ uptr chunk_size;
+ u32 access_type : 2;
+ u32 alloc_type : 2;
+};
+
+struct HeapAddressDescription {
+ uptr addr;
+ uptr alloc_tid;
+ uptr free_tid;
+ u32 alloc_stack_id;
+ u32 free_stack_id;
+ ChunkAccess chunk_access;
+
+ void Print() const;
+};
+
+bool GetHeapAddressInformation(uptr addr, uptr access_size,
+ HeapAddressDescription *descr);
+bool DescribeAddressIfHeap(uptr addr, uptr access_size = 1);
+
+struct StackAddressDescription {
+ uptr addr;
+ uptr tid;
+ uptr offset;
+ uptr frame_pc;
+ uptr access_size;
+ const char *frame_descr;
+
+ void Print() const;
+};
+
+bool GetStackAddressInformation(uptr addr, uptr access_size,
+ StackAddressDescription *descr);
+
+struct GlobalAddressDescription {
+ uptr addr;
+ // Assume address is close to at most four globals.
+ static const int kMaxGlobals = 4;
+ __asan_global globals[kMaxGlobals];
+ u32 reg_sites[kMaxGlobals];
+ uptr access_size;
+ u8 size;
+
+ void Print(const char *bug_type = "") const;
+};
+
+bool GetGlobalAddressInformation(uptr addr, uptr access_size,
+ GlobalAddressDescription *descr);
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size, const char *bug_type);
+
+// General function to describe an address. Will try to describe the address as
+// a shadow, global (variable), stack, or heap address.
+// bug_type is optional and is used for checking if we're reporting an
+// initialization-order-fiasco
+// The proper access_size should be passed for stack, global, and heap
+// addresses. Defaults to 1.
+// Each of the *AddressDescription functions has its own Print() member, which
+// may take access_size and bug_type parameters if needed.
+void PrintAddressDescription(uptr addr, uptr access_size = 1,
+ const char *bug_type = "");
+
+enum AddressKind {
+ kAddressKindWild,
+ kAddressKindShadow,
+ kAddressKindHeap,
+ kAddressKindStack,
+ kAddressKindGlobal,
+};
+
+class AddressDescription {
+ struct AddressDescriptionData {
+ AddressKind kind;
+ union {
+ ShadowAddressDescription shadow;
+ HeapAddressDescription heap;
+ StackAddressDescription stack;
+ GlobalAddressDescription global;
+ uptr addr;
+ };
+ };
+
+ AddressDescriptionData data;
+
+ public:
+ AddressDescription() = default;
+ // shouldLockThreadRegistry allows us to skip locking if we're sure we already
+ // have done it.
+ AddressDescription(uptr addr, bool shouldLockThreadRegistry = true)
+ : AddressDescription(addr, 1, shouldLockThreadRegistry) {}
+ AddressDescription(uptr addr, uptr access_size,
+ bool shouldLockThreadRegistry = true);
+
+ uptr Address() const {
+ switch (data.kind) {
+ case kAddressKindWild:
+ return data.addr;
+ case kAddressKindShadow:
+ return data.shadow.addr;
+ case kAddressKindHeap:
+ return data.heap.addr;
+ case kAddressKindStack:
+ return data.stack.addr;
+ case kAddressKindGlobal:
+ return data.global.addr;
+ }
+ UNREACHABLE("AddressInformation kind is invalid");
+ }
+ void Print(const char *bug_descr = nullptr) const {
+ switch (data.kind) {
+ case kAddressKindWild:
+ Printf("Address %p is a wild pointer.\n", data.addr);
+ return;
+ case kAddressKindShadow:
+ return data.shadow.Print();
+ case kAddressKindHeap:
+ return data.heap.Print();
+ case kAddressKindStack:
+ return data.stack.Print();
+ case kAddressKindGlobal:
+ // initialization-order-fiasco has a special Print()
+ return data.global.Print(bug_descr);
+ }
+ UNREACHABLE("AddressInformation kind is invalid");
+ }
+
+ void StoreTo(AddressDescriptionData *dst) const { *dst = data; }
+
+ const ShadowAddressDescription *AsShadow() const {
+ return data.kind == kAddressKindShadow ? &data.shadow : nullptr;
+ }
+ const HeapAddressDescription *AsHeap() const {
+ return data.kind == kAddressKindHeap ? &data.heap : nullptr;
+ }
+ const StackAddressDescription *AsStack() const {
+ return data.kind == kAddressKindStack ? &data.stack : nullptr;
+ }
+ const GlobalAddressDescription *AsGlobal() const {
+ return data.kind == kAddressKindGlobal ? &data.global : nullptr;
+ }
+};
+
+} // namespace __asan
+
+#endif // ASAN_DESCRIPTIONS_H
diff --git a/libsanitizer/asan/asan_errors.cc b/libsanitizer/asan/asan_errors.cc
new file mode 100644
index 00000000000..73c4cca843b
--- /dev/null
+++ b/libsanitizer/asan/asan_errors.cc
@@ -0,0 +1,494 @@
+//===-- asan_errors.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.
+//
+// ASan implementation for error structures.
+//===----------------------------------------------------------------------===//
+
+#include "asan_errors.h"
+#include <signal.h>
+#include "asan_descriptions.h"
+#include "asan_mapping.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __asan {
+
+void ErrorStackOverflow::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: stack-overflow on address %p"
+ " (pc %p bp %p sp %p T%d)\n",
+ (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
+ Printf("%s", d.EndWarning());
+ scariness.Print();
+ BufferedStackTrace stack;
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
+ common_flags()->fast_unwind_on_fatal);
+ stack.Print();
+ ReportErrorSummary("stack-overflow", &stack);
+}
+
+static void MaybeDumpInstructionBytes(uptr pc) {
+ if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return;
+ InternalScopedString str(1024);
+ str.append("First 16 instruction bytes at pc: ");
+ if (IsAccessibleMemoryRange(pc, 16)) {
+ for (int i = 0; i < 16; ++i) {
+ PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " ");
+ }
+ str.append("\n");
+ } else {
+ str.append("unaccessible\n");
+ }
+ Report("%s", str.data());
+}
+
+void ErrorDeadlySignal::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ const char *description = DescribeSignalOrException(signo);
+ Report(
+ "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p "
+ "T%d)\n",
+ description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
+ Printf("%s", d.EndWarning());
+ if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n");
+ if (is_memory_access) {
+ const char *access_type =
+ write_flag == SignalContext::WRITE
+ ? "WRITE"
+ : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
+ Report("The signal is caused by a %s memory access.\n", access_type);
+ if (addr < GetPageSizeCached())
+ Report("Hint: address points to the zero page.\n");
+ }
+ scariness.Print();
+ BufferedStackTrace stack;
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
+ common_flags()->fast_unwind_on_fatal);
+ stack.Print();
+ MaybeDumpInstructionBytes(pc);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary(description, &stack);
+}
+
+void ErrorDoubleFree::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ Report(
+ "ERROR: AddressSanitizer: attempting double-free on %p in "
+ "thread T%d%s:\n",
+ addr_description.addr, tid,
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ scariness.Print();
+ GET_STACK_TRACE_FATAL(second_free_stack->trace[0],
+ second_free_stack->top_frame_bp);
+ stack.Print();
+ addr_description.Print();
+ ReportErrorSummary("double-free", &stack);
+}
+
+void ErrorNewDeleteSizeMismatch::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ Report(
+ "ERROR: AddressSanitizer: new-delete-type-mismatch on %p in thread "
+ "T%d%s:\n",
+ addr_description.addr, tid,
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
+ Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
+ Printf(
+ " size of the allocated type: %zd bytes;\n"
+ " size of the deallocated type: %zd bytes.\n",
+ addr_description.chunk_access.chunk_size, delete_size);
+ CHECK_GT(free_stack->size, 0);
+ scariness.Print();
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ addr_description.Print();
+ ReportErrorSummary("new-delete-type-mismatch", &stack);
+ Report(
+ "HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+}
+
+void ErrorFreeNotMalloced::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ char tname[128];
+ Report(
+ "ERROR: AddressSanitizer: attempting free on address "
+ "which was not malloc()-ed: %p in thread T%d%s\n",
+ addr_description.Address(), tid,
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
+ Printf("%s", d.EndWarning());
+ CHECK_GT(free_stack->size, 0);
+ scariness.Print();
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ stack.Print();
+ addr_description.Print();
+ ReportErrorSummary("bad-free", &stack);
+}
+
+void ErrorAllocTypeMismatch::Print() {
+ static const char *alloc_names[] = {"INVALID", "malloc", "operator new",
+ "operator new []"};
+ static const char *dealloc_names[] = {"INVALID", "free", "operator delete",
+ "operator delete []"};
+ CHECK_NE(alloc_type, dealloc_type);
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
+ alloc_names[alloc_type], dealloc_names[dealloc_type],
+ addr_description.addr);
+ Printf("%s", d.EndWarning());
+ CHECK_GT(dealloc_stack->size, 0);
+ scariness.Print();
+ GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp);
+ stack.Print();
+ addr_description.Print();
+ ReportErrorSummary("alloc-dealloc-mismatch", &stack);
+ Report(
+ "HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
+}
+
+void ErrorMallocUsableSizeNotOwned::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for "
+ "pointer which is not owned: %p\n",
+ addr_description.Address());
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ addr_description.Print();
+ ReportErrorSummary("bad-malloc_usable_size", stack);
+}
+
+void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: attempting to call "
+ "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n",
+ addr_description.Address());
+ Printf("%s", d.EndWarning());
+ stack->Print();
+ addr_description.Print();
+ ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
+}
+
+void ErrorStringFunctionMemoryRangesOverlap::Print() {
+ Decorator d;
+ char bug_type[100];
+ internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
+ Printf("%s", d.Warning());
+ Report(
+ "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) "
+ "overlap\n",
+ bug_type, addr1_description.Address(),
+ addr1_description.Address() + length1, addr2_description.Address(),
+ addr2_description.Address() + length2);
+ Printf("%s", d.EndWarning());
+ scariness.Print();
+ stack->Print();
+ addr1_description.Print();
+ addr2_description.Print();
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ErrorStringFunctionSizeOverflow::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ const char *bug_type = "negative-size-param";
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
+ Printf("%s", d.EndWarning());
+ scariness.Print();
+ stack->Print();
+ addr_description.Print();
+ ReportErrorSummary(bug_type, stack);
+}
+
+void ErrorBadParamsToAnnotateContiguousContainer::Print() {
+ Report(
+ "ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_contiguous_container:\n"
+ " beg : %p\n"
+ " end : %p\n"
+ " old_mid : %p\n"
+ " new_mid : %p\n",
+ beg, end, old_mid, new_mid);
+ uptr granularity = SHADOW_GRANULARITY;
+ if (!IsAligned(beg, granularity))
+ Report("ERROR: beg is not aligned by %d\n", granularity);
+ stack->Print();
+ ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+}
+
+void ErrorODRViolation::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: odr-violation (%p):\n", global1.beg);
+ Printf("%s", d.EndWarning());
+ InternalScopedString g1_loc(256), g2_loc(256);
+ PrintGlobalLocation(&g1_loc, global1);
+ PrintGlobalLocation(&g2_loc, global2);
+ Printf(" [1] size=%zd '%s' %s\n", global1.size,
+ MaybeDemangleGlobalName(global1.name), g1_loc.data());
+ Printf(" [2] size=%zd '%s' %s\n", global2.size,
+ MaybeDemangleGlobalName(global2.name), g2_loc.data());
+ if (stack_id1 && stack_id2) {
+ Printf("These globals were registered at these points:\n");
+ Printf(" [1]:\n");
+ StackDepotGet(stack_id1).Print();
+ Printf(" [2]:\n");
+ StackDepotGet(stack_id2).Print();
+ }
+ Report(
+ "HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=detect_odr_violation=0\n");
+ InternalScopedString error_msg(256);
+ error_msg.append("odr-violation: global '%s' at %s",
+ MaybeDemangleGlobalName(global1.name), g1_loc.data());
+ ReportErrorSummary(error_msg.data());
+}
+
+void ErrorInvalidPointerPair::Print() {
+ const char *bug_type = "invalid-pointer-pair";
+ Decorator d;
+ Printf("%s", d.Warning());
+ Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n",
+ addr1_description.Address(), addr2_description.Address());
+ Printf("%s", d.EndWarning());
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+ addr1_description.Print();
+ addr2_description.Print();
+ ReportErrorSummary(bug_type, &stack);
+}
+
+static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) {
+ return s[-1] > 127 && s[1] > 127;
+}
+
+ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr,
+ bool is_write_, uptr access_size_)
+ : ErrorBase(tid),
+ addr_description(addr, access_size_, /*shouldLockThreadRegistry=*/false),
+ pc(pc_),
+ bp(bp_),
+ sp(sp_),
+ access_size(access_size_),
+ is_write(is_write_),
+ shadow_val(0) {
+ scariness.Clear();
+ if (access_size) {
+ if (access_size <= 9) {
+ char desr[] = "?-byte";
+ desr[0] = '0' + access_size;
+ scariness.Scare(access_size + access_size / 2, desr);
+ } else if (access_size >= 10) {
+ scariness.Scare(15, "multi-byte");
+ }
+ is_write ? scariness.Scare(20, "write") : scariness.Scare(1, "read");
+
+ // Determine the error type.
+ 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++;
+ bool far_from_bounds = false;
+ shadow_val = *shadow_addr;
+ int bug_type_score = 0;
+ // For use-after-frees reads are almost as bad as writes.
+ int read_after_free_bonus = 0;
+ switch (shadow_val) {
+ case kAsanHeapLeftRedzoneMagic:
+ case kAsanArrayCookieMagic:
+ bug_descr = "heap-buffer-overflow";
+ bug_type_score = 10;
+ far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
+ break;
+ case kAsanHeapFreeMagic:
+ bug_descr = "heap-use-after-free";
+ bug_type_score = 20;
+ if (!is_write) read_after_free_bonus = 18;
+ break;
+ case kAsanStackLeftRedzoneMagic:
+ bug_descr = "stack-buffer-underflow";
+ bug_type_score = 25;
+ far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
+ break;
+ case kAsanInitializationOrderMagic:
+ bug_descr = "initialization-order-fiasco";
+ bug_type_score = 1;
+ break;
+ case kAsanStackMidRedzoneMagic:
+ case kAsanStackRightRedzoneMagic:
+ bug_descr = "stack-buffer-overflow";
+ bug_type_score = 25;
+ far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
+ break;
+ case kAsanStackAfterReturnMagic:
+ bug_descr = "stack-use-after-return";
+ bug_type_score = 30;
+ if (!is_write) read_after_free_bonus = 18;
+ break;
+ case kAsanUserPoisonedMemoryMagic:
+ bug_descr = "use-after-poison";
+ bug_type_score = 20;
+ break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ bug_type_score = 10;
+ break;
+ case kAsanStackUseAfterScopeMagic:
+ bug_descr = "stack-use-after-scope";
+ bug_type_score = 10;
+ break;
+ case kAsanGlobalRedzoneMagic:
+ bug_descr = "global-buffer-overflow";
+ bug_type_score = 10;
+ far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
+ break;
+ case kAsanIntraObjectRedzone:
+ bug_descr = "intra-object-overflow";
+ bug_type_score = 10;
+ break;
+ case kAsanAllocaLeftMagic:
+ case kAsanAllocaRightMagic:
+ bug_descr = "dynamic-stack-buffer-overflow";
+ bug_type_score = 25;
+ far_from_bounds = AdjacentShadowValuesAreFullyPoisoned(shadow_addr);
+ break;
+ }
+ scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr);
+ if (far_from_bounds) scariness.Scare(10, "far-from-bounds");
+ }
+ }
+}
+
+static void PrintContainerOverflowHint() {
+ Printf("HINT: if you don't care about these errors you may set "
+ "ASAN_OPTIONS=detect_container_overflow=0.\n"
+ "If you suspect a false positive see also: "
+ "https://github.com/google/sanitizers/wiki/"
+ "AddressSanitizerContainerOverflow.\n");
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+ u8 byte, const char *after = "\n") {
+ PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
+}
+
+static void PrintLegend(InternalScopedString *str) {
+ str->append(
+ "Shadow byte legend (one shadow byte represents %d "
+ "application bytes):\n",
+ (int)SHADOW_GRANULARITY);
+ PrintShadowByte(str, " Addressable: ", 0);
+ str->append(" Partially addressable: ");
+ for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
+ str->append("\n");
+ PrintShadowByte(str, " Heap left redzone: ",
+ kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(str, " Stack left redzone: ",
+ kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(str, " Stack mid redzone: ",
+ kAsanStackMidRedzoneMagic);
+ PrintShadowByte(str, " Stack right redzone: ",
+ kAsanStackRightRedzoneMagic);
+ PrintShadowByte(str, " Stack after return: ",
+ kAsanStackAfterReturnMagic);
+ PrintShadowByte(str, " Stack use after scope: ",
+ kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(str, " Global init order: ",
+ kAsanInitializationOrderMagic);
+ PrintShadowByte(str, " Poisoned by user: ",
+ kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(str, " Container overflow: ",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(str, " Array cookie: ",
+ kAsanArrayCookieMagic);
+ PrintShadowByte(str, " Intra object redzone: ",
+ kAsanIntraObjectRedzone);
+ PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
+ PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
+}
+
+static void PrintShadowBytes(InternalScopedString *str, const char *before,
+ u8 *bytes, u8 *guilty, uptr n) {
+ Decorator d;
+ if (before) str->append("%s%p:", before, bytes);
+ for (uptr i = 0; i < n; i++) {
+ u8 *p = bytes + i;
+ const char *before =
+ p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
+ const char *after = p == guilty ? "]" : "";
+ PrintShadowByte(str, before, *p, after);
+ }
+ str->append("\n");
+}
+
+static void PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr)) return;
+ uptr shadow_addr = MemToShadow(addr);
+ const uptr n_bytes_per_row = 16;
+ uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+ InternalScopedString str(4096 * 8);
+ str.append("Shadow bytes around the buggy address:\n");
+ for (int i = -5; i <= 5; i++) {
+ const char *prefix = (i == 0) ? "=>" : " ";
+ PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
+ (u8 *)shadow_addr, n_bytes_per_row);
+ }
+ if (flags()->print_legend) PrintLegend(&str);
+ Printf("%s", str.data());
+}
+
+void ErrorGeneric::Print() {
+ Decorator d;
+ Printf("%s", d.Warning());
+ uptr addr = addr_description.Address();
+ Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n",
+ bug_descr, (void *)addr, pc, bp, sp);
+ Printf("%s", d.EndWarning());
+
+ char tname[128];
+ Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(),
+ access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size,
+ (void *)addr, tid,
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess());
+
+ scariness.Print();
+ GET_STACK_TRACE_FATAL(pc, bp);
+ stack.Print();
+
+ // Pass bug_descr because we have a special case for
+ // initialization-order-fiasco
+ addr_description.Print(bug_descr);
+ if (shadow_val == kAsanContiguousContainerOOBMagic)
+ PrintContainerOverflowHint();
+ ReportErrorSummary(bug_descr, &stack);
+ PrintShadowMemoryForAddress(addr);
+}
+
+} // namespace __asan
diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h
new file mode 100644
index 00000000000..6262dcf3506
--- /dev/null
+++ b/libsanitizer/asan/asan_errors.h
@@ -0,0 +1,376 @@
+//===-- asan_errors.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 structures.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_ERRORS_H
+#define ASAN_ERRORS_H
+
+#include "asan_descriptions.h"
+#include "asan_scariness_score.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace __asan {
+
+struct ErrorBase {
+ ErrorBase() = default;
+ explicit ErrorBase(u32 tid_) : tid(tid_) {}
+ ScarinessScoreBase scariness;
+ u32 tid;
+};
+
+struct ErrorStackOverflow : ErrorBase {
+ uptr addr, pc, bp, sp;
+ // ErrorStackOverflow never owns the context.
+ void *context;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorStackOverflow() = default;
+ ErrorStackOverflow(u32 tid, const SignalContext &sig)
+ : ErrorBase(tid),
+ addr(sig.addr),
+ pc(sig.pc),
+ bp(sig.bp),
+ sp(sig.sp),
+ context(sig.context) {
+ scariness.Clear();
+ scariness.Scare(10, "stack-overflow");
+ }
+ void Print();
+};
+
+struct ErrorDeadlySignal : ErrorBase {
+ uptr addr, pc, bp, sp;
+ // ErrorDeadlySignal never owns the context.
+ void *context;
+ int signo;
+ SignalContext::WriteFlag write_flag;
+ bool is_memory_access;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorDeadlySignal() = default;
+ ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_)
+ : ErrorBase(tid),
+ addr(sig.addr),
+ pc(sig.pc),
+ bp(sig.bp),
+ sp(sig.sp),
+ context(sig.context),
+ signo(signo_),
+ write_flag(sig.write_flag),
+ is_memory_access(sig.is_memory_access) {
+ scariness.Clear();
+ if (is_memory_access) {
+ if (addr < GetPageSizeCached()) {
+ scariness.Scare(10, "null-deref");
+ } else if (addr == pc) {
+ scariness.Scare(60, "wild-jump");
+ } else if (write_flag == SignalContext::WRITE) {
+ scariness.Scare(30, "wild-addr-write");
+ } else if (write_flag == SignalContext::READ) {
+ scariness.Scare(20, "wild-addr-read");
+ } else {
+ scariness.Scare(25, "wild-addr");
+ }
+ } else {
+ scariness.Scare(10, "signal");
+ }
+ }
+ void Print();
+};
+
+struct ErrorDoubleFree : ErrorBase {
+ // ErrorDoubleFree doesn't own the stack trace.
+ const BufferedStackTrace *second_free_stack;
+ HeapAddressDescription addr_description;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorDoubleFree() = default;
+ ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr)
+ : ErrorBase(tid), second_free_stack(stack) {
+ CHECK_GT(second_free_stack->size, 0);
+ GetHeapAddressInformation(addr, 1, &addr_description);
+ scariness.Clear();
+ scariness.Scare(42, "double-free");
+ }
+ void Print();
+};
+
+struct ErrorNewDeleteSizeMismatch : ErrorBase {
+ // ErrorNewDeleteSizeMismatch doesn't own the stack trace.
+ const BufferedStackTrace *free_stack;
+ HeapAddressDescription addr_description;
+ uptr delete_size;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorNewDeleteSizeMismatch() = default;
+ ErrorNewDeleteSizeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
+ uptr delete_size_)
+ : ErrorBase(tid), free_stack(stack), delete_size(delete_size_) {
+ GetHeapAddressInformation(addr, 1, &addr_description);
+ scariness.Clear();
+ scariness.Scare(10, "new-delete-type-mismatch");
+ }
+ void Print();
+};
+
+struct ErrorFreeNotMalloced : ErrorBase {
+ // ErrorFreeNotMalloced doesn't own the stack trace.
+ const BufferedStackTrace *free_stack;
+ AddressDescription addr_description;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorFreeNotMalloced() = default;
+ ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr)
+ : ErrorBase(tid),
+ free_stack(stack),
+ addr_description(addr, /*shouldLockThreadRegistry=*/false) {
+ scariness.Clear();
+ scariness.Scare(40, "bad-free");
+ }
+ void Print();
+};
+
+struct ErrorAllocTypeMismatch : ErrorBase {
+ // ErrorAllocTypeMismatch doesn't own the stack trace.
+ const BufferedStackTrace *dealloc_stack;
+ HeapAddressDescription addr_description;
+ AllocType alloc_type, dealloc_type;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorAllocTypeMismatch() = default;
+ ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr,
+ AllocType alloc_type_, AllocType dealloc_type_)
+ : ErrorBase(tid),
+ dealloc_stack(stack),
+ alloc_type(alloc_type_),
+ dealloc_type(dealloc_type_) {
+ GetHeapAddressInformation(addr, 1, &addr_description);
+ scariness.Clear();
+ scariness.Scare(10, "alloc-dealloc-mismatch");
+ };
+ void Print();
+};
+
+struct ErrorMallocUsableSizeNotOwned : ErrorBase {
+ // ErrorMallocUsableSizeNotOwned doesn't own the stack trace.
+ const BufferedStackTrace *stack;
+ AddressDescription addr_description;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorMallocUsableSizeNotOwned() = default;
+ ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr)
+ : ErrorBase(tid),
+ stack(stack_),
+ addr_description(addr, /*shouldLockThreadRegistry=*/false) {
+ scariness.Clear();
+ }
+ void Print();
+};
+
+struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
+ // ErrorSanitizerGetAllocatedSizeNotOwned doesn't own the stack trace.
+ const BufferedStackTrace *stack;
+ AddressDescription addr_description;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorSanitizerGetAllocatedSizeNotOwned() = default;
+ ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_,
+ uptr addr)
+ : ErrorBase(tid),
+ stack(stack_),
+ addr_description(addr, /*shouldLockThreadRegistry=*/false) {
+ scariness.Clear();
+ }
+ void Print();
+};
+
+struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase {
+ // ErrorStringFunctionMemoryRangesOverlap doesn't own the stack trace.
+ const BufferedStackTrace *stack;
+ uptr length1, length2;
+ AddressDescription addr1_description;
+ AddressDescription addr2_description;
+ const char *function;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorStringFunctionMemoryRangesOverlap() = default;
+ ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_,
+ uptr addr1, uptr length1_, uptr addr2,
+ uptr length2_, const char *function_)
+ : ErrorBase(tid),
+ stack(stack_),
+ length1(length1_),
+ length2(length2_),
+ addr1_description(addr1, length1, /*shouldLockThreadRegistry=*/false),
+ addr2_description(addr2, length2, /*shouldLockThreadRegistry=*/false),
+ function(function_) {
+ char bug_type[100];
+ internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
+ scariness.Clear();
+ scariness.Scare(10, bug_type);
+ }
+ void Print();
+};
+
+struct ErrorStringFunctionSizeOverflow : ErrorBase {
+ // ErrorStringFunctionSizeOverflow doesn't own the stack trace.
+ const BufferedStackTrace *stack;
+ AddressDescription addr_description;
+ uptr size;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorStringFunctionSizeOverflow() = default;
+ ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_,
+ uptr addr, uptr size_)
+ : ErrorBase(tid),
+ stack(stack_),
+ addr_description(addr, /*shouldLockThreadRegistry=*/false),
+ size(size_) {
+ scariness.Clear();
+ scariness.Scare(10, "negative-size-param");
+ }
+ void Print();
+};
+
+struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
+ // ErrorBadParamsToAnnotateContiguousContainer doesn't own the stack trace.
+ const BufferedStackTrace *stack;
+ uptr beg, end, old_mid, new_mid;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorBadParamsToAnnotateContiguousContainer() = default;
+ // PS4: Do we want an AddressDescription for beg?
+ ErrorBadParamsToAnnotateContiguousContainer(u32 tid,
+ BufferedStackTrace *stack_,
+ uptr beg_, uptr end_,
+ uptr old_mid_, uptr new_mid_)
+ : ErrorBase(tid),
+ stack(stack_),
+ beg(beg_),
+ end(end_),
+ old_mid(old_mid_),
+ new_mid(new_mid_) {}
+ void Print();
+};
+
+struct ErrorODRViolation : ErrorBase {
+ __asan_global global1, global2;
+ u32 stack_id1, stack_id2;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorODRViolation() = default;
+ ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_,
+ const __asan_global *g2, u32 stack_id2_)
+ : ErrorBase(tid),
+ global1(*g1),
+ global2(*g2),
+ stack_id1(stack_id1_),
+ stack_id2(stack_id2_) {}
+ void Print();
+};
+
+struct ErrorInvalidPointerPair : ErrorBase {
+ uptr pc, bp, sp;
+ AddressDescription addr1_description;
+ AddressDescription addr2_description;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorInvalidPointerPair() = default;
+ ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1,
+ uptr p2)
+ : ErrorBase(tid),
+ pc(pc_),
+ bp(bp_),
+ sp(sp_),
+ addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
+ addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}
+ void Print();
+};
+
+struct ErrorGeneric : ErrorBase {
+ AddressDescription addr_description;
+ uptr pc, bp, sp;
+ uptr access_size;
+ const char *bug_descr;
+ bool is_write;
+ u8 shadow_val;
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ ErrorGeneric() = default;
+ ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_,
+ uptr access_size_);
+ void Print();
+};
+
+// clang-format off
+#define ASAN_FOR_EACH_ERROR_KIND(macro) \
+ macro(StackOverflow) \
+ macro(DeadlySignal) \
+ macro(DoubleFree) \
+ macro(NewDeleteSizeMismatch) \
+ macro(FreeNotMalloced) \
+ macro(AllocTypeMismatch) \
+ macro(MallocUsableSizeNotOwned) \
+ macro(SanitizerGetAllocatedSizeNotOwned) \
+ macro(StringFunctionMemoryRangesOverlap) \
+ macro(StringFunctionSizeOverflow) \
+ macro(BadParamsToAnnotateContiguousContainer) \
+ macro(ODRViolation) \
+ macro(InvalidPointerPair) \
+ macro(Generic)
+// clang-format on
+
+#define ASAN_DEFINE_ERROR_KIND(name) kErrorKind##name,
+#define ASAN_ERROR_DESCRIPTION_MEMBER(name) Error##name name;
+#define ASAN_ERROR_DESCRIPTION_CONSTRUCTOR(name) \
+ ErrorDescription(Error##name const &e) : kind(kErrorKind##name), name(e) {}
+#define ASAN_ERROR_DESCRIPTION_PRINT(name) \
+ case kErrorKind##name: \
+ return name.Print();
+
+enum ErrorKind {
+ kErrorKindInvalid = 0,
+ ASAN_FOR_EACH_ERROR_KIND(ASAN_DEFINE_ERROR_KIND)
+};
+
+struct ErrorDescription {
+ ErrorKind kind;
+ // We're using a tagged union because it allows us to have a trivially
+ // copiable type and use the same structures as the public interface.
+ //
+ // We can add a wrapper around it to make it "more c++-like", but that would
+ // add a lot of code and the benefit wouldn't be that big.
+ union {
+ ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
+ };
+
+ ErrorDescription() { internal_memset(this, 0, sizeof(*this)); }
+ ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR)
+
+ bool IsValid() { return kind != kErrorKindInvalid; }
+ void Print() {
+ switch (kind) {
+ ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_PRINT)
+ case kErrorKindInvalid:
+ CHECK(0);
+ }
+ CHECK(0);
+ }
+};
+
+#undef ASAN_FOR_EACH_ERROR_KIND
+#undef ASAN_DEFINE_ERROR_KIND
+#undef ASAN_ERROR_DESCRIPTION_MEMBER
+#undef ASAN_ERROR_DESCRIPTION_CONSTRUCTOR
+#undef ASAN_ERROR_DESCRIPTION_PRINT
+
+} // namespace __asan
+
+#endif // ASAN_ERRORS_H
diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc
index de190d11a16..bf7566a334e 100644
--- a/libsanitizer/asan/asan_fake_stack.cc
+++ b/libsanitizer/asan/asan_fake_stack.cc
@@ -29,7 +29,7 @@ ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3.
u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
if (class_id <= 6) {
- for (uptr i = 0; i < (1U << class_id); i++) {
+ for (uptr i = 0; i < (((uptr)1) << class_id); i++) {
shadow[i] = magic;
// Make sure this does not become memset.
SanitizerBreakOptimization(nullptr);
@@ -98,7 +98,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
// if the signal arrives between checking and setting flags[pos], the
// signal handler's fake stack will start from a different hint_position
// and so will not touch this particular byte. So, it is safe to do this
- // with regular non-atimic load and store (at least I was not able to make
+ // with regular non-atomic load and store (at least I was not able to make
// this code crash).
if (flags[pos]) continue;
flags[pos] = 1;
@@ -119,7 +119,7 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
uptr class_id = (ptr - beg) >> stack_size_log;
uptr base = beg + (class_id << stack_size_log);
CHECK_LE(base, ptr);
- CHECK_LT(ptr, base + (1UL << stack_size_log));
+ CHECK_LT(ptr, base + (((uptr)1) << stack_size_log));
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
uptr res = base + pos * BytesInSizeClass(class_id);
*frame_end = res + BytesInSizeClass(class_id);
diff --git a/libsanitizer/asan/asan_fake_stack.h b/libsanitizer/asan/asan_fake_stack.h
index 550a86e2972..6ac61ddd24e 100644
--- a/libsanitizer/asan/asan_fake_stack.h
+++ b/libsanitizer/asan/asan_fake_stack.h
@@ -50,7 +50,7 @@ struct FakeFrame {
// Allocate() flips the appropriate allocation flag atomically, thus achieving
// async-signal safety.
// This allocator does not have quarantine per se, but it tries to allocate the
-// frames in round robin fasion to maximize the delay between a deallocation
+// frames in round robin fashion to maximize the delay between a deallocation
// and the next allocation.
class FakeStack {
static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B.
@@ -67,12 +67,12 @@ class FakeStack {
// stack_size_log is at least 15 (stack_size >= 32K).
static uptr SizeRequiredForFlags(uptr stack_size_log) {
- return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog);
+ return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog);
}
// Each size class occupies stack_size bytes.
static uptr SizeRequiredForFrames(uptr stack_size_log) {
- return (1ULL << stack_size_log) * kNumberOfSizeClasses;
+ return (((uptr)1) << stack_size_log) * kNumberOfSizeClasses;
}
// Number of bytes requires for the whole object.
@@ -89,20 +89,20 @@ class FakeStack {
// and so on.
static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
uptr t = kNumberOfSizeClasses - 1 - class_id;
- const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1;
+ const uptr all_ones = (((uptr)1) << (kNumberOfSizeClasses - 1)) - 1;
return ((all_ones >> t) << t) << (stack_size_log - 15);
}
static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
- return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id);
+ return ((uptr)1) << (stack_size_log - kMinStackFrameSizeLog - class_id);
}
- // Divide n by the numbe of frames in size class.
+ // Divide n by the number of frames in size class.
static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) {
return n & (NumberOfFrames(stack_size_log, class_id) - 1);
}
- // The the pointer to the flags of the given class_id.
+ // The pointer to the flags of the given class_id.
u8 *GetFlags(uptr stack_size_log, uptr class_id) {
return reinterpret_cast<u8 *>(this) + kFlagsOffset +
FlagsOffset(stack_size_log, class_id);
@@ -112,7 +112,8 @@ class FakeStack {
u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
return reinterpret_cast<u8 *>(this) + kFlagsOffset +
SizeRequiredForFlags(stack_size_log) +
- (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos;
+ (((uptr)1) << stack_size_log) * class_id +
+ BytesInSizeClass(class_id) * pos;
}
// Allocate the fake frame.
@@ -135,7 +136,7 @@ class FakeStack {
// Number of bytes in a fake frame of this size class.
static uptr BytesInSizeClass(uptr class_id) {
- return 1UL << (class_id + kMinStackFrameSizeLog);
+ return ((uptr)1) << (class_id + kMinStackFrameSizeLog);
}
// The fake frame is guaranteed to have a right redzone.
@@ -157,7 +158,7 @@ class FakeStack {
static const uptr kFlagsOffset = 4096; // This is were the flags begin.
// Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
COMPILER_CHECK(kNumberOfSizeClasses == 11);
- static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+ static const uptr kMaxStackMallocSize = ((uptr)1) << kMaxStackFrameSizeLog;
uptr hint_position_[kNumberOfSizeClasses];
uptr stack_size_log_;
diff --git a/libsanitizer/asan/asan_flags.cc b/libsanitizer/asan/asan_flags.cc
index 9a68ad4eaa8..c18174beed0 100644
--- a/libsanitizer/asan/asan_flags.cc
+++ b/libsanitizer/asan/asan_flags.cc
@@ -114,15 +114,7 @@ void InitializeFlags() {
ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
#endif
- // Let activation flags override current settings. On Android they come
- // from a system property. On other platforms this is no-op.
- if (!flags()->start_deactivated) {
- char buf[100];
- GetExtraActivationFlags(buf, sizeof(buf));
- asan_parser.ParseString(buf);
- }
-
- SetVerbosity(common_flags()->verbosity);
+ InitializeCommonFlags();
// TODO(eugenis): dump all flags at verbosity>=2?
if (Verbosity()) ReportUnrecognizedFlags();
@@ -165,6 +157,14 @@ void InitializeFlags() {
(ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8;
f->quarantine_size_mb = kDefaultQuarantineSizeMb;
}
+ if (!f->replace_str && common_flags()->intercept_strlen) {
+ Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
+ "Use intercept_strlen=0 to disable it.");
+ }
+ if (!f->replace_str && common_flags()->intercept_strchr) {
+ Report("WARNING: strchr* interceptors are enabled even though "
+ "replace_str=0. Use intercept_strchr=0 to disable them.");
+ }
}
} // namespace __asan
diff --git a/libsanitizer/asan/asan_flags.inc b/libsanitizer/asan/asan_flags.inc
index 563b464bff1..34493eededf 100644
--- a/libsanitizer/asan/asan_flags.inc
+++ b/libsanitizer/asan/asan_flags.inc
@@ -41,10 +41,7 @@ ASAN_FLAG(
"If set, uses custom wrappers and replacements for libc string functions "
"to find more errors.")
ASAN_FLAG(bool, replace_intrin, true,
- "If set, uses custom wrappers for memset/memcpy/memmove intinsics.")
-ASAN_FLAG(bool, mac_ignore_invalid_free, false,
- "Ignore invalid free() calls to work around some bugs. Used on OS X "
- "only.")
+ "If set, uses custom wrappers for memset/memcpy/memmove intrinsics.")
ASAN_FLAG(bool, detect_stack_use_after_return, false,
"Enables stack-use-after-return checking at run-time.")
ASAN_FLAG(int, min_uar_stack_size_log, 16, // We can't do smaller anyway.
@@ -78,6 +75,8 @@ ASAN_FLAG(bool, print_stats, false,
"Print various statistics after printing an error message or if "
"atexit=1.")
ASAN_FLAG(bool, print_legend, true, "Print the legend for the shadow bytes.")
+ASAN_FLAG(bool, print_scariness, false,
+ "Print the scariness score. Experimental.")
ASAN_FLAG(bool, atexit, false,
"If set, prints ASan exit stats even after program terminates "
"successfully.")
@@ -97,15 +96,15 @@ ASAN_FLAG(bool, poison_array_cookie, true,
"Poison (or not) the array cookie after operator new[].")
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
-// https://code.google.com/p/address-sanitizer/issues/detail?id=131
-// https://code.google.com/p/address-sanitizer/issues/detail?id=309
+// https://github.com/google/sanitizers/issues/131
+// https://github.com/google/sanitizers/issues/309
// TODO(glider,timurrrr): Fix known issues and enable this back.
ASAN_FLAG(bool, alloc_dealloc_mismatch,
- (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0),
+ !SANITIZER_MAC && !SANITIZER_WINDOWS && !SANITIZER_ANDROID,
"Report errors on malloc/delete, new/free, new/delete[], etc.")
ASAN_FLAG(bool, new_delete_type_mismatch, true,
- "Report errors on mismatch betwen size of new and delete.")
+ "Report errors on mismatch between size of new and delete.")
ASAN_FLAG(
bool, strict_init_order, false,
"If true, assume that dynamic initializers can never access globals from "
@@ -124,8 +123,8 @@ ASAN_FLAG(
"The bigger the value the harder we try.")
ASAN_FLAG(
bool, detect_container_overflow, true,
- "If true, honor the container overflow annotations. "
- "See https://code.google.com/p/address-sanitizer/wiki/ContainerOverflow")
+ "If true, honor the container overflow annotations. See "
+ "https://github.com/google/sanitizers/wiki/AddressSanitizerContainerOverflow")
ASAN_FLAG(int, detect_odr_violation, 2,
"If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables "
@@ -136,3 +135,5 @@ ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report "
"(WARNING: USE AT YOUR OWN RISK!)")
+ASAN_FLAG(bool, use_odr_indicator, false,
+ "Use special ODR indicator symbol for ODR violation detection")
diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc
index f3531cbd133..f2292926e6a 100644
--- a/libsanitizer/asan/asan_globals.cc
+++ b/libsanitizer/asan/asan_globals.cc
@@ -23,6 +23,7 @@
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
namespace __asan {
@@ -121,16 +122,51 @@ int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites,
return res;
}
-bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
- Global g = {};
- if (GetGlobalsForAddress(addr, &g, nullptr, 1)) {
- internal_strncpy(descr->name, g.name, descr->name_size);
- descr->region_address = g.beg;
- descr->region_size = g.size;
- descr->region_kind = "global";
- return true;
+enum GlobalSymbolState {
+ UNREGISTERED = 0,
+ REGISTERED = 1
+};
+
+// Check ODR violation for given global G via special ODR indicator. We use
+// this method in case compiler instruments global variables through their
+// local aliases.
+static void CheckODRViolationViaIndicator(const Global *g) {
+ u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
+ if (*odr_indicator == UNREGISTERED) {
+ *odr_indicator = REGISTERED;
+ return;
+ }
+ // If *odr_indicator is DEFINED, some module have already registered
+ // externally visible symbol with the same name. This is an ODR violation.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->odr_indicator == l->g->odr_indicator &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
+ !IsODRViolationSuppressed(g->name))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
}
- return false;
+}
+
+// Clang provides two different ways for global variables protection:
+// it can poison the global itself or its private alias. In former
+// case we may poison same symbol multiple times, that can help us to
+// cheaply detect ODR violation: if we try to poison an already poisoned
+// global, we have ODR violation error.
+// In latter case, we poison each symbol exactly once, so we use special
+// indicator symbol to perform similar check.
+// In either case, compiler provides a special odr_indicator field to Global
+// structure, that can contain two kinds of values:
+// 1) Non-zero value. In this case, odr_indicator is an address of
+// corresponding indicator variable for given global.
+// 2) Zero. This means that we don't use private aliases for global variables
+// and can freely check ODR violation with the first method.
+//
+// This routine chooses between two different methods of ODR violation
+// detection.
+static inline bool UseODRIndicator(const Global *g) {
+ // Use ODR indicator method iff use_odr_indicator flag is set and
+ // indicator symbol address is not 0.
+ return flags()->use_odr_indicator && g->odr_indicator > 0;
}
// Register a global variable.
@@ -142,24 +178,22 @@ static void RegisterGlobal(const Global *g) {
ReportGlobal(*g, "Added");
CHECK(flags()->report_globals);
CHECK(AddrIsInMem(g->beg));
- CHECK(AddrIsAlignedByGranularity(g->beg));
+ if (!AddrIsAlignedByGranularity(g->beg)) {
+ Report("The following global variable is not properly aligned.\n");
+ Report("This may happen if another global with the same name\n");
+ Report("resides in another non-instrumented module.\n");
+ Report("Or the global comes from a C file built w/o -fno-common.\n");
+ Report("In either case this is likely an ODR violation bug,\n");
+ Report("but AddressSanitizer can not provide more details.\n");
+ ReportODRViolation(g, FindRegistrationSite(g), g, FindRegistrationSite(g));
+ CHECK(AddrIsAlignedByGranularity(g->beg));
+ }
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
- // This "ODR violation" detection is fundamentally incompatible with
- // how GCC registers globals. Disable as useless until rewritten upstream.
- if (0 && flags()->detect_odr_violation) {
+ if (flags()->detect_odr_violation) {
// Try detecting ODR (One Definition Rule) violation, i.e. the situation
// where two globals with the same name are defined in different modules.
- if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
- // This check may not be enough: if the first global is much larger
- // the entire redzone of the second global may be within the first global.
- for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
- if (g->beg == l->g->beg &&
- (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
- !IsODRViolationSuppressed(g->name))
- ReportODRViolation(g, FindRegistrationSite(g),
- l->g, FindRegistrationSite(l->g));
- }
- }
+ if (UseODRIndicator(g))
+ CheckODRViolationViaIndicator(g);
}
if (CanPoisonMemory())
PoisonRedZones(*g);
@@ -190,6 +224,12 @@ static void UnregisterGlobal(const Global *g) {
// 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.
+
+ // Release ODR indicator.
+ if (UseODRIndicator(g)) {
+ u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
+ *odr_indicator = UNREGISTERED;
+ }
}
void StopInitOrderChecking() {
@@ -207,11 +247,70 @@ void StopInitOrderChecking() {
}
}
+static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; }
+
+const char *MaybeDemangleGlobalName(const char *name) {
+ // We can spoil names of globals with C linkage, so use an heuristic
+ // approach to check if the name should be demangled.
+ bool should_demangle = false;
+ if (name[0] == '_' && name[1] == 'Z')
+ should_demangle = true;
+ else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
+ should_demangle = true;
+
+ return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
+}
+
+// Check if the global is a zero-terminated ASCII string. If so, print it.
+void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g) {
+ for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
+ unsigned char c = *(unsigned char *)p;
+ if (c == '\0' || !IsASCII(c)) return;
+ }
+ if (*(char *)(g.beg + g.size - 1) != '\0') return;
+ str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
+ (char *)g.beg);
+}
+
+static const char *GlobalFilename(const __asan_global &g) {
+ const char *res = g.module_name;
+ // Prefer the filename from source location, if is available.
+ if (g.location) res = g.location->filename;
+ CHECK(res);
+ return res;
+}
+
+void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g) {
+ str->append("%s", GlobalFilename(g));
+ if (!g.location) return;
+ if (g.location->line_no) str->append(":%d", g.location->line_no);
+ if (g.location->column_no) str->append(":%d", g.location->column_no);
+}
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
using namespace __asan; // NOLINT
+
+// Apply __asan_register_globals to all globals found in the same loaded
+// executable or shared library as `flag'. The flag tracks whether globals have
+// already been registered or not for this image.
+void __asan_register_image_globals(uptr *flag) {
+ if (*flag)
+ return;
+ AsanApplyToGlobals(__asan_register_globals, flag);
+ *flag = 1;
+}
+
+// This mirrors __asan_register_image_globals.
+void __asan_unregister_image_globals(uptr *flag) {
+ if (!*flag)
+ return;
+ AsanApplyToGlobals(__asan_unregister_globals, flag);
+ *flag = 0;
+}
+
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
diff --git a/libsanitizer/asan/asan_init_version.h b/libsanitizer/asan/asan_init_version.h
index 2cda18849dd..51e8324fc13 100644
--- a/libsanitizer/asan/asan_init_version.h
+++ b/libsanitizer/asan/asan_init_version.h
@@ -17,16 +17,20 @@ extern "C" {
// Every time the ASan ABI changes we also change the version number in the
// __asan_init function name. Objects built with incompatible ASan ABI
// versions will not link with run-time.
+ //
// Changes between ABI versions:
// v1=>v2: added 'module_name' to __asan_global
// v2=>v3: stack frame description (created by the compiler)
- // contains the function PC as the 3-rd field (see
- // DescribeAddressIfStack).
- // v3=>v4: added '__asan_global_source_location' to __asan_global.
+ // contains the function PC as the 3rd field (see
+ // DescribeAddressIfStack)
+ // v3=>v4: added '__asan_global_source_location' to __asan_global
// v4=>v5: changed the semantics and format of __asan_stack_malloc_ and
- // __asan_stack_free_ functions.
+ // __asan_stack_free_ functions
// v5=>v6: changed the name of the version check symbol
- #define __asan_version_mismatch_check __asan_version_mismatch_check_v6
+ // v6=>v7: added 'odr_indicator' to __asan_global
+ // v7=>v8: added '__asan_(un)register_image_globals' functions for dead
+ // stripping support on Mach-O platforms
+ #define __asan_version_mismatch_check __asan_version_mismatch_check_v8
}
#endif // ASAN_INIT_VERSION_H
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index 356f2c02897..743abe51481 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -19,6 +19,7 @@
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_suppressions.h"
+#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#if SANITIZER_POSIX
@@ -108,7 +109,7 @@ static inline bool RangesOverlap(const char *offset1, uptr length1,
} while (0)
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
-#if ASAN_INTERCEPT_STRNLEN
+#if SANITIZER_INTERCEPT_STRNLEN
if (REAL(strnlen)) {
return REAL(strnlen)(s, maxlen);
}
@@ -141,6 +142,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
(void) ctx; \
#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
+#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
+ ASAN_INTERCEPT_FUNC_VER(name, ver)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
ASAN_WRITE_RANGE(ctx, ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
@@ -176,7 +179,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
// Strict init-order checking is dlopen-hostile:
-// https://code.google.com/p/address-sanitizer/issues/detail?id=178
+// https://github.com/google/sanitizers/issues/178
#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
if (flags()->strict_init_order) { \
StopInitOrderChecking(); \
@@ -193,6 +196,10 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} else { \
*begin = *end = 0; \
}
+// Asan needs custom handling of these:
+#undef SANITIZER_INTERCEPT_MEMSET
+#undef SANITIZER_INTERCEPT_MEMMOVE
+#undef SANITIZER_INTERCEPT_MEMCPY
#include "sanitizer_common/sanitizer_common_interceptors.inc"
// Syscall interceptors don't have contexts, we don't support suppressions
@@ -216,6 +223,7 @@ struct ThreadStartParam {
atomic_uintptr_t is_registered;
};
+#if ASAN_INTERCEPT_PTHREAD_CREATE
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
AsanThread *t = nullptr;
@@ -226,7 +234,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
return t->ThreadStart(GetTid(), &param->is_registered);
}
-#if ASAN_INTERCEPT_PTHREAD_CREATE
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
EnsureMainThreadIDIsCorrect();
@@ -240,7 +247,17 @@ INTERCEPTOR(int, pthread_create, void *thread,
ThreadStartParam param;
atomic_store(&param.t, 0, memory_order_relaxed);
atomic_store(&param.is_registered, 0, memory_order_relaxed);
- int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ int result;
+ {
+ // Ignore all allocations made by pthread_create: thread stack/TLS may be
+ // stored by pthread for future reuse even after thread destruction, and
+ // the linked list it's stored in doesn't even hold valid pointers to the
+ // objects, the latter are calculated by obscure pointer arithmetic.
+#if CAN_SANITIZE_LEAKS
+ __lsan::ScopedInterceptorDisabler disabler;
+#endif
+ result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
+ }
if (result == 0) {
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t =
@@ -269,7 +286,8 @@ DEFINE_REAL_PTHREAD_FUNCTIONS
#if SANITIZER_ANDROID
INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
- if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ if (!IsHandledDeadlySignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(bsd_signal)(signum, handler);
}
return 0;
@@ -277,7 +295,8 @@ INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
#endif
INTERCEPTOR(void*, signal, int signum, void *handler) {
- if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ if (!IsHandledDeadlySignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(signal)(signum, handler);
}
return nullptr;
@@ -285,7 +304,8 @@ INTERCEPTOR(void*, signal, int signum, void *handler) {
INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
struct sigaction *oldact) {
- if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
+ if (!IsHandledDeadlySignal(signum) ||
+ common_flags()->allow_user_segv_handler) {
return REAL(sigaction)(signum, act, oldact);
}
return 0;
@@ -451,25 +471,6 @@ INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
ASAN_MEMSET_IMPL(ctx, block, c, size);
}
-INTERCEPTOR(char*, strchr, const char *str, int c) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, strchr);
- if (UNLIKELY(!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 len = REAL(strlen)(str);
- uptr bytes_read = (result ? result - str : len) + 1;
- ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
- }
- return result;
-}
-
#if ASAN_INTERCEPT_INDEX
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
INTERCEPTOR(char*, index, const char *string, int c)
@@ -547,7 +548,6 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
return REAL(strcpy)(to, from); // NOLINT
}
-#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strdup);
@@ -562,29 +562,28 @@ INTERCEPTOR(char*, strdup, const char *s) {
REAL(memcpy)(new_mem, s, length + 1);
return reinterpret_cast<char*>(new_mem);
}
-#endif
-INTERCEPTOR(SIZE_T, strlen, const char *s) {
+#if ASAN_INTERCEPT___STRDUP
+INTERCEPTOR(char*, __strdup, const char *s) {
void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, strlen);
- if (UNLIKELY(!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);
- }
+ ASAN_INTERCEPTOR_ENTER(ctx, strdup);
+ if (UNLIKELY(!asan_inited)) return internal_strdup(s);
ENSURE_ASAN_INITED();
- SIZE_T length = REAL(strlen)(s);
+ uptr length = REAL(strlen)(s);
if (flags()->replace_str) {
ASAN_READ_RANGE(ctx, s, length + 1);
}
- return length;
+ GET_STACK_TRACE_MALLOC;
+ void *new_mem = asan_malloc(length + 1, &stack);
+ REAL(memcpy)(new_mem, s, length + 1);
+ return reinterpret_cast<char*>(new_mem);
}
+#endif // ASAN_INTERCEPT___STRDUP
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
- SIZE_T length = REAL(wcslen)(s);
+ SIZE_T length = internal_wcslen(s);
if (!asan_init_is_running) {
ENSURE_ASAN_INITED();
ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
@@ -605,19 +604,6 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
return REAL(strncpy)(to, from, size);
}
-#if ASAN_INTERCEPT_STRNLEN
-INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
- ENSURE_ASAN_INITED();
- uptr length = REAL(strnlen)(s, maxlen);
- if (flags()->replace_str) {
- ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
- }
- return length;
-}
-#endif // ASAN_INTERCEPT_STRNLEN
-
INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
char **endptr, int base) {
void *ctx;
@@ -700,12 +686,12 @@ INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
}
#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
+#if ASAN_INTERCEPT___CXA_ATEXIT
static void AtCxaAtexit(void *unused) {
(void)unused;
StopInitOrderChecking();
}
-#if ASAN_INTERCEPT___CXA_ATEXIT
INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
void *dso_handle) {
#if SANITIZER_MAC
@@ -732,7 +718,7 @@ INTERCEPTOR(int, fork, void) {
namespace __asan {
void InitializeAsanInterceptors() {
static bool was_called_once;
- CHECK(was_called_once == false);
+ CHECK(!was_called_once);
was_called_once = true;
InitializeCommonInterceptors();
@@ -740,22 +726,22 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(memmove);
ASAN_INTERCEPT_FUNC(memset);
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
+ // In asan, REAL(memmove) is not used, but it is used in msan.
ASAN_INTERCEPT_FUNC(memcpy);
+ } else {
+ ASSIGN_REAL(memcpy, memmove);
}
+ CHECK(REAL(memcpy));
// Intercept str* functions.
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
- ASAN_INTERCEPT_FUNC(strchr);
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
- ASAN_INTERCEPT_FUNC(strlen);
ASAN_INTERCEPT_FUNC(wcslen);
ASAN_INTERCEPT_FUNC(strncat);
ASAN_INTERCEPT_FUNC(strncpy);
-#if ASAN_INTERCEPT_STRDUP
ASAN_INTERCEPT_FUNC(strdup);
-#endif
-#if ASAN_INTERCEPT_STRNLEN
- ASAN_INTERCEPT_FUNC(strnlen);
+#if ASAN_INTERCEPT___STRDUP
+ ASAN_INTERCEPT_FUNC(__strdup);
#endif
#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
ASAN_INTERCEPT_FUNC(index);
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 46c74176ed3..7053bb7faf5 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -21,14 +21,12 @@
#if !SANITIZER_WINDOWS
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 1
# define ASAN_INTERCEPT__LONGJMP 1
-# define ASAN_INTERCEPT_STRDUP 1
# define ASAN_INTERCEPT_INDEX 1
# define ASAN_INTERCEPT_PTHREAD_CREATE 1
# define ASAN_INTERCEPT_FORK 1
#else
# define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0
# define ASAN_INTERCEPT__LONGJMP 0
-# define ASAN_INTERCEPT_STRDUP 0
# define ASAN_INTERCEPT_INDEX 0
# define ASAN_INTERCEPT_PTHREAD_CREATE 0
# define ASAN_INTERCEPT_FORK 0
@@ -40,12 +38,6 @@
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif
-#if !SANITIZER_MAC
-# define ASAN_INTERCEPT_STRNLEN 1
-#else
-# define ASAN_INTERCEPT_STRNLEN 0
-#endif
-
#if SANITIZER_LINUX && !SANITIZER_ANDROID
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
@@ -78,6 +70,12 @@
# define ASAN_INTERCEPT___CXA_ATEXIT 0
#endif
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT___STRDUP 1
+#else
+# define ASAN_INTERCEPT___STRDUP 0
+#endif
+
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)
diff --git a/libsanitizer/asan/asan_interface_internal.h b/libsanitizer/asan/asan_interface_internal.h
index 079da9ca522..05605a8065f 100644
--- a/libsanitizer/asan/asan_interface_internal.h
+++ b/libsanitizer/asan/asan_interface_internal.h
@@ -21,6 +21,8 @@
#include "asan_init_version.h"
using __sanitizer::uptr;
+using __sanitizer::u64;
+using __sanitizer::u32;
extern "C" {
// This function should be called at the very beginning of the process,
@@ -52,8 +54,17 @@ extern "C" {
uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
__asan_global_source_location *location; // Source location of a global,
// or NULL if it is unknown.
+ uptr odr_indicator; // The address of the ODR indicator symbol.
};
+ // These functions can be called on some platforms to find globals in the same
+ // loaded image as `flag' and apply __asan_(un)register_globals to them,
+ // filtering out redundant calls.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_image_globals(uptr *flag);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_image_globals(uptr *flag);
+
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
SANITIZER_INTERFACE_ATTRIBUTE
@@ -68,6 +79,20 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_after_dynamic_init();
+ // Sets bytes of the given range of the shadow memory into specific value.
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_00(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_f1(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_f2(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_f3(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_f5(uptr addr, uptr size);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_set_shadow_f8(uptr addr, uptr size);
+
// These two functions are used by instrumented code in the
// use-after-scope mode. They mark memory for local variables as
// unaddressable when they leave scope and addressable before the
@@ -145,6 +170,9 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ const char* __asan_default_options();
+ SANITIZER_INTERFACE_ATTRIBUTE
+ extern uptr __asan_shadow_memory_dynamic_address;
+
// Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return
SANITIZER_INTERFACE_ATTRIBUTE
extern int __asan_option_detect_stack_use_after_return;
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index e31f2648b1a..15a28ff777b 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -34,9 +34,9 @@
// 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
-#if SANITIZER_WORDSIZE == 32
+# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32)
# define ASAN_LOW_MEMORY 1
-#else
+# else
# define ASAN_LOW_MEMORY 0
# endif
#endif
@@ -60,6 +60,12 @@ using __sanitizer::StackTrace;
void AsanInitFromRtl();
+// asan_win.cc
+void InitializePlatformExceptionHandlers();
+
+// asan_win.cc / asan_posix.cc
+const char *DescribeSignalOrException(int signo);
+
// asan_rtl.cc
void NORETURN ShowStatsAndAbort();
@@ -71,10 +77,15 @@ void *AsanDoesNotSupportStaticLinkage();
void AsanCheckDynamicRTPrereqs();
void AsanCheckIncompatibleRT();
+// Support function for __asan_(un)register_image_globals. Searches for the
+// loaded image containing `needle' and then enumerates all global metadata
+// structures declared in that image, applying `op' (e.g.,
+// __asan_(un)register_globals) to them.
+typedef void (*globals_op_fptr)(__asan_global *, uptr);
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
+
void AsanOnDeadlySignal(int, void *siginfo, void *context);
-void DisableReexec();
-void MaybeReexec();
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
void StopInitOrderChecking();
@@ -95,16 +106,24 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
bool PlatformHasDifferentMemcpyAndMemmove();
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
(PlatformHasDifferentMemcpyAndMemmove())
+#elif SANITIZER_WINDOWS64
+# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
#else
# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
#endif // SANITIZER_MAC
// Add convenient macro for interface functions that may be represented as
// weak hooks.
-#define ASAN_MALLOC_HOOK(ptr, size) \
- if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
-#define ASAN_FREE_HOOK(ptr) \
- if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
+#define ASAN_MALLOC_HOOK(ptr, size) \
+ do { \
+ if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size); \
+ RunMallocHooks(ptr, size); \
+ } while (false)
+#define ASAN_FREE_HOOK(ptr) \
+ do { \
+ if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr); \
+ RunFreeHooks(ptr); \
+ } while (false)
#define ASAN_ON_ERROR() \
if (&__asan_on_error) __asan_on_error()
@@ -112,15 +131,12 @@ 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;
diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc
index 4e47d5a0496..9f058df71a5 100644
--- a/libsanitizer/asan/asan_linux.cc
+++ b/libsanitizer/asan/asan_linux.cc
@@ -67,20 +67,17 @@ asan_rt_version_t __asan_rt_version;
namespace __asan {
void InitializePlatformInterceptors() {}
-
-void DisableReexec() {
- // No need to re-exec on Linux.
-}
-
-void MaybeReexec() {
- // No need to re-exec on Linux.
-}
+void InitializePlatformExceptionHandlers() {}
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
return &_DYNAMIC; // defined in link.h
}
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
+ UNIMPLEMENTED();
+}
+
#if SANITIZER_ANDROID
// FIXME: should we do anything for Android?
void AsanCheckDynamicRTPrereqs() {}
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index ab3c6560825..4bf79be1728 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -22,18 +22,11 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mac.h"
-#if !SANITIZER_IOS
-#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
-#else
-extern "C" {
- extern char ***_NSGetArgv(void);
-}
-#endif
-
-#include <dlfcn.h> // for dladdr()
+#include <dlfcn.h>
#include <fcntl.h>
#include <libkern/OSAtomic.h>
#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
#include <mach-o/loader.h>
#include <pthread.h>
#include <stdlib.h> // for free()
@@ -43,193 +36,26 @@ extern "C" {
#include <sys/ucontext.h>
#include <unistd.h>
+// from <crt_externs.h>, but we don't have that file on iOS
+extern "C" {
+ extern char ***_NSGetArgv(void);
+ extern char ***_NSGetEnviron(void);
+}
+
namespace __asan {
void InitializePlatformInterceptors() {}
+void InitializePlatformExceptionHandlers() {}
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.
+ // See also https://github.com/google/sanitizers/issues/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";
-LowLevelAllocator allocator_for_env;
-
-// Change the value of the env var |name|, leaking the original value.
-// If |name_value| is NULL, the variable is deleted from the environment,
-// otherwise the corresponding "NAME=value" string is replaced with
-// |name_value|.
-void LeakyResetEnv(const char *name, const char *name_value) {
- char **env = GetEnviron();
- uptr name_len = internal_strlen(name);
- while (*env != 0) {
- uptr len = internal_strlen(*env);
- if (len > name_len) {
- const char *p = *env;
- if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
- // Match.
- if (name_value) {
- // Replace the old value with the new one.
- *env = const_cast<char*>(name_value);
- } else {
- // Shift the subsequent pointers back.
- char **del = env;
- do {
- del[0] = del[1];
- } while (*del++);
- }
- }
- }
- env++;
- }
-}
-
-static bool reexec_disabled = false;
-
-void DisableReexec() {
- reexec_disabled = true;
-}
-
-extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber;
-static const double kMinDyldVersionWithAutoInterposition = 360.0;
-
-bool DyldNeedsEnvVariable() {
- // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users
- // still may want use them on older systems. On older Darwin platforms, dyld
- // doesn't export dyldVersionNumber symbol and we simply return true.
- if (!&dyldVersionNumber) return true;
- // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
- // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via
- // GetMacosVersion() doesn't work for the simulator. Let's instead check
- // `dyldVersionNumber`, which is exported by dyld, against a known version
- // number from the first OS release where this appeared.
- return dyldVersionNumber < kMinDyldVersionWithAutoInterposition;
-}
-
-void MaybeReexec() {
- if (reexec_disabled) return;
-
- // Make sure the dynamic ASan runtime 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));
- char *dyld_insert_libraries =
- const_cast<char*>(GetEnv(kDyldInsertLibraries));
- uptr old_env_len = dyld_insert_libraries ?
- internal_strlen(dyld_insert_libraries) : 0;
- uptr fname_len = internal_strlen(info.dli_fname);
- const char *dylib_name = StripModuleName(info.dli_fname);
- uptr dylib_name_len = internal_strlen(dylib_name);
-
- bool lib_is_in_env =
- dyld_insert_libraries && REAL(strstr)(dyld_insert_libraries, dylib_name);
- if (DyldNeedsEnvVariable() && !lib_is_in_env) {
- // 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);
- char *new_env = const_cast<char*>(info.dli_fname);
- if (dyld_insert_libraries) {
- // Append the runtime dylib name to the existing value of
- // DYLD_INSERT_LIBRARIES.
- new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
- internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
- new_env[old_env_len] = ':';
- // Copy fname_len and add a trailing zero.
- internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
- fname_len + 1);
- // Ok to use setenv() since the wrappers don't depend on the value of
- // asan_inited.
- setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
- } else {
- // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
- setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
- }
- VReport(1, "exec()-ing the program with\n");
- VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
- VReport(1, "to enable ASan wrappers.\n");
- execv(program_name, *_NSGetArgv());
-
- // We get here only if execv() failed.
- Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
- "which is required for ASan to work. ASan tried to set the "
- "environment variable and re-execute itself, but execv() failed, "
- "possibly because of sandbox restrictions. Make sure to launch the "
- "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
- CHECK("execv failed" && 0);
- }
-
- if (!lib_is_in_env)
- return;
-
- // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
- // the dylib from the environment variable, because interceptors are installed
- // and we don't want our children to inherit the variable.
-
- uptr env_name_len = internal_strlen(kDyldInsertLibraries);
- // Allocate memory to hold the previous env var name, its value, the '='
- // sign and the '\0' char.
- char *new_env = (char*)allocator_for_env.Allocate(
- old_env_len + 2 + env_name_len);
- CHECK(new_env);
- internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
- internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
- new_env[env_name_len] = '=';
- char *new_env_pos = new_env + env_name_len + 1;
-
- // Iterate over colon-separated pieces of |dyld_insert_libraries|.
- char *piece_start = dyld_insert_libraries;
- char *piece_end = NULL;
- char *old_env_end = dyld_insert_libraries + old_env_len;
- do {
- if (piece_start[0] == ':') piece_start++;
- piece_end = REAL(strchr)(piece_start, ':');
- if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
- if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
- uptr piece_len = piece_end - piece_start;
-
- char *filename_start =
- (char *)internal_memrchr(piece_start, '/', piece_len);
- uptr filename_len = piece_len;
- if (filename_start) {
- filename_start += 1;
- filename_len = piece_len - (filename_start - piece_start);
- } else {
- filename_start = piece_start;
- }
-
- // If the current piece isn't the runtime library name,
- // append it to new_env.
- if ((dylib_name_len != filename_len) ||
- (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
- if (new_env_pos != new_env + env_name_len + 1) {
- new_env_pos[0] = ':';
- new_env_pos++;
- }
- internal_strncpy(new_env_pos, piece_start, piece_len);
- new_env_pos += piece_len;
- }
- // Move on to the next piece.
- piece_start = piece_end;
- } while (piece_start < old_env_end);
-
- // Can't use setenv() here, because it requires the allocator to be
- // initialized.
- // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
- // a separate function called after InitializeAllocator().
- if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
- LeakyResetEnv(kDyldInsertLibraries, new_env);
-}
-
// No-op. Mac does not support static linkage anyway.
void *AsanDoesNotSupportStaticLinkage() {
return 0;
@@ -241,6 +67,30 @@ void AsanCheckDynamicRTPrereqs() {}
// No-op. Mac does not support static linkage anyway.
void AsanCheckIncompatibleRT() {}
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
+ // Find the Mach-O header for the image containing the needle
+ Dl_info info;
+ int err = dladdr(needle, &info);
+ if (err == 0) return;
+
+#if __LP64__
+ const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase;
+#else
+ const struct mach_header *mh = (struct mach_header *)info.dli_fbase;
+#endif
+
+ // Look up the __asan_globals section in that image and register its globals
+ unsigned long size = 0;
+ __asan_global *globals = (__asan_global *)getsectiondata(
+ mh,
+ "__DATA", "__asan_globals",
+ &size);
+
+ if (!globals) return;
+ if (size % sizeof(__asan_global) != 0) return;
+ op(globals, size / sizeof(__asan_global));
+}
+
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
UNIMPLEMENTED();
}
diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc
index bfe72af69e6..cc50a388495 100644
--- a/libsanitizer/asan/asan_malloc_linux.cc
+++ b/libsanitizer/asan/asan_malloc_linux.cc
@@ -76,7 +76,13 @@ INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
- void *new_ptr = asan_malloc(size, &stack);
+ void *new_ptr;
+ if (UNLIKELY(!asan_inited)) {
+ new_ptr = AllocateFromLocalPool(size);
+ } else {
+ copy_size = size;
+ new_ptr = asan_malloc(copy_size, &stack);
+ }
internal_memcpy(new_ptr, ptr, copy_size);
return new_ptr;
}
@@ -96,7 +102,7 @@ INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
- DTLS_on_libc_memalign(res, size * boundary);
+ DTLS_on_libc_memalign(res, size);
return res;
}
diff --git a/libsanitizer/asan/asan_malloc_mac.cc b/libsanitizer/asan/asan_malloc_mac.cc
index 33ccbf09470..1ca665d84c5 100644
--- a/libsanitizer/asan/asan_malloc_mac.cc
+++ b/libsanitizer/asan/asan_malloc_mac.cc
@@ -52,10 +52,6 @@ using namespace __asan;
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
GET_STACK_TRACE_FREE; \
ReportMacMzReallocUnknown((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
-#define COMMON_MALLOC_IGNORE_INVALID_FREE flags()->mac_ignore_invalid_free
-#define COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name) \
- GET_STACK_TRACE_FREE; \
- WarnMacFreeUnallocated((uptr)ptr, (uptr)zone_ptr, zone_name, &stack);
#define COMMON_MALLOC_NAMESPACE __asan
#include "sanitizer_common/sanitizer_malloc_mac.inc"
diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc
index f2ab188bf5b..f38cd054bb0 100644
--- a/libsanitizer/asan/asan_malloc_win.cc
+++ b/libsanitizer/asan/asan_malloc_win.cc
@@ -12,6 +12,8 @@
#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
#include "asan_allocator.h"
#include "asan_interceptors.h"
@@ -47,6 +49,11 @@ void _free_dbg(void *ptr, int) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
+void _free_base(void *ptr) {
+ free(ptr);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
void cfree(void *ptr) {
CHECK(!"cfree() should not be used on Windows");
}
@@ -58,6 +65,11 @@ void *malloc(size_t size) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
+void *_malloc_base(size_t size) {
+ return malloc(size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_malloc_dbg(size_t size, int, const char *, int) {
return malloc(size);
}
@@ -69,6 +81,11 @@ void *calloc(size_t nmemb, size_t size) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
+void *_calloc_base(size_t nmemb, size_t size) {
+ return calloc(nmemb, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
return calloc(nmemb, size);
}
@@ -91,6 +108,11 @@ void *_realloc_dbg(void *ptr, size_t size, int) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
+void *_realloc_base(void *ptr, size_t size) {
+ return realloc(ptr, size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
void *_recalloc(void *p, size_t n, size_t elem_size) {
if (!p)
return calloc(n, elem_size);
@@ -101,7 +123,12 @@ void *_recalloc(void *p, size_t n, size_t elem_size) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize(void *ptr) {
+void *_recalloc_base(void *p, size_t n, size_t elem_size) {
+ return _recalloc(p, n, elem_size);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
+size_t _msize(const void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return asan_malloc_usable_size(ptr, pc, bp);
@@ -137,38 +164,90 @@ int _CrtSetReportMode(int, int) {
}
} // extern "C"
+INTERCEPTOR_WINAPI(LPVOID, HeapAlloc, HANDLE hHeap, DWORD dwFlags,
+ SIZE_T dwBytes) {
+ GET_STACK_TRACE_MALLOC;
+ void *p = asan_malloc(dwBytes, &stack);
+ // Reading MSDN suggests that the *entire* usable allocation is zeroed out.
+ // Otherwise it is difficult to HeapReAlloc with HEAP_ZERO_MEMORY.
+ // https://blogs.msdn.microsoft.com/oldnewthing/20120316-00/?p=8083
+ if (dwFlags == HEAP_ZERO_MEMORY)
+ internal_memset(p, 0, asan_mz_size(p));
+ else
+ CHECK(dwFlags == 0 && "unsupported heap flags");
+ return p;
+}
+
+INTERCEPTOR_WINAPI(BOOL, HeapFree, HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) {
+ CHECK(dwFlags == 0 && "unsupported heap flags");
+ GET_STACK_TRACE_FREE;
+ asan_free(lpMem, &stack, FROM_MALLOC);
+ return true;
+}
+
+INTERCEPTOR_WINAPI(LPVOID, HeapReAlloc, HANDLE hHeap, DWORD dwFlags,
+ LPVOID lpMem, SIZE_T dwBytes) {
+ GET_STACK_TRACE_MALLOC;
+ // Realloc should never reallocate in place.
+ if (dwFlags & HEAP_REALLOC_IN_PLACE_ONLY)
+ return nullptr;
+ CHECK(dwFlags == 0 && "unsupported heap flags");
+ return asan_realloc(lpMem, dwBytes, &stack);
+}
+
+INTERCEPTOR_WINAPI(SIZE_T, HeapSize, HANDLE hHeap, DWORD dwFlags,
+ LPCVOID lpMem) {
+ CHECK(dwFlags == 0 && "unsupported heap flags");
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(lpMem, pc, bp);
+}
+
namespace __asan {
+
+static void TryToOverrideFunction(const char *fname, uptr new_func) {
+ // Failure here is not fatal. The CRT may not be present, and different CRT
+ // versions use different symbols.
+ if (!__interception::OverrideFunction(fname, new_func))
+ VPrintf(2, "Failed to override function %s\n", fname);
+}
+
void ReplaceSystemMalloc() {
#if defined(ASAN_DYNAMIC)
- // We don't check the result because CRT might not be used in the process.
- __interception::OverrideFunction("free", (uptr)free);
- __interception::OverrideFunction("malloc", (uptr)malloc);
- __interception::OverrideFunction("_malloc_crt", (uptr)malloc);
- __interception::OverrideFunction("calloc", (uptr)calloc);
- __interception::OverrideFunction("_calloc_crt", (uptr)calloc);
- __interception::OverrideFunction("realloc", (uptr)realloc);
- __interception::OverrideFunction("_realloc_crt", (uptr)realloc);
- __interception::OverrideFunction("_recalloc", (uptr)_recalloc);
- __interception::OverrideFunction("_recalloc_crt", (uptr)_recalloc);
- __interception::OverrideFunction("_msize", (uptr)_msize);
- __interception::OverrideFunction("_expand", (uptr)_expand);
-
- // Override different versions of 'operator new' and 'operator delete'.
- // No need to override the nothrow versions as they just wrap the throw
- // versions.
- // FIXME: Unfortunately, MSVC miscompiles the statements that take the
- // addresses of the array versions of these operators,
- // see https://connect.microsoft.com/VisualStudio/feedbackdetail/view/946992
- // We might want to try to work around this by [inline] assembly or compiling
- // parts of the RTL with Clang.
- void *(*op_new)(size_t sz) = operator new;
- void (*op_delete)(void *p) = operator delete;
- void *(*op_array_new)(size_t sz) = operator new[];
- void (*op_array_delete)(void *p) = operator delete[];
- __interception::OverrideFunction("??2@YAPAXI@Z", (uptr)op_new);
- __interception::OverrideFunction("??3@YAXPAX@Z", (uptr)op_delete);
- __interception::OverrideFunction("??_U@YAPAXI@Z", (uptr)op_array_new);
- __interception::OverrideFunction("??_V@YAXPAX@Z", (uptr)op_array_delete);
+ TryToOverrideFunction("free", (uptr)free);
+ TryToOverrideFunction("_free_base", (uptr)free);
+ TryToOverrideFunction("malloc", (uptr)malloc);
+ TryToOverrideFunction("_malloc_base", (uptr)malloc);
+ TryToOverrideFunction("_malloc_crt", (uptr)malloc);
+ TryToOverrideFunction("calloc", (uptr)calloc);
+ TryToOverrideFunction("_calloc_base", (uptr)calloc);
+ TryToOverrideFunction("_calloc_crt", (uptr)calloc);
+ TryToOverrideFunction("realloc", (uptr)realloc);
+ TryToOverrideFunction("_realloc_base", (uptr)realloc);
+ TryToOverrideFunction("_realloc_crt", (uptr)realloc);
+ TryToOverrideFunction("_recalloc", (uptr)_recalloc);
+ TryToOverrideFunction("_recalloc_base", (uptr)_recalloc);
+ TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
+ TryToOverrideFunction("_msize", (uptr)_msize);
+ TryToOverrideFunction("_expand", (uptr)_expand);
+ TryToOverrideFunction("_expand_base", (uptr)_expand);
+
+ // Recent versions of ucrtbase.dll appear to be built with PGO and LTCG, which
+ // enable cross-module inlining. This means our _malloc_base hook won't catch
+ // all CRT allocations. This code here patches the import table of
+ // ucrtbase.dll so that all attempts to use the lower-level win32 heap
+ // allocation API will be directed to ASan's heap. We don't currently
+ // intercept all calls to HeapAlloc. If we did, we would have to check on
+ // HeapFree whether the pointer came from ASan of from the system.
+#define INTERCEPT_UCRT_FUNCTION(func) \
+ if (!INTERCEPT_FUNCTION_DLLIMPORT("ucrtbase.dll", \
+ "api-ms-win-core-heap-l1-1-0.dll", func)) \
+ VPrintf(2, "Failed to intercept ucrtbase.dll import %s\n", #func);
+ INTERCEPT_UCRT_FUNCTION(HeapAlloc);
+ INTERCEPT_UCRT_FUNCTION(HeapFree);
+ INTERCEPT_UCRT_FUNCTION(HeapReAlloc);
+ INTERCEPT_UCRT_FUNCTION(HeapSize);
+#undef INTERCEPT_UCRT_FUNCTION
#endif
}
} // namespace __asan
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index b584cfa2f3c..b9fa5f79481 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -15,7 +15,7 @@
#include "asan_internal.h"
// The full explanation of the memory mapping could be found here:
-// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm
//
// Typical shadow mapping on Linux/x86_64 with SHADOW_OFFSET == 0x00007fff8000:
// || `[0x10007fff8000, 0x7fffffffffff]` || HighMem ||
@@ -85,6 +85,20 @@
// || `[0x08000000000, 0x08fffffffff]` || lowshadow ||
// || `[0x00000000000, 0x07fffffffff]` || lowmem ||
//
+// Default Linux/S390 mapping:
+// || `[0x30000000, 0x7fffffff]` || HighMem ||
+// || `[0x26000000, 0x2fffffff]` || HighShadow ||
+// || `[0x24000000, 0x25ffffff]` || ShadowGap ||
+// || `[0x20000000, 0x23ffffff]` || LowShadow ||
+// || `[0x00000000, 0x1fffffff]` || LowMem ||
+//
+// Default Linux/SystemZ mapping:
+// || `[0x14000000000000, 0x1fffffffffffff]` || HighMem ||
+// || `[0x12800000000000, 0x13ffffffffffff]` || HighShadow ||
+// || `[0x12000000000000, 0x127fffffffffff]` || ShadowGap ||
+// || `[0x10000000000000, 0x11ffffffffffff]` || LowShadow ||
+// || `[0x00000000000000, 0x0fffffffffffff]` || LowMem ||
+//
// Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
// || `[0x500000000000, 0x7fffffffffff]` || HighMem ||
// || `[0x4a0000000000, 0x4fffffffffff]` || HighShadow ||
@@ -109,17 +123,19 @@
// || `[0x00000000, 0x2fffffff]` || LowMem ||
static const u64 kDefaultShadowScale = 3;
+static const u64 kDefaultShadowSentinel = ~(uptr)0;
static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000
static const u64 kDefaultShadowOffset64 = 1ULL << 44;
static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G.
static const u64 kIosShadowOffset32 = 1ULL << 30; // 0x40000000
-static const u64 kIosShadowOffset64 = 0x130000000;
+static const u64 kIosShadowOffset64 = 0x120200000;
static const u64 kIosSimShadowOffset32 = 1ULL << 30;
static const u64 kIosSimShadowOffset64 = kDefaultShadowOffset64;
static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37;
static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
+static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
@@ -136,28 +152,36 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# define SHADOW_OFFSET kFreeBSD_ShadowOffset32
# elif SANITIZER_WINDOWS
# define SHADOW_OFFSET kWindowsShadowOffset32
-# elif SANITIZER_IOSSIM
-# define SHADOW_OFFSET kIosSimShadowOffset32
# elif SANITIZER_IOS
-# define SHADOW_OFFSET kIosShadowOffset32
+# if SANITIZER_IOSSIM
+# define SHADOW_OFFSET kIosSimShadowOffset32
+# else
+# define SHADOW_OFFSET kIosShadowOffset32
+# endif
# else
# define SHADOW_OFFSET kDefaultShadowOffset32
# endif
#else
-# if defined(__aarch64__)
+# if SANITIZER_IOS
+# if SANITIZER_IOSSIM
+# define SHADOW_OFFSET kIosSimShadowOffset64
+# else
+# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
+# endif
+# elif defined(__aarch64__)
# define SHADOW_OFFSET kAArch64_ShadowOffset64
# elif defined(__powerpc64__)
# define SHADOW_OFFSET kPPC64_ShadowOffset64
+# elif defined(__s390x__)
+# define SHADOW_OFFSET kSystemZ_ShadowOffset64
# elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
# elif SANITIZER_MAC
# define SHADOW_OFFSET kDefaultShadowOffset64
# elif defined(__mips64)
# define SHADOW_OFFSET kMIPS64_ShadowOffset64
-# elif SANITIZER_IOSSIM
-# define SHADOW_OFFSET kIosSimShadowOffset64
-# elif SANITIZER_IOS
-# define SHADOW_OFFSET kIosShadowOffset64
+# elif SANITIZER_WINDOWS64
+# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
# else
# define SHADOW_OFFSET kDefaultShort64bitShadowOffset
# endif
@@ -243,9 +267,25 @@ static inline bool AddrIsInMidMem(uptr a) {
return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd;
}
+static inline bool AddrIsInShadowGap(uptr a) {
+ PROFILE_ASAN_MAPPING();
+ if (kMidMemBeg) {
+ if (a <= kShadowGapEnd)
+ return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
+ return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
+ (a >= kShadowGap3Beg && a <= kShadowGap3End);
+ }
+ // In zero-based shadow mode we treat addresses near zero as addresses
+ // in shadow gap as well.
+ if (SHADOW_OFFSET == 0)
+ return a <= kShadowGapEnd;
+ return a >= kShadowGapBeg && a <= kShadowGapEnd;
+}
+
static inline bool AddrIsInMem(uptr a) {
PROFILE_ASAN_MAPPING();
- return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a);
+ return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) ||
+ (flags()->protect_shadow_gap == 0 && AddrIsInShadowGap(a));
}
static inline uptr MemToShadow(uptr p) {
@@ -269,21 +309,6 @@ static inline bool AddrIsInShadow(uptr a) {
return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a);
}
-static inline bool AddrIsInShadowGap(uptr a) {
- PROFILE_ASAN_MAPPING();
- if (kMidMemBeg) {
- if (a <= kShadowGapEnd)
- return SHADOW_OFFSET == 0 || a >= kShadowGapBeg;
- return (a >= kShadowGap2Beg && a <= kShadowGap2End) ||
- (a >= kShadowGap3Beg && a <= kShadowGap3End);
- }
- // In zero-based shadow mode we treat addresses near zero as addresses
- // in shadow gap as well.
- if (SHADOW_OFFSET == 0)
- return a <= kShadowGapEnd;
- return a >= kShadowGapBeg && a <= kShadowGapEnd;
-}
-
static inline bool AddrIsAlignedByGranularity(uptr a) {
PROFILE_ASAN_MAPPING();
return (a & (SHADOW_GRANULARITY - 1)) == 0;
diff --git a/libsanitizer/asan/asan_memory_profile.cc b/libsanitizer/asan/asan_memory_profile.cc
new file mode 100644
index 00000000000..5a2578596ad
--- /dev/null
+++ b/libsanitizer/asan/asan_memory_profile.cc
@@ -0,0 +1,98 @@
+//===-- asan_memory_profile.cc.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 implements __sanitizer_print_memory_profile.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "lsan/lsan_common.h"
+#include "asan/asan_allocator.h"
+
+#if CAN_SANITIZE_LEAKS
+
+namespace __asan {
+
+struct AllocationSite {
+ u32 id;
+ uptr total_size;
+ uptr count;
+};
+
+class HeapProfile {
+ public:
+ HeapProfile() : allocations_(1024) {}
+ void Insert(u32 id, uptr size) {
+ total_allocated_ += size;
+ total_count_++;
+ // Linear lookup will be good enough for most cases (although not all).
+ for (uptr i = 0; i < allocations_.size(); i++) {
+ if (allocations_[i].id == id) {
+ allocations_[i].total_size += size;
+ allocations_[i].count++;
+ return;
+ }
+ }
+ allocations_.push_back({id, size, 1});
+ }
+
+ void Print(uptr top_percent) {
+ InternalSort(&allocations_, allocations_.size(),
+ [](const AllocationSite &a, const AllocationSite &b) {
+ return a.total_size > b.total_size;
+ });
+ CHECK(total_allocated_);
+ uptr total_shown = 0;
+ Printf("Live Heap Allocations: %zd bytes from %zd allocations; "
+ "showing top %zd%%\n", total_allocated_, total_count_, top_percent);
+ for (uptr i = 0; i < allocations_.size(); i++) {
+ auto &a = allocations_[i];
+ Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,
+ a.total_size * 100 / total_allocated_, a.count);
+ StackDepotGet(a.id).Print();
+ total_shown += a.total_size;
+ if (total_shown * 100 / total_allocated_ > top_percent)
+ break;
+ }
+ }
+
+ private:
+ uptr total_allocated_ = 0;
+ uptr total_count_ = 0;
+ InternalMmapVector<AllocationSite> allocations_;
+};
+
+static void ChunkCallback(uptr chunk, void *arg) {
+ HeapProfile *hp = reinterpret_cast<HeapProfile*>(arg);
+ AsanChunkView cv = FindHeapChunkByAllocBeg(chunk);
+ if (!cv.IsAllocated()) return;
+ u32 id = cv.GetAllocStackId();
+ if (!id) return;
+ hp->Insert(id, cv.UsedSize());
+}
+
+static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
+ HeapProfile hp;
+ __lsan::ForEachChunk(ChunkCallback, &hp);
+ hp.Print(reinterpret_cast<uptr>(argument));
+}
+
+} // namespace __asan
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_memory_profile(uptr top_percent) {
+ __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent);
+}
+} // extern "C"
+
+#endif // CAN_SANITIZE_LEAKS
diff --git a/libsanitizer/asan/asan_new_delete.cc b/libsanitizer/asan/asan_new_delete.cc
index bf7a34ac87b..2c4642cb27e 100644
--- a/libsanitizer/asan/asan_new_delete.cc
+++ b/libsanitizer/asan/asan_new_delete.cc
@@ -18,9 +18,25 @@
#include <stddef.h>
-// C++ operators can't have visibility attributes on Windows.
+// C++ operators can't have dllexport attributes on Windows. We export them
+// anyway by passing extra -export flags to the linker, which is exactly that
+// dllexport would normally do. We need to export them in order to make the
+// VS2015 dynamic CRT (MD) work.
#if SANITIZER_WINDOWS
# define CXX_OPERATOR_ATTRIBUTE
+# ifdef _WIN64
+# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new
+# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete
+# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete
+# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[]
+# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[]
+# else
+# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new
+# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete
+# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete
+# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[]
+# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[]
+# endif
#else
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
#endif
@@ -37,7 +53,7 @@ using namespace __asan; // NOLINT
#endif // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
// This code has issues on OSX.
-// See https://code.google.com/p/address-sanitizer/issues/detail?id=131.
+// See https://github.com/google/sanitizers/issues/131.
// Fake std::nothrow_t and std::align_val_t to avoid including <new>.
namespace std {
diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc
index 39f74879b38..8fe2bd42bdb 100644
--- a/libsanitizer/asan/asan_poisoning.cc
+++ b/libsanitizer/asan/asan_poisoning.cc
@@ -67,7 +67,7 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
uptr page_size = GetPageSizeCached();
uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
- FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+ ReleaseMemoryToOS(shadow_beg, shadow_end - shadow_beg);
}
void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
@@ -100,7 +100,7 @@ using namespace __asan; // NOLINT
// 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).
+// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm).
//
// * if user asks to poison region [left, right), the program poisons
// at least [left, AlignDown(right)).
@@ -115,9 +115,9 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
- CHECK(beg.offset < end.offset);
+ CHECK_LT(beg.offset, end.offset);
s8 value = beg.value;
- CHECK(value == end.value);
+ CHECK_EQ(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) {
@@ -129,7 +129,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
}
return;
}
- CHECK(beg.chunk < end.chunk);
+ CHECK_LT(beg.chunk, end.chunk);
if (beg.offset > 0) {
// Mark bytes from beg.offset as unaddressable.
if (beg.value == 0) {
@@ -155,9 +155,9 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
ShadowSegmentEndpoint beg(beg_addr);
ShadowSegmentEndpoint end(end_addr);
if (beg.chunk == end.chunk) {
- CHECK(beg.offset < end.offset);
+ CHECK_LT(beg.offset, end.offset);
s8 value = beg.value;
- CHECK(value == end.value);
+ CHECK_EQ(value, end.value);
// We unpoison memory bytes up to enbytes up to end.offset if it is not
// unpoisoned already.
if (value != 0) {
@@ -165,7 +165,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
}
return;
}
- CHECK(beg.chunk < end.chunk);
+ CHECK_LT(beg.chunk, end.chunk);
if (beg.offset > 0) {
*beg.chunk = 0;
beg.chunk++;
@@ -312,6 +312,30 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
}
+void __asan_set_shadow_00(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0, size);
+}
+
+void __asan_set_shadow_f1(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0xf1, size);
+}
+
+void __asan_set_shadow_f2(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0xf2, size);
+}
+
+void __asan_set_shadow_f3(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0xf3, size);
+}
+
+void __asan_set_shadow_f5(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0xf5, size);
+}
+
+void __asan_set_shadow_f8(uptr addr, uptr size) {
+ REAL(memset)((void *)addr, 0xf8, size);
+}
+
void __asan_poison_stack_memory(uptr addr, uptr size) {
VReport(1, "poisoning: %p %zx\n", (void *)addr, size);
PoisonAlignedStackMemory(addr, size, true);
@@ -341,7 +365,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
&stack);
}
CHECK_LE(end - beg,
- FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
+ FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
@@ -352,7 +376,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
// Make a quick sanity check that we are indeed in this state.
//
// FIXME: Two of these three checks are disabled until we fix
- // https://code.google.com/p/address-sanitizer/issues/detail?id=258.
+ // https://github.com/google/sanitizers/issues/258.
// if (d1 != d2)
// CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
if (a + granularity <= d1)
diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h
index 30e39e9077c..4ddcbc314d4 100644
--- a/libsanitizer/asan/asan_poisoning.h
+++ b/libsanitizer/asan/asan_poisoning.h
@@ -84,7 +84,7 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
}
}
-// Calls __sanitizer::FlushUnneededShadowMemory() on
+// Calls __sanitizer::ReleaseMemoryToOS() on
// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
void FlushUnneededASanShadowMemory(uptr p, uptr size);
diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc
index 5b532e950bb..532afb37f1a 100644
--- a/libsanitizer/asan/asan_posix.cc
+++ b/libsanitizer/asan/asan_posix.cc
@@ -31,17 +31,39 @@
namespace __asan {
+const char *DescribeSignalOrException(int signo) {
+ switch (signo) {
+ case SIGFPE:
+ return "FPE";
+ case SIGILL:
+ return "ILL";
+ case SIGABRT:
+ return "ABRT";
+ default:
+ return "SEGV";
+ }
+}
+
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
ScopedDeadlySignal signal_scope(GetCurrentThread());
int code = (int)((siginfo_t*)siginfo)->si_code;
- // Write the first message using the bullet-proof write.
- if (18 != internal_write(2, "ASAN:DEADLYSIGNAL\n", 18)) Die();
+ // Write the first message using fd=2, just in case.
+ // It may actually fail to write in case stderr is closed.
+ internal_write(2, "ASAN:DEADLYSIGNAL\n", 18);
SignalContext sig = SignalContext::Create(siginfo, context);
// Access at a reasonable offset above SP, or slightly below it (to account
// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
// probably a stack overflow.
+#ifdef __s390__
+ // On s390, the fault address in siginfo points to start of the page, not
+ // to the precise word that was accessed. Mask off the low bits of sp to
+ // take it into account.
+ bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
+ sig.addr < sig.sp + 0xFFFF;
+#else
bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
+#endif
#if __powerpc__
// Large stack frames can be allocated with e.g.
@@ -73,10 +95,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
// unaligned memory access.
if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
ReportStackOverflow(sig);
- else if (signo == SIGFPE)
- ReportDeadlySignal("FPE", sig);
else
- ReportDeadlySignal("SEGV", sig);
+ ReportDeadlySignal(signo, sig);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index 7f7eaf515e7..84d67646b40 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -10,10 +10,13 @@
// This file contains error reporting code.
//===----------------------------------------------------------------------===//
+#include "asan_errors.h"
#include "asan_flags.h"
+#include "asan_descriptions.h"
#include "asan_internal.h"
#include "asan_mapping.h"
#include "asan_report.h"
+#include "asan_scariness_score.h"
#include "asan_stack.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_common.h"
@@ -28,88 +31,31 @@ namespace __asan {
static void (*error_report_callback)(const char*);
static char *error_message_buffer = nullptr;
static uptr error_message_buffer_pos = 0;
-static uptr error_message_buffer_size = 0;
-
-struct ReportData {
- uptr pc;
- uptr sp;
- uptr bp;
- uptr addr;
- bool is_write;
- uptr access_size;
- const char *description;
-};
-
-static bool report_happened = false;
-static ReportData report_data = {};
+static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
+static const unsigned kAsanBuggyPcPoolSize = 25;
+static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
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 += Min(remaining, length);
+ BlockingMutexLock l(&error_message_buf_mutex);
+ if (!error_message_buffer) {
+ error_message_buffer =
+ (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
+ error_message_buffer_pos = 0;
}
+ uptr length = internal_strlen(buffer);
+ RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
+ uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
+ internal_strncpy(error_message_buffer + error_message_buffer_pos,
+ buffer, remaining);
+ error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
+ // FIXME: reallocate the buffer instead of truncating the message.
+ error_message_buffer_pos += Min(remaining, length);
}
-// ---------------------- Decorator ------------------------------ {{{1
-class Decorator: public __sanitizer::SanitizerCommonDecorator {
- public:
- Decorator() : SanitizerCommonDecorator() { }
- const char *Access() { return Blue(); }
- const char *EndAccess() { return Default(); }
- const char *Location() { return Green(); }
- const char *EndLocation() { return Default(); }
- const char *Allocation() { return Magenta(); }
- const char *EndAllocation() { return Default(); }
-
- const char *ShadowByte(u8 byte) {
- switch (byte) {
- case kAsanHeapLeftRedzoneMagic:
- case kAsanHeapRightRedzoneMagic:
- case kAsanArrayCookieMagic:
- return Red();
- case kAsanHeapFreeMagic:
- return Magenta();
- case kAsanStackLeftRedzoneMagic:
- case kAsanStackMidRedzoneMagic:
- case kAsanStackRightRedzoneMagic:
- case kAsanStackPartialRedzoneMagic:
- return Red();
- case kAsanStackAfterReturnMagic:
- return Magenta();
- case kAsanInitializationOrderMagic:
- return Cyan();
- case kAsanUserPoisonedMemoryMagic:
- case kAsanContiguousContainerOOBMagic:
- case kAsanAllocaLeftMagic:
- case kAsanAllocaRightMagic:
- return Blue();
- case kAsanStackUseAfterScopeMagic:
- return Magenta();
- case kAsanGlobalRedzoneMagic:
- return Red();
- case kAsanInternalHeapMagic:
- return Yellow();
- case kAsanIntraObjectRedzone:
- return Yellow();
- default:
- return Default();
- }
- }
- const char *EndShadowByte() { return Default(); }
- const char *MemoryByte() { return Magenta(); }
- const char *EndMemoryByte() { return Default(); }
-};
-
// ---------------------- Helper functions ----------------------- {{{1
-static void PrintMemoryByte(InternalScopedString *str, const char *before,
- u8 byte, bool in_shadow, const char *after = "\n") {
+void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
+ bool in_shadow, const char *after) {
Decorator d;
str->append("%s%s%x%x%s%s", before,
in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
@@ -117,99 +63,6 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
}
-static void PrintShadowByte(InternalScopedString *str, const char *before,
- u8 byte, const char *after = "\n") {
- PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
-}
-
-static void PrintShadowBytes(InternalScopedString *str, const char *before,
- u8 *bytes, u8 *guilty, uptr n) {
- Decorator d;
- if (before) str->append("%s%p:", before, bytes);
- for (uptr i = 0; i < n; i++) {
- u8 *p = bytes + i;
- const char *before =
- p == guilty ? "[" : (p - 1 == guilty && i != 0) ? "" : " ";
- const char *after = p == guilty ? "]" : "";
- PrintShadowByte(str, before, *p, after);
- }
- str->append("\n");
-}
-
-static void PrintLegend(InternalScopedString *str) {
- str->append(
- "Shadow byte legend (one shadow byte represents %d "
- "application bytes):\n",
- (int)SHADOW_GRANULARITY);
- PrintShadowByte(str, " Addressable: ", 0);
- str->append(" Partially addressable: ");
- for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte(str, "", i, " ");
- str->append("\n");
- PrintShadowByte(str, " Heap left redzone: ",
- kAsanHeapLeftRedzoneMagic);
- PrintShadowByte(str, " Heap right redzone: ",
- kAsanHeapRightRedzoneMagic);
- PrintShadowByte(str, " Freed heap region: ", kAsanHeapFreeMagic);
- PrintShadowByte(str, " Stack left redzone: ",
- kAsanStackLeftRedzoneMagic);
- PrintShadowByte(str, " Stack mid redzone: ",
- kAsanStackMidRedzoneMagic);
- PrintShadowByte(str, " Stack right redzone: ",
- kAsanStackRightRedzoneMagic);
- PrintShadowByte(str, " Stack partial redzone: ",
- kAsanStackPartialRedzoneMagic);
- PrintShadowByte(str, " Stack after return: ",
- kAsanStackAfterReturnMagic);
- PrintShadowByte(str, " Stack use after scope: ",
- kAsanStackUseAfterScopeMagic);
- PrintShadowByte(str, " Global redzone: ", kAsanGlobalRedzoneMagic);
- PrintShadowByte(str, " Global init order: ",
- kAsanInitializationOrderMagic);
- PrintShadowByte(str, " Poisoned by user: ",
- kAsanUserPoisonedMemoryMagic);
- PrintShadowByte(str, " Container overflow: ",
- kAsanContiguousContainerOOBMagic);
- PrintShadowByte(str, " Array cookie: ",
- kAsanArrayCookieMagic);
- PrintShadowByte(str, " Intra object redzone: ",
- kAsanIntraObjectRedzone);
- PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic);
- PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic);
- PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic);
-}
-
-void MaybeDumpInstructionBytes(uptr pc) {
- if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
- return;
- InternalScopedString str(1024);
- str.append("First 16 instruction bytes at pc: ");
- if (IsAccessibleMemoryRange(pc, 16)) {
- for (int i = 0; i < 16; ++i) {
- PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
- }
- str.append("\n");
- } else {
- str.append("unaccessible\n");
- }
- Report("%s", str.data());
-}
-
-static void PrintShadowMemoryForAddress(uptr addr) {
- if (!AddrIsInMem(addr)) return;
- uptr shadow_addr = MemToShadow(addr);
- const uptr n_bytes_per_row = 16;
- uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
- InternalScopedString str(4096 * 8);
- str.append("Shadow bytes around the buggy address:\n");
- for (int i = -5; i <= 5; i++) {
- const char *prefix = (i == 0) ? "=>" : " ";
- PrintShadowBytes(&str, prefix, (u8 *)(aligned_shadow + i * n_bytes_per_row),
- (u8 *)shadow_addr, n_bytes_per_row);
- }
- if (flags()->print_legend) PrintLegend(&str);
- Printf("%s", str.data());
-}
-
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
const char *zone_name) {
if (zone_ptr) {
@@ -225,191 +78,8 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
}
}
-static void DescribeThread(AsanThread *t) {
- if (t)
- DescribeThread(t->context());
-}
-
// ---------------------- Address Descriptions ------------------- {{{1
-static bool IsASCII(unsigned char c) {
- return /*0x00 <= c &&*/ c <= 0x7F;
-}
-
-static const char *MaybeDemangleGlobalName(const char *name) {
- // We can spoil names of globals with C linkage, so use an heuristic
- // approach to check if the name should be demangled.
- bool should_demangle = false;
- if (name[0] == '_' && name[1] == 'Z')
- should_demangle = true;
- else if (SANITIZER_WINDOWS && name[0] == '\01' && name[1] == '?')
- should_demangle = true;
-
- return should_demangle ? Symbolizer::GetOrInit()->Demangle(name) : name;
-}
-
-// Check if the global is a zero-terminated ASCII string. If so, print it.
-static void PrintGlobalNameIfASCII(InternalScopedString *str,
- const __asan_global &g) {
- for (uptr p = g.beg; p < g.beg + g.size - 1; p++) {
- unsigned char c = *(unsigned char*)p;
- if (c == '\0' || !IsASCII(c)) return;
- }
- if (*(char*)(g.beg + g.size - 1) != '\0') return;
- str->append(" '%s' is ascii string '%s'\n", MaybeDemangleGlobalName(g.name),
- (char *)g.beg);
-}
-
-static const char *GlobalFilename(const __asan_global &g) {
- const char *res = g.module_name;
- // Prefer the filename from source location, if is available.
- if (g.location)
- res = g.location->filename;
- CHECK(res);
- return res;
-}
-
-static void PrintGlobalLocation(InternalScopedString *str,
- const __asan_global &g) {
- str->append("%s", GlobalFilename(g));
- if (!g.location)
- return;
- if (g.location->line_no)
- str->append(":%d", g.location->line_no);
- if (g.location->column_no)
- str->append(":%d", g.location->column_no);
-}
-
-static void DescribeAddressRelativeToGlobal(uptr addr, uptr size,
- const __asan_global &g) {
- InternalScopedString str(4096);
- Decorator d;
- str.append("%s", d.Location());
- if (addr < g.beg) {
- str.append("%p is located %zd bytes to the left", (void *)addr,
- g.beg - addr);
- } else if (addr + size > g.beg + g.size) {
- if (addr < g.beg + g.size)
- addr = g.beg + g.size;
- str.append("%p is located %zd bytes to the right", (void *)addr,
- addr - (g.beg + g.size));
- } else {
- // Can it happen?
- str.append("%p is located %zd bytes inside", (void *)addr, addr - g.beg);
- }
- str.append(" of global variable '%s' defined in '",
- MaybeDemangleGlobalName(g.name));
- PrintGlobalLocation(&str, g);
- str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
- str.append("%s", d.EndLocation());
- PrintGlobalNameIfASCII(&str, g);
- Printf("%s", str.data());
-}
-
-static bool DescribeAddressIfGlobal(uptr addr, uptr size,
- const char *bug_type) {
- // Assume address is close to at most four globals.
- const int kMaxGlobalsInReport = 4;
- __asan_global globals[kMaxGlobalsInReport];
- u32 reg_sites[kMaxGlobalsInReport];
- int globals_num =
- GetGlobalsForAddress(addr, globals, reg_sites, ARRAY_SIZE(globals));
- if (globals_num == 0)
- return false;
- for (int i = 0; i < globals_num; i++) {
- DescribeAddressRelativeToGlobal(addr, size, globals[i]);
- if (0 == internal_strcmp(bug_type, "initialization-order-fiasco") &&
- reg_sites[i]) {
- Printf(" registered at:\n");
- StackDepotGet(reg_sites[i]).Print();
- }
- }
- return true;
-}
-
-bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
- if (AddrIsInMem(addr))
- return false;
- const char *area_type = nullptr;
- if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
- else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
- else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
- if (area_type != nullptr) {
- if (print) {
- Printf("Address %p is located in the %s area.\n", addr, area_type);
- } else {
- CHECK(descr);
- descr->region_kind = area_type;
- }
- return true;
- }
- CHECK(0 && "Address is not in memory and not in shadow?");
- return false;
-}
-
-// Return " (thread_name) " or an empty string if the name is empty.
-const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[],
- uptr buff_len) {
- const char *name = t->name;
- if (name[0] == '\0') return "";
- buff[0] = 0;
- internal_strncat(buff, " (", 3);
- internal_strncat(buff, name, buff_len - 4);
- internal_strncat(buff, ")", 2);
- return buff;
-}
-
-const char *ThreadNameWithParenthesis(u32 tid, char buff[],
- uptr buff_len) {
- if (tid == kInvalidTid) return "";
- asanThreadRegistry().CheckLocked();
- AsanThreadContext *t = GetThreadContextByTidLocked(tid);
- return ThreadNameWithParenthesis(t, buff, buff_len);
-}
-
-static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
- uptr access_size, uptr prev_var_end,
- uptr next_var_beg) {
- uptr var_end = var.beg + var.size;
- uptr addr_end = addr + access_size;
- const char *pos_descr = nullptr;
- // If the variable [var.beg, var_end) is the nearest variable to the
- // current memory access, indicate it in the log.
- if (addr >= var.beg) {
- if (addr_end <= var_end)
- pos_descr = "is inside"; // May happen if this is a use-after-return.
- else if (addr < var_end)
- pos_descr = "partially overflows";
- else if (addr_end <= next_var_beg &&
- next_var_beg - addr_end >= addr - var_end)
- pos_descr = "overflows";
- } else {
- if (addr_end > var.beg)
- pos_descr = "partially underflows";
- else if (addr >= prev_var_end &&
- addr - prev_var_end >= var.beg - addr_end)
- pos_descr = "underflows";
- }
- InternalScopedString str(1024);
- str.append(" [%zd, %zd)", var.beg, var_end);
- // Render variable name.
- str.append(" '");
- for (uptr i = 0; i < var.name_len; ++i) {
- str.append("%c", var.name_pos[i]);
- }
- str.append("'");
- if (pos_descr) {
- Decorator d;
- // FIXME: we may want to also print the size of the access here,
- // but in case of accesses generated by memset it may be confusing.
- str.append("%s <== Memory access at offset %zd %s this variable%s\n",
- d.Location(), addr, pos_descr, d.EndLocation());
- } else {
- str.append("\n");
- }
- Printf("%s", str.data());
-}
-
bool ParseFrameDescription(const char *frame_descr,
InternalMmapVector<StackVarDescr> *vars) {
CHECK(frame_descr);
@@ -437,195 +107,17 @@ bool ParseFrameDescription(const char *frame_descr,
return true;
}
-bool DescribeAddressIfStack(uptr addr, uptr access_size) {
- AsanThread *t = FindThreadByStackAddress(addr);
- if (!t) return false;
-
- Decorator d;
- char tname[128];
- Printf("%s", d.Location());
- Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
- ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
-
- // Try to fetch precise stack frame for this access.
- AsanThread::StackFrameAccess access;
- if (!t->GetStackFrameAccessByAddr(addr, &access)) {
- Printf("%s\n", d.EndLocation());
- return true;
- }
- Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
-
- // Now we print the frame where the alloca has happened.
- // We print this frame as a stack trace with one element.
- // The symbolizer may print more than one frame if inlining was involved.
- // The frame numbers may be different than those in the stack trace printed
- // previously. That's unfortunate, but I have no better solution,
- // especially given that the alloca may be from entirely different place
- // (e.g. use-after-scope, or different thread's stack).
-#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
- // On PowerPC64 ELFv1, the address of a function actually points to a
- // three-doubleword data structure with the first field containing
- // the address of the function's code.
- access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
-#endif
- access.frame_pc += 16;
- Printf("%s", d.EndLocation());
- StackTrace alloca_stack(&access.frame_pc, 1);
- alloca_stack.Print();
-
- InternalMmapVector<StackVarDescr> vars(16);
- if (!ParseFrameDescription(access.frame_descr, &vars)) {
- Printf("AddressSanitizer can't parse the stack frame "
- "descriptor: |%s|\n", access.frame_descr);
- // 'addr' is a stack address, so return true even if we can't parse frame
- return true;
- }
- uptr n_objects = vars.size();
- // Report the number of stack objects.
- 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 prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
- uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
- PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
- prev_var_end, next_var_beg);
- }
- Printf("HINT: this may be a false positive if your program uses "
- "some custom stack unwind mechanism or swapcontext\n");
- if (SANITIZER_WINDOWS)
- Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n");
- else
- Printf(" (longjmp and C++ exceptions *are* supported)\n");
-
- DescribeThread(t);
- return true;
-}
-
-static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
- uptr access_size) {
- sptr offset;
- Decorator d;
- InternalScopedString str(4096);
- str.append("%s", d.Location());
- if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
- str.append("%p is located %zd bytes to the left of", (void *)addr, offset);
- } else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
- if (offset < 0) {
- addr -= offset;
- offset = 0;
- }
- str.append("%p is located %zd bytes to the right of", (void *)addr, offset);
- } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
- str.append("%p is located %zd bytes inside of", (void*)addr, offset);
- } else {
- str.append("%p is located somewhere around (this is AddressSanitizer bug!)",
- (void *)addr);
- }
- str.append(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
- (void *)(chunk.Beg()), (void *)(chunk.End()));
- str.append("%s", d.EndLocation());
- Printf("%s", str.data());
-}
-
-void DescribeHeapAddress(uptr addr, uptr access_size) {
- AsanChunkView chunk = FindHeapChunkByAddress(addr);
- if (!chunk.IsValid()) {
- Printf("AddressSanitizer can not describe address in more detail "
- "(wild memory access suspected).\n");
- return;
- }
- DescribeAccessToHeapChunk(chunk, addr, access_size);
- CHECK(chunk.AllocTid() != kInvalidTid);
- asanThreadRegistry().CheckLocked();
- AsanThreadContext *alloc_thread =
- GetThreadContextByTidLocked(chunk.AllocTid());
- StackTrace alloc_stack = chunk.GetAllocStack();
- char tname[128];
- Decorator d;
- AsanThreadContext *free_thread = nullptr;
- if (chunk.FreeTid() != kInvalidTid) {
- free_thread = GetThreadContextByTidLocked(chunk.FreeTid());
- Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
- free_thread->tid,
- ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
- d.EndAllocation());
- StackTrace free_stack = chunk.GetFreeStack();
- free_stack.Print();
- Printf("%spreviously allocated by thread T%d%s here:%s\n",
- d.Allocation(), alloc_thread->tid,
- ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
- } else {
- Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
- alloc_thread->tid,
- ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
- }
- alloc_stack.Print();
- DescribeThread(GetCurrentThread());
- if (free_thread)
- DescribeThread(free_thread);
- DescribeThread(alloc_thread);
-}
-
-static void DescribeAddress(uptr addr, uptr access_size, const char *bug_type) {
- // Check if this is shadow or shadow gap.
- if (DescribeAddressIfShadow(addr))
- return;
- CHECK(AddrIsInMem(addr));
- if (DescribeAddressIfGlobal(addr, access_size, bug_type))
- return;
- if (DescribeAddressIfStack(addr, access_size))
- return;
- // Assume it is a heap address.
- DescribeHeapAddress(addr, access_size);
-}
-
-// ------------------- Thread description -------------------- {{{1
-
-void DescribeThread(AsanThreadContext *context) {
- CHECK(context);
- asanThreadRegistry().CheckLocked();
- // No need to announce the main thread.
- if (context->tid == 0 || context->announced) {
- return;
- }
- context->announced = true;
- char tname[128];
- InternalScopedString str(1024);
- str.append("Thread T%d%s", context->tid,
- ThreadNameWithParenthesis(context->tid, tname, sizeof(tname)));
- if (context->parent_tid == kInvalidTid) {
- str.append(" created by unknown thread\n");
- Printf("%s", str.data());
- return;
- }
- str.append(
- " created by T%d%s here:\n", context->parent_tid,
- ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
- Printf("%s", str.data());
- StackDepotGet(context->stack_id).Print();
- // Recursively described parent thread if needed.
- if (flags()->print_full_thread_history) {
- AsanThreadContext *parent_context =
- GetThreadContextByTidLocked(context->parent_tid);
- DescribeThread(parent_context);
- }
-}
-
// -------------------- Different kinds of reports ----------------- {{{1
// Use ScopedInErrorReport to run common actions just before and
// immediately after printing error report.
class ScopedInErrorReport {
public:
- explicit ScopedInErrorReport(ReportData *report = nullptr,
- bool fatal = false) {
+ explicit ScopedInErrorReport(bool fatal = false) {
halt_on_error_ = fatal || flags()->halt_on_error;
if (lock_.TryLock()) {
- StartReporting(report);
+ StartReporting();
return;
}
@@ -667,10 +159,13 @@ class ScopedInErrorReport {
lock_.Lock();
}
- StartReporting(report);
+ StartReporting();
}
~ScopedInErrorReport() {
+ ASAN_ON_ERROR();
+ if (current_error_.IsValid()) current_error_.Print();
+
// Make sure the current thread is announced.
DescribeThread(GetCurrentThread());
// We may want to grab this lock again when printing stats.
@@ -678,9 +173,30 @@ class ScopedInErrorReport {
// Print memory stats.
if (flags()->print_stats)
__asan_print_accumulated_stats();
+
+ if (common_flags()->print_cmdline)
+ PrintCmdline();
+
+ // Copy the message buffer so that we could start logging without holding a
+ // lock that gets aquired during printing.
+ InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
+ {
+ BlockingMutexLock l(&error_message_buf_mutex);
+ internal_memcpy(buffer_copy.data(),
+ error_message_buffer, kErrorMessageBufferSize);
+ }
+
+ LogFullErrorReport(buffer_copy.data());
+
if (error_report_callback) {
- error_report_callback(error_message_buffer);
+ error_report_callback(buffer_copy.data());
}
+
+ // In halt_on_error = false mode, reset the current error object (before
+ // unlocking).
+ if (!halt_on_error_)
+ internal_memset(&current_error_, 0, sizeof(current_error_));
+
CommonSanitizerReportMutex.Unlock();
reporting_thread_tid_ = kInvalidTid;
lock_.Unlock();
@@ -690,11 +206,18 @@ class ScopedInErrorReport {
}
}
+ void ReportError(const ErrorDescription &description) {
+ // Can only report one error per ScopedInErrorReport.
+ CHECK_EQ(current_error_.kind, kErrorKindInvalid);
+ current_error_ = description;
+ }
+
+ static ErrorDescription &CurrentError() {
+ return current_error_;
+ }
+
private:
- void StartReporting(ReportData *report) {
- if (report) report_data = *report;
- report_happened = true;
- ASAN_ON_ERROR();
+ void StartReporting() {
// Make sure the registry and sanitizer report mutexes are locked while
// we're printing an error report.
// We can lock them only here to avoid self-deadlock in case of
@@ -708,154 +231,69 @@ class ScopedInErrorReport {
static StaticSpinMutex lock_;
static u32 reporting_thread_tid_;
+ // Error currently being reported. This enables the destructor to interact
+ // with the debugger and point it to an error description.
+ static ErrorDescription current_error_;
bool halt_on_error_;
};
StaticSpinMutex ScopedInErrorReport::lock_;
-u32 ScopedInErrorReport::reporting_thread_tid_;
+u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
+ErrorDescription ScopedInErrorReport::current_error_;
void ReportStackOverflow(const SignalContext &sig) {
- ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- Report(
- "ERROR: AddressSanitizer: stack-overflow on address %p"
- " (pc %p bp %p sp %p T%d)\n",
- (void *)sig.addr, (void *)sig.pc, (void *)sig.bp, (void *)sig.sp,
- GetCurrentTidOrInvalid());
- Printf("%s", d.EndWarning());
- GET_STACK_TRACE_SIGNAL(sig);
- stack.Print();
- ReportErrorSummary("stack-overflow", &stack);
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig);
+ in_report.ReportError(error);
}
-void ReportDeadlySignal(const char *description, const SignalContext &sig) {
- ScopedInErrorReport in_report(/*report*/nullptr, /*fatal*/true);
- Decorator d;
- Printf("%s", d.Warning());
- Report(
- "ERROR: AddressSanitizer: %s on unknown address %p"
- " (pc %p bp %p sp %p T%d)\n",
- description, (void *)sig.addr, (void *)sig.pc, (void *)sig.bp,
- (void *)sig.sp, GetCurrentTidOrInvalid());
- if (sig.pc < GetPageSizeCached()) {
- Report("Hint: pc points to the zero page.\n");
- }
- Printf("%s", d.EndWarning());
- GET_STACK_TRACE_SIGNAL(sig);
- stack.Print();
- MaybeDumpInstructionBytes(sig.pc);
- Printf("AddressSanitizer can not provide additional info.\n");
- ReportErrorSummary(description, &stack);
+void ReportDeadlySignal(int signo, const SignalContext &sig) {
+ ScopedInErrorReport in_report(/*fatal*/ true);
+ ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
+ in_report.ReportError(error);
}
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- char tname[128];
- u32 curr_tid = GetCurrentTidOrInvalid();
- Report("ERROR: AddressSanitizer: attempting double-free on %p in "
- "thread T%d%s:\n",
- addr, curr_tid,
- ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
- CHECK_GT(free_stack->size, 0);
- GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- stack.Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("double-free", &stack);
+ ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr);
+ in_report.ReportError(error);
}
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- char tname[128];
- u32 curr_tid = GetCurrentTidOrInvalid();
- Report("ERROR: AddressSanitizer: new-delete-type-mismatch on %p in "
- "thread T%d%s:\n",
- addr, curr_tid,
- ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
- Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
- Printf(" size of the allocated type: %zd bytes;\n"
- " size of the deallocated type: %zd bytes.\n",
- asan_mz_size(reinterpret_cast<void*>(addr)), delete_size);
- CHECK_GT(free_stack->size, 0);
- GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- stack.Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("new-delete-type-mismatch", &stack);
- Report("HINT: if you don't care about these errors you may set "
- "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
+ ErrorNewDeleteSizeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
+ delete_size);
+ in_report.ReportError(error);
}
void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- char tname[128];
- u32 curr_tid = GetCurrentTidOrInvalid();
- Report("ERROR: AddressSanitizer: attempting free on address "
- "which was not malloc()-ed: %p in thread T%d%s\n", addr,
- curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
- CHECK_GT(free_stack->size, 0);
- GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- stack.Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("bad-free", &stack);
+ ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr);
+ in_report.ReportError(error);
}
void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
- static const char *alloc_names[] =
- {"INVALID", "malloc", "operator new", "operator new []"};
- static const char *dealloc_names[] =
- {"INVALID", "free", "operator delete", "operator delete []"};
- CHECK_NE(alloc_type, dealloc_type);
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
- alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
- Printf("%s", d.EndWarning());
- CHECK_GT(free_stack->size, 0);
- GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
- stack.Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("alloc-dealloc-mismatch", &stack);
- Report("HINT: if you don't care about these errors you may set "
- "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
+ ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
+ alloc_type, dealloc_type);
+ in_report.ReportError(error);
}
void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: attempting to call "
- "malloc_usable_size() for pointer which is "
- "not owned: %p\n", addr);
- Printf("%s", d.EndWarning());
- stack->Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("bad-malloc_usable_size", stack);
+ ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr);
+ in_report.ReportError(error);
}
void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: attempting to call "
- "__sanitizer_get_allocated_size() for pointer which is "
- "not owned: %p\n", addr);
- Printf("%s", d.EndWarning());
- stack->Print();
- DescribeHeapAddress(addr, 1);
- ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
+ ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack,
+ addr);
+ in_report.ReportError(error);
}
void ReportStringFunctionMemoryRangesOverlap(const char *function,
@@ -863,94 +301,43 @@ void ReportStringFunctionMemoryRangesOverlap(const char *function,
const char *offset2, uptr length2,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
- Decorator d;
- char bug_type[100];
- internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: %s: "
- "memory ranges [%p,%p) and [%p, %p) overlap\n", \
- bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
- Printf("%s", d.EndWarning());
- stack->Print();
- DescribeAddress((uptr)offset1, length1, bug_type);
- DescribeAddress((uptr)offset2, length2, bug_type);
- ReportErrorSummary(bug_type, stack);
+ ErrorStringFunctionMemoryRangesOverlap error(
+ GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2,
+ length2, function);
+ in_report.ReportError(error);
}
void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
- Decorator d;
- const char *bug_type = "negative-size-param";
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
- Printf("%s", d.EndWarning());
- stack->Print();
- DescribeAddress(offset, size, bug_type);
- ReportErrorSummary(bug_type, stack);
+ ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
+ size);
+ in_report.ReportError(error);
}
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
uptr old_mid, uptr new_mid,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
- Report("ERROR: AddressSanitizer: bad parameters to "
- "__sanitizer_annotate_contiguous_container:\n"
- " beg : %p\n"
- " end : %p\n"
- " old_mid : %p\n"
- " new_mid : %p\n",
- beg, end, old_mid, new_mid);
- uptr granularity = SHADOW_GRANULARITY;
- if (!IsAligned(beg, granularity))
- Report("ERROR: beg is not aligned by %d\n", granularity);
- stack->Print();
- ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+ ErrorBadParamsToAnnotateContiguousContainer error(
+ GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid);
+ in_report.ReportError(error);
}
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2) {
ScopedInErrorReport in_report;
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: odr-violation (%p):\n", g1->beg);
- Printf("%s", d.EndWarning());
- InternalScopedString g1_loc(256), g2_loc(256);
- PrintGlobalLocation(&g1_loc, *g1);
- PrintGlobalLocation(&g2_loc, *g2);
- Printf(" [1] size=%zd '%s' %s\n", g1->size,
- MaybeDemangleGlobalName(g1->name), g1_loc.data());
- Printf(" [2] size=%zd '%s' %s\n", g2->size,
- MaybeDemangleGlobalName(g2->name), g2_loc.data());
- if (stack_id1 && stack_id2) {
- Printf("These globals were registered at these points:\n");
- Printf(" [1]:\n");
- StackDepotGet(stack_id1).Print();
- Printf(" [2]:\n");
- StackDepotGet(stack_id2).Print();
- }
- Report("HINT: if you don't care about these errors you may set "
- "ASAN_OPTIONS=detect_odr_violation=0\n");
- InternalScopedString error_msg(256);
- error_msg.append("odr-violation: global '%s' at %s",
- MaybeDemangleGlobalName(g1->name), g1_loc.data());
- ReportErrorSummary(error_msg.data());
+ ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2,
+ stack_id2);
+ in_report.ReportError(error);
}
// ----------------------- CheckForInvalidPointerPair ----------- {{{1
-static NOINLINE void
-ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp, uptr a1, uptr a2) {
+static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
+ uptr a1, uptr a2) {
ScopedInErrorReport in_report;
- const char *bug_type = "invalid-pointer-pair";
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n", a1, a2);
- Printf("%s", d.EndWarning());
- GET_STACK_TRACE_FATAL(pc, bp);
- stack.Print();
- DescribeAddress(a1, 1, bug_type);
- DescribeAddress(a2, 1, bug_type);
- ReportErrorSummary(bug_type, &stack);
+ ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2);
+ in_report.ReportError(error);
}
static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
@@ -959,26 +346,15 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
uptr a2 = reinterpret_cast<uptr>(p2);
AsanChunkView chunk1 = FindHeapChunkByAddress(a1);
AsanChunkView chunk2 = FindHeapChunkByAddress(a2);
- bool valid1 = chunk1.IsValid();
- bool valid2 = chunk2.IsValid();
- if ((valid1 != valid2) || (valid1 && valid2 && !chunk1.Eq(chunk2))) {
- GET_CALLER_PC_BP_SP; \
+ bool valid1 = chunk1.IsAllocated();
+ bool valid2 = chunk2.IsAllocated();
+ if (!valid1 || !valid2 || !chunk1.Eq(chunk2)) {
+ GET_CALLER_PC_BP_SP;
return ReportInvalidPointerPair(pc, bp, sp, a1, a2);
}
}
// ----------------------- Mac-specific reports ----------------- {{{1
-void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *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);
- stack->Print();
- DescribeHeapAddress(addr, 1);
-}
-
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
BufferedStackTrace *stack) {
ScopedInErrorReport in_report;
@@ -987,22 +363,26 @@ void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
addr);
PrintZoneForPointer(addr, zone_ptr, zone_name);
stack->Print();
- DescribeHeapAddress(addr, 1);
+ DescribeAddressIfHeap(addr);
}
-void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *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);
- stack->Print();
- DescribeHeapAddress(addr, 1);
+// -------------- SuppressErrorReport -------------- {{{1
+// Avoid error reports duplicating for ASan recover mode.
+static bool SuppressErrorReport(uptr pc) {
+ if (!common_flags()->suppress_equal_pcs) return false;
+ for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
+ uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
+ if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
+ pc, memory_order_relaxed))
+ return false;
+ if (cmp == pc) return true;
+ }
+ Die();
}
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal) {
+ if (!fatal && SuppressErrorReport(pc)) return;
ENABLE_FRAME_POINTER;
// Optimization experiments.
@@ -1014,87 +394,10 @@ void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
// The reaction to a non-zero value of exp is to be defined.
(void)exp;
- // 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:
- case kAsanArrayCookieMagic:
- 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 kAsanContiguousContainerOOBMagic:
- bug_descr = "container-overflow";
- break;
- case kAsanStackUseAfterScopeMagic:
- bug_descr = "stack-use-after-scope";
- break;
- case kAsanGlobalRedzoneMagic:
- bug_descr = "global-buffer-overflow";
- break;
- case kAsanIntraObjectRedzone:
- bug_descr = "intra-object-overflow";
- break;
- case kAsanAllocaLeftMagic:
- case kAsanAllocaRightMagic:
- bug_descr = "dynamic-stack-buffer-overflow";
- break;
- }
- }
-
- ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
- bug_descr };
- ScopedInErrorReport in_report(&report, fatal);
-
- Decorator d;
- Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: %s on address "
- "%p at pc %p bp %p sp %p\n",
- bug_descr, (void*)addr, pc, bp, sp);
- Printf("%s", d.EndWarning());
-
- u32 curr_tid = GetCurrentTidOrInvalid();
- char tname[128];
- Printf("%s%s of size %zu at %p thread T%d%s%s\n",
- d.Access(),
- access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
- access_size, (void*)addr, curr_tid,
- ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)),
- d.EndAccess());
-
- GET_STACK_TRACE_FATAL(pc, bp);
- stack.Print();
-
- DescribeAddress(addr, access_size, bug_descr);
- ReportErrorSummary(bug_descr, &stack);
- PrintShadowMemoryForAddress(addr);
+ ScopedInErrorReport in_report(fatal);
+ ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write,
+ access_size);
+ in_report.ReportError(error);
}
} // namespace __asan
@@ -1110,52 +413,62 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
}
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
+ BlockingMutexLock l(&error_message_buf_mutex);
error_report_callback = callback;
- if (callback) {
- error_message_buffer_size = 1 << 16;
- error_message_buffer =
- (char*)MmapOrDie(error_message_buffer_size, __func__);
- error_message_buffer_pos = 0;
- }
}
void __asan_describe_address(uptr addr) {
// Thread registry must be locked while we're describing an address.
asanThreadRegistry().Lock();
- DescribeAddress(addr, 1, "");
+ PrintAddressDescription(addr, 1, "");
asanThreadRegistry().Unlock();
}
int __asan_report_present() {
- return report_happened ? 1 : 0;
+ return ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric;
}
uptr __asan_get_report_pc() {
- return report_data.pc;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.pc;
+ return 0;
}
uptr __asan_get_report_bp() {
- return report_data.bp;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.bp;
+ return 0;
}
uptr __asan_get_report_sp() {
- return report_data.sp;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.sp;
+ return 0;
}
uptr __asan_get_report_address() {
- return report_data.addr;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError()
+ .Generic.addr_description.Address();
+ return 0;
}
int __asan_get_report_access_type() {
- return report_data.is_write ? 1 : 0;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.is_write;
+ return 0;
}
uptr __asan_get_report_access_size() {
- return report_data.access_size;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.access_size;
+ return 0;
}
const char *__asan_get_report_description() {
- return report_data.description;
+ if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
+ return ScopedInErrorReport::CurrentError().Generic.bug_descr;
+ return nullptr;
}
extern "C" {
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index f2a18155232..111b8400153 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -23,34 +23,28 @@ struct StackVarDescr {
uptr name_len;
};
-struct AddressDescription {
- char *name;
- uptr name_size;
- uptr region_address;
- uptr region_size;
- const char *region_kind;
-};
-
// Returns the number of globals close to the provided address and copies
// them to "globals" array.
int GetGlobalsForAddress(uptr addr, __asan_global *globals, u32 *reg_sites,
int max_globals);
-bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+
+const char *MaybeDemangleGlobalName(const char *name);
+void PrintGlobalNameIfASCII(InternalScopedString *str, const __asan_global &g);
+void PrintGlobalLocation(InternalScopedString *str, const __asan_global &g);
+
+void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
+ bool in_shadow, const char *after = "\n");
+
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
-void DescribeHeapAddress(uptr addr, uptr access_size);
-bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
- bool print = true);
bool ParseFrameDescription(const char *frame_descr,
InternalMmapVector<StackVarDescr> *vars);
-bool DescribeAddressIfStack(uptr addr, uptr access_size);
-void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal);
void ReportStackOverflow(const SignalContext &sig);
-void ReportDeadlySignal(const char *description, const SignalContext &sig);
+void ReportDeadlySignal(int signo, const SignalContext &sig);
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
@@ -75,8 +69,6 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2);
// Mac-specific errors and warnings.
-void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
- BufferedStackTrace *stack);
void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
const char *zone_name,
BufferedStackTrace *stack);
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 50b02453a2b..38009d2905f 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -30,6 +30,7 @@
#include "ubsan/ubsan_init.h"
#include "ubsan/ubsan_platform.h"
+uptr __asan_shadow_memory_dynamic_address; // Global interface symbol.
int __asan_option_detect_stack_use_after_return; // Global interface symbol.
uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan.
@@ -84,8 +85,8 @@ void ShowStatsAndAbort() {
// Reserve memory range [beg, end].
// We need to use inclusive range because end+1 may not be representable.
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
- CHECK_EQ((beg % GetPageSizeCached()), 0);
- CHECK_EQ(((end + 1) % GetPageSizeCached()), 0);
+ CHECK_EQ((beg % GetMmapGranularity()), 0);
+ CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
uptr size = end - beg + 1;
DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
void *res = MmapFixedNoReserve(beg, size, name);
@@ -261,6 +262,7 @@ 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.
+ // clang-format off
switch (fake_condition) {
case 1: __asan_report_load1(0); break;
case 2: __asan_report_load2(0); break;
@@ -300,7 +302,14 @@ static NOINLINE void force_interface_symbols() {
case 37: __asan_unpoison_stack_memory(0, 0); break;
case 38: __asan_region_is_poisoned(0, 0); break;
case 39: __asan_describe_address(0); break;
+ case 40: __asan_set_shadow_00(0, 0); break;
+ case 41: __asan_set_shadow_f1(0, 0); break;
+ case 42: __asan_set_shadow_f2(0, 0); break;
+ case 43: __asan_set_shadow_f3(0, 0); break;
+ case 44: __asan_set_shadow_f5(0, 0); break;
+ case 45: __asan_set_shadow_f8(0, 0); break;
}
+ // clang-format on
}
static void asan_atexit() {
@@ -318,26 +327,39 @@ static void InitializeHighMemEnd() {
kHighMemEnd = GetMaxVirtualAddress();
// Increase kHighMemEnd to make sure it's properly
// aligned together with kHighMemBeg:
- kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1;
+ kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
#endif // !ASAN_FIXED_MAPPING
- CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0);
+ CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
}
static void ProtectGap(uptr addr, uptr size) {
- if (!flags()->protect_shadow_gap)
+ if (!flags()->protect_shadow_gap) {
+ // The shadow gap is unprotected, so there is a chance that someone
+ // is actually using this memory. Which means it needs a shadow...
+ uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
+ uptr GapShadowEnd =
+ RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
+ if (Verbosity())
+ Printf("protect_shadow_gap=0:"
+ " not protecting shadow gap, allocating gap's shadow\n"
+ "|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
+ GapShadowEnd);
+ ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
+ "unprotected gap shadow");
return;
- void *res = MmapNoAccess(addr, size, "shadow gap");
+ }
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res)
return;
// A few pages at the start of the address space can not be protected.
// But we really want to protect as much as possible, to prevent this memory
// being returned as a result of a non-FIXED mmap().
if (addr == kZeroBaseShadowStart) {
- uptr step = GetPageSizeCached();
+ uptr step = GetMmapGranularity();
while (size > step && addr < kZeroBaseMaxShadowStart) {
addr += step;
size -= step;
- void *res = MmapNoAccess(addr, size, "shadow gap");
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
if (addr == (uptr)res)
return;
}
@@ -413,10 +435,13 @@ static void AsanInitInternal() {
AsanCheckIncompatibleRT();
AsanCheckDynamicRTPrereqs();
+ AvoidCVE_2016_2143();
SetCanPoisonMemory(flags()->poison_heap);
SetMallocContextSize(common_flags()->malloc_context_size);
+ InitializePlatformExceptionHandlers();
+
InitializeHighMemEnd();
// Make sure we are not statically linked.
@@ -429,7 +454,6 @@ static void AsanInitInternal() {
__sanitizer_set_report_path(common_flags()->log_path);
- // Enable UAR detection, if required.
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
@@ -448,7 +472,30 @@ static void AsanInitInternal() {
ReplaceSystemMalloc();
+ // Set the shadow memory address to uninitialized.
+ __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
+
uptr shadow_start = kLowShadowBeg;
+ // Detect if a dynamic shadow address must used and find a available location
+ // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
+ // expands to |__asan_shadow_memory_dynamic_address| which is
+ // |kDefaultShadowSentinel|.
+ if (shadow_start == kDefaultShadowSentinel) {
+ __asan_shadow_memory_dynamic_address = 0;
+ CHECK_EQ(0, kLowShadowBeg);
+
+ uptr granularity = GetMmapGranularity();
+ uptr alignment = 8 * granularity;
+ uptr left_padding = granularity;
+ uptr space_size = kHighShadowEnd + left_padding;
+
+ shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity);
+ CHECK_NE((uptr)0, shadow_start);
+ CHECK(IsAligned(shadow_start, alignment));
+ }
+ // Update the shadow memory address (potentially) used by instrumentation.
+ __asan_shadow_memory_dynamic_address = shadow_start;
+
if (kLowShadowBeg)
shadow_start -= GetMmapGranularity();
bool full_shadow_is_available =
@@ -537,12 +584,12 @@ static void AsanInitInternal() {
force_interface_symbols(); // no-op.
SanitizerInitializeUnwinder();
-#if CAN_SANITIZE_LEAKS
- __lsan::InitCommonLsan();
- if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
- Atexit(__lsan::DoLeakCheck);
+ if (CAN_SANITIZE_LEAKS) {
+ __lsan::InitCommonLsan();
+ if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
+ Atexit(__lsan::DoLeakCheck);
+ }
}
-#endif // CAN_SANITIZE_LEAKS
#if CAN_SANITIZE_UB
__ubsan::InitAsPlugin();
@@ -550,6 +597,15 @@ static void AsanInitInternal() {
InitializeSuppressions();
+ if (CAN_SANITIZE_LEAKS) {
+ // LateInitialize() calls dlsym, which can allocate an error string buffer
+ // in the TLS. Let's ignore the allocation to avoid reporting a leak.
+ __lsan::ScopedInterceptorDisabler disabler;
+ Symbolizer::LateInitialize();
+ } else {
+ Symbolizer::LateInitialize();
+ }
+
VReport(1, "AddressSanitizer Init done\n");
}
@@ -579,6 +635,9 @@ static AsanInitializer asan_initializer;
using namespace __asan; // NOLINT
void NOINLINE __asan_handle_no_return() {
+ if (asan_init_is_running)
+ return;
+
int local_stack;
AsanThread *curr_thread = GetCurrentThread();
uptr PageSize = GetPageSizeCached();
@@ -603,7 +662,7 @@ void NOINLINE __asan_handle_no_return() {
"stack top: %p; bottom %p; size: %p (%zd)\n"
"False positive error reports may follow\n"
"For details see "
- "http://code.google.com/p/address-sanitizer/issues/detail?id=189\n",
+ "https://github.com/google/sanitizers/issues/189\n",
top, bottom, top - bottom, top - bottom);
return;
}
diff --git a/libsanitizer/asan/asan_scariness_score.h b/libsanitizer/asan/asan_scariness_score.h
new file mode 100644
index 00000000000..d72fce69d64
--- /dev/null
+++ b/libsanitizer/asan/asan_scariness_score.h
@@ -0,0 +1,72 @@
+//===-- asan_scariness_score.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.
+//
+// Compute the level of scariness of the error message.
+// Don't expect any deep science here, just a set of heuristics that suggest
+// that e.g. 1-byte-read-global-buffer-overflow is less scary than
+// 8-byte-write-stack-use-after-return.
+//
+// Every error report has one or more features, such as memory access size,
+// type (read or write), type of accessed memory (e.g. free-d heap, or a global
+// redzone), etc. Every such feature has an int score and a string description.
+// The overall score is the sum of all feature scores and the description
+// is a concatenation of feature descriptions.
+// Examples:
+// 17 (4-byte-read-heap-buffer-overflow)
+// 65 (multi-byte-write-stack-use-after-return)
+// 10 (null-deref)
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_SCARINESS_SCORE_H
+#define ASAN_SCARINESS_SCORE_H
+
+#include "asan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libc.h"
+
+namespace __asan {
+struct ScarinessScoreBase {
+ void Clear() {
+ descr[0] = 0;
+ score = 0;
+ }
+ void Scare(int add_to_score, const char *reason) {
+ if (descr[0])
+ internal_strlcat(descr, "-", sizeof(descr));
+ internal_strlcat(descr, reason, sizeof(descr));
+ score += add_to_score;
+ };
+ int GetScore() const { return score; }
+ const char *GetDescription() const { return descr; }
+ void Print() {
+ if (score && flags()->print_scariness)
+ Printf("SCARINESS: %d (%s)\n", score, descr);
+ }
+ static void PrintSimple(int score, const char *descr) {
+ ScarinessScoreBase SSB;
+ SSB.Clear();
+ SSB.Scare(score, descr);
+ SSB.Print();
+ }
+
+ private:
+ int score;
+ char descr[1024];
+};
+
+struct ScarinessScore : ScarinessScoreBase {
+ ScarinessScore() {
+ Clear();
+ }
+};
+
+} // namespace __asan
+
+#endif // ASAN_SCARINESS_SCORE_H
diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
index 30dc5921303..2b8738156ea 100644
--- a/libsanitizer/asan/asan_stack.h
+++ b/libsanitizer/asan/asan_stack.h
@@ -46,7 +46,10 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
uptr stack_top = t->stack_top();
uptr stack_bottom = t->stack_bottom();
ScopedUnwinding unwind_scope(t);
- stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
+ if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) {
+ stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom,
+ fast);
+ }
} else if (!t && !fast) {
/* If GetCurrentThread() has failed, try to do slow unwind anyways. */
stack->Unwind(max_depth, pc, bp, context, 0, 0, false);
diff --git a/libsanitizer/asan/asan_suppressions.cc b/libsanitizer/asan/asan_suppressions.cc
index c94fff0500a..1dc9d474240 100644
--- a/libsanitizer/asan/asan_suppressions.cc
+++ b/libsanitizer/asan/asan_suppressions.cc
@@ -87,6 +87,7 @@ bool IsStackTraceSuppressed(const StackTrace *stack) {
if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+ CHECK(frames);
for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
const char *function_name = cur->info.function;
if (!function_name) {
diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc
index 92f968bdee4..818e1261400 100644
--- a/libsanitizer/asan/asan_thread.cc
+++ b/libsanitizer/asan/asan_thread.cc
@@ -118,6 +118,77 @@ void AsanThread::Destroy() {
DTLS_Destroy();
}
+void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
+ uptr size) {
+ if (atomic_load(&stack_switching_, memory_order_relaxed)) {
+ Report("ERROR: starting fiber switch while in fiber switch\n");
+ Die();
+ }
+
+ next_stack_bottom_ = bottom;
+ next_stack_top_ = bottom + size;
+ atomic_store(&stack_switching_, 1, memory_order_release);
+
+ FakeStack *current_fake_stack = fake_stack_;
+ if (fake_stack_save)
+ *fake_stack_save = fake_stack_;
+ fake_stack_ = nullptr;
+ SetTLSFakeStack(nullptr);
+ // if fake_stack_save is null, the fiber will die, delete the fakestack
+ if (!fake_stack_save && current_fake_stack)
+ current_fake_stack->Destroy(this->tid());
+}
+
+void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
+ uptr *bottom_old,
+ uptr *size_old) {
+ if (!atomic_load(&stack_switching_, memory_order_relaxed)) {
+ Report("ERROR: finishing a fiber switch that has not started\n");
+ Die();
+ }
+
+ if (fake_stack_save) {
+ SetTLSFakeStack(fake_stack_save);
+ fake_stack_ = fake_stack_save;
+ }
+
+ if (bottom_old)
+ *bottom_old = stack_bottom_;
+ if (size_old)
+ *size_old = stack_top_ - stack_bottom_;
+ stack_bottom_ = next_stack_bottom_;
+ stack_top_ = next_stack_top_;
+ atomic_store(&stack_switching_, 0, memory_order_release);
+ next_stack_top_ = 0;
+ next_stack_bottom_ = 0;
+}
+
+inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
+ if (!atomic_load(&stack_switching_, memory_order_acquire))
+ return StackBounds{stack_bottom_, stack_top_}; // NOLINT
+ char local;
+ const uptr cur_stack = (uptr)&local;
+ // Note: need to check next stack first, because FinishSwitchFiber
+ // may be in process of overwriting stack_top_/bottom_. But in such case
+ // we are already on the next stack.
+ if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
+ return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT
+ return StackBounds{stack_bottom_, stack_top_}; // NOLINT
+}
+
+uptr AsanThread::stack_top() {
+ return GetStackBounds().top;
+}
+
+uptr AsanThread::stack_bottom() {
+ return GetStackBounds().bottom;
+}
+
+uptr AsanThread::stack_size() {
+ const auto bounds = GetStackBounds();
+ return bounds.top - bounds.bottom;
+}
+
// We want to create the FakeStack lazyly on the first use, but not eralier
// than the stack size is known and the procedure has to be async-signal safe.
FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
@@ -148,6 +219,8 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
}
void AsanThread::Init() {
+ next_stack_top_ = next_stack_bottom_ = 0;
+ atomic_store(&stack_switching_, false, memory_order_release);
fake_stack_ = nullptr; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U);
SetThreadStackAndTls();
@@ -193,10 +266,12 @@ thread_return_t AsanThread::ThreadStart(
void AsanThread::SetThreadStackAndTls() {
uptr tls_size = 0;
- GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_,
- &tls_size);
- stack_top_ = stack_bottom_ + stack_size_;
+ uptr stack_size = 0;
+ GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
+ const_cast<uptr *>(&stack_size), &tls_begin_, &tls_size);
+ stack_top_ = stack_bottom_ + stack_size;
tls_end_ = tls_begin_ + tls_size;
+ dtls_ = DTLS_Get();
int local;
CHECK(AddrIsInStack((uptr)&local));
@@ -247,6 +322,11 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
return true;
}
+bool AsanThread::AddrIsInStack(uptr addr) {
+ const auto bounds = GetStackBounds();
+ return addr >= bounds.bottom && addr < bounds.top;
+}
+
static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
void *addr) {
AsanThreadContext *tctx = static_cast<AsanThreadContext*>(tctx_base);
@@ -269,7 +349,7 @@ AsanThread *GetCurrentThread() {
// limits, so only do this magic on Android, and only if the found thread
// is the main thread.
AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
- if (ThreadStackContainsAddress(tctx, &context)) {
+ if (tctx && ThreadStackContainsAddress(tctx, &context)) {
SetCurrentThread(tctx->thread);
return tctx->thread;
}
@@ -320,8 +400,8 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
- uptr *tls_begin, uptr *tls_end,
- uptr *cache_begin, uptr *cache_end) {
+ uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+ uptr *cache_end, DTLS **dtls) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (!t) return false;
*stack_begin = t->stack_bottom();
@@ -331,6 +411,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
// ASan doesn't keep allocator caches in TLS, so these are unused.
*cache_begin = 0;
*cache_end = 0;
+ *dtls = t->dtls();
return true;
}
@@ -353,3 +434,33 @@ void EnsureMainThreadIDIsCorrect() {
__asan::EnsureMainThreadIDIsCorrect();
}
} // namespace __lsan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan; // NOLINT
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_start_switch_fiber(void **fakestacksave, const void *bottom,
+ uptr size) {
+ AsanThread *t = GetCurrentThread();
+ if (!t) {
+ VReport(1, "__asan_start_switch_fiber called from unknown thread\n");
+ return;
+ }
+ t->StartSwitchFiber((FakeStack**)fakestacksave, (uptr)bottom, size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_finish_switch_fiber(void* fakestack,
+ const void **bottom_old,
+ uptr *size_old) {
+ AsanThread *t = GetCurrentThread();
+ if (!t) {
+ VReport(1, "__asan_finish_switch_fiber called from unknown thread\n");
+ return;
+ }
+ t->FinishSwitchFiber((FakeStack*)fakestack,
+ (uptr*)bottom_old,
+ (uptr*)size_old);
+}
+}
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index 27a3367d8e7..c51a58ad0bb 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -21,6 +21,10 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
+namespace __sanitizer {
+struct DTLS;
+} // namespace __sanitizer
+
namespace __asan {
const u32 kInvalidTid = 0xffffff; // Must fit into 24 bits.
@@ -60,11 +64,12 @@ class AsanThread {
thread_return_t ThreadStart(uptr os_id,
atomic_uintptr_t *signal_thread_is_registered);
- uptr stack_top() { return stack_top_; }
- uptr stack_bottom() { return stack_bottom_; }
- uptr stack_size() { return stack_size_; }
+ uptr stack_top();
+ uptr stack_bottom();
+ uptr stack_size();
uptr tls_begin() { return tls_begin_; }
uptr tls_end() { return tls_end_; }
+ DTLS *dtls() { return dtls_; }
u32 tid() { return context_->tid; }
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
@@ -76,9 +81,7 @@ class AsanThread {
};
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
- bool AddrIsInStack(uptr addr) {
- return addr >= stack_bottom_ && addr < stack_top_;
- }
+ bool AddrIsInStack(uptr addr);
void DeleteFakeStack(int tid) {
if (!fake_stack_) return;
@@ -88,13 +91,20 @@ class AsanThread {
t->Destroy(tid);
}
+ void StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom, uptr size);
+ void FinishSwitchFiber(FakeStack *fake_stack_save, uptr *bottom_old,
+ uptr *size_old);
+
bool has_fake_stack() {
- return (reinterpret_cast<uptr>(fake_stack_) > 1);
+ return !atomic_load(&stack_switching_, memory_order_relaxed) &&
+ (reinterpret_cast<uptr>(fake_stack_) > 1);
}
FakeStack *fake_stack() {
if (!__asan_option_detect_stack_use_after_return)
return nullptr;
+ if (atomic_load(&stack_switching_, memory_order_relaxed))
+ return nullptr;
if (!has_fake_stack())
return AsyncSignalSafeLazyInitFakeStack();
return fake_stack_;
@@ -120,16 +130,27 @@ class AsanThread {
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
+ struct StackBounds {
+ uptr bottom;
+ uptr top;
+ };
+ StackBounds GetStackBounds() const;
+
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
+
uptr stack_top_;
uptr stack_bottom_;
- // stack_size_ == stack_top_ - stack_bottom_;
- // It needs to be set in a async-signal-safe manner.
- uptr stack_size_;
+ // these variables are used when the thread is about to switch stack
+ uptr next_stack_top_;
+ uptr next_stack_bottom_;
+ // true if switching is in progress
+ atomic_uint8_t stack_switching_;
+
uptr tls_begin_;
uptr tls_end_;
+ DTLS *dtls_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc
index 6c12523498a..efd82bfc3b0 100644
--- a/libsanitizer/asan/asan_win.cc
+++ b/libsanitizer/asan/asan_win.cc
@@ -22,6 +22,7 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_thread.h"
+#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -34,7 +35,13 @@ int __asan_should_detect_stack_use_after_return() {
return __asan_option_detect_stack_use_after_return;
}
-// -------------------- A workaround for the abscence of weak symbols ----- {{{
+SANITIZER_INTERFACE_ATTRIBUTE
+uptr __asan_get_shadow_memory_dynamic_address() {
+ __asan_init();
+ return __asan_shadow_memory_dynamic_address;
+}
+
+// -------------------- A workaround for the absence of weak symbols ----- {{{
// We don't have a direct equivalent of weak symbols when using MSVC, but we can
// use the /alternatename directive to tell the linker to default a specific
// symbol to a specific value, which works nicely for allocator hooks and
@@ -44,21 +51,49 @@ void __sanitizer_default_free_hook(void *ptr) { }
const char* __asan_default_default_options() { return ""; }
const char* __asan_default_default_suppressions() { return ""; }
void __asan_default_on_error() {}
+// 64-bit msvc will not prepend an underscore for symbols.
+#ifdef _WIN64
+#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT
+#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT
+#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT
+#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT
+#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT
+#else
#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
+#endif
// }}}
} // extern "C"
-// ---------------------- Windows-specific inteceptors ---------------- {{{
+// ---------------------- Windows-specific interceptors ---------------- {{{
+INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) {
+ CHECK(REAL(RtlRaiseException));
+ // This is a noreturn function, unless it's one of the exceptions raised to
+ // communicate with the debugger, such as the one from OutputDebugString.
+ if (ExceptionRecord->ExceptionCode != DBG_PRINTEXCEPTION_C)
+ __asan_handle_no_return();
+ REAL(RtlRaiseException)(ExceptionRecord);
+}
+
INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
CHECK(REAL(RaiseException));
__asan_handle_no_return();
REAL(RaiseException)(a, b, c, d);
}
+#ifdef _WIN64
+
+INTERCEPTOR_WINAPI(int, __C_specific_handler, void *a, void *b, void *c, void *d) { // NOLINT
+ CHECK(REAL(__C_specific_handler));
+ __asan_handle_no_return();
+ return REAL(__C_specific_handler)(a, b, c, d);
+}
+
+#else
+
INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
CHECK(REAL(_except_handler3));
__asan_handle_no_return();
@@ -74,6 +109,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
__asan_handle_no_return();
return REAL(_except_handler4)(a, b, c, d);
}
+#endif
static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
AsanThread *t = (AsanThread*)arg;
@@ -99,52 +135,33 @@ INTERCEPTOR_WINAPI(DWORD, CreateThread,
asan_thread_start, t, thr_flags, tid);
}
-namespace {
-BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
-
-void EnsureWorkerThreadRegistered() {
- // FIXME: GetCurrentThread relies on TSD, which might not play well with
- // system thread pools. We might want to use something like reference
- // counting to zero out GetCurrentThread() underlying storage when the last
- // work item finishes? Or can we disable reclaiming of threads in the pool?
- BlockingMutexLock l(&mu_for_thread_tracking);
- if (__asan::GetCurrentThread())
- return;
-
- AsanThread *t = AsanThread::Create(
- /* start_routine */ nullptr, /* arg */ nullptr,
- /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true);
- t->Init();
- asanThreadRegistry().StartThread(t->tid(), 0, 0);
- SetCurrentThread(t);
-}
-} // namespace
-
-INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) {
- // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to
- // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc.
- // System worker pool threads are created at arbitraty point in time and
- // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory
- // instead and don't register a specific parent_tid/stack.
- EnsureWorkerThreadRegistered();
- return REAL(NtWaitForWorkViaWorkerFactory)(a, b);
-}
-
// }}}
namespace __asan {
void InitializePlatformInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
- ASAN_INTERCEPT_FUNC(RaiseException);
+
+#ifdef _WIN64
+ ASAN_INTERCEPT_FUNC(__C_specific_handler);
+#else
ASAN_INTERCEPT_FUNC(_except_handler3);
ASAN_INTERCEPT_FUNC(_except_handler4);
+#endif
+
+ // Try to intercept kernel32!RaiseException, and if that fails, intercept
+ // ntdll!RtlRaiseException instead.
+ if (!::__interception::OverrideFunction("RaiseException",
+ (uptr)WRAP(RaiseException),
+ (uptr *)&REAL(RaiseException))) {
+ CHECK(::__interception::OverrideFunction("RtlRaiseException",
+ (uptr)WRAP(RtlRaiseException),
+ (uptr *)&REAL(RtlRaiseException)));
+ }
+}
- // NtWaitForWorkViaWorkerFactory is always linked dynamically.
- CHECK(::__interception::OverrideFunction(
- "NtWaitForWorkViaWorkerFactory",
- (uptr)WRAP(NtWaitForWorkViaWorkerFactory),
- (uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
+ UNIMPLEMENTED();
}
// ---------------------- TSD ---------------- {{{
@@ -173,14 +190,6 @@ void PlatformTSDDtor(void *tsd) {
// }}}
// ---------------------- Various stuff ---------------- {{{
-void DisableReexec() {
- // No need to re-exec on Windows.
-}
-
-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
@@ -200,20 +209,95 @@ void AsanOnDeadlySignal(int, void *siginfo, void *context) {
UNIMPLEMENTED();
}
+#if SANITIZER_WINDOWS64
+// Exception handler for dealing with shadow memory.
+static LONG CALLBACK
+ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
+ uptr page_size = GetPageSizeCached();
+ // Only handle access violations.
+ if (exception_pointers->ExceptionRecord->ExceptionCode !=
+ EXCEPTION_ACCESS_VIOLATION) {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ // Only handle access violations that land within the shadow memory.
+ uptr addr =
+ (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]);
+
+ // Check valid shadow range.
+ if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH;
+
+ // This is an access violation while trying to read from the shadow. Commit
+ // the relevant page and let execution continue.
+
+ // Determine the address of the page that is being accessed.
+ uptr page = RoundDownTo(addr, page_size);
+
+ // Query the existing page.
+ MEMORY_BASIC_INFORMATION mem_info = {};
+ if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ // Commit the page.
+ uptr result =
+ (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE);
+ if (result != page) return EXCEPTION_CONTINUE_SEARCH;
+
+ // The page mapping succeeded, so continue execution as usual.
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+#endif
+
+void InitializePlatformExceptionHandlers() {
+#if SANITIZER_WINDOWS64
+ // On Win64, we map memory on demand with access violation handler.
+ // Install our exception handler.
+ CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler));
+#endif
+}
+
static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+// Check based on flags if we should report this exception.
+static bool ShouldReportDeadlyException(unsigned code) {
+ switch (code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_IN_PAGE_ERROR:
+ return common_flags()->handle_segv;
+ case EXCEPTION_BREAKPOINT:
+ case EXCEPTION_ILLEGAL_INSTRUCTION: {
+ return common_flags()->handle_sigill;
+ }
+ }
+ return false;
+}
+
+// Return the textual name for this exception.
+const char *DescribeSignalOrException(int signo) {
+ unsigned code = signo;
+ // Get the string description of the exception if this is a known deadly
+ // exception.
+ switch (code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ return "access-violation";
+ case EXCEPTION_IN_PAGE_ERROR:
+ return "in-page-error";
+ case EXCEPTION_BREAKPOINT:
+ return "breakpoint";
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ return "illegal-instruction";
+ }
+ return nullptr;
+}
+
static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
CONTEXT *context = info->ContextRecord;
- if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
- exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
- const char *description =
- (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
- ? "access-violation"
- : "in-page-error";
+ if (ShouldReportDeadlyException(exception_record->ExceptionCode)) {
SignalContext sig = SignalContext::Create(exception_record, context);
- ReportDeadlySignal(description, sig);
+ ReportDeadlySignal(exception_record->ExceptionCode, sig);
}
// FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
@@ -248,10 +332,16 @@ int __asan_set_seh_filter() {
}
#if !ASAN_DYNAMIC
-// Put a pointer to __asan_set_seh_filter at the end of the global list
-// of C initializers, after the default EH is set by the CRT.
-#pragma section(".CRT$XIZ", long, read) // NOLINT
-__declspec(allocate(".CRT$XIZ"))
+// The CRT runs initializers in this order:
+// - C initializers, from XIA to XIZ
+// - C++ initializers, from XCA to XCZ
+// Prior to 2015, the CRT set the unhandled exception filter at priority XIY,
+// near the end of C initialization. Starting in 2015, it was moved to the
+// beginning of C++ initialization. We set our priority to XCAB to run
+// immediately after the CRT runs. This way, our exception filter is called
+// first and we can delegate to their filter if appropriate.
+#pragma section(".CRT$XCAB", long, read) // NOLINT
+__declspec(allocate(".CRT$XCAB"))
int (*__intercept_seh)() = __asan_set_seh_filter;
#endif
// }}}
diff --git a/libsanitizer/asan/asan_win_dll_thunk.cc b/libsanitizer/asan/asan_win_dll_thunk.cc
index 691aaf36fd0..f7c9a37bf79 100644
--- a/libsanitizer/asan/asan_win_dll_thunk.cc
+++ b/libsanitizer/asan/asan_win_dll_thunk.cc
@@ -10,16 +10,16 @@
// This file defines a family of thunks that should be statically linked into
// the DLLs that have ASan instrumentation in order to delegate the calls to the
// shared runtime that lives in the main binary.
-// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
-// details.
+// See https://github.com/google/sanitizers/issues/209 for the details.
//===----------------------------------------------------------------------===//
-// Only compile this code when buidling asan_dll_thunk.lib
+// Only compile this code when building asan_dll_thunk.lib
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DLL_THUNK
#include "asan_init_version.h"
#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
// ---------- Function interception helper functions and macros ----------- {{{1
extern "C" {
@@ -28,6 +28,8 @@ void *__stdcall GetProcAddress(void *module, const char *proc_name);
void abort();
}
+using namespace __sanitizer;
+
static uptr getRealProcAddressOrDie(const char *name) {
uptr ret =
__interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
@@ -196,9 +198,11 @@ static void InterceptHooks();
// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
// want to call it in the __asan_init interceptor.
WRAP_W_V(__asan_should_detect_stack_use_after_return)
+WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
extern "C" {
int __asan_option_detect_stack_use_after_return;
+ uptr __asan_shadow_memory_dynamic_address;
// Manually wrap __asan_init as we need to initialize
// __asan_option_detect_stack_use_after_return afterwards.
@@ -212,7 +216,8 @@ extern "C" {
fn();
__asan_option_detect_stack_use_after_return =
(__asan_should_detect_stack_use_after_return() != 0);
-
+ __asan_shadow_memory_dynamic_address =
+ (uptr)__asan_get_shadow_memory_dynamic_address();
InterceptHooks();
}
}
@@ -255,6 +260,13 @@ INTERFACE_FUNCTION(__asan_memcpy);
INTERFACE_FUNCTION(__asan_memset);
INTERFACE_FUNCTION(__asan_memmove);
+INTERFACE_FUNCTION(__asan_set_shadow_00);
+INTERFACE_FUNCTION(__asan_set_shadow_f1);
+INTERFACE_FUNCTION(__asan_set_shadow_f2);
+INTERFACE_FUNCTION(__asan_set_shadow_f3);
+INTERFACE_FUNCTION(__asan_set_shadow_f5);
+INTERFACE_FUNCTION(__asan_set_shadow_f8);
+
INTERFACE_FUNCTION(__asan_alloca_poison);
INTERFACE_FUNCTION(__asan_allocas_unpoison);
@@ -309,8 +321,6 @@ INTERFACE_FUNCTION(__sanitizer_cov_init)
INTERFACE_FUNCTION(__sanitizer_cov_module_init)
INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
-INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp)
-INTERFACE_FUNCTION(__sanitizer_cov_trace_switch)
INTERFACE_FUNCTION(__sanitizer_cov_with_check)
INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
@@ -324,6 +334,8 @@ INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
+INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
+INTERFACE_FUNCTION(__sanitizer_symbolize_global)
INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
INTERFACE_FUNCTION(__sanitizer_ptr_sub)
INTERFACE_FUNCTION(__sanitizer_report_error_summary)
@@ -333,6 +345,7 @@ INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
INTERFACE_FUNCTION(__sanitizer_set_death_callback)
INTERFACE_FUNCTION(__sanitizer_set_report_path)
+INTERFACE_FUNCTION(__sanitizer_set_report_fd)
INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
@@ -340,23 +353,31 @@ INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
+INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
+INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
// TODO(timurrrr): Add more interface functions on the as-needed basis.
// ----------------- Memory allocation functions ---------------------
WRAP_V_W(free)
+WRAP_V_W(_free_base)
WRAP_V_WW(_free_dbg)
WRAP_W_W(malloc)
+WRAP_W_W(_malloc_base)
WRAP_W_WWWW(_malloc_dbg)
WRAP_W_WW(calloc)
+WRAP_W_WW(_calloc_base)
WRAP_W_WWWWW(_calloc_dbg)
WRAP_W_WWW(_calloc_impl)
WRAP_W_WW(realloc)
+WRAP_W_WW(_realloc_base)
WRAP_W_WWW(_realloc_dbg)
WRAP_W_WWW(_recalloc)
+WRAP_W_WWW(_recalloc_base)
WRAP_W_W(_msize)
WRAP_W_W(_expand)
@@ -369,6 +390,10 @@ WRAP_W_W(_expand_dbg)
INTERCEPT_LIBRARY_FUNCTION(atoi);
INTERCEPT_LIBRARY_FUNCTION(atol);
+
+#ifdef _WIN64
+INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
+#else
INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
// _except_handler4 checks -GS cookie which is different for each module, so we
@@ -377,10 +402,13 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
__asan_handle_no_return();
return REAL(_except_handler4)(a, b, c, d);
}
+#endif
INTERCEPT_LIBRARY_FUNCTION(frexp);
INTERCEPT_LIBRARY_FUNCTION(longjmp);
+#if SANITIZER_INTERCEPT_MEMCHR
INTERCEPT_LIBRARY_FUNCTION(memchr);
+#endif
INTERCEPT_LIBRARY_FUNCTION(memcmp);
INTERCEPT_LIBRARY_FUNCTION(memcpy);
INTERCEPT_LIBRARY_FUNCTION(memmove);
@@ -390,12 +418,14 @@ INTERCEPT_LIBRARY_FUNCTION(strchr);
INTERCEPT_LIBRARY_FUNCTION(strcmp);
INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
INTERCEPT_LIBRARY_FUNCTION(strcspn);
+INTERCEPT_LIBRARY_FUNCTION(strdup);
INTERCEPT_LIBRARY_FUNCTION(strlen);
INTERCEPT_LIBRARY_FUNCTION(strncat);
INTERCEPT_LIBRARY_FUNCTION(strncmp);
INTERCEPT_LIBRARY_FUNCTION(strncpy);
INTERCEPT_LIBRARY_FUNCTION(strnlen);
INTERCEPT_LIBRARY_FUNCTION(strpbrk);
+INTERCEPT_LIBRARY_FUNCTION(strrchr);
INTERCEPT_LIBRARY_FUNCTION(strspn);
INTERCEPT_LIBRARY_FUNCTION(strstr);
INTERCEPT_LIBRARY_FUNCTION(strtol);
@@ -405,7 +435,9 @@ INTERCEPT_LIBRARY_FUNCTION(wcslen);
// is defined.
void InterceptHooks() {
INTERCEPT_HOOKS();
+#ifndef _WIN64
INTERCEPT_FUNCTION(_except_handler4);
+#endif
}
// We want to call __asan_init before C/C++ initializers/constructors are
diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
index f7358539a1c..8989159cc52 100644
--- a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
+++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
@@ -1,4 +1,4 @@
-//===-- asan_win_uar_thunk.cc ---------------------------------------------===//
+//===-- asan_win_dynamic_runtime_thunk.cc ---------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
@@ -14,11 +14,11 @@
// This includes:
// - forwarding the detect_stack_use_after_return runtime option
// - working around deficiencies of the MD runtime
-// - installing a custom SEH handlerx
+// - installing a custom SEH handler
//
//===----------------------------------------------------------------------===//
-// Only compile this code when buidling asan_dynamic_runtime_thunk.lib
+// Only compile this code when building asan_dynamic_runtime_thunk.lib
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
@@ -27,7 +27,7 @@
// First, declare CRT sections we'll be using in this file
#pragma section(".CRT$XID", long, read) // NOLINT
-#pragma section(".CRT$XIZ", long, read) // NOLINT
+#pragma section(".CRT$XCAB", long, read) // NOLINT
#pragma section(".CRT$XTW", long, read) // NOLINT
#pragma section(".CRT$XTY", long, read) // NOLINT
@@ -40,12 +40,16 @@
// attribute adds __imp_ prefix to the symbol name of a variable.
// Since in general we don't know if a given TU is going to be used
// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
-// just to work around this issue, let's clone the a variable that is
-// constant after initialization anyways.
+// just to work around this issue, let's clone the variable that is constant
+// after initialization anyways.
extern "C" {
__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
int __asan_option_detect_stack_use_after_return =
__asan_should_detect_stack_use_after_return();
+
+__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address();
+void* __asan_shadow_memory_dynamic_address =
+ __asan_get_shadow_memory_dynamic_address();
}
////////////////////////////////////////////////////////////////////////////////
@@ -57,6 +61,7 @@ int __asan_option_detect_stack_use_after_return =
// using atexit() that calls a small subset of C terminators
// where LLVM global_dtors is placed. Fingers crossed, no other C terminators
// are there.
+extern "C" int __cdecl atexit(void (__cdecl *f)(void));
extern "C" void __cdecl _initterm(void *a, void *b);
namespace {
@@ -70,6 +75,7 @@ void UnregisterGlobals() {
int ScheduleUnregisterGlobals() {
return atexit(UnregisterGlobals);
}
+} // namespace
// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after
// atexit() is initialized (.CRT$XIC). As this is executed before C++
@@ -78,8 +84,6 @@ int ScheduleUnregisterGlobals() {
__declspec(allocate(".CRT$XID"))
int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
-} // namespace
-
////////////////////////////////////////////////////////////////////////////////
// ASan SEH handling.
// We need to set the ASan-specific SEH handler at the end of CRT initialization
@@ -90,7 +94,8 @@ static int SetSEHFilter() { return __asan_set_seh_filter(); }
// Unfortunately, putting a pointer to __asan_set_seh_filter into
// __asan_intercept_seh gets optimized out, so we have to use an extra function.
-__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
+ SetSEHFilter;
}
#endif // ASAN_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/asan/libtool-version b/libsanitizer/asan/libtool-version
index 7e838a5740b..0f14ee34185 100644
--- a/libsanitizer/asan/libtool-version
+++ b/libsanitizer/asan/libtool-version
@@ -3,4 +3,4 @@
# a separate file so that version updates don't involve re-running
# automake.
# CURRENT:REVISION:AGE
-3:0:0
+4:0:0
diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
new file mode 100644
index 00000000000..5e36b5a5edf
--- /dev/null
+++ b/libsanitizer/builtins/assembly.h
@@ -0,0 +1,169 @@
+/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in compiler-rt assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define CONST_SECTION .section .rodata
+
+#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__)
+#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
+#else
+#define NO_EXEC_STACK_DIRECTIVE
+#endif
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#define CONST_SECTION .section .rdata,"rd"
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#endif
+
+#if defined(__arm__)
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && \
+ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+// pop {pc} can't switch Thumb mode on ARMv4T
+#if __ARM_ARCH >= 5
+#define POP_PC() pop {pc}
+#else
+#define POP_PC() \
+ pop {ip}; \
+ JMP(ip)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#else
+#define IT(cond)
+#define ITT(cond)
+#endif
+
+#if __ARM_ARCH_ISA_THUMB == 2
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#endif
+
+#define GLUE2(a, b) a##b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .thumb_func SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ name:
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR \
+ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#endif
+
+#endif /* COMPILERRT_ASSEMBLY_H */
diff --git a/libsanitizer/configure b/libsanitizer/configure
index 97218bb3c41..b6c715b09f7 100755
--- a/libsanitizer/configure
+++ b/libsanitizer/configure
@@ -604,6 +604,7 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS
TSAN_TARGET_DEPENDENT_OBJECTS
LIBBACKTRACE_SUPPORTED_FALSE
LIBBACKTRACE_SUPPORTED_TRUE
@@ -12027,7 +12028,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12030 "configure"
+#line 12031 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12133,7 +12134,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12136 "configure"
+#line 12137 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -16498,6 +16499,7 @@ fi
+
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac
index 93192e15971..e9018498074 100644
--- a/libsanitizer/configure.ac
+++ b/libsanitizer/configure.ac
@@ -375,5 +375,6 @@ _EOF
fi
AC_SUBST([TSAN_TARGET_DEPENDENT_OBJECTS])
+AC_SUBST([SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS])
AC_OUTPUT
diff --git a/libsanitizer/configure.tgt b/libsanitizer/configure.tgt
index 05ead765e62..8d884f4bf52 100644
--- a/libsanitizer/configure.tgt
+++ b/libsanitizer/configure.tgt
@@ -20,12 +20,14 @@
# Filter out unsupported systems.
TSAN_TARGET_DEPENDENT_OBJECTS=
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS=
case "${target}" in
x86_64-*-linux* | i?86-*-linux*)
if test x$ac_cv_sizeof_void_p = x8; then
TSAN_SUPPORTED=yes
LSAN_SUPPORTED=yes
TSAN_TARGET_DEPENDENT_OBJECTS=tsan_rtl_amd64.lo
+ SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS=sanitizer_linux_x86_64.lo
fi
;;
powerpc*-*-linux*)
diff --git a/libsanitizer/include/sanitizer/allocator_interface.h b/libsanitizer/include/sanitizer/allocator_interface.h
index 97a72a258eb..d4801e9ff0c 100644
--- a/libsanitizer/include/sanitizer/allocator_interface.h
+++ b/libsanitizer/include/sanitizer/allocator_interface.h
@@ -57,6 +57,23 @@ extern "C" {
deallocation of "ptr". */
void __sanitizer_malloc_hook(const volatile void *ptr, size_t size);
void __sanitizer_free_hook(const volatile void *ptr);
+
+ /* Installs a pair of hooks for malloc/free.
+ Several (currently, 5) hook pairs may be installed, they are executed
+ in the order they were installed and after calling
+ __sanitizer_malloc_hook/__sanitizer_free_hook.
+ Unlike __sanitizer_malloc_hook/__sanitizer_free_hook these hooks can be
+ chained and do not rely on weak symbols working on the platform, but
+ require __sanitizer_install_malloc_and_free_hooks to be called at startup
+ and thus will not be called on malloc/free very early in the process.
+ Returns the number of hooks currently installed or 0 on failure.
+ Not thread-safe, should be called in the main thread before starting
+ other threads.
+ */
+ int __sanitizer_install_malloc_and_free_hooks(
+ void (*malloc_hook)(const volatile void *, size_t),
+ void (*free_hook)(const volatile void *));
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index 35463e08fbb..fd38c55a235 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -39,6 +39,9 @@ extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
void __sanitizer_set_report_path(const char *path);
+ // Tell the tools to write their reports to the provided file descriptor
+ // (casted to void *).
+ void __sanitizer_set_report_fd(void *fd);
// Notify the tools that the sandbox is going to be turned on. The reserved
// parameter will be used in the future to hold a structure with functions
@@ -112,6 +115,16 @@ extern "C" {
// Print the stack trace leading to this call. Useful for debugging user code.
void __sanitizer_print_stack_trace();
+ // Symbolizes the supplied 'pc' using the format string 'fmt'.
+ // Outputs at most 'out_buf_size' bytes into 'out_buf'.
+ // The format syntax is described in
+ // lib/sanitizer_common/sanitizer_stacktrace_printer.h.
+ void __sanitizer_symbolize_pc(void *pc, const char *fmt, char *out_buf,
+ size_t out_buf_size);
+ // Same as __sanitizer_symbolize_pc, but for data section (i.e. globals).
+ void __sanitizer_symbolize_global(void *data_ptr, const char *fmt,
+ char *out_buf, size_t out_buf_size);
+
// Sets the callback to be called right before death on error.
// Passing 0 will unset the callback.
void __sanitizer_set_death_callback(void (*callback)(void));
@@ -123,9 +136,50 @@ extern "C" {
// to know what is being passed to libc functions, e.g. memcmp.
// FIXME: implement more hooks.
void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
- const void *s2, size_t n);
+ const void *s2, size_t n, int result);
void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
- const char *s2, size_t n);
+ const char *s2, size_t n, int result);
+ void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
+ const char *s2, size_t n, int result);
+ void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
+ const char *s2, int result);
+ void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
+ const char *s2, int result);
+ void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
+ const char *s2, char *result);
+ void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
+ const char *s2, char *result);
+ void __sanitizer_weak_hook_memmem(void *called_pc,
+ const void *s1, size_t len1,
+ const void *s2, size_t len2, void *result);
+
+ // Prints stack traces for all live heap allocations ordered by total
+ // allocation size until `top_percent` of total live heap is shown.
+ // `top_percent` should be between 1 and 100.
+ // Experimental feature currently available only with asan on Linux/x86_64.
+ void __sanitizer_print_memory_profile(size_t top_percent);
+
+ // Fiber annotation interface.
+ // Before switching to a different stack, one must call
+ // __sanitizer_start_switch_fiber with a pointer to the bottom of the
+ // destination stack and its size. When code starts running on the new stack,
+ // it must call __sanitizer_finish_switch_fiber to finalize the switch.
+ // The start_switch function takes a void** to store the current fake stack if
+ // there is one (it is needed when detect_stack_use_after_return is enabled).
+ // When restoring a stack, this pointer must be given to the finish_switch
+ // function. In most cases, this void* can be stored on the stack just before
+ // switching. When leaving a fiber definitely, null must be passed as first
+ // argument to the start_switch function so that the fake stack is destroyed.
+ // If you do not want support for stack use-after-return detection, you can
+ // always pass null to these two functions.
+ // Note that the fake stack mechanism is disabled during fiber switch, so if a
+ // signal callback runs during the switch, it will not benefit from the stack
+ // use-after-return detection.
+ void __sanitizer_start_switch_fiber(void **fake_stack_save,
+ const void *bottom, size_t size);
+ void __sanitizer_finish_switch_fiber(void *fake_stack_save,
+ const void **bottom_old,
+ size_t *size_old);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/coverage_interface.h b/libsanitizer/include/sanitizer/coverage_interface.h
index 37c133aae3c..ffb956c39db 100644
--- a/libsanitizer/include/sanitizer/coverage_interface.h
+++ b/libsanitizer/include/sanitizer/coverage_interface.h
@@ -56,6 +56,7 @@ extern "C" {
// __sanitizer_get_number_of_counters bytes long and 8-aligned.
uintptr_t
__sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/esan_interface.h b/libsanitizer/include/sanitizer/esan_interface.h
new file mode 100644
index 00000000000..cd18f34fc00
--- /dev/null
+++ b/libsanitizer/include/sanitizer/esan_interface.h
@@ -0,0 +1,48 @@
+//===-- sanitizer/esan_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 EfficiencySanitizer, a family of performance tuners.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ESAN_INTERFACE_H
+#define SANITIZER_ESAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+// We declare our interface routines as weak to allow the user to avoid
+// ifdefs and instead use this pattern to allow building the same sources
+// with and without our runtime library:
+// if (__esan_report)
+// __esan_report();
+#ifdef _MSC_VER
+/* selectany is as close to weak as we'll get. */
+#define COMPILER_RT_WEAK __declspec(selectany)
+#elif __GNUC__
+#define COMPILER_RT_WEAK __attribute__((weak))
+#else
+#define COMPILER_RT_WEAK
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// This function can be called mid-run (or at the end of a run for
+// a server process that doesn't shut down normally) to request that
+// data for that point in the run be reported from the tool.
+void COMPILER_RT_WEAK __esan_report();
+
+// This function returns the number of samples that the esan tool has collected
+// to this point. This is useful for testing.
+unsigned int COMPILER_RT_WEAK __esan_get_sample_count();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_ESAN_INTERFACE_H
diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
index 17742b6c1c4..34bb2912406 100644
--- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
+++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
@@ -1833,6 +1833,17 @@
__sanitizer_syscall_pre_impl_vfork()
#define __sanitizer_syscall_post_vfork(res) \
__sanitizer_syscall_post_impl_vfork(res)
+#define __sanitizer_syscall_pre_sigaction(signum, act, oldact) \
+ __sanitizer_syscall_pre_impl_sigaction((long)signum, (long)act, (long)oldact)
+#define __sanitizer_syscall_post_sigaction(res, signum, act, oldact) \
+ __sanitizer_syscall_post_impl_sigaction(res, (long)signum, (long)act, \
+ (long)oldact)
+#define __sanitizer_syscall_pre_rt_sigaction(signum, act, oldact, sz) \
+ __sanitizer_syscall_pre_impl_rt_sigaction((long)signum, (long)act, \
+ (long)oldact, (long)sz)
+#define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \
+ __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \
+ (long)oldact, (long)sz)
// And now a few syscalls we don't handle yet.
#define __sanitizer_syscall_pre_afs_syscall(...)
@@ -1887,7 +1898,6 @@
#define __sanitizer_syscall_pre_query_module(...)
#define __sanitizer_syscall_pre_readahead(...)
#define __sanitizer_syscall_pre_readdir(...)
-#define __sanitizer_syscall_pre_rt_sigaction(...)
#define __sanitizer_syscall_pre_rt_sigreturn(...)
#define __sanitizer_syscall_pre_rt_sigsuspend(...)
#define __sanitizer_syscall_pre_security(...)
@@ -1901,7 +1911,6 @@
#define __sanitizer_syscall_pre_setreuid32(...)
#define __sanitizer_syscall_pre_set_thread_area(...)
#define __sanitizer_syscall_pre_setuid32(...)
-#define __sanitizer_syscall_pre_sigaction(...)
#define __sanitizer_syscall_pre_sigaltstack(...)
#define __sanitizer_syscall_pre_sigreturn(...)
#define __sanitizer_syscall_pre_sigsuspend(...)
@@ -1969,7 +1978,6 @@
#define __sanitizer_syscall_post_query_module(res, ...)
#define __sanitizer_syscall_post_readahead(res, ...)
#define __sanitizer_syscall_post_readdir(res, ...)
-#define __sanitizer_syscall_post_rt_sigaction(res, ...)
#define __sanitizer_syscall_post_rt_sigreturn(res, ...)
#define __sanitizer_syscall_post_rt_sigsuspend(res, ...)
#define __sanitizer_syscall_post_security(res, ...)
@@ -1983,7 +1991,6 @@
#define __sanitizer_syscall_post_setreuid32(res, ...)
#define __sanitizer_syscall_post_set_thread_area(res, ...)
#define __sanitizer_syscall_post_setuid32(res, ...)
-#define __sanitizer_syscall_post_sigaction(res, ...)
#define __sanitizer_syscall_post_sigaltstack(res, ...)
#define __sanitizer_syscall_post_sigreturn(res, ...)
#define __sanitizer_syscall_post_sigsuspend(res, ...)
@@ -3060,7 +3067,13 @@ void __sanitizer_syscall_pre_impl_fork();
void __sanitizer_syscall_post_impl_fork(long res);
void __sanitizer_syscall_pre_impl_vfork();
void __sanitizer_syscall_post_impl_vfork(long res);
-
+void __sanitizer_syscall_pre_impl_sigaction(long signum, long act, long oldact);
+void __sanitizer_syscall_post_impl_sigaction(long res, long signum, long act,
+ long oldact);
+void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act,
+ long oldact, long sz);
+void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
+ long oldact, long sz);
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in
index 3dfa7746779..550c8f5c3f9 100644
--- a/libsanitizer/interception/Makefile.in
+++ b/libsanitizer/interception/Makefile.in
@@ -169,6 +169,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index f2d48c9332f..0db36ddf28e 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -90,8 +90,8 @@ typedef __sanitizer::OFF64_T OFF64_T;
// Just a pair of pointers.
struct interpose_substitution {
- const uptr replacement;
- const uptr original;
+ const __sanitizer::uptr replacement;
+ const __sanitizer::uptr original;
};
// For a function foo() create a global pair of pointers { wrap_foo, foo } in
@@ -156,10 +156,12 @@ const interpose_substitution substitution_##func_name[] \
namespace __interception { \
extern FUNC_TYPE(func) PTR_TO_REAL(func); \
}
+# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src)
#else // __APPLE__
# define REAL(x) x
# define DECLARE_REAL(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__);
+# define ASSIGN_REAL(x, y)
#endif // __APPLE__
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
diff --git a/libsanitizer/interception/interception_win.cc b/libsanitizer/interception/interception_win.cc
index df51fa21ead..fa81162097e 100644
--- a/libsanitizer/interception/interception_win.cc
+++ b/libsanitizer/interception/interception_win.cc
@@ -8,19 +8,178 @@
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Windows-specific interception methods.
+//
+// This file is implementing several hooking techniques to intercept calls
+// to functions. The hooks are dynamically installed by modifying the assembly
+// code.
+//
+// The hooking techniques are making assumptions on the way the code is
+// generated and are safe under these assumptions.
+//
+// On 64-bit architecture, there is no direct 64-bit jump instruction. To allow
+// arbitrary branching on the whole memory space, the notion of trampoline
+// region is used. A trampoline region is a memory space withing 2G boundary
+// where it is safe to add custom assembly code to build 64-bit jumps.
+//
+// Hooking techniques
+// ==================
+//
+// 1) Detour
+//
+// The Detour hooking technique is assuming the presence of an header with
+// padding and an overridable 2-bytes nop instruction (mov edi, edi). The
+// nop instruction can safely be replaced by a 2-bytes jump without any need
+// to save the instruction. A jump to the target is encoded in the function
+// header and the nop instruction is replaced by a short jump to the header.
+//
+// head: 5 x nop head: jmp <hook>
+// func: mov edi, edi --> func: jmp short <head>
+// [...] real: [...]
+//
+// This technique is only implemented on 32-bit architecture.
+// Most of the time, Windows API are hookable with the detour technique.
+//
+// 2) Redirect Jump
+//
+// The redirect jump is applicable when the first instruction is a direct
+// jump. The instruction is replaced by jump to the hook.
+//
+// func: jmp <label> --> func: jmp <hook>
+//
+// On an 64-bit architecture, a trampoline is inserted.
+//
+// func: jmp <label> --> func: jmp <tramp>
+// [...]
+//
+// [trampoline]
+// tramp: jmp QWORD [addr]
+// addr: .bytes <hook>
+//
+// Note: <real> is equilavent to <label>.
+//
+// 3) HotPatch
+//
+// The HotPatch hooking is assuming the presence of an header with padding
+// and a first instruction with at least 2-bytes.
+//
+// The reason to enforce the 2-bytes limitation is to provide the minimal
+// space to encode a short jump. HotPatch technique is only rewriting one
+// instruction to avoid breaking a sequence of instructions containing a
+// branching target.
+//
+// Assumptions are enforced by MSVC compiler by using the /HOTPATCH flag.
+// see: https://msdn.microsoft.com/en-us/library/ms173507.aspx
+// Default padding length is 5 bytes in 32-bits and 6 bytes in 64-bits.
+//
+// head: 5 x nop head: jmp <hook>
+// func: <instr> --> func: jmp short <head>
+// [...] body: [...]
+//
+// [trampoline]
+// real: <instr>
+// jmp <body>
+//
+// On an 64-bit architecture:
+//
+// head: 6 x nop head: jmp QWORD [addr1]
+// func: <instr> --> func: jmp short <head>
+// [...] body: [...]
+//
+// [trampoline]
+// addr1: .bytes <hook>
+// real: <instr>
+// jmp QWORD [addr2]
+// addr2: .bytes <body>
+//
+// 4) Trampoline
+//
+// The Trampoline hooking technique is the most aggressive one. It is
+// assuming that there is a sequence of instructions that can be safely
+// replaced by a jump (enough room and no incoming branches).
+//
+// Unfortunately, these assumptions can't be safely presumed and code may
+// be broken after hooking.
+//
+// func: <instr> --> func: jmp <hook>
+// <instr>
+// [...] body: [...]
+//
+// [trampoline]
+// real: <instr>
+// <instr>
+// jmp <body>
+//
+// On an 64-bit architecture:
+//
+// func: <instr> --> func: jmp QWORD [addr1]
+// <instr>
+// [...] body: [...]
+//
+// [trampoline]
+// addr1: .bytes <hook>
+// real: <instr>
+// <instr>
+// jmp QWORD [addr2]
+// addr2: .bytes <body>
//===----------------------------------------------------------------------===//
#ifdef _WIN32
#include "interception.h"
+#include "sanitizer_common/sanitizer_platform.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace __interception {
+static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
+static const int kJumpInstructionLength = 5;
+static const int kShortJumpInstructionLength = 2;
+static const int kIndirectJumpInstructionLength = 6;
+static const int kBranchLength =
+ FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
+static const int kDirectBranchLength = kBranchLength + kAddressLength;
+
+static void InterceptionFailed() {
+ // Do we have a good way to abort with an error message here?
+ __debugbreak();
+}
+
+static bool DistanceIsWithin2Gig(uptr from, uptr target) {
+ if (from < target)
+ return target - from <= (uptr)0x7FFFFFFFU;
+ else
+ return from - target <= (uptr)0x80000000U;
+}
+
+static uptr GetMmapGranularity() {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwAllocationGranularity;
+}
+
+static uptr RoundUpTo(uptr size, uptr boundary) {
+ return (size + boundary - 1) & ~(boundary - 1);
+}
+
// FIXME: internal_str* and internal_mem* functions should be moved from the
// ASan sources into interception/.
+static size_t _strlen(const char *str) {
+ const char* p = str;
+ while (*p != '\0') ++p;
+ return p - str;
+}
+
+static char* _strchr(char* str, char c) {
+ while (*str) {
+ if (*str == c)
+ return str;
+ ++str;
+ }
+ return nullptr;
+}
+
static void _memset(void *p, int value, size_t sz) {
for (size_t i = 0; i < sz; ++i)
((char*)p)[i] = (char)value;
@@ -33,163 +192,641 @@ static void _memcpy(void *dst, void *src, size_t sz) {
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;
-}
-
-static char *GetMemoryForTrampoline(size_t size) {
- // Trampolines are allocated from a common pool.
- const int POOL_SIZE = 1024;
- static char *pool = NULL;
- static size_t pool_used = 0;
- if (!pool) {
- pool = (char *)VirtualAlloc(NULL, POOL_SIZE, MEM_RESERVE | MEM_COMMIT,
- PAGE_EXECUTE_READWRITE);
- // FIXME: Might want to apply PAGE_EXECUTE_READ access after all the
- // interceptors are in place.
- if (!pool)
- return NULL;
- _memset(pool, 0xCC /* int 3 */, POOL_SIZE);
+static bool ChangeMemoryProtection(
+ uptr address, uptr size, DWORD *old_protection) {
+ return ::VirtualProtect((void*)address, size,
+ PAGE_EXECUTE_READWRITE,
+ old_protection) != FALSE;
+}
+
+static bool RestoreMemoryProtection(
+ uptr address, uptr size, DWORD old_protection) {
+ DWORD unused;
+ return ::VirtualProtect((void*)address, size,
+ old_protection,
+ &unused) != FALSE;
+}
+
+static bool IsMemoryPadding(uptr address, uptr size) {
+ u8* function = (u8*)address;
+ for (size_t i = 0; i < size; ++i)
+ if (function[i] != 0x90 && function[i] != 0xCC)
+ return false;
+ return true;
+}
+
+static const u8 kHintNop10Bytes[] = {
+ 0x66, 0x66, 0x0F, 0x1F, 0x84,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+template<class T>
+static bool FunctionHasPrefix(uptr address, const T &pattern) {
+ u8* function = (u8*)address - sizeof(pattern);
+ for (size_t i = 0; i < sizeof(pattern); ++i)
+ if (function[i] != pattern[i])
+ return false;
+ return true;
+}
+
+static bool FunctionHasPadding(uptr address, uptr size) {
+ if (IsMemoryPadding(address - size, size))
+ return true;
+ if (size <= sizeof(kHintNop10Bytes) &&
+ FunctionHasPrefix(address, kHintNop10Bytes))
+ return true;
+ return false;
+}
+
+static void WritePadding(uptr from, uptr size) {
+ _memset((void*)from, 0xCC, (size_t)size);
+}
+
+static void WriteJumpInstruction(uptr from, uptr target) {
+ if (!DistanceIsWithin2Gig(from + kJumpInstructionLength, target))
+ InterceptionFailed();
+ ptrdiff_t offset = target - from - kJumpInstructionLength;
+ *(u8*)from = 0xE9;
+ *(u32*)(from + 1) = offset;
+}
+
+static void WriteShortJumpInstruction(uptr from, uptr target) {
+ sptr offset = target - from - kShortJumpInstructionLength;
+ if (offset < -128 || offset > 127)
+ InterceptionFailed();
+ *(u8*)from = 0xEB;
+ *(u8*)(from + 1) = (u8)offset;
+}
+
+#if SANITIZER_WINDOWS64
+static void WriteIndirectJumpInstruction(uptr from, uptr indirect_target) {
+ // jmp [rip + <offset>] = FF 25 <offset> where <offset> is a relative
+ // offset.
+ // The offset is the distance from then end of the jump instruction to the
+ // memory location containing the targeted address. The displacement is still
+ // 32-bit in x64, so indirect_target must be located within +/- 2GB range.
+ int offset = indirect_target - from - kIndirectJumpInstructionLength;
+ if (!DistanceIsWithin2Gig(from + kIndirectJumpInstructionLength,
+ indirect_target)) {
+ InterceptionFailed();
}
+ *(u16*)from = 0x25FF;
+ *(u32*)(from + 2) = offset;
+}
+#endif
+
+static void WriteBranch(
+ uptr from, uptr indirect_target, uptr target) {
+#if SANITIZER_WINDOWS64
+ WriteIndirectJumpInstruction(from, indirect_target);
+ *(u64*)indirect_target = target;
+#else
+ (void)indirect_target;
+ WriteJumpInstruction(from, target);
+#endif
+}
+
+static void WriteDirectBranch(uptr from, uptr target) {
+#if SANITIZER_WINDOWS64
+ // Emit an indirect jump through immediately following bytes:
+ // jmp [rip + kBranchLength]
+ // .quad <target>
+ WriteBranch(from, from + kBranchLength, target);
+#else
+ WriteJumpInstruction(from, target);
+#endif
+}
+
+struct TrampolineMemoryRegion {
+ uptr content;
+ uptr allocated_size;
+ uptr max_size;
+};
+
+static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
+static const int kMaxTrampolineRegion = 1024;
+static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
- if (pool_used + size > POOL_SIZE)
- return NULL;
+static void *AllocateTrampolineRegion(uptr image_address, size_t granularity) {
+#if SANITIZER_WINDOWS64
+ uptr address = image_address;
+ uptr scanned = 0;
+ while (scanned < kTrampolineScanLimitRange) {
+ MEMORY_BASIC_INFORMATION info;
+ if (!::VirtualQuery((void*)address, &info, sizeof(info)))
+ return nullptr;
- char *ret = pool + pool_used;
- pool_used += size;
- return ret;
+ // Check whether a region can be allocated at |address|.
+ if (info.State == MEM_FREE && info.RegionSize >= granularity) {
+ void *page = ::VirtualAlloc((void*)RoundUpTo(address, granularity),
+ granularity,
+ MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+ return page;
+ }
+
+ // Move to the next region.
+ address = (uptr)info.BaseAddress + info.RegionSize;
+ scanned += info.RegionSize;
+ }
+ return nullptr;
+#else
+ return ::VirtualAlloc(nullptr,
+ granularity,
+ MEM_RESERVE | MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE);
+#endif
+}
+
+// Used by unittests to release mapped memory space.
+void TestOnlyReleaseTrampolineRegions() {
+ for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) {
+ TrampolineMemoryRegion *current = &TrampolineRegions[bucket];
+ if (current->content == 0)
+ return;
+ ::VirtualFree((void*)current->content, 0, MEM_RELEASE);
+ current->content = 0;
+ }
+}
+
+static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
+ // Find a region within 2G with enough space to allocate |size| bytes.
+ TrampolineMemoryRegion *region = nullptr;
+ for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) {
+ TrampolineMemoryRegion* current = &TrampolineRegions[bucket];
+ if (current->content == 0) {
+ // No valid region found, allocate a new region.
+ size_t bucket_size = GetMmapGranularity();
+ void *content = AllocateTrampolineRegion(image_address, bucket_size);
+ if (content == nullptr)
+ return 0U;
+
+ current->content = (uptr)content;
+ current->allocated_size = 0;
+ current->max_size = bucket_size;
+ region = current;
+ break;
+ } else if (current->max_size - current->allocated_size > size) {
+#if SANITIZER_WINDOWS64
+ // In 64-bits, the memory space must be allocated within 2G boundary.
+ uptr next_address = current->content + current->allocated_size;
+ if (next_address < image_address ||
+ next_address - image_address >= 0x7FFF0000)
+ continue;
+#endif
+ // The space can be allocated in the current region.
+ region = current;
+ break;
+ }
+ }
+
+ // Failed to find a region.
+ if (region == nullptr)
+ return 0U;
+
+ // Allocate the space in the current region.
+ uptr allocated_space = region->content + region->allocated_size;
+ region->allocated_size += size;
+ WritePadding(allocated_space, size);
+
+ return allocated_space;
}
// Returns 0 on error.
-static size_t RoundUpToInstrBoundary(size_t size, char *code) {
+static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
+ switch (*(u64*)address) {
+ case 0x90909090909006EB: // stub: jmp over 6 x nop.
+ return 8;
+ }
+
+ switch (*(u8*)address) {
+ case 0x90: // 90 : nop
+ return 1;
+
+ case 0x50: // push eax / rax
+ case 0x51: // push ecx / rcx
+ case 0x52: // push edx / rdx
+ case 0x53: // push ebx / rbx
+ case 0x54: // push esp / rsp
+ case 0x55: // push ebp / rbp
+ case 0x56: // push esi / rsi
+ case 0x57: // push edi / rdi
+ case 0x5D: // pop ebp / rbp
+ return 1;
+
+ case 0x6A: // 6A XX = push XX
+ return 2;
+
+ case 0xb8: // b8 XX XX XX XX : mov eax, XX XX XX XX
+ case 0xB9: // b9 XX XX XX XX : mov ecx, XX XX XX XX
+ return 5;
+
+ // Cannot overwrite control-instruction. Return 0 to indicate failure.
+ case 0xE9: // E9 XX XX XX XX : jmp <label>
+ case 0xE8: // E8 XX XX XX XX : call <func>
+ case 0xC3: // C3 : ret
+ case 0xEB: // EB XX : jmp XX (short jump)
+ case 0x70: // 7Y YY : jy XX (short conditional jump)
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ case 0x78:
+ case 0x79:
+ case 0x7A:
+ case 0x7B:
+ case 0x7C:
+ case 0x7D:
+ case 0x7E:
+ case 0x7F:
+ return 0;
+ }
+
+ switch (*(u16*)(address)) {
+ case 0xFF8B: // 8B FF : mov edi, edi
+ case 0xEC8B: // 8B EC : mov ebp, esp
+ case 0xc889: // 89 C8 : mov eax, ecx
+ case 0xC18B: // 8B C1 : mov eax, ecx
+ case 0xC033: // 33 C0 : xor eax, eax
+ case 0xC933: // 33 C9 : xor ecx, ecx
+ case 0xD233: // 33 D2 : xor edx, edx
+ return 2;
+
+ // Cannot overwrite control-instruction. Return 0 to indicate failure.
+ case 0x25FF: // FF 25 XX XX XX XX : jmp [XXXXXXXX]
+ return 0;
+ }
+
+ switch (0x00FFFFFF & *(u32*)address) {
+ case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]
+ return 7;
+ }
+
+#if SANITIZER_WINDOWS64
+ switch (*(u8*)address) {
+ case 0xA1: // A1 XX XX XX XX XX XX XX XX :
+ // movabs eax, dword ptr ds:[XXXXXXXX]
+ return 8;
+ }
+
+ switch (*(u16*)address) {
+ case 0x5040: // push rax
+ case 0x5140: // push rcx
+ case 0x5240: // push rdx
+ case 0x5340: // push rbx
+ case 0x5440: // push rsp
+ case 0x5540: // push rbp
+ case 0x5640: // push rsi
+ case 0x5740: // push rdi
+ case 0x5441: // push r12
+ case 0x5541: // push r13
+ case 0x5641: // push r14
+ case 0x5741: // push r15
+ case 0x9066: // Two-byte NOP
+ return 2;
+ }
+
+ switch (0x00FFFFFF & *(u32*)address) {
+ case 0xe58948: // 48 8b c4 : mov rbp, rsp
+ case 0xc18b48: // 48 8b c1 : mov rax, rcx
+ case 0xc48b48: // 48 8b c4 : mov rax, rsp
+ case 0xd9f748: // 48 f7 d9 : neg rcx
+ case 0xd12b48: // 48 2b d1 : sub rdx, rcx
+ case 0x07c1f6: // f6 c1 07 : test cl, 0x7
+ case 0xc98548: // 48 85 C9 : test rcx, rcx
+ case 0xc0854d: // 4d 85 c0 : test r8, r8
+ case 0xc2b60f: // 0f b6 c2 : movzx eax, dl
+ case 0xc03345: // 45 33 c0 : xor r8d, r8d
+ case 0xdb3345: // 45 33 DB : xor r11d, r11d
+ case 0xd98b4c: // 4c 8b d9 : mov r11, rcx
+ case 0xd28b4c: // 4c 8b d2 : mov r10, rdx
+ case 0xc98b4c: // 4C 8B C9 : mov r9, rcx
+ case 0xd2b60f: // 0f b6 d2 : movzx edx, dl
+ case 0xca2b48: // 48 2b ca : sub rcx, rdx
+ case 0x10b70f: // 0f b7 10 : movzx edx, WORD PTR [rax]
+ case 0xc00b4d: // 3d 0b c0 : or r8, r8
+ case 0xd18b48: // 48 8b d1 : mov rdx, rcx
+ case 0xdc8b4c: // 4c 8b dc : mov r11, rsp
+ case 0xd18b4c: // 4c 8b d1 : mov r10, rcx
+ return 3;
+
+ case 0xec8348: // 48 83 ec XX : sub rsp, XX
+ case 0xf88349: // 49 83 f8 XX : cmp r8, XX
+ case 0x588948: // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx
+ return 4;
+
+ case 0xec8148: // 48 81 EC XX XX XX XX : sub rsp, XXXXXXXX
+ return 7;
+
+ case 0x058b48: // 48 8b 05 XX XX XX XX :
+ // mov rax, QWORD PTR [rip + XXXXXXXX]
+ case 0x25ff48: // 48 ff 25 XX XX XX XX :
+ // rex.W jmp QWORD PTR [rip + XXXXXXXX]
+
+ // Instructions having offset relative to 'rip' need offset adjustment.
+ if (rel_offset)
+ *rel_offset = 3;
+ return 7;
+
+ case 0x2444c7: // C7 44 24 XX YY YY YY YY
+ // mov dword ptr [rsp + XX], YYYYYYYY
+ return 8;
+ }
+
+ switch (*(u32*)(address)) {
+ case 0x24448b48: // 48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]
+ case 0x246c8948: // 48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp
+ case 0x245c8948: // 48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx
+ case 0x24748948: // 48 89 74 24 XX : mov QWORD PTR [rsp + XX], rsi
+ return 5;
+ }
+
+#else
+
+ switch (*(u8*)address) {
+ case 0xA1: // A1 XX XX XX XX : mov eax, dword ptr ds:[XXXXXXXX]
+ return 5;
+ }
+ switch (*(u16*)address) {
+ case 0x458B: // 8B 45 XX : mov eax, dword ptr [ebp + XX]
+ case 0x5D8B: // 8B 5D XX : mov ebx, dword ptr [ebp + XX]
+ case 0x7D8B: // 8B 7D XX : mov edi, dword ptr [ebp + XX]
+ case 0xEC83: // 83 EC XX : sub esp, XX
+ case 0x75FF: // FF 75 XX : push dword ptr [ebp + XX]
+ return 3;
+ case 0xC1F7: // F7 C1 XX YY ZZ WW : test ecx, WWZZYYXX
+ case 0x25FF: // FF 25 XX YY ZZ WW : jmp dword ptr ds:[WWZZYYXX]
+ return 6;
+ case 0x3D83: // 83 3D XX YY ZZ WW TT : cmp TT, WWZZYYXX
+ return 7;
+ case 0x7D83: // 83 7D XX YY : cmp dword ptr [ebp + XX], YY
+ return 4;
+ }
+
+ switch (0x00FFFFFF & *(u32*)address) {
+ case 0x24448A: // 8A 44 24 XX : mov eal, dword ptr [esp + XX]
+ case 0x24448B: // 8B 44 24 XX : mov eax, dword ptr [esp + XX]
+ case 0x244C8B: // 8B 4C 24 XX : mov ecx, dword ptr [esp + XX]
+ case 0x24548B: // 8B 54 24 XX : mov edx, dword ptr [esp + XX]
+ case 0x24748B: // 8B 74 24 XX : mov esi, dword ptr [esp + XX]
+ case 0x247C8B: // 8B 7C 24 XX : mov edi, dword ptr [esp + XX]
+ return 4;
+ }
+
+ switch (*(u32*)address) {
+ case 0x2444B60F: // 0F B6 44 24 XX : movzx eax, byte ptr [esp + XX]
+ return 5;
+ }
+#endif
+
+ // Unknown instruction!
+ // FIXME: Unknown instruction failures might happen when we add a new
+ // interceptor or a new compiler version. In either case, they should result
+ // in visible and readable error messages. However, merely calling abort()
+ // leads to an infinite recursion in CheckFailed.
+ InterceptionFailed();
+ return 0;
+}
+
+// Returns 0 on error.
+static size_t RoundUpToInstrBoundary(size_t size, uptr address) {
size_t cursor = 0;
while (cursor < size) {
- switch (code[cursor]) {
- case '\x51': // push ecx
- case '\x52': // push edx
- case '\x53': // push ebx
- case '\x54': // push esp
- case '\x55': // push ebp
- case '\x56': // push esi
- case '\x57': // push edi
- case '\x5D': // pop ebp
- cursor++;
- continue;
- case '\x6A': // 6A XX = push XX
- cursor += 2;
- continue;
- case '\xE9': // E9 XX YY ZZ WW = jmp WWZZYYXX
- case '\xB8': // B8 XX YY ZZ WW = mov eax, WWZZYYXX
- cursor += 5;
- continue;
- }
- switch (*(unsigned short*)(code + cursor)) { // NOLINT
- case 0xFF8B: // 8B FF = mov edi, edi
- case 0xEC8B: // 8B EC = mov ebp, esp
- case 0xC033: // 33 C0 = xor eax, eax
- cursor += 2;
- continue;
- case 0x458B: // 8B 45 XX = mov eax, dword ptr [ebp+XXh]
- case 0x5D8B: // 8B 5D XX = mov ebx, dword ptr [ebp+XXh]
- case 0xEC83: // 83 EC XX = sub esp, XX
- case 0x75FF: // FF 75 XX = push dword ptr [ebp+XXh]
- cursor += 3;
- continue;
- case 0xC1F7: // F7 C1 XX YY ZZ WW = test ecx, WWZZYYXX
- case 0x25FF: // FF 25 XX YY ZZ WW = jmp dword ptr ds:[WWZZYYXX]
- cursor += 6;
- continue;
- case 0x3D83: // 83 3D XX YY ZZ WW TT = cmp TT, WWZZYYXX
- cursor += 7;
- continue;
- }
- switch (0x00FFFFFF & *(unsigned int*)(code + cursor)) {
- case 0x24448A: // 8A 44 24 XX = mov eal, dword ptr [esp+XXh]
- case 0x24448B: // 8B 44 24 XX = mov eax, 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 0x24748B: // 8B 74 24 XX = mov esi, dword ptr [esp+XXh]
- case 0x247C8B: // 8B 7C 24 XX = mov edi, dword ptr [esp+XXh]
- cursor += 4;
- continue;
+ size_t instruction_size = GetInstructionSize(address + cursor);
+ if (!instruction_size)
+ return 0;
+ cursor += instruction_size;
+ }
+ return cursor;
+}
+
+static bool CopyInstructions(uptr to, uptr from, size_t size) {
+ size_t cursor = 0;
+ while (cursor != size) {
+ size_t rel_offset = 0;
+ size_t instruction_size = GetInstructionSize(from + cursor, &rel_offset);
+ _memcpy((void*)(to + cursor), (void*)(from + cursor),
+ (size_t)instruction_size);
+ if (rel_offset) {
+ uptr delta = to - from;
+ uptr relocated_offset = *(u32*)(to + cursor + rel_offset) - delta;
+#if SANITIZER_WINDOWS64
+ if (relocated_offset + 0x80000000U >= 0xFFFFFFFFU)
+ return false;
+#endif
+ *(u32*)(to + cursor + rel_offset) = relocated_offset;
}
+ cursor += instruction_size;
+ }
+ return true;
+}
- // Unknown instruction!
- // FIXME: Unknown instruction failures might happen when we add a new
- // interceptor or a new compiler version. In either case, they should result
- // in visible and readable error messages. However, merely calling abort()
- // leads to an infinite recursion in CheckFailed.
- // Do we have a good way to abort with an error message here?
- __debugbreak();
- return 0;
+
+#if !SANITIZER_WINDOWS64
+bool OverrideFunctionWithDetour(
+ uptr old_func, uptr new_func, uptr *orig_old_func) {
+ const int kDetourHeaderLen = 5;
+ const u16 kDetourInstruction = 0xFF8B;
+
+ uptr header = (uptr)old_func - kDetourHeaderLen;
+ uptr patch_length = kDetourHeaderLen + kShortJumpInstructionLength;
+
+ // Validate that the function is hookable.
+ if (*(u16*)old_func != kDetourInstruction ||
+ !IsMemoryPadding(header, kDetourHeaderLen))
+ return false;
+
+ // Change memory protection to writable.
+ DWORD protection = 0;
+ if (!ChangeMemoryProtection(header, patch_length, &protection))
+ return false;
+
+ // Write a relative jump to the redirected function.
+ WriteJumpInstruction(header, new_func);
+
+ // Write the short jump to the function prefix.
+ WriteShortJumpInstruction(old_func, header);
+
+ // Restore previous memory protection.
+ if (!RestoreMemoryProtection(header, patch_length, protection))
+ return false;
+
+ if (orig_old_func)
+ *orig_old_func = old_func + kShortJumpInstructionLength;
+
+ return true;
+}
+#endif
+
+bool OverrideFunctionWithRedirectJump(
+ uptr old_func, uptr new_func, uptr *orig_old_func) {
+ // Check whether the first instruction is a relative jump.
+ if (*(u8*)old_func != 0xE9)
+ return false;
+
+ if (orig_old_func) {
+ uptr relative_offset = *(u32*)(old_func + 1);
+ uptr absolute_target = old_func + relative_offset + kJumpInstructionLength;
+ *orig_old_func = absolute_target;
}
- return cursor;
+#if SANITIZER_WINDOWS64
+ // If needed, get memory space for a trampoline jump.
+ uptr trampoline = AllocateMemoryForTrampoline(old_func, kDirectBranchLength);
+ if (!trampoline)
+ return false;
+ WriteDirectBranch(trampoline, new_func);
+#endif
+
+ // Change memory protection to writable.
+ DWORD protection = 0;
+ if (!ChangeMemoryProtection(old_func, kJumpInstructionLength, &protection))
+ return false;
+
+ // Write a relative jump to the redirected function.
+ WriteJumpInstruction(old_func, FIRST_32_SECOND_64(new_func, trampoline));
+
+ // Restore previous memory protection.
+ if (!RestoreMemoryProtection(old_func, kJumpInstructionLength, protection))
+ return false;
+
+ return true;
}
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
-#ifdef _WIN64
-#error OverrideFunction is not yet supported on x64
+bool OverrideFunctionWithHotPatch(
+ uptr old_func, uptr new_func, uptr *orig_old_func) {
+ const int kHotPatchHeaderLen = kBranchLength;
+
+ uptr header = (uptr)old_func - kHotPatchHeaderLen;
+ uptr patch_length = kHotPatchHeaderLen + kShortJumpInstructionLength;
+
+ // Validate that the function is hot patchable.
+ size_t instruction_size = GetInstructionSize(old_func);
+ if (instruction_size < kShortJumpInstructionLength ||
+ !FunctionHasPadding(old_func, kHotPatchHeaderLen))
+ return false;
+
+ if (orig_old_func) {
+ // Put the needed instructions into the trampoline bytes.
+ uptr trampoline_length = instruction_size + kDirectBranchLength;
+ uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length);
+ if (!trampoline)
+ return false;
+ if (!CopyInstructions(trampoline, old_func, instruction_size))
+ return false;
+ WriteDirectBranch(trampoline + instruction_size,
+ old_func + instruction_size);
+ *orig_old_func = trampoline;
+ }
+
+ // If needed, get memory space for indirect address.
+ uptr indirect_address = 0;
+#if SANITIZER_WINDOWS64
+ indirect_address = AllocateMemoryForTrampoline(old_func, kAddressLength);
+ if (!indirect_address)
+ return false;
#endif
- // Function overriding works basically like this:
- // We write "jmp <new_func>" (5 bytes) at the beginning of the 'old_func'
- // to override it.
- // We might want to be able to execute the original 'old_func' from the
- // wrapper, in this case we need to keep the leading 5+ bytes ('head')
- // of the original code somewhere with a "jmp <old_func+head>".
- // We call these 'head'+5 bytes of instructions a "trampoline".
- char *old_bytes = (char *)old_func;
-
- // We'll need at least 5 bytes for a 'jmp'.
- size_t head = 5;
+
+ // Change memory protection to writable.
+ DWORD protection = 0;
+ if (!ChangeMemoryProtection(header, patch_length, &protection))
+ return false;
+
+ // Write jumps to the redirected function.
+ WriteBranch(header, indirect_address, new_func);
+ WriteShortJumpInstruction(old_func, header);
+
+ // Restore previous memory protection.
+ if (!RestoreMemoryProtection(header, patch_length, protection))
+ return false;
+
+ return true;
+}
+
+bool OverrideFunctionWithTrampoline(
+ uptr old_func, uptr new_func, uptr *orig_old_func) {
+
+ size_t instructions_length = kBranchLength;
+ size_t padding_length = 0;
+ uptr indirect_address = 0;
+
if (orig_old_func) {
// Find out the number of bytes of the instructions we need to copy
- // to the trampoline and store it in 'head'.
- head = RoundUpToInstrBoundary(head, old_bytes);
- if (!head)
+ // to the trampoline.
+ instructions_length = RoundUpToInstrBoundary(kBranchLength, old_func);
+ if (!instructions_length)
return false;
// Put the needed instructions into the trampoline bytes.
- char *trampoline = GetMemoryForTrampoline(head + 5);
+ uptr trampoline_length = instructions_length + kDirectBranchLength;
+ uptr trampoline = AllocateMemoryForTrampoline(old_func, trampoline_length);
if (!trampoline)
return false;
- _memcpy(trampoline, old_bytes, head);
- WriteJumpInstruction(trampoline + head, old_bytes + head);
- *orig_old_func = (uptr)trampoline;
+ if (!CopyInstructions(trampoline, old_func, instructions_length))
+ return false;
+ WriteDirectBranch(trampoline + instructions_length,
+ old_func + instructions_length);
+ *orig_old_func = trampoline;
}
- // Now put the "jmp <new_func>" instruction at the original code location.
- // We should preserve the EXECUTE flag as some of our own code might be
- // located in the same page (sic!). FIXME: might consider putting the
- // __interception code into a separate section or something?
- DWORD old_prot, unused_prot;
- if (!VirtualProtect((void *)old_bytes, head, PAGE_EXECUTE_READWRITE,
- &old_prot))
+#if SANITIZER_WINDOWS64
+ // Check if the targeted address can be encoded in the function padding.
+ // Otherwise, allocate it in the trampoline region.
+ if (IsMemoryPadding(old_func - kAddressLength, kAddressLength)) {
+ indirect_address = old_func - kAddressLength;
+ padding_length = kAddressLength;
+ } else {
+ indirect_address = AllocateMemoryForTrampoline(old_func, kAddressLength);
+ if (!indirect_address)
+ return false;
+ }
+#endif
+
+ // Change memory protection to writable.
+ uptr patch_address = old_func - padding_length;
+ uptr patch_length = instructions_length + padding_length;
+ DWORD protection = 0;
+ if (!ChangeMemoryProtection(patch_address, patch_length, &protection))
return false;
- WriteJumpInstruction(old_bytes, (char *)new_func);
- _memset(old_bytes + 5, 0xCC /* int 3 */, head - 5);
+ // Patch the original function.
+ WriteBranch(old_func, indirect_address, new_func);
- // Restore the original permissions.
- if (!VirtualProtect((void *)old_bytes, head, old_prot, &unused_prot))
- return false; // not clear if this failure bothers us.
+ // Restore previous memory protection.
+ if (!RestoreMemoryProtection(patch_address, patch_length, protection))
+ return false;
return true;
}
+bool OverrideFunction(
+ uptr old_func, uptr new_func, uptr *orig_old_func) {
+#if !SANITIZER_WINDOWS64
+ if (OverrideFunctionWithDetour(old_func, new_func, orig_old_func))
+ return true;
+#endif
+ if (OverrideFunctionWithRedirectJump(old_func, new_func, orig_old_func))
+ return true;
+ if (OverrideFunctionWithHotPatch(old_func, new_func, orig_old_func))
+ return true;
+ if (OverrideFunctionWithTrampoline(old_func, new_func, orig_old_func))
+ return true;
+ return false;
+}
+
static void **InterestingDLLsAvailable() {
- const char *InterestingDLLs[] = {
- "kernel32.dll",
- "msvcr110.dll", // VS2012
- "msvcr120.dll", // VS2013
- // NTDLL should go last as it exports some functions that we should override
- // in the CRT [presumably only used internally].
- "ntdll.dll", NULL
- };
+ static const char *InterestingDLLs[] = {
+ "kernel32.dll",
+ "msvcr110.dll", // VS2012
+ "msvcr120.dll", // VS2013
+ "vcruntime140.dll", // VS2015
+ "ucrtbase.dll", // Universal CRT
+ // NTDLL should go last as it exports some functions that we should
+ // override in the CRT [presumably only used internally].
+ "ntdll.dll", NULL};
static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
if (!result[0]) {
for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
@@ -244,6 +881,32 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
if (!strcmp(func_name, name)) {
DWORD index = ordinals[i];
RVAPtr<char> func(module, functions[index]);
+
+ // Handle forwarded functions.
+ DWORD offset = functions[index];
+ if (offset >= export_directory->VirtualAddress &&
+ offset < export_directory->VirtualAddress + export_directory->Size) {
+ // An entry for a forwarded function is a string with the following
+ // format: "<module> . <function_name>" that is stored into the
+ // exported directory.
+ char function_name[256];
+ size_t funtion_name_length = _strlen(func);
+ if (funtion_name_length >= sizeof(function_name) - 1)
+ InterceptionFailed();
+
+ _memcpy(function_name, func, funtion_name_length);
+ function_name[funtion_name_length] = '\0';
+ char* separator = _strchr(function_name, '.');
+ if (!separator)
+ InterceptionFailed();
+ *separator = '\0';
+
+ void* redirected_module = GetModuleHandleA(function_name);
+ if (!redirected_module)
+ InterceptionFailed();
+ return InternalGetProcAddress(redirected_module, separator + 1);
+ }
+
return (uptr)(char *)func;
}
}
@@ -251,19 +914,83 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
return 0;
}
-static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) {
- *func_addr = 0;
+bool OverrideFunction(
+ const char *func_name, uptr new_func, uptr *orig_old_func) {
+ bool hooked = false;
void **DLLs = InterestingDLLsAvailable();
- for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i)
- *func_addr = InternalGetProcAddress(DLLs[i], func_name);
- return (*func_addr != 0);
+ for (size_t i = 0; DLLs[i]; ++i) {
+ uptr func_addr = InternalGetProcAddress(DLLs[i], func_name);
+ if (func_addr &&
+ OverrideFunction(func_addr, new_func, orig_old_func)) {
+ hooked = true;
+ }
+ }
+ return hooked;
}
-bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func) {
- uptr orig_func;
- if (!GetFunctionAddressInDLLs(name, &orig_func))
+bool OverrideImportedFunction(const char *module_to_patch,
+ const char *imported_module,
+ const char *function_name, uptr new_function,
+ uptr *orig_old_func) {
+ HMODULE module = GetModuleHandleA(module_to_patch);
+ if (!module)
+ return false;
+
+ // Check that the module header is full and present.
+ RVAPtr<IMAGE_DOS_HEADER> dos_stub(module, 0);
+ RVAPtr<IMAGE_NT_HEADERS> headers(module, dos_stub->e_lfanew);
+ if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ"
+ headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0"
+ headers->FileHeader.SizeOfOptionalHeader <
+ sizeof(IMAGE_OPTIONAL_HEADER)) {
return false;
- return OverrideFunction(orig_func, new_func, orig_old_func);
+ }
+
+ IMAGE_DATA_DIRECTORY *import_directory =
+ &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+
+ // Iterate the list of imported DLLs. FirstThunk will be null for the last
+ // entry.
+ RVAPtr<IMAGE_IMPORT_DESCRIPTOR> imports(module,
+ import_directory->VirtualAddress);
+ for (; imports->FirstThunk != 0; ++imports) {
+ RVAPtr<const char> modname(module, imports->Name);
+ if (_stricmp(&*modname, imported_module) == 0)
+ break;
+ }
+ if (imports->FirstThunk == 0)
+ return false;
+
+ // We have two parallel arrays: the import address table (IAT) and the table
+ // of names. They start out containing the same data, but the loader rewrites
+ // the IAT to hold imported addresses and leaves the name table in
+ // OriginalFirstThunk alone.
+ RVAPtr<IMAGE_THUNK_DATA> name_table(module, imports->OriginalFirstThunk);
+ RVAPtr<IMAGE_THUNK_DATA> iat(module, imports->FirstThunk);
+ for (; name_table->u1.Ordinal != 0; ++name_table, ++iat) {
+ if (!IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+ RVAPtr<IMAGE_IMPORT_BY_NAME> import_by_name(
+ module, name_table->u1.ForwarderString);
+ const char *funcname = &import_by_name->Name[0];
+ if (strcmp(funcname, function_name) == 0)
+ break;
+ }
+ }
+ if (name_table->u1.Ordinal == 0)
+ return false;
+
+ // Now we have the correct IAT entry. Do the swap. We have to make the page
+ // read/write first.
+ if (orig_old_func)
+ *orig_old_func = iat->u1.AddressOfData;
+ DWORD old_prot, unused_prot;
+ if (!VirtualProtect(&iat->u1.AddressOfData, 4, PAGE_EXECUTE_READWRITE,
+ &old_prot))
+ return false;
+ iat->u1.AddressOfData = new_function;
+ if (!VirtualProtect(&iat->u1.AddressOfData, 4, old_prot, &unused_prot))
+ return false; // Not clear if this failure bothers us.
+ return true;
}
} // namespace __interception
diff --git a/libsanitizer/interception/interception_win.h b/libsanitizer/interception/interception_win.h
index 6388209dcc1..f092d18d28f 100644
--- a/libsanitizer/interception/interception_win.h
+++ b/libsanitizer/interception/interception_win.h
@@ -32,6 +32,31 @@ bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0);
// Windows-only replacement for GetProcAddress. Useful for some sanitizers.
uptr InternalGetProcAddress(void *module, const char *func_name);
+// Overrides a function only when it is called from a specific DLL. For example,
+// this is used to override calls to HeapAlloc/HeapFree from ucrtbase without
+// affecting other third party libraries.
+bool OverrideImportedFunction(const char *module_to_patch,
+ const char *imported_module,
+ const char *function_name, uptr new_function,
+ uptr *orig_old_func);
+
+#if !SANITIZER_WINDOWS64
+// Exposed for unittests
+bool OverrideFunctionWithDetour(
+ uptr old_func, uptr new_func, uptr *orig_old_func);
+#endif
+
+// Exposed for unittests
+bool OverrideFunctionWithRedirectJump(
+ uptr old_func, uptr new_func, uptr *orig_old_func);
+bool OverrideFunctionWithHotPatch(
+ uptr old_func, uptr new_func, uptr *orig_old_func);
+bool OverrideFunctionWithTrampoline(
+ uptr old_func, uptr new_func, uptr *orig_old_func);
+
+// Exposed for unittests
+void TestOnlyReleaseTrampolineRegions();
+
} // namespace __interception
#if defined(INTERCEPTION_DYNAMIC_CRT)
@@ -48,5 +73,10 @@ uptr InternalGetProcAddress(void *module, const char *func_name);
#define INTERCEPT_FUNCTION_VER_WIN(func, symver) INTERCEPT_FUNCTION_WIN(func)
+#define INTERCEPT_FUNCTION_DLLIMPORT(user_dll, provider_dll, func) \
+ ::__interception::OverrideImportedFunction( \
+ user_dll, provider_dll, #func, (::__interception::uptr)WRAP(func), \
+ (::__interception::uptr *)&REAL(func))
+
#endif // INTERCEPTION_WIN_H
#endif // _WIN32
diff --git a/libsanitizer/libbacktrace/Makefile.in b/libsanitizer/libbacktrace/Makefile.in
index ff37a81e4ec..3a618ecb838 100644
--- a/libsanitizer/libbacktrace/Makefile.in
+++ b/libsanitizer/libbacktrace/Makefile.in
@@ -211,6 +211,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index b02c3736a49..a0c8ae9b7c6 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -210,6 +210,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc
index 6e7429c95a5..2ded5544c71 100644
--- a/libsanitizer/lsan/lsan.cc
+++ b/libsanitizer/lsan/lsan.cc
@@ -41,6 +41,7 @@ static void InitializeFlags() {
cf.CopyFrom(*common_flags());
cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
cf.malloc_context_size = 30;
+ cf.intercept_tls_get_addr = true;
cf.detect_leaks = true;
cf.exitcode = 23;
OverrideCommonFlags(cf);
@@ -69,6 +70,7 @@ extern "C" void __lsan_init() {
lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
CacheBinaryName();
+ AvoidCVE_2016_2143();
InitializeFlags();
InitCommonLsan();
InitializeAllocator();
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index ee2fc02cf08..6d2d427b27d 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -22,8 +22,11 @@
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
- stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
- /* context */ 0, stack_top, stack_bottom, fast); \
+ if (!SANITIZER_MIPS || \
+ IsValidFrame(GET_CURRENT_FRAME(), stack_top, stack_bottom)) { \
+ stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
+ /* context */ 0, stack_top, stack_bottom, fast); \
+ } \
}
#define GET_STACK_TRACE_FATAL \
diff --git a/libsanitizer/lsan/lsan_allocator.cc b/libsanitizer/lsan/lsan_allocator.cc
index 22b5f7e1a4a..0d2fceac71b 100644
--- a/libsanitizer/lsan/lsan_allocator.cc
+++ b/libsanitizer/lsan/lsan_allocator.cc
@@ -41,10 +41,17 @@ typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
PrimaryAllocator;
#else
static const uptr kMaxAllowedMallocSize = 8UL << 30;
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
- sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
+
+struct AP64 { // Allocator64 parameters. Deliberately using a short name.
+ static const uptr kSpaceBeg = 0x600000000000ULL;
+ static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
+ static const uptr kMetadataSize = sizeof(ChunkMetadata);
+ typedef DefaultSizeClassMap SizeClassMap;
+ typedef NoOpMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+
+typedef SizeClassAllocator64<AP64> PrimaryAllocator;
#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator;
@@ -97,11 +104,13 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
memset(p, 0, size);
RegisterAllocation(stack, p, size);
if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(p, size);
+ RunMallocHooks(p, size);
return p;
}
void Deallocate(void *p) {
if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
+ RunFreeHooks(p);
RegisterDeallocation(p);
allocator.Deallocate(&cache, p);
}
diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc
index 6d674c5e437..41024e11873 100644
--- a/libsanitizer/lsan/lsan_common.cc
+++ b/libsanitizer/lsan/lsan_common.cc
@@ -21,6 +21,7 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#if CAN_SANITIZE_LEAKS
namespace __lsan {
@@ -29,8 +30,17 @@ namespace __lsan {
// also to protect the global list of root regions.
BlockingMutex global_mutex(LINKER_INITIALIZED);
+__attribute__((tls_model("initial-exec")))
THREADLOCAL int disable_counter;
bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+ if (!disable_counter && common_flags()->detect_leaks) {
+ Report("Unmatched call to __lsan_enable().\n");
+ Die();
+ }
+ disable_counter--;
+}
Flags lsan_flags;
@@ -183,9 +193,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
LOG_THREADS("Processing thread %d.\n", os_id);
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
+ DTLS *dtls;
bool thread_found = GetThreadRangesLocked(os_id, &stack_begin, &stack_end,
&tls_begin, &tls_end,
- &cache_begin, &cache_end);
+ &cache_begin, &cache_end, &dtls);
if (!thread_found) {
// If a thread can't be found in the thread registry, it's probably in the
// process of destruction. Log this event and move on.
@@ -209,9 +220,18 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
LOG_THREADS("Stack at %p-%p (SP = %p).\n", stack_begin, stack_end, sp);
if (sp < stack_begin || sp >= stack_end) {
// SP is outside the recorded stack range (e.g. the thread is running a
- // signal handler on alternate stack). Again, consider the entire stack
- // range to be reachable.
+ // signal handler on alternate stack, or swapcontext was used).
+ // Again, consider the entire stack range to be reachable.
LOG_THREADS("WARNING: stack pointer not in stack range.\n");
+ uptr page_size = GetPageSizeCached();
+ int skipped = 0;
+ while (stack_begin < stack_end &&
+ !IsAccessibleMemoryRange(stack_begin, 1)) {
+ skipped++;
+ stack_begin += page_size;
+ }
+ LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n",
+ skipped, stack_begin, stack_end);
} else {
// Shrink the stack range to ignore out-of-scope values.
stack_begin = sp;
@@ -236,6 +256,17 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
if (tls_end > cache_end)
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
}
+ if (dtls) {
+ for (uptr j = 0; j < dtls->dtv_size; ++j) {
+ uptr dtls_beg = dtls->dtv[j].beg;
+ uptr dtls_end = dtls_beg + dtls->dtv[j].size;
+ if (dtls_beg < dtls_end) {
+ LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
+ ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
+ kReachable);
+ }
+ }
+ }
}
}
}
@@ -414,6 +445,11 @@ static bool CheckForLeaks() {
if (!param.success) {
Report("LeakSanitizer has encountered a fatal error.\n");
+ Report(
+ "HINT: For debugging, try setting environment variable "
+ "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
+ Report(
+ "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
Die();
}
param.leak_report.ApplySuppressions();
@@ -615,6 +651,13 @@ uptr LeakReport::UnsuppressedLeakCount() {
}
} // namespace __lsan
+#else // CAN_SANITIZE_LEAKS
+namespace __lsan {
+void InitCommonLsan() { }
+void DoLeakCheck() { }
+void DisableInThisThread() { }
+void EnableInThisThread() { }
+}
#endif // CAN_SANITIZE_LEAKS
using namespace __lsan; // NOLINT
@@ -680,18 +723,14 @@ void __lsan_unregister_root_region(const void *begin, uptr size) {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_disable() {
#if CAN_SANITIZE_LEAKS
- __lsan::disable_counter++;
+ __lsan::DisableInThisThread();
#endif
}
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_enable() {
#if CAN_SANITIZE_LEAKS
- if (!__lsan::disable_counter && common_flags()->detect_leaks) {
- Report("Unmatched call to __lsan_enable().\n");
- Die();
- }
- __lsan::disable_counter--;
+ __lsan::EnableInThisThread();
#endif
}
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index b415567e7f3..1091b84f108 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -29,6 +29,7 @@
namespace __sanitizer {
class FlagParser;
+struct DTLS;
}
namespace __lsan {
@@ -116,6 +117,16 @@ void InitCommonLsan();
void DoLeakCheck();
bool DisabledInThisThread();
+// Used to implement __lsan::ScopedDisabler.
+void DisableInThisThread();
+void EnableInThisThread();
+// Can be used to ignore memory allocated by an intercepted
+// function.
+struct ScopedInterceptorDisabler {
+ ScopedInterceptorDisabler() { DisableInThisThread(); }
+ ~ScopedInterceptorDisabler() { EnableInThisThread(); }
+};
+
// Special case for "new T[0]" where T is a type with DTOR.
// new T[0] will allocate one word for the array size (0) and store a pointer
// to the end of allocated chunk.
@@ -139,8 +150,8 @@ bool WordIsPoisoned(uptr addr);
void LockThreadRegistry();
void UnlockThreadRegistry();
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
- uptr *tls_begin, uptr *tls_end,
- uptr *cache_begin, uptr *cache_end);
+ uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+ uptr *cache_end, DTLS **dtls);
void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
void *arg);
// If called from the main thread, updates the main thread's TID in the thread
diff --git a/libsanitizer/lsan/lsan_common_linux.cc b/libsanitizer/lsan/lsan_common_linux.cc
index 0456dce890a..abbb61f07c9 100644
--- a/libsanitizer/lsan/lsan_common_linux.cc
+++ b/libsanitizer/lsan/lsan_common_linux.cc
@@ -24,9 +24,8 @@
namespace __lsan {
static const char kLinkerName[] = "ld";
-// We request 2 modules matching "ld", so we can print a warning if there's more
-// than one match. But only the first one is actually used.
-static char linker_placeholder[2 * sizeof(LoadedModule)] ALIGNED(64);
+
+static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
static LoadedModule *linker = nullptr;
static bool IsLinker(const char* full_name) {
@@ -34,20 +33,24 @@ static bool IsLinker(const char* full_name) {
}
void InitializePlatformSpecificModules() {
- internal_memset(linker_placeholder, 0, sizeof(linker_placeholder));
- uptr num_matches = GetListOfModules(
- reinterpret_cast<LoadedModule *>(linker_placeholder), 2, IsLinker);
- if (num_matches == 1) {
- linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
- return;
+ ListOfModules modules;
+ modules.init();
+ for (LoadedModule &module : modules) {
+ if (!IsLinker(module.full_name())) continue;
+ if (linker == nullptr) {
+ linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
+ *linker = module;
+ module = LoadedModule();
+ } else {
+ VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
+ "TLS will not be handled correctly.\n", kLinkerName);
+ linker->clear();
+ linker = nullptr;
+ return;
+ }
}
- if (num_matches == 0)
- VReport(1, "LeakSanitizer: Dynamic linker not found. "
- "TLS will not be handled correctly.\n");
- else if (num_matches > 1)
- VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
- "TLS will not be handled correctly.\n", kLinkerName);
- linker = nullptr;
+ VReport(1, "LeakSanitizer: Dynamic linker not found. "
+ "TLS will not be handled correctly.\n");
}
static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
@@ -66,7 +69,7 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
if (begin <= allocator_begin && allocator_begin < end) {
CHECK_LE(allocator_begin, allocator_end);
- CHECK_LT(allocator_end, end);
+ CHECK_LE(allocator_end, end);
if (begin < allocator_begin)
ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
kReachable);
@@ -98,6 +101,7 @@ static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
struct ProcessPlatformAllocParam {
Frontier *frontier;
StackDepotReverseMap *stack_depot_reverse_map;
+ bool skip_linker_allocations;
};
// ForEachChunk callback. Identifies unreachable chunks which must be treated as
@@ -115,7 +119,8 @@ static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
// If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
// it as reachable, as we can't properly report its allocation stack anyway.
- if (caller_pc == 0 || linker->containsAddress(caller_pc)) {
+ if (caller_pc == 0 || (param->skip_linker_allocations &&
+ linker->containsAddress(caller_pc))) {
m.set_tag(kReachable);
param->frontier->push_back(chunk);
}
@@ -140,10 +145,12 @@ static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
// guaranteed to include all dynamic TLS blocks (and possibly other allocations
// which we don't care about).
void ProcessPlatformSpecificAllocations(Frontier *frontier) {
- if (!flags()->use_tls) return;
- if (!linker) return;
StackDepotReverseMap stack_depot_reverse_map;
- ProcessPlatformAllocParam arg = {frontier, &stack_depot_reverse_map};
+ ProcessPlatformAllocParam arg;
+ arg.frontier = frontier;
+ arg.stack_depot_reverse_map = &stack_depot_reverse_map;
+ arg.skip_linker_allocations =
+ flags()->use_tls && flags()->use_ld_allocations && linker != nullptr;
ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg);
}
diff --git a/libsanitizer/lsan/lsan_flags.inc b/libsanitizer/lsan/lsan_flags.inc
index 73a980e1724..98611257494 100644
--- a/libsanitizer/lsan/lsan_flags.inc
+++ b/libsanitizer/lsan/lsan_flags.inc
@@ -32,6 +32,10 @@ LSAN_FLAG(bool, use_tls, true,
"Root set: include TLS and thread-specific storage")
LSAN_FLAG(bool, use_root_regions, true,
"Root set: include regions added via __lsan_register_root_region().")
+LSAN_FLAG(bool, use_ld_allocations, true,
+ "Root set: mark as reachable all allocations made from dynamic "
+ "linker. This was the old way to handle dynamic TLS, and will "
+ "be removed soon. Do not use this flag.")
LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
LSAN_FLAG(bool, use_poisoned, false,
diff --git a/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc
index 57581e855c4..160ed5979c4 100644
--- a/libsanitizer/lsan/lsan_interceptors.cc
+++ b/libsanitizer/lsan/lsan_interceptors.cc
@@ -18,8 +18,10 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan.h"
#include "lsan_allocator.h"
+#include "lsan_common.h"
#include "lsan_thread.h"
using namespace __lsan;
@@ -102,6 +104,14 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
return 0;
}
+INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
+ ENSURE_LSAN_INITED;
+ GET_STACK_TRACE_MALLOC;
+ void *res = Allocate(stack, size, alignment, kAlwaysClearMemory);
+ DTLS_on_libc_memalign(res, size);
+ return res;
+}
+
INTERCEPTOR(void*, valloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
@@ -172,11 +182,6 @@ void operator delete[](void *ptr, std::nothrow_t const &) {
OPERATOR_DELETE_BODY;
}
-// We need this to intercept the __libc_memalign calls that are used to
-// allocate dynamic TLS space in ld-linux.so.
-INTERCEPTOR(void *, __libc_memalign, uptr align, uptr s)
- ALIAS(WRAPPER_NAME(memalign));
-
///// Thread initialization and finalization. /////
static unsigned g_thread_finalize_key;
@@ -235,7 +240,15 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
p.callback = callback;
p.param = param;
atomic_store(&p.tid, 0, memory_order_relaxed);
- int res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+ int res;
+ {
+ // Ignore all allocations made by pthread_create: thread stack/TLS may be
+ // stored by pthread for future reuse even after thread destruction, and
+ // the linked list it's stored in doesn't even hold valid pointers to the
+ // objects, the latter are calculated by obscure pointer arithmetic.
+ ScopedInterceptorDisabler disabler;
+ res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
+ }
if (res == 0) {
int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
CHECK_NE(tid, 0);
diff --git a/libsanitizer/lsan/lsan_thread.cc b/libsanitizer/lsan/lsan_thread.cc
index 1313ea2dce1..af5ad47913f 100644
--- a/libsanitizer/lsan/lsan_thread.cc
+++ b/libsanitizer/lsan/lsan_thread.cc
@@ -15,6 +15,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan_allocator.h"
namespace __lsan {
@@ -33,7 +34,7 @@ static const uptr kMaxThreads = 1 << 13;
static const uptr kThreadQuarantineSize = 64;
void InitializeThreadRegistry() {
- static char thread_registry_placeholder[sizeof(ThreadRegistry)] ALIGNED(64);
+ static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)];
thread_registry = new(thread_registry_placeholder)
ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
}
@@ -47,18 +48,20 @@ void SetCurrentThread(u32 tid) {
}
ThreadContext::ThreadContext(int tid)
- : ThreadContextBase(tid),
- stack_begin_(0),
- stack_end_(0),
- cache_begin_(0),
- cache_end_(0),
- tls_begin_(0),
- tls_end_(0) {}
+ : ThreadContextBase(tid),
+ stack_begin_(0),
+ stack_end_(0),
+ cache_begin_(0),
+ cache_end_(0),
+ tls_begin_(0),
+ tls_end_(0),
+ dtls_(nullptr) {}
struct OnStartedArgs {
uptr stack_begin, stack_end,
cache_begin, cache_end,
tls_begin, tls_end;
+ DTLS *dtls;
};
void ThreadContext::OnStarted(void *arg) {
@@ -69,10 +72,12 @@ void ThreadContext::OnStarted(void *arg) {
tls_end_ = args->tls_end;
cache_begin_ = args->cache_begin;
cache_end_ = args->cache_end;
+ dtls_ = args->dtls;
}
void ThreadContext::OnFinished() {
AllocatorThreadFinish();
+ DTLS_Destroy();
}
u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
@@ -89,6 +94,7 @@ void ThreadStart(u32 tid, uptr os_id) {
args.stack_end = args.stack_begin + stack_size;
args.tls_end = args.tls_begin + tls_size;
GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
+ args.dtls = DTLS_Get();
thread_registry->StartThread(tid, os_id, &args);
}
@@ -129,8 +135,8 @@ void EnsureMainThreadIDIsCorrect() {
///// Interface to the common LSan module. /////
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
- uptr *tls_begin, uptr *tls_end,
- uptr *cache_begin, uptr *cache_end) {
+ uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+ uptr *cache_end, DTLS **dtls) {
ThreadContext *context = static_cast<ThreadContext *>(
thread_registry->FindThreadContextByOsIDLocked(os_id));
if (!context) return false;
@@ -140,6 +146,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
*tls_end = context->tls_end();
*cache_begin = context->cache_begin();
*cache_end = context->cache_end();
+ *dtls = context->dtls();
return true;
}
diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
index 70c3ff92616..dafd8af0a29 100644
--- a/libsanitizer/lsan/lsan_thread.h
+++ b/libsanitizer/lsan/lsan_thread.h
@@ -15,6 +15,10 @@
#include "sanitizer_common/sanitizer_thread_registry.h"
+namespace __sanitizer {
+struct DTLS;
+}
+
namespace __lsan {
class ThreadContext : public ThreadContextBase {
@@ -28,10 +32,13 @@ class ThreadContext : public ThreadContextBase {
uptr tls_end() { return tls_end_; }
uptr cache_begin() { return cache_begin_; }
uptr cache_end() { return cache_end_; }
+ DTLS *dtls() { return dtls_; }
+
private:
uptr stack_begin_, stack_end_,
cache_begin_, cache_end_,
tls_begin_, tls_end_;
+ DTLS *dtls_;
};
void InitializeThreadRegistry();
diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh
index 29e444248f1..b3321027733 100755
--- a/libsanitizer/merge.sh
+++ b/libsanitizer/merge.sh
@@ -72,6 +72,10 @@ merge lib/sanitizer_common sanitizer_common
merge lib/interception interception
merge lib/ubsan ubsan
+# Need to merge lib/builtins/assembly.h file:
+mkdir -p builtins
+cp -v upstream/lib/builtins/assembly.h builtins/assembly.h
+
rm -rf upstream
# Update the MERGE file.
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am
index ee7a3f1dd2c..8b6336fd3ad 100644
--- a/libsanitizer/sanitizer_common/Makefile.am
+++ b/libsanitizer/sanitizer_common/Makefile.am
@@ -32,6 +32,7 @@ sanitizer_common_files = \
sanitizer_libignore.cc \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
+ sanitizer_linux_s390.cc \
sanitizer_mac.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
@@ -55,6 +56,7 @@ sanitizer_common_files = \
sanitizer_symbolizer_libcdep.cc \
sanitizer_symbolizer_posix_libcdep.cc \
sanitizer_symbolizer_win.cc \
+ sanitizer_termination.cc \
sanitizer_thread_registry.cc \
sanitizer_tls_get_addr.cc \
sanitizer_unwind_linux_libcdep.cc \
@@ -62,6 +64,9 @@ sanitizer_common_files = \
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
+EXTRA_libsanitizer_common_la_SOURCES = sanitizer_linux_mips64.S sanitizer_linux_x86_64.S
+libsanitizer_common_la_LIBADD = $(SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS)
+libsanitizer_common_la_DEPENDENCIES = $(SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS)
# 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
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index 4b008ad7ae6..052802e176a 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -79,7 +79,7 @@ CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
-libsanitizer_common_la_LIBADD =
+am__DEPENDENCIES_1 =
am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_common_libcdep.lo sanitizer_coverage_libcdep.lo \
sanitizer_coverage_mapping_libcdep.lo \
@@ -87,8 +87,8 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_deadlock_detector2.lo sanitizer_flags.lo \
sanitizer_flag_parser.lo sanitizer_libc.lo \
sanitizer_libignore.lo sanitizer_linux.lo \
- sanitizer_linux_libcdep.lo sanitizer_mac.lo \
- sanitizer_persistent_allocator.lo \
+ sanitizer_linux_libcdep.lo sanitizer_linux_s390.lo \
+ sanitizer_mac.lo sanitizer_persistent_allocator.lo \
sanitizer_platform_limits_linux.lo \
sanitizer_platform_limits_posix.lo sanitizer_posix.lo \
sanitizer_posix_libcdep.lo sanitizer_printf.lo \
@@ -102,15 +102,20 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_symbolizer_libbacktrace.lo \
sanitizer_symbolizer_libcdep.lo \
sanitizer_symbolizer_posix_libcdep.lo \
- sanitizer_symbolizer_win.lo sanitizer_thread_registry.lo \
- sanitizer_tls_get_addr.lo sanitizer_unwind_linux_libcdep.lo \
- sanitizer_win.lo
+ sanitizer_symbolizer_win.lo sanitizer_termination.lo \
+ sanitizer_thread_registry.lo sanitizer_tls_get_addr.lo \
+ sanitizer_unwind_linux_libcdep.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@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/../depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
+CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS)
+LTCPPASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS)
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
@@ -120,7 +125,17 @@ CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(libsanitizer_common_la_SOURCES)
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libsanitizer_common_la_SOURCES) \
+ $(EXTRA_libsanitizer_common_la_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -198,6 +213,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -296,6 +312,7 @@ sanitizer_common_files = \
sanitizer_libignore.cc \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
+ sanitizer_linux_s390.cc \
sanitizer_mac.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
@@ -319,12 +336,16 @@ sanitizer_common_files = \
sanitizer_symbolizer_libcdep.cc \
sanitizer_symbolizer_posix_libcdep.cc \
sanitizer_symbolizer_win.cc \
+ sanitizer_termination.cc \
sanitizer_thread_registry.cc \
sanitizer_tls_get_addr.cc \
sanitizer_unwind_linux_libcdep.cc \
sanitizer_win.cc
libsanitizer_common_la_SOURCES = $(sanitizer_common_files)
+EXTRA_libsanitizer_common_la_SOURCES = sanitizer_linux_mips64.S sanitizer_linux_x86_64.S
+libsanitizer_common_la_LIBADD = $(SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS)
+libsanitizer_common_la_DEPENDENCIES = $(SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS)
# 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
@@ -368,7 +389,7 @@ MAKEOVERRIDES =
all: all-am
.SUFFIXES:
-.SUFFIXES: .cc .lo .o .obj
+.SUFFIXES: .S .cc .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
@@ -430,6 +451,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libignore.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_mips64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_s390.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_x86_64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_persistent_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@
@@ -453,11 +477,33 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_posix_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_termination.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_tls_get_addr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_unwind_linux_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@
+.S.o:
+@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ $<
+
+.S.obj:
+@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCCAS_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.S.lo:
+@am__fastdepCCAS_TRUE@ $(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@ $(LTCPPASCOMPILE) -c -o $@ $<
+
.cc.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cc b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
index b5e0bab91f1..2755853acbc 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
@@ -11,39 +11,72 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_allocator.h"
+
#include "sanitizer_allocator_internal.h"
+#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
namespace __sanitizer {
// ThreadSanitizer for Go uses libc malloc/free.
-#if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
+#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
# if SANITIZER_LINUX && !SANITIZER_ANDROID
extern "C" void *__libc_malloc(uptr size);
+# if !SANITIZER_GO
+extern "C" void *__libc_memalign(uptr alignment, uptr size);
+# endif
+extern "C" void *__libc_realloc(void *ptr, uptr size);
extern "C" void __libc_free(void *ptr);
-# define LIBC_MALLOC __libc_malloc
-# define LIBC_FREE __libc_free
# else
# include <stdlib.h>
-# define LIBC_MALLOC malloc
-# define LIBC_FREE free
+# define __libc_malloc malloc
+# if !SANITIZER_GO
+static void *__libc_memalign(uptr alignment, uptr size) {
+ void *p;
+ uptr error = posix_memalign(&p, alignment, size);
+ if (error) return nullptr;
+ return p;
+}
+# endif
+# define __libc_realloc realloc
+# define __libc_free free
# endif
-static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache,
+ uptr alignment) {
+ (void)cache;
+#if !SANITIZER_GO
+ if (alignment == 0)
+ return __libc_malloc(size);
+ else
+ return __libc_memalign(alignment, size);
+#else
+ // Windows does not provide __libc_memalign/posix_memalign. It provides
+ // __aligned_malloc, but the allocated blocks can't be passed to free,
+ // they need to be passed to __aligned_free. InternalAlloc interface does
+ // not account for such requirement. Alignemnt does not seem to be used
+ // anywhere in runtime, so just call __libc_malloc for now.
+ DCHECK_EQ(alignment, 0);
+ return __libc_malloc(size);
+#endif
+}
+
+static void *RawInternalRealloc(void *ptr, uptr size,
+ InternalAllocatorCache *cache) {
(void)cache;
- return LIBC_MALLOC(size);
+ return __libc_realloc(ptr, size);
}
static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
(void)cache;
- LIBC_FREE(ptr);
+ __libc_free(ptr);
}
InternalAllocator *internal_allocator() {
return 0;
}
-#else // SANITIZER_GO
+#else // SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
static atomic_uint8_t internal_allocator_initialized;
@@ -66,13 +99,26 @@ InternalAllocator *internal_allocator() {
return internal_allocator_instance;
}
-static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) {
+static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache,
+ uptr alignment) {
+ if (alignment == 0) alignment = 8;
+ if (cache == 0) {
+ SpinMutexLock l(&internal_allocator_cache_mu);
+ return internal_allocator()->Allocate(&internal_allocator_cache, size,
+ alignment, false);
+ }
+ return internal_allocator()->Allocate(cache, size, alignment, false);
+}
+
+static void *RawInternalRealloc(void *ptr, uptr size,
+ InternalAllocatorCache *cache) {
+ uptr alignment = 8;
if (cache == 0) {
SpinMutexLock l(&internal_allocator_cache_mu);
- return internal_allocator()->Allocate(&internal_allocator_cache, size, 8,
- false);
+ return internal_allocator()->Reallocate(&internal_allocator_cache, ptr,
+ size, alignment);
}
- return internal_allocator()->Allocate(cache, size, 8, false);
+ return internal_allocator()->Reallocate(cache, ptr, size, alignment);
}
static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
@@ -83,20 +129,42 @@ static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
internal_allocator()->Deallocate(cache, ptr);
}
-#endif // SANITIZER_GO
+#endif // SANITIZER_GO || defined(SANITIZER_USE_MALLOC)
const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull;
-void *InternalAlloc(uptr size, InternalAllocatorCache *cache) {
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
if (size + sizeof(u64) < size)
return nullptr;
- void *p = RawInternalAlloc(size + sizeof(u64), cache);
+ void *p = RawInternalAlloc(size + sizeof(u64), cache, alignment);
if (!p)
return nullptr;
((u64*)p)[0] = kBlockMagic;
return (char*)p + sizeof(u64);
}
+void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
+ if (!addr)
+ return InternalAlloc(size, cache);
+ if (size + sizeof(u64) < size)
+ return nullptr;
+ addr = (char*)addr - sizeof(u64);
+ size = size + sizeof(u64);
+ CHECK_EQ(kBlockMagic, ((u64*)addr)[0]);
+ void *p = RawInternalRealloc(addr, size, cache);
+ if (!p)
+ return nullptr;
+ return (char*)p + sizeof(u64);
+}
+
+void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
+ if (CallocShouldReturnNullDueToOverflow(count, size))
+ return internal_allocator()->ReturnNullOrDieOnBadRequest();
+ void *p = InternalAlloc(count * size, cache);
+ if (p) internal_memset(p, 0, count * size);
+ return p;
+}
+
void InternalFree(void *addr, InternalAllocatorCache *cache) {
if (!addr)
return;
@@ -138,7 +206,12 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
return (max / size) < n;
}
-void NORETURN ReportAllocatorCannotReturnNull() {
+static atomic_uint8_t reporting_out_of_memory = {0};
+
+bool IsReportingOOM() { return atomic_load_relaxed(&reporting_out_of_memory); }
+
+void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) {
+ if (out_of_memory) atomic_store_relaxed(&reporting_out_of_memory, 1);
Report("%s's allocator is terminating the process instead of returning 0\n",
SanitizerToolName);
Report("If you don't like this behavior set allocator_may_return_null=1\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h
index d98528c722c..ba50acddbbf 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h
@@ -18,271 +18,16 @@
#include "sanitizer_list.h"
#include "sanitizer_mutex.h"
#include "sanitizer_lfstack.h"
+#include "sanitizer_procmaps.h"
namespace __sanitizer {
-// Prints error message and kills the program.
-void NORETURN ReportAllocatorCannotReturnNull();
-
-// SizeClassMap maps allocation sizes into size classes and back.
-// Class 0 corresponds to size 0.
-// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
-// Next 4 classes: 256 + i * 64 (i = 1 to 4).
-// Next 4 classes: 512 + i * 128 (i = 1 to 4).
-// ...
-// Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4).
-// Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
-//
-// This structure of the size class map gives us:
-// - Efficient table-free class-to-size and size-to-class functions.
-// - Difference between two consequent size classes is betweed 14% and 25%
-//
-// This class also gives a hint to a thread-caching allocator about the amount
-// of chunks that need to be cached per-thread:
-// - kMaxNumCached is the maximal number of chunks per size class.
-// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
-//
-// Part of output of SizeClassMap::Print():
-// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
-// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
-// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
-// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
-// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
-// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
-// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
-// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
-//
-// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
-// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
-// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
-// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
-// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
-// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
-// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
-// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
-//
-// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
-// c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17
-// c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18
-// c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19
-//
-// c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20
-// c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21
-// c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22
-// c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23
-//
-// c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24
-// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25
-// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26
-// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27
-//
-// ...
-//
-// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48
-// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49
-// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50
-// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51
-//
-// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
-
-template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog>
-class SizeClassMap {
- static const uptr kMinSizeLog = 4;
- static const uptr kMidSizeLog = kMinSizeLog + 4;
- static const uptr kMinSize = 1 << kMinSizeLog;
- static const uptr kMidSize = 1 << kMidSizeLog;
- static const uptr kMidClass = kMidSize / kMinSize;
- static const uptr S = 2;
- static const uptr M = (1 << S) - 1;
-
- public:
- static const uptr kMaxNumCached = kMaxNumCachedT;
- // We transfer chunks between central and thread-local free lists in batches.
- // For small size classes we allocate batches separately.
- // For large size classes we use one of the chunks to store the batch.
- struct TransferBatch {
- TransferBatch *next;
- uptr count;
- void *batch[kMaxNumCached];
- };
-
- static const uptr kMaxSize = 1UL << kMaxSizeLog;
- static const uptr kNumClasses =
- kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
- COMPILER_CHECK(kNumClasses >= 32 && kNumClasses <= 256);
- static const uptr kNumClassesRounded =
- kNumClasses == 32 ? 32 :
- kNumClasses <= 64 ? 64 :
- kNumClasses <= 128 ? 128 : 256;
-
- static uptr Size(uptr class_id) {
- if (class_id <= kMidClass)
- return kMinSize * class_id;
- class_id -= kMidClass;
- uptr t = kMidSize << (class_id >> S);
- return t + (t >> S) * (class_id & M);
- }
-
- static uptr ClassID(uptr size) {
- if (size <= kMidSize)
- return (size + kMinSize - 1) >> kMinSizeLog;
- if (size > kMaxSize) return 0;
- uptr l = MostSignificantSetBitIndex(size);
- uptr hbits = (size >> (l - S)) & M;
- uptr lbits = size & ((1 << (l - S)) - 1);
- uptr l1 = l - kMidSizeLog;
- return kMidClass + (l1 << S) + hbits + (lbits > 0);
- }
-
- static uptr MaxCached(uptr class_id) {
- if (class_id == 0) return 0;
- uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
- return Max<uptr>(1, Min(kMaxNumCached, n));
- }
-
- static void Print() {
- uptr prev_s = 0;
- uptr total_cached = 0;
- for (uptr i = 0; i < kNumClasses; i++) {
- uptr s = Size(i);
- if (s >= kMidSize / 2 && (s & (s - 1)) == 0)
- Printf("\n");
- uptr d = s - prev_s;
- uptr p = prev_s ? (d * 100 / prev_s) : 0;
- uptr l = s ? MostSignificantSetBitIndex(s) : 0;
- uptr cached = MaxCached(i) * s;
- Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
- "cached: %zd %zd; id %zd\n",
- i, Size(i), d, p, l, MaxCached(i), cached, ClassID(s));
- total_cached += cached;
- prev_s = s;
- }
- Printf("Total cached: %zd\n", total_cached);
- }
-
- static bool SizeClassRequiresSeparateTransferBatch(uptr class_id) {
- return Size(class_id) < sizeof(TransferBatch) -
- sizeof(uptr) * (kMaxNumCached - MaxCached(class_id));
- }
-
- static void Validate() {
- for (uptr c = 1; c < kNumClasses; c++) {
- // Printf("Validate: c%zd\n", c);
- uptr s = Size(c);
- CHECK_NE(s, 0U);
- CHECK_EQ(ClassID(s), c);
- if (c != kNumClasses - 1)
- CHECK_EQ(ClassID(s + 1), c + 1);
- CHECK_EQ(ClassID(s - 1), c);
- if (c)
- CHECK_GT(Size(c), Size(c-1));
- }
- CHECK_EQ(ClassID(kMaxSize + 1), 0);
-
- for (uptr s = 1; s <= kMaxSize; s++) {
- uptr c = ClassID(s);
- // Printf("s%zd => c%zd\n", s, c);
- CHECK_LT(c, kNumClasses);
- CHECK_GE(Size(c), s);
- if (c > 0)
- CHECK_LT(Size(c-1), s);
- }
- }
-};
+// Returns true if ReportAllocatorCannotReturnNull(true) was called.
+// Can be use to avoid memory hungry operations.
+bool IsReportingOOM();
-typedef SizeClassMap<17, 128, 16> DefaultSizeClassMap;
-typedef SizeClassMap<17, 64, 14> CompactSizeClassMap;
-template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
-
-// Memory allocator statistics
-enum AllocatorStat {
- AllocatorStatAllocated,
- AllocatorStatMapped,
- AllocatorStatCount
-};
-
-typedef uptr AllocatorStatCounters[AllocatorStatCount];
-
-// Per-thread stats, live in per-thread cache.
-class AllocatorStats {
- public:
- void Init() {
- internal_memset(this, 0, sizeof(*this));
- }
- void InitLinkerInitialized() {}
-
- void Add(AllocatorStat i, uptr v) {
- v += atomic_load(&stats_[i], memory_order_relaxed);
- atomic_store(&stats_[i], v, memory_order_relaxed);
- }
-
- void Sub(AllocatorStat i, uptr v) {
- v = atomic_load(&stats_[i], memory_order_relaxed) - v;
- atomic_store(&stats_[i], v, memory_order_relaxed);
- }
-
- void Set(AllocatorStat i, uptr v) {
- atomic_store(&stats_[i], v, memory_order_relaxed);
- }
-
- uptr Get(AllocatorStat i) const {
- return atomic_load(&stats_[i], memory_order_relaxed);
- }
-
- private:
- friend class AllocatorGlobalStats;
- AllocatorStats *next_;
- AllocatorStats *prev_;
- atomic_uintptr_t stats_[AllocatorStatCount];
-};
-
-// Global stats, used for aggregation and querying.
-class AllocatorGlobalStats : public AllocatorStats {
- public:
- void InitLinkerInitialized() {
- next_ = this;
- prev_ = this;
- }
- void Init() {
- internal_memset(this, 0, sizeof(*this));
- InitLinkerInitialized();
- }
-
- void Register(AllocatorStats *s) {
- SpinMutexLock l(&mu_);
- s->next_ = next_;
- s->prev_ = this;
- next_->prev_ = s;
- next_ = s;
- }
-
- void Unregister(AllocatorStats *s) {
- SpinMutexLock l(&mu_);
- s->prev_->next_ = s->next_;
- s->next_->prev_ = s->prev_;
- for (int i = 0; i < AllocatorStatCount; i++)
- Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
- }
-
- void Get(AllocatorStatCounters s) const {
- internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
- SpinMutexLock l(&mu_);
- const AllocatorStats *stats = this;
- for (;;) {
- for (int i = 0; i < AllocatorStatCount; i++)
- s[i] += stats->Get(AllocatorStat(i));
- stats = stats->next_;
- if (stats == this)
- break;
- }
- // All stats must be non-negative.
- for (int i = 0; i < AllocatorStatCount; i++)
- s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
- }
-
- private:
- mutable SpinMutex mu_;
-};
+// Prints error message and kills the program.
+void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory);
// Allocators call these callbacks on mmap/munmap.
struct NoOpMapUnmapCallback {
@@ -293,1161 +38,18 @@ struct NoOpMapUnmapCallback {
// Callback type for iterating over chunks.
typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
-// SizeClassAllocator64 -- allocator for 64-bit address space.
-//
-// 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.
-// At the beginning the entire space is mprotect-ed, then small parts of it
-// are mapped on demand.
-//
-// 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 MapUnmapCallback = NoOpMapUnmapCallback>
-class SizeClassAllocator64 {
- public:
- typedef typename SizeClassMap::TransferBatch Batch;
- typedef SizeClassAllocator64<kSpaceBeg, kSpaceSize, kMetadataSize,
- SizeClassMap, MapUnmapCallback> ThisT;
- typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
-
- void Init() {
- CHECK_EQ(kSpaceBeg,
- reinterpret_cast<uptr>(MmapNoAccess(kSpaceBeg, kSpaceSize)));
- MapWithCallback(kSpaceEnd, AdditionalSize());
- }
-
- void MapWithCallback(uptr beg, uptr size) {
- CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
- MapUnmapCallback().OnMap(beg, size);
- }
-
- void UnmapWithCallback(uptr beg, uptr size) {
- MapUnmapCallback().OnUnmap(beg, size);
- UnmapOrDie(reinterpret_cast<void *>(beg), size);
- }
-
- static bool CanAllocate(uptr size, uptr alignment) {
- return size <= SizeClassMap::kMaxSize &&
- alignment <= SizeClassMap::kMaxSize;
- }
-
- NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
- uptr class_id) {
- CHECK_LT(class_id, kNumClasses);
- RegionInfo *region = GetRegionInfo(class_id);
- Batch *b = region->free_list.Pop();
- if (!b)
- b = PopulateFreeList(stat, c, class_id, region);
- region->n_allocated += b->count;
- return b;
- }
-
- NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
- RegionInfo *region = GetRegionInfo(class_id);
- CHECK_GT(b->count, 0);
- region->free_list.Push(b);
- region->n_freed += b->count;
- }
-
- static bool PointerIsMine(const void *p) {
- return reinterpret_cast<uptr>(p) / kSpaceSize == kSpaceBeg / kSpaceSize;
- }
-
- static uptr GetSizeClass(const void *p) {
- return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClassesRounded;
- }
-
- void *GetBlockBegin(const void *p) {
- uptr class_id = GetSizeClass(p);
- uptr size = SizeClassMap::Size(class_id);
- if (!size) return nullptr;
- uptr chunk_idx = GetChunkIdx((uptr)p, size);
- uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
- uptr beg = chunk_idx * size;
- uptr next_beg = beg + size;
- if (class_id >= kNumClasses) return nullptr;
- RegionInfo *region = GetRegionInfo(class_id);
- if (region->mapped_user >= next_beg)
- return reinterpret_cast<void*>(reg_beg + beg);
- return nullptr;
- }
-
- static uptr GetActuallyAllocatedSize(void *p) {
- CHECK(PointerIsMine(p));
- return SizeClassMap::Size(GetSizeClass(p));
- }
-
- uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
-
- void *GetMetaData(const 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() {
- UnmapWithCallback(kSpaceBeg, kSpaceSize + AdditionalSize());
- }
-
- void PrintStats() {
- uptr total_mapped = 0;
- uptr n_allocated = 0;
- uptr n_freed = 0;
- for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
- RegionInfo *region = GetRegionInfo(class_id);
- total_mapped += region->mapped_user;
- n_allocated += region->n_allocated;
- n_freed += region->n_freed;
- }
- Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
- "remains %zd\n",
- total_mapped >> 20, n_allocated, n_allocated - n_freed);
- for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
- RegionInfo *region = GetRegionInfo(class_id);
- if (region->mapped_user == 0) continue;
- Printf(" %02zd (%zd): total: %zd K allocs: %zd remains: %zd\n",
- class_id,
- SizeClassMap::Size(class_id),
- region->mapped_user >> 10,
- region->n_allocated,
- region->n_allocated - region->n_freed);
- }
- }
-
- // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
- // introspection API.
- void ForceLock() {
- for (uptr i = 0; i < kNumClasses; i++) {
- GetRegionInfo(i)->mutex.Lock();
- }
- }
-
- void ForceUnlock() {
- for (int i = (int)kNumClasses - 1; i >= 0; i--) {
- GetRegionInfo(i)->mutex.Unlock();
- }
- }
-
- // Iterate over all existing chunks.
- // The allocator must be locked when calling this function.
- void ForEachChunk(ForEachChunkCallback callback, void *arg) {
- for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
- RegionInfo *region = GetRegionInfo(class_id);
- uptr chunk_size = SizeClassMap::Size(class_id);
- uptr region_beg = kSpaceBeg + class_id * kRegionSize;
- for (uptr chunk = region_beg;
- chunk < region_beg + region->allocated_user;
- chunk += chunk_size) {
- // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
- callback(chunk, arg);
- }
- }
- }
-
- static uptr AdditionalSize() {
- return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
- GetPageSizeCached());
- }
-
- typedef SizeClassMap SizeClassMapT;
- static const uptr kNumClasses = SizeClassMap::kNumClasses;
- static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
-
- private:
- static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
- static const uptr kSpaceEnd = kSpaceBeg + kSpaceSize;
- COMPILER_CHECK(kSpaceBeg % kSpaceSize == 0);
- // kRegionSize must be >= 2^32.
- COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2)));
- // 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 << 14;
- // Call mmap for user memory with at least this size.
- static const uptr kUserMapSize = 1 << 16;
- // Call mmap for metadata memory with at least this size.
- static const uptr kMetaMapSize = 1 << 16;
-
- struct RegionInfo {
- BlockingMutex mutex;
- LFStack<Batch> free_list;
- uptr allocated_user; // Bytes allocated for user memory.
- uptr allocated_meta; // Bytes allocated for metadata.
- uptr mapped_user; // Bytes mapped for user memory.
- uptr mapped_meta; // Bytes mapped for metadata.
- uptr n_allocated, n_freed; // Just stats.
- };
- COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
-
- RegionInfo *GetRegionInfo(uptr class_id) {
- CHECK_LT(class_id, kNumClasses);
- RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
- return &regions[class_id];
- }
-
- static uptr GetChunkIdx(uptr chunk, uptr size) {
- uptr offset = chunk % kRegionSize;
- // Here we divide by a non-constant. This is costly.
- // size always fits into 32-bits. If the offset fits too, use 32-bit div.
- if (offset >> (SANITIZER_WORDSIZE / 2))
- return offset / size;
- return (u32)offset / (u32)size;
- }
-
- NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
- uptr class_id, RegionInfo *region) {
- BlockingMutexLock l(&region->mutex);
- Batch *b = region->free_list.Pop();
- if (b)
- return b;
- uptr size = SizeClassMap::Size(class_id);
- uptr count = size < kPopulateSize ? SizeClassMap::MaxCached(class_id) : 1;
- uptr beg_idx = region->allocated_user;
- uptr end_idx = beg_idx + count * size;
- uptr region_beg = kSpaceBeg + kRegionSize * class_id;
- if (end_idx + size > region->mapped_user) {
- // Do the mmap for the user memory.
- uptr map_size = kUserMapSize;
- while (end_idx + size > region->mapped_user + map_size)
- map_size += kUserMapSize;
- CHECK_GE(region->mapped_user + map_size, end_idx);
- MapWithCallback(region_beg + region->mapped_user, map_size);
- stat->Add(AllocatorStatMapped, map_size);
- region->mapped_user += map_size;
- }
- uptr total_count = (region->mapped_user - beg_idx - size)
- / size / count * count;
- region->allocated_meta += total_count * kMetadataSize;
- if (region->allocated_meta > region->mapped_meta) {
- uptr map_size = kMetaMapSize;
- while (region->allocated_meta > region->mapped_meta + map_size)
- map_size += kMetaMapSize;
- // Do the mmap for the metadata.
- CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
- MapWithCallback(region_beg + kRegionSize -
- region->mapped_meta - map_size, map_size);
- region->mapped_meta += map_size;
- }
- CHECK_LE(region->allocated_meta, region->mapped_meta);
- if (region->mapped_user + region->mapped_meta > kRegionSize) {
- Printf("%s: Out of memory. Dying. ", SanitizerToolName);
- Printf("The process has exhausted %zuMB for size class %zu.\n",
- kRegionSize / 1024 / 1024, size);
- Die();
- }
- for (;;) {
- if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
- b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
- else
- b = (Batch*)(region_beg + beg_idx);
- b->count = count;
- for (uptr i = 0; i < count; i++)
- b->batch[i] = (void*)(region_beg + beg_idx + i * size);
- region->allocated_user += count * size;
- CHECK_LE(region->allocated_user, region->mapped_user);
- beg_idx += count * size;
- if (beg_idx + count * size + size > region->mapped_user)
- break;
- CHECK_GT(b->count, 0);
- region->free_list.Push(b);
- }
- return b;
- }
-};
-
-// Maps integers in rage [0, kSize) to u8 values.
-template<u64 kSize>
-class FlatByteMap {
- public:
- void TestOnlyInit() {
- internal_memset(map_, 0, sizeof(map_));
- }
-
- void set(uptr idx, u8 val) {
- CHECK_LT(idx, kSize);
- CHECK_EQ(0U, map_[idx]);
- map_[idx] = val;
- }
- u8 operator[] (uptr idx) {
- CHECK_LT(idx, kSize);
- // FIXME: CHECK may be too expensive here.
- return map_[idx];
- }
- private:
- u8 map_[kSize];
-};
-
-// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
-// It is implemented as a two-dimensional array: array of kSize1 pointers
-// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
-// Each value is initially zero and can be set to something else only once.
-// Setting and getting values from multiple threads is safe w/o extra locking.
-template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
-class TwoLevelByteMap {
- public:
- void TestOnlyInit() {
- internal_memset(map1_, 0, sizeof(map1_));
- mu_.Init();
- }
-
- void TestOnlyUnmap() {
- for (uptr i = 0; i < kSize1; i++) {
- u8 *p = Get(i);
- if (!p) continue;
- MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
- UnmapOrDie(p, kSize2);
- }
- }
-
- uptr size() const { return kSize1 * kSize2; }
- uptr size1() const { return kSize1; }
- uptr size2() const { return kSize2; }
-
- void set(uptr idx, u8 val) {
- CHECK_LT(idx, kSize1 * kSize2);
- u8 *map2 = GetOrCreate(idx / kSize2);
- CHECK_EQ(0U, map2[idx % kSize2]);
- map2[idx % kSize2] = val;
- }
-
- u8 operator[] (uptr idx) const {
- CHECK_LT(idx, kSize1 * kSize2);
- u8 *map2 = Get(idx / kSize2);
- if (!map2) return 0;
- return map2[idx % kSize2];
- }
-
- private:
- u8 *Get(uptr idx) const {
- CHECK_LT(idx, kSize1);
- return reinterpret_cast<u8 *>(
- atomic_load(&map1_[idx], memory_order_acquire));
- }
-
- u8 *GetOrCreate(uptr idx) {
- u8 *res = Get(idx);
- if (!res) {
- SpinMutexLock l(&mu_);
- if (!(res = Get(idx))) {
- res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
- MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
- atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
- memory_order_release);
- }
- }
- return res;
- }
-
- atomic_uintptr_t map1_[kSize1];
- StaticSpinMutex mu_;
-};
-
-// SizeClassAllocator32 -- allocator for 32-bit address space.
-// This allocator can theoretically be used on 64-bit arch, but there it is less
-// efficient than SizeClassAllocator64.
-//
-// [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can
-// be returned by MmapOrDie().
-//
-// Region:
-// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
-// Since the regions are aligned by kRegionSize, there are exactly
-// kNumPossibleRegions possible regions in the address space and so we keep
-// a ByteMap possible_regions to store the size classes of each Region.
-// 0 size class means the region is not used by the allocator.
-//
-// One Region is used to allocate chunks of a single size class.
-// A Region looks like this:
-// UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1
-//
-// In order to avoid false sharing the objects of this class should be
-// chache-line aligned.
-template <const uptr kSpaceBeg, const u64 kSpaceSize,
- const uptr kMetadataSize, class SizeClassMap,
- const uptr kRegionSizeLog,
- class ByteMap,
- class MapUnmapCallback = NoOpMapUnmapCallback>
-class SizeClassAllocator32 {
- public:
- typedef typename SizeClassMap::TransferBatch Batch;
- typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
- SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
- typedef SizeClassAllocatorLocalCache<ThisT> AllocatorCache;
-
- void Init() {
- possible_regions.TestOnlyInit();
- internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
- }
-
- void *MapWithCallback(uptr size) {
- size = RoundUpTo(size, GetPageSizeCached());
- void *res = MmapOrDie(size, "SizeClassAllocator32");
- MapUnmapCallback().OnMap((uptr)res, size);
- return res;
- }
-
- void UnmapWithCallback(uptr beg, uptr size) {
- MapUnmapCallback().OnUnmap(beg, size);
- UnmapOrDie(reinterpret_cast<void *>(beg), size);
- }
-
- static bool CanAllocate(uptr size, uptr alignment) {
- return size <= SizeClassMap::kMaxSize &&
- alignment <= SizeClassMap::kMaxSize;
- }
-
- void *GetMetaData(const void *p) {
- CHECK(PointerIsMine(p));
- uptr mem = reinterpret_cast<uptr>(p);
- uptr beg = ComputeRegionBeg(mem);
- uptr size = SizeClassMap::Size(GetSizeClass(p));
- u32 offset = mem - beg;
- uptr n = offset / (u32)size; // 32-bit division
- uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize;
- return reinterpret_cast<void*>(meta);
- }
-
- NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
- uptr class_id) {
- CHECK_LT(class_id, kNumClasses);
- SizeClassInfo *sci = GetSizeClassInfo(class_id);
- SpinMutexLock l(&sci->mutex);
- if (sci->free_list.empty())
- PopulateFreeList(stat, c, sci, class_id);
- CHECK(!sci->free_list.empty());
- Batch *b = sci->free_list.front();
- sci->free_list.pop_front();
- return b;
- }
-
- NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
- CHECK_LT(class_id, kNumClasses);
- SizeClassInfo *sci = GetSizeClassInfo(class_id);
- SpinMutexLock l(&sci->mutex);
- CHECK_GT(b->count, 0);
- sci->free_list.push_front(b);
- }
-
- bool PointerIsMine(const void *p) {
- return GetSizeClass(p) != 0;
- }
-
- uptr GetSizeClass(const void *p) {
- return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
- }
-
- void *GetBlockBegin(const void *p) {
- CHECK(PointerIsMine(p));
- uptr mem = reinterpret_cast<uptr>(p);
- uptr beg = ComputeRegionBeg(mem);
- uptr size = SizeClassMap::Size(GetSizeClass(p));
- u32 offset = mem - beg;
- u32 n = offset / (u32)size; // 32-bit division
- uptr res = beg + (n * (u32)size);
- return reinterpret_cast<void*>(res);
- }
-
- uptr GetActuallyAllocatedSize(void *p) {
- CHECK(PointerIsMine(p));
- return SizeClassMap::Size(GetSizeClass(p));
- }
-
- uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
-
- uptr TotalMemoryUsed() {
- // No need to lock here.
- uptr res = 0;
- for (uptr i = 0; i < kNumPossibleRegions; i++)
- if (possible_regions[i])
- res += kRegionSize;
- return res;
- }
-
- void TestOnlyUnmap() {
- for (uptr i = 0; i < kNumPossibleRegions; i++)
- if (possible_regions[i])
- UnmapWithCallback((i * kRegionSize), kRegionSize);
- }
-
- // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
- // introspection API.
- void ForceLock() {
- for (uptr i = 0; i < kNumClasses; i++) {
- GetSizeClassInfo(i)->mutex.Lock();
- }
- }
-
- void ForceUnlock() {
- for (int i = kNumClasses - 1; i >= 0; i--) {
- GetSizeClassInfo(i)->mutex.Unlock();
- }
- }
-
- // Iterate over all existing chunks.
- // The allocator must be locked when calling this function.
- void ForEachChunk(ForEachChunkCallback callback, void *arg) {
- for (uptr region = 0; region < kNumPossibleRegions; region++)
- if (possible_regions[region]) {
- uptr chunk_size = SizeClassMap::Size(possible_regions[region]);
- uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
- uptr region_beg = region * kRegionSize;
- for (uptr chunk = region_beg;
- chunk < region_beg + max_chunks_in_region * chunk_size;
- chunk += chunk_size) {
- // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
- callback(chunk, arg);
- }
- }
- }
-
- void PrintStats() {
- }
-
- static uptr AdditionalSize() {
- return 0;
- }
-
- typedef SizeClassMap SizeClassMapT;
- static const uptr kNumClasses = SizeClassMap::kNumClasses;
-
- private:
- static const uptr kRegionSize = 1 << kRegionSizeLog;
- static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
-
- struct SizeClassInfo {
- SpinMutex mutex;
- IntrusiveList<Batch> free_list;
- char padding[kCacheLineSize - sizeof(uptr) - sizeof(IntrusiveList<Batch>)];
- };
- COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize);
-
- uptr ComputeRegionId(uptr mem) {
- uptr res = mem >> kRegionSizeLog;
- CHECK_LT(res, kNumPossibleRegions);
- return res;
- }
-
- uptr ComputeRegionBeg(uptr mem) {
- return mem & ~(kRegionSize - 1);
- }
-
- uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
- CHECK_LT(class_id, kNumClasses);
- uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
- "SizeClassAllocator32"));
- MapUnmapCallback().OnMap(res, kRegionSize);
- stat->Add(AllocatorStatMapped, kRegionSize);
- CHECK_EQ(0U, (res & (kRegionSize - 1)));
- possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
- return res;
- }
-
- SizeClassInfo *GetSizeClassInfo(uptr class_id) {
- CHECK_LT(class_id, kNumClasses);
- return &size_class_info_array[class_id];
- }
-
- void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
- SizeClassInfo *sci, uptr class_id) {
- uptr size = SizeClassMap::Size(class_id);
- uptr reg = AllocateRegion(stat, class_id);
- uptr n_chunks = kRegionSize / (size + kMetadataSize);
- uptr max_count = SizeClassMap::MaxCached(class_id);
- Batch *b = nullptr;
- for (uptr i = reg; i < reg + n_chunks * size; i += size) {
- if (!b) {
- if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
- b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch)));
- else
- b = (Batch*)i;
- b->count = 0;
- }
- b->batch[b->count++] = (void*)i;
- if (b->count == max_count) {
- CHECK_GT(b->count, 0);
- sci->free_list.push_back(b);
- b = nullptr;
- }
- }
- if (b) {
- CHECK_GT(b->count, 0);
- sci->free_list.push_back(b);
- }
- }
-
- ByteMap possible_regions;
- SizeClassInfo size_class_info_array[kNumClasses];
-};
-
-// Objects of this type should be used as local caches for SizeClassAllocator64
-// or SizeClassAllocator32. Since the typical use of this class is to have one
-// object per thread in TLS, is has to be POD.
-template<class SizeClassAllocator>
-struct SizeClassAllocatorLocalCache {
- typedef SizeClassAllocator Allocator;
- static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
-
- void Init(AllocatorGlobalStats *s) {
- stats_.Init();
- if (s)
- s->Register(&stats_);
- }
-
- void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
- Drain(allocator);
- if (s)
- s->Unregister(&stats_);
- }
-
- void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
- CHECK_NE(class_id, 0UL);
- CHECK_LT(class_id, kNumClasses);
- stats_.Add(AllocatorStatAllocated, SizeClassMap::Size(class_id));
- PerClass *c = &per_class_[class_id];
- if (UNLIKELY(c->count == 0))
- Refill(allocator, class_id);
- void *res = c->batch[--c->count];
- PREFETCH(c->batch[c->count - 1]);
- return res;
- }
-
- void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
- CHECK_NE(class_id, 0UL);
- CHECK_LT(class_id, kNumClasses);
- // If the first allocator call on a new thread is a deallocation, then
- // max_count will be zero, leading to check failure.
- InitCache();
- stats_.Sub(AllocatorStatAllocated, SizeClassMap::Size(class_id));
- PerClass *c = &per_class_[class_id];
- CHECK_NE(c->max_count, 0UL);
- if (UNLIKELY(c->count == c->max_count))
- Drain(allocator, class_id);
- c->batch[c->count++] = p;
- }
-
- void Drain(SizeClassAllocator *allocator) {
- for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
- PerClass *c = &per_class_[class_id];
- while (c->count > 0)
- Drain(allocator, class_id);
- }
- }
-
- // private:
- typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
- typedef typename SizeClassMap::TransferBatch Batch;
- struct PerClass {
- uptr count;
- uptr max_count;
- void *batch[2 * SizeClassMap::kMaxNumCached];
- };
- PerClass per_class_[kNumClasses];
- AllocatorStats stats_;
-
- void InitCache() {
- if (per_class_[1].max_count)
- return;
- for (uptr i = 0; i < kNumClasses; i++) {
- PerClass *c = &per_class_[i];
- c->max_count = 2 * SizeClassMap::MaxCached(i);
- }
- }
-
- NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
- InitCache();
- PerClass *c = &per_class_[class_id];
- Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
- CHECK_GT(b->count, 0);
- for (uptr i = 0; i < b->count; i++)
- c->batch[i] = b->batch[i];
- c->count = b->count;
- if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
- Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
- }
-
- NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
- InitCache();
- PerClass *c = &per_class_[class_id];
- Batch *b;
- if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id))
- b = (Batch*)Allocate(allocator, SizeClassMap::ClassID(sizeof(Batch)));
- else
- b = (Batch*)c->batch[0];
- uptr cnt = Min(c->max_count / 2, c->count);
- for (uptr i = 0; i < cnt; i++) {
- b->batch[i] = c->batch[i];
- c->batch[i] = c->batch[i + c->max_count / 2];
- }
- b->count = cnt;
- c->count -= cnt;
- CHECK_GT(b->count, 0);
- allocator->DeallocateBatch(&stats_, class_id, b);
- }
-};
-
-// 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).
-template <class MapUnmapCallback = NoOpMapUnmapCallback>
-class LargeMmapAllocator {
- public:
- void InitLinkerInitialized(bool may_return_null) {
- page_size_ = GetPageSizeCached();
- atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
- }
-
- void Init(bool may_return_null) {
- internal_memset(this, 0, sizeof(*this));
- InitLinkerInitialized(may_return_null);
- }
-
- void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
- CHECK(IsPowerOfTwo(alignment));
- uptr map_size = RoundUpMapSize(size);
- if (alignment > page_size_)
- map_size += alignment;
- // Overflow.
- if (map_size < size)
- return ReturnNullOrDie();
- uptr map_beg = reinterpret_cast<uptr>(
- MmapOrDie(map_size, "LargeMmapAllocator"));
- CHECK(IsAligned(map_beg, page_size_));
- MapUnmapCallback().OnMap(map_beg, map_size);
- uptr map_end = map_beg + map_size;
- uptr res = map_beg + page_size_;
- if (res & (alignment - 1)) // Align.
- res += alignment - (res & (alignment - 1));
- CHECK(IsAligned(res, alignment));
- CHECK(IsAligned(res, page_size_));
- CHECK_GE(res + size, map_beg);
- CHECK_LE(res + size, map_end);
- Header *h = GetHeader(res);
- h->size = size;
- h->map_beg = map_beg;
- h->map_size = map_size;
- uptr size_log = MostSignificantSetBitIndex(map_size);
- CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
- {
- SpinMutexLock l(&mutex_);
- uptr idx = n_chunks_++;
- chunks_sorted_ = false;
- CHECK_LT(idx, kMaxNumChunks);
- h->chunk_idx = idx;
- chunks_[idx] = h;
- stats.n_allocs++;
- stats.currently_allocated += map_size;
- stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
- stats.by_size_log[size_log]++;
- stat->Add(AllocatorStatAllocated, map_size);
- stat->Add(AllocatorStatMapped, map_size);
- }
- return reinterpret_cast<void*>(res);
- }
-
- void *ReturnNullOrDie() {
- if (atomic_load(&may_return_null_, memory_order_acquire))
- return nullptr;
- ReportAllocatorCannotReturnNull();
- }
-
- void SetMayReturnNull(bool may_return_null) {
- atomic_store(&may_return_null_, may_return_null, memory_order_release);
- }
-
- void Deallocate(AllocatorStats *stat, void *p) {
- Header *h = GetHeader(p);
- {
- SpinMutexLock l(&mutex_);
- uptr idx = h->chunk_idx;
- CHECK_EQ(chunks_[idx], h);
- CHECK_LT(idx, n_chunks_);
- chunks_[idx] = chunks_[n_chunks_ - 1];
- chunks_[idx]->chunk_idx = idx;
- n_chunks_--;
- chunks_sorted_ = false;
- stats.n_frees++;
- stats.currently_allocated -= h->map_size;
- stat->Sub(AllocatorStatAllocated, h->map_size);
- stat->Sub(AllocatorStatMapped, h->map_size);
- }
- MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
- UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
- }
-
- uptr TotalMemoryUsed() {
- SpinMutexLock l(&mutex_);
- uptr res = 0;
- for (uptr i = 0; i < n_chunks_; i++) {
- Header *h = chunks_[i];
- CHECK_EQ(h->chunk_idx, i);
- res += RoundUpMapSize(h->size);
- }
- return res;
- }
-
- bool PointerIsMine(const void *p) {
- return GetBlockBegin(p) != nullptr;
- }
-
- uptr GetActuallyAllocatedSize(void *p) {
- return RoundUpTo(GetHeader(p)->size, page_size_);
- }
-
- // At least page_size_/2 metadata bytes is available.
- void *GetMetaData(const void *p) {
- // Too slow: CHECK_EQ(p, GetBlockBegin(p));
- if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) {
- Printf("%s: bad pointer %p\n", SanitizerToolName, p);
- CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
- }
- return GetHeader(p) + 1;
- }
-
- void *GetBlockBegin(const void *ptr) {
- uptr p = reinterpret_cast<uptr>(ptr);
- SpinMutexLock l(&mutex_);
- uptr nearest_chunk = 0;
- // Cache-friendly linear search.
- for (uptr i = 0; i < n_chunks_; i++) {
- uptr ch = reinterpret_cast<uptr>(chunks_[i]);
- if (p < ch) continue; // p is at left to this chunk, skip it.
- if (p - ch < p - nearest_chunk)
- nearest_chunk = ch;
- }
- if (!nearest_chunk)
- return nullptr;
- Header *h = reinterpret_cast<Header *>(nearest_chunk);
- CHECK_GE(nearest_chunk, h->map_beg);
- CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
- CHECK_LE(nearest_chunk, p);
- if (h->map_beg + h->map_size <= p)
- return nullptr;
- return GetUser(h);
- }
-
- // This function does the same as GetBlockBegin, but is much faster.
- // Must be called with the allocator locked.
- void *GetBlockBeginFastLocked(void *ptr) {
- mutex_.CheckLocked();
- uptr p = reinterpret_cast<uptr>(ptr);
- uptr n = n_chunks_;
- if (!n) return nullptr;
- if (!chunks_sorted_) {
- // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
- SortArray(reinterpret_cast<uptr*>(chunks_), n);
- for (uptr i = 0; i < n; i++)
- chunks_[i]->chunk_idx = i;
- chunks_sorted_ = true;
- min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
- max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
- chunks_[n - 1]->map_size;
- }
- if (p < min_mmap_ || p >= max_mmap_)
- return nullptr;
- uptr beg = 0, end = n - 1;
- // This loop is a log(n) lower_bound. It does not check for the exact match
- // to avoid expensive cache-thrashing loads.
- while (end - beg >= 2) {
- uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1
- if (p < reinterpret_cast<uptr>(chunks_[mid]))
- end = mid - 1; // We are not interested in chunks_[mid].
- else
- beg = mid; // chunks_[mid] may still be what we want.
- }
-
- if (beg < end) {
- CHECK_EQ(beg + 1, end);
- // There are 2 chunks left, choose one.
- if (p >= reinterpret_cast<uptr>(chunks_[end]))
- beg = end;
- }
-
- Header *h = chunks_[beg];
- if (h->map_beg + h->map_size <= p || p < h->map_beg)
- return nullptr;
- return GetUser(h);
- }
-
- void PrintStats() {
- Printf("Stats: LargeMmapAllocator: allocated %zd times, "
- "remains %zd (%zd K) max %zd M; by size logs: ",
- stats.n_allocs, stats.n_allocs - stats.n_frees,
- stats.currently_allocated >> 10, stats.max_allocated >> 20);
- for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) {
- uptr c = stats.by_size_log[i];
- if (!c) continue;
- Printf("%zd:%zd; ", i, c);
- }
- Printf("\n");
- }
-
- // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
- // introspection API.
- void ForceLock() {
- mutex_.Lock();
- }
-
- void ForceUnlock() {
- mutex_.Unlock();
- }
-
- // Iterate over all existing chunks.
- // The allocator must be locked when calling this function.
- void ForEachChunk(ForEachChunkCallback callback, void *arg) {
- for (uptr i = 0; i < n_chunks_; i++)
- callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
- }
-
- private:
- static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
- struct Header {
- uptr map_beg;
- uptr map_size;
- uptr size;
- uptr chunk_idx;
- };
-
- Header *GetHeader(uptr p) {
- CHECK(IsAligned(p, page_size_));
- return reinterpret_cast<Header*>(p - page_size_);
- }
- Header *GetHeader(const void *p) {
- return GetHeader(reinterpret_cast<uptr>(p));
- }
-
- void *GetUser(Header *h) {
- CHECK(IsAligned((uptr)h, page_size_));
- return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
- }
-
- uptr RoundUpMapSize(uptr size) {
- return RoundUpTo(size, page_size_) + page_size_;
- }
-
- uptr page_size_;
- Header *chunks_[kMaxNumChunks];
- uptr n_chunks_;
- uptr min_mmap_, max_mmap_;
- bool chunks_sorted_;
- struct Stats {
- uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
- } stats;
- atomic_uint8_t may_return_null_;
- 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 InitCommon(bool may_return_null) {
- primary_.Init();
- atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
- }
-
- void InitLinkerInitialized(bool may_return_null) {
- secondary_.InitLinkerInitialized(may_return_null);
- stats_.InitLinkerInitialized();
- InitCommon(may_return_null);
- }
-
- void Init(bool may_return_null) {
- secondary_.Init(may_return_null);
- stats_.Init();
- InitCommon(may_return_null);
- }
-
- void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
- bool cleared = false, bool check_rss_limit = false) {
- // Returning 0 on malloc(0) may break a lot of code.
- if (size == 0)
- size = 1;
- if (size + alignment < size)
- return ReturnNullOrDie();
- if (check_rss_limit && RssLimitIsExceeded())
- return ReturnNullOrDie();
- if (alignment > 8)
- size = RoundUpTo(size, alignment);
- void *res;
- bool from_primary = primary_.CanAllocate(size, alignment);
- if (from_primary)
- res = cache->Allocate(&primary_, primary_.ClassID(size));
- else
- res = secondary_.Allocate(&stats_, size, alignment);
- if (alignment > 8)
- CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
- if (cleared && res && from_primary)
- internal_bzero_aligned16(res, RoundUpTo(size, 16));
- return res;
- }
-
- bool MayReturnNull() const {
- return atomic_load(&may_return_null_, memory_order_acquire);
- }
-
- void *ReturnNullOrDie() {
- if (MayReturnNull())
- return nullptr;
- ReportAllocatorCannotReturnNull();
- }
-
- void SetMayReturnNull(bool may_return_null) {
- secondary_.SetMayReturnNull(may_return_null);
- atomic_store(&may_return_null_, may_return_null, memory_order_release);
- }
-
- bool RssLimitIsExceeded() {
- return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire);
- }
-
- void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) {
- atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded,
- memory_order_release);
- }
-
- void Deallocate(AllocatorCache *cache, void *p) {
- if (!p) return;
- if (primary_.PointerIsMine(p))
- cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
- else
- secondary_.Deallocate(&stats_, 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 nullptr;
- }
- 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);
- }
-
- bool FromPrimary(void *p) {
- return primary_.PointerIsMine(p);
- }
-
- void *GetMetaData(const void *p) {
- if (primary_.PointerIsMine(p))
- return primary_.GetMetaData(p);
- return secondary_.GetMetaData(p);
- }
-
- void *GetBlockBegin(const void *p) {
- if (primary_.PointerIsMine(p))
- return primary_.GetBlockBegin(p);
- return secondary_.GetBlockBegin(p);
- }
-
- // This function does the same as GetBlockBegin, but is much faster.
- // Must be called with the allocator locked.
- void *GetBlockBeginFastLocked(void *p) {
- if (primary_.PointerIsMine(p))
- return primary_.GetBlockBegin(p);
- return secondary_.GetBlockBeginFastLocked(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 InitCache(AllocatorCache *cache) {
- cache->Init(&stats_);
- }
-
- void DestroyCache(AllocatorCache *cache) {
- cache->Destroy(&primary_, &stats_);
- }
-
- void SwallowCache(AllocatorCache *cache) {
- cache->Drain(&primary_);
- }
-
- void GetStats(AllocatorStatCounters s) const {
- stats_.Get(s);
- }
-
- void PrintStats() {
- primary_.PrintStats();
- secondary_.PrintStats();
- }
-
- // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
- // introspection API.
- void ForceLock() {
- primary_.ForceLock();
- secondary_.ForceLock();
- }
-
- void ForceUnlock() {
- secondary_.ForceUnlock();
- primary_.ForceUnlock();
- }
-
- // Iterate over all existing chunks.
- // The allocator must be locked when calling this function.
- void ForEachChunk(ForEachChunkCallback callback, void *arg) {
- primary_.ForEachChunk(callback, arg);
- secondary_.ForEachChunk(callback, arg);
- }
-
- private:
- PrimaryAllocator primary_;
- SecondaryAllocator secondary_;
- AllocatorGlobalStats stats_;
- atomic_uint8_t may_return_null_;
- atomic_uint8_t rss_limit_is_exceeded_;
-};
-
// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+#include "sanitizer_allocator_size_class_map.h"
+#include "sanitizer_allocator_stats.h"
+#include "sanitizer_allocator_primary64.h"
+#include "sanitizer_allocator_bytemap.h"
+#include "sanitizer_allocator_primary32.h"
+#include "sanitizer_allocator_local_cache.h"
+#include "sanitizer_allocator_secondary.h"
+#include "sanitizer_allocator_combined.h"
+
} // namespace __sanitizer
#endif // SANITIZER_ALLOCATOR_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_bytemap.h b/libsanitizer/sanitizer_common/sanitizer_allocator_bytemap.h
new file mode 100644
index 00000000000..5e768ce9ef9
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_bytemap.h
@@ -0,0 +1,100 @@
+//===-- sanitizer_allocator_bytemap.h ---------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// Maps integers in rage [0, kSize) to u8 values.
+template<u64 kSize>
+class FlatByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map_, 0, sizeof(map_));
+ }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize);
+ CHECK_EQ(0U, map_[idx]);
+ map_[idx] = val;
+ }
+ u8 operator[] (uptr idx) {
+ CHECK_LT(idx, kSize);
+ // FIXME: CHECK may be too expensive here.
+ return map_[idx];
+ }
+ private:
+ u8 map_[kSize];
+};
+
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map1_, 0, sizeof(map1_));
+ mu_.Init();
+ }
+
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kSize1; i++) {
+ u8 *p = Get(i);
+ if (!p) continue;
+ MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+ UnmapOrDie(p, kSize2);
+ }
+ }
+
+ uptr size() const { return kSize1 * kSize2; }
+ uptr size1() const { return kSize1; }
+ uptr size2() const { return kSize2; }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = GetOrCreate(idx / kSize2);
+ CHECK_EQ(0U, map2[idx % kSize2]);
+ map2[idx % kSize2] = val;
+ }
+
+ u8 operator[] (uptr idx) const {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = Get(idx / kSize2);
+ if (!map2) return 0;
+ return map2[idx % kSize2];
+ }
+
+ private:
+ u8 *Get(uptr idx) const {
+ CHECK_LT(idx, kSize1);
+ return reinterpret_cast<u8 *>(
+ atomic_load(&map1_[idx], memory_order_acquire));
+ }
+
+ u8 *GetOrCreate(uptr idx) {
+ u8 *res = Get(idx);
+ if (!res) {
+ SpinMutexLock l(&mu_);
+ if (!(res = Get(idx))) {
+ res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+ MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+ atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+ memory_order_release);
+ }
+ }
+ return res;
+ }
+
+ atomic_uintptr_t map1_[kSize1];
+ StaticSpinMutex mu_;
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
new file mode 100644
index 00000000000..4dc9ca7401f
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
@@ -0,0 +1,209 @@
+//===-- sanitizer_allocator_combined.h --------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// 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 InitCommon(bool may_return_null) {
+ primary_.Init();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void InitLinkerInitialized(bool may_return_null) {
+ secondary_.InitLinkerInitialized(may_return_null);
+ stats_.InitLinkerInitialized();
+ InitCommon(may_return_null);
+ }
+
+ void Init(bool may_return_null) {
+ secondary_.Init(may_return_null);
+ stats_.Init();
+ InitCommon(may_return_null);
+ }
+
+ void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
+ bool cleared = false, bool check_rss_limit = false) {
+ // Returning 0 on malloc(0) may break a lot of code.
+ if (size == 0)
+ size = 1;
+ if (size + alignment < size) return ReturnNullOrDieOnBadRequest();
+ if (check_rss_limit && RssLimitIsExceeded()) return ReturnNullOrDieOnOOM();
+ if (alignment > 8)
+ size = RoundUpTo(size, alignment);
+ void *res;
+ bool from_primary = primary_.CanAllocate(size, alignment);
+ if (from_primary)
+ res = cache->Allocate(&primary_, primary_.ClassID(size));
+ else
+ res = secondary_.Allocate(&stats_, size, alignment);
+ if (alignment > 8)
+ CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
+ if (cleared && res && from_primary)
+ internal_bzero_aligned16(res, RoundUpTo(size, 16));
+ return res;
+ }
+
+ bool MayReturnNull() const {
+ return atomic_load(&may_return_null_, memory_order_acquire);
+ }
+
+ void *ReturnNullOrDieOnBadRequest() {
+ if (MayReturnNull())
+ return nullptr;
+ ReportAllocatorCannotReturnNull(false);
+ }
+
+ void *ReturnNullOrDieOnOOM() {
+ if (MayReturnNull()) return nullptr;
+ ReportAllocatorCannotReturnNull(true);
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ secondary_.SetMayReturnNull(may_return_null);
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ bool RssLimitIsExceeded() {
+ return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire);
+ }
+
+ void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) {
+ atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded,
+ memory_order_release);
+ }
+
+ void Deallocate(AllocatorCache *cache, void *p) {
+ if (!p) return;
+ if (primary_.PointerIsMine(p))
+ cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
+ else
+ secondary_.Deallocate(&stats_, 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 nullptr;
+ }
+ 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);
+ }
+
+ bool FromPrimary(void *p) {
+ return primary_.PointerIsMine(p);
+ }
+
+ void *GetMetaData(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetMetaData(p);
+ return secondary_.GetMetaData(p);
+ }
+
+ void *GetBlockBegin(const void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBegin(p);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *p) {
+ if (primary_.PointerIsMine(p))
+ return primary_.GetBlockBegin(p);
+ return secondary_.GetBlockBeginFastLocked(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 InitCache(AllocatorCache *cache) {
+ cache->Init(&stats_);
+ }
+
+ void DestroyCache(AllocatorCache *cache) {
+ cache->Destroy(&primary_, &stats_);
+ }
+
+ void SwallowCache(AllocatorCache *cache) {
+ cache->Drain(&primary_);
+ }
+
+ void GetStats(AllocatorStatCounters s) const {
+ stats_.Get(s);
+ }
+
+ void PrintStats() {
+ primary_.PrintStats();
+ secondary_.PrintStats();
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ primary_.ForceLock();
+ secondary_.ForceLock();
+ }
+
+ void ForceUnlock() {
+ secondary_.ForceUnlock();
+ primary_.ForceUnlock();
+ }
+
+ void ReleaseToOS() { primary_.ReleaseToOS(); }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ primary_.ForEachChunk(callback, arg);
+ secondary_.ForEachChunk(callback, arg);
+ }
+
+ private:
+ PrimaryAllocator primary_;
+ SecondaryAllocator secondary_;
+ AllocatorGlobalStats stats_;
+ atomic_uint8_t may_return_null_;
+ atomic_uint8_t rss_limit_is_exceeded_;
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
index fd5bed30c4b..166f8c22049 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
@@ -27,10 +27,18 @@ SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes();
SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes();
+SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks(
+ void (*malloc_hook)(const void *, uptr),
+ void (*free_hook)(const void *));
+
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
/* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
+
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_print_memory_profile(int top_percent);
} // extern "C"
#endif // SANITIZER_ALLOCATOR_INTERFACE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
index 99d8516d8cf..6a8da8f3584 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
@@ -43,7 +43,12 @@ typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
LargeMmapAllocator<> > InternalAllocator;
-void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr);
+void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr,
+ uptr alignment = 0);
+void *InternalRealloc(void *p, uptr size,
+ InternalAllocatorCache *cache = nullptr);
+void *InternalCalloc(uptr countr, uptr size,
+ InternalAllocatorCache *cache = nullptr);
void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
InternalAllocator *internal_allocator();
@@ -54,8 +59,8 @@ enum InternalAllocEnum {
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
- InternalAllocEnum) {
- return InternalAlloc(size);
+ __sanitizer::InternalAllocEnum) {
+ return __sanitizer::InternalAlloc(size);
}
#endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h
new file mode 100644
index 00000000000..40ef0781adb
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h
@@ -0,0 +1,246 @@
+//===-- sanitizer_allocator_local_cache.h -----------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// Objects of this type should be used as local caches for SizeClassAllocator64
+// or SizeClassAllocator32. Since the typical use of this class is to have one
+// object per thread in TLS, is has to be POD.
+template<class SizeClassAllocator>
+struct SizeClassAllocatorLocalCache
+ : SizeClassAllocator::AllocatorCache {
+};
+
+// Cache used by SizeClassAllocator64.
+template <class SizeClassAllocator>
+struct SizeClassAllocator64LocalCache {
+ typedef SizeClassAllocator Allocator;
+ static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
+ typedef typename Allocator::SizeClassMapT SizeClassMap;
+ typedef typename Allocator::CompactPtrT CompactPtrT;
+
+ void Init(AllocatorGlobalStats *s) {
+ stats_.Init();
+ if (s)
+ s->Register(&stats_);
+ }
+
+ void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+ Drain(allocator);
+ if (s)
+ s->Unregister(&stats_);
+ }
+
+ void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
+ PerClass *c = &per_class_[class_id];
+ if (UNLIKELY(c->count == 0))
+ Refill(c, allocator, class_id);
+ CHECK_GT(c->count, 0);
+ CompactPtrT chunk = c->chunks[--c->count];
+ void *res = reinterpret_cast<void *>(allocator->CompactPtrToPointer(
+ allocator->GetRegionBeginBySizeClass(class_id), chunk));
+ return res;
+ }
+
+ void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ // If the first allocator call on a new thread is a deallocation, then
+ // max_count will be zero, leading to check failure.
+ InitCache();
+ stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
+ PerClass *c = &per_class_[class_id];
+ CHECK_NE(c->max_count, 0UL);
+ if (UNLIKELY(c->count == c->max_count))
+ Drain(c, allocator, class_id, c->max_count / 2);
+ CompactPtrT chunk = allocator->PointerToCompactPtr(
+ allocator->GetRegionBeginBySizeClass(class_id),
+ reinterpret_cast<uptr>(p));
+ c->chunks[c->count++] = chunk;
+ }
+
+ void Drain(SizeClassAllocator *allocator) {
+ for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
+ PerClass *c = &per_class_[class_id];
+ while (c->count > 0)
+ Drain(c, allocator, class_id, c->count);
+ }
+ }
+
+ // private:
+ struct PerClass {
+ u32 count;
+ u32 max_count;
+ CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint];
+ };
+ PerClass per_class_[kNumClasses];
+ AllocatorStats stats_;
+
+ void InitCache() {
+ if (per_class_[1].max_count)
+ return;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
+ c->max_count = 2 * SizeClassMap::MaxCachedHint(i);
+ }
+ }
+
+ NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator,
+ uptr class_id) {
+ InitCache();
+ uptr num_requested_chunks = SizeClassMap::MaxCachedHint(class_id);
+ allocator->GetFromAllocator(&stats_, class_id, c->chunks,
+ num_requested_chunks);
+ c->count = num_requested_chunks;
+ }
+
+ NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id,
+ uptr count) {
+ InitCache();
+ CHECK_GE(c->count, count);
+ uptr first_idx_to_drain = c->count - count;
+ c->count -= count;
+ allocator->ReturnToAllocator(&stats_, class_id,
+ &c->chunks[first_idx_to_drain], count);
+ }
+};
+
+// Cache used by SizeClassAllocator32.
+template <class SizeClassAllocator>
+struct SizeClassAllocator32LocalCache {
+ typedef SizeClassAllocator Allocator;
+ typedef typename Allocator::TransferBatch TransferBatch;
+ static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
+
+ void Init(AllocatorGlobalStats *s) {
+ stats_.Init();
+ if (s)
+ s->Register(&stats_);
+ }
+
+ void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+ Drain(allocator);
+ if (s)
+ s->Unregister(&stats_);
+ }
+
+ void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
+ PerClass *c = &per_class_[class_id];
+ if (UNLIKELY(c->count == 0))
+ Refill(allocator, class_id);
+ void *res = c->batch[--c->count];
+ PREFETCH(c->batch[c->count - 1]);
+ return res;
+ }
+
+ void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
+ CHECK_NE(class_id, 0UL);
+ CHECK_LT(class_id, kNumClasses);
+ // If the first allocator call on a new thread is a deallocation, then
+ // max_count will be zero, leading to check failure.
+ InitCache();
+ stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
+ PerClass *c = &per_class_[class_id];
+ CHECK_NE(c->max_count, 0UL);
+ if (UNLIKELY(c->count == c->max_count))
+ Drain(allocator, class_id);
+ c->batch[c->count++] = p;
+ }
+
+ void Drain(SizeClassAllocator *allocator) {
+ for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
+ PerClass *c = &per_class_[class_id];
+ while (c->count > 0)
+ Drain(allocator, class_id);
+ }
+ }
+
+ // private:
+ typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
+ struct PerClass {
+ uptr count;
+ uptr max_count;
+ void *batch[2 * TransferBatch::kMaxNumCached];
+ };
+ PerClass per_class_[kNumClasses];
+ AllocatorStats stats_;
+
+ void InitCache() {
+ if (per_class_[1].max_count)
+ return;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
+ c->max_count = 2 * TransferBatch::MaxCached(i);
+ }
+ }
+
+ // TransferBatch class is declared in SizeClassAllocator.
+ // We transfer chunks between central and thread-local free lists in batches.
+ // For small size classes we allocate batches separately.
+ // For large size classes we may use one of the chunks to store the batch.
+ // sizeof(TransferBatch) must be a power of 2 for more efficient allocation.
+ static uptr SizeClassForTransferBatch(uptr class_id) {
+ if (Allocator::ClassIdToSize(class_id) <
+ TransferBatch::AllocationSizeRequiredForNElements(
+ TransferBatch::MaxCached(class_id)))
+ return SizeClassMap::ClassID(sizeof(TransferBatch));
+ return 0;
+ }
+
+ // Returns a TransferBatch suitable for class_id.
+ // For small size classes allocates the batch from the allocator.
+ // For large size classes simply returns b.
+ TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator,
+ TransferBatch *b) {
+ if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
+ return (TransferBatch*)Allocate(allocator, batch_class_id);
+ return b;
+ }
+
+ // Destroys TransferBatch b.
+ // For small size classes deallocates b to the allocator.
+ // Does notthing for large size classes.
+ void DestroyBatch(uptr class_id, SizeClassAllocator *allocator,
+ TransferBatch *b) {
+ if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
+ Deallocate(allocator, batch_class_id, b);
+ }
+
+ NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id);
+ CHECK_GT(b->Count(), 0);
+ b->CopyToArray(c->batch);
+ c->count = b->Count();
+ DestroyBatch(class_id, allocator, b);
+ }
+
+ NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
+ InitCache();
+ PerClass *c = &per_class_[class_id];
+ uptr cnt = Min(c->max_count / 2, c->count);
+ uptr first_idx_to_drain = c->count - cnt;
+ TransferBatch *b = CreateBatch(
+ class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);
+ b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id),
+ &c->batch[first_idx_to_drain], cnt);
+ c->count -= cnt;
+ allocator->DeallocateBatch(&stats_, class_id, b);
+ }
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
new file mode 100644
index 00000000000..989b87a1923
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
@@ -0,0 +1,302 @@
+//===-- sanitizer_allocator_primary32.h -------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+template<class SizeClassAllocator> struct SizeClassAllocator32LocalCache;
+
+// SizeClassAllocator32 -- allocator for 32-bit address space.
+// This allocator can theoretically be used on 64-bit arch, but there it is less
+// efficient than SizeClassAllocator64.
+//
+// [kSpaceBeg, kSpaceBeg + kSpaceSize) is the range of addresses which can
+// be returned by MmapOrDie().
+//
+// Region:
+// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
+// Since the regions are aligned by kRegionSize, there are exactly
+// kNumPossibleRegions possible regions in the address space and so we keep
+// a ByteMap possible_regions to store the size classes of each Region.
+// 0 size class means the region is not used by the allocator.
+//
+// One Region is used to allocate chunks of a single size class.
+// A Region looks like this:
+// UserChunk1 .. UserChunkN <gap> MetaChunkN .. MetaChunk1
+//
+// In order to avoid false sharing the objects of this class should be
+// chache-line aligned.
+template <const uptr kSpaceBeg, const u64 kSpaceSize,
+ const uptr kMetadataSize, class SizeClassMap,
+ const uptr kRegionSizeLog,
+ class ByteMap,
+ class MapUnmapCallback = NoOpMapUnmapCallback>
+class SizeClassAllocator32 {
+ public:
+ struct TransferBatch {
+ static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2;
+ void SetFromArray(uptr region_beg_unused, void *batch[], uptr count) {
+ count_ = count;
+ CHECK_LE(count_, kMaxNumCached);
+ for (uptr i = 0; i < count; i++)
+ batch_[i] = batch[i];
+ }
+ uptr Count() const { return count_; }
+ void Clear() { count_ = 0; }
+ void Add(void *ptr) {
+ batch_[count_++] = ptr;
+ CHECK_LE(count_, kMaxNumCached);
+ }
+ void CopyToArray(void *to_batch[]) {
+ for (uptr i = 0, n = Count(); i < n; i++)
+ to_batch[i] = batch_[i];
+ }
+
+ // How much memory do we need for a batch containing n elements.
+ static uptr AllocationSizeRequiredForNElements(uptr n) {
+ return sizeof(uptr) * 2 + sizeof(void *) * n;
+ }
+ static uptr MaxCached(uptr class_id) {
+ return Min(kMaxNumCached, SizeClassMap::MaxCachedHint(class_id));
+ }
+
+ TransferBatch *next;
+
+ private:
+ uptr count_;
+ void *batch_[kMaxNumCached];
+ };
+
+ static const uptr kBatchSize = sizeof(TransferBatch);
+ COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0);
+ COMPILER_CHECK(sizeof(TransferBatch) ==
+ SizeClassMap::kMaxNumCachedHint * sizeof(uptr));
+
+ static uptr ClassIdToSize(uptr class_id) {
+ return SizeClassMap::Size(class_id);
+ }
+
+ typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
+ SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
+
+ void Init() {
+ possible_regions.TestOnlyInit();
+ internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
+ }
+
+ void *MapWithCallback(uptr size) {
+ size = RoundUpTo(size, GetPageSizeCached());
+ void *res = MmapOrDie(size, "SizeClassAllocator32");
+ MapUnmapCallback().OnMap((uptr)res, size);
+ return res;
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ void *GetMetaData(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = ClassIdToSize(GetSizeClass(p));
+ u32 offset = mem - beg;
+ uptr n = offset / (u32)size; // 32-bit division
+ uptr meta = (beg + kRegionSize) - (n + 1) * kMetadataSize;
+ return reinterpret_cast<void*>(meta);
+ }
+
+ NOINLINE TransferBatch *AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ if (sci->free_list.empty())
+ PopulateFreeList(stat, c, sci, class_id);
+ CHECK(!sci->free_list.empty());
+ TransferBatch *b = sci->free_list.front();
+ sci->free_list.pop_front();
+ return b;
+ }
+
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id,
+ TransferBatch *b) {
+ CHECK_LT(class_id, kNumClasses);
+ SizeClassInfo *sci = GetSizeClassInfo(class_id);
+ SpinMutexLock l(&sci->mutex);
+ CHECK_GT(b->Count(), 0);
+ sci->free_list.push_front(b);
+ }
+
+ uptr GetRegionBeginBySizeClass(uptr class_id) { return 0; }
+
+ bool PointerIsMine(const void *p) {
+ uptr mem = reinterpret_cast<uptr>(p);
+ if (mem < kSpaceBeg || mem >= kSpaceBeg + kSpaceSize)
+ return false;
+ return GetSizeClass(p) != 0;
+ }
+
+ uptr GetSizeClass(const void *p) {
+ return possible_regions[ComputeRegionId(reinterpret_cast<uptr>(p))];
+ }
+
+ void *GetBlockBegin(const void *p) {
+ CHECK(PointerIsMine(p));
+ uptr mem = reinterpret_cast<uptr>(p);
+ uptr beg = ComputeRegionBeg(mem);
+ uptr size = ClassIdToSize(GetSizeClass(p));
+ u32 offset = mem - beg;
+ u32 n = offset / (u32)size; // 32-bit division
+ uptr res = beg + (n * (u32)size);
+ return reinterpret_cast<void*>(res);
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return ClassIdToSize(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ uptr TotalMemoryUsed() {
+ // No need to lock here.
+ uptr res = 0;
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ res += kRegionSize;
+ return res;
+ }
+
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kNumPossibleRegions; i++)
+ if (possible_regions[i])
+ UnmapWithCallback((i * kRegionSize), kRegionSize);
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetSizeClassInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = kNumClasses - 1; i >= 0; i--) {
+ GetSizeClassInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr region = 0; region < kNumPossibleRegions; region++)
+ if (possible_regions[region]) {
+ uptr chunk_size = ClassIdToSize(possible_regions[region]);
+ uptr max_chunks_in_region = kRegionSize / (chunk_size + kMetadataSize);
+ uptr region_beg = region * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + max_chunks_in_region * chunk_size;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ void PrintStats() {
+ }
+
+ static uptr AdditionalSize() {
+ return 0;
+ }
+
+ // This is empty here. Currently only implemented in 64-bit allocator.
+ void ReleaseToOS() { }
+
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+
+ private:
+ static const uptr kRegionSize = 1 << kRegionSizeLog;
+ static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
+
+ struct SizeClassInfo {
+ SpinMutex mutex;
+ IntrusiveList<TransferBatch> free_list;
+ char padding[kCacheLineSize - sizeof(uptr) -
+ sizeof(IntrusiveList<TransferBatch>)];
+ };
+ COMPILER_CHECK(sizeof(SizeClassInfo) == kCacheLineSize);
+
+ uptr ComputeRegionId(uptr mem) {
+ uptr res = mem >> kRegionSizeLog;
+ CHECK_LT(res, kNumPossibleRegions);
+ return res;
+ }
+
+ uptr ComputeRegionBeg(uptr mem) {
+ return mem & ~(kRegionSize - 1);
+ }
+
+ uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
+ "SizeClassAllocator32"));
+ MapUnmapCallback().OnMap(res, kRegionSize);
+ stat->Add(AllocatorStatMapped, kRegionSize);
+ CHECK_EQ(0U, (res & (kRegionSize - 1)));
+ possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
+ return res;
+ }
+
+ SizeClassInfo *GetSizeClassInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ return &size_class_info_array[class_id];
+ }
+
+ void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ SizeClassInfo *sci, uptr class_id) {
+ uptr size = ClassIdToSize(class_id);
+ uptr reg = AllocateRegion(stat, class_id);
+ uptr n_chunks = kRegionSize / (size + kMetadataSize);
+ uptr max_count = TransferBatch::MaxCached(class_id);
+ TransferBatch *b = nullptr;
+ for (uptr i = reg; i < reg + n_chunks * size; i += size) {
+ if (!b) {
+ b = c->CreateBatch(class_id, this, (TransferBatch*)i);
+ b->Clear();
+ }
+ b->Add((void*)i);
+ if (b->Count() == max_count) {
+ CHECK_GT(b->Count(), 0);
+ sci->free_list.push_back(b);
+ b = nullptr;
+ }
+ }
+ if (b) {
+ CHECK_GT(b->Count(), 0);
+ sci->free_list.push_back(b);
+ }
+ }
+
+ ByteMap possible_regions;
+ SizeClassInfo size_class_info_array[kNumClasses];
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
new file mode 100644
index 00000000000..620639afbfd
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
@@ -0,0 +1,503 @@
+//===-- sanitizer_allocator_primary64.h -------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
+
+// SizeClassAllocator64 -- allocator for 64-bit address space.
+// The template parameter Params is a class containing the actual parameters.
+//
+// Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
+// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
+// Otherwise SpaceBeg=kSpaceBeg (fixed address).
+// kSpaceSize is a power of two.
+// At the beginning the entire space is mprotect-ed, then small parts of it
+// are mapped on demand.
+//
+// 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.
+
+// FreeArray is an array free-d chunks (stored as 4-byte offsets)
+//
+// A Region looks like this:
+// UserChunk1 ... UserChunkN <gap> MetaChunkN ... MetaChunk1 FreeArray
+
+struct SizeClassAllocator64FlagMasks { // Bit masks.
+ enum {
+ kRandomShuffleChunks = 1,
+ };
+};
+
+template <class Params>
+class SizeClassAllocator64 {
+ public:
+ static const uptr kSpaceBeg = Params::kSpaceBeg;
+ static const uptr kSpaceSize = Params::kSpaceSize;
+ static const uptr kMetadataSize = Params::kMetadataSize;
+ typedef typename Params::SizeClassMap SizeClassMap;
+ typedef typename Params::MapUnmapCallback MapUnmapCallback;
+
+ static const bool kRandomShuffleChunks =
+ Params::kFlags & SizeClassAllocator64FlagMasks::kRandomShuffleChunks;
+
+ typedef SizeClassAllocator64<Params> ThisT;
+ typedef SizeClassAllocator64LocalCache<ThisT> AllocatorCache;
+
+ // When we know the size class (the region base) we can represent a pointer
+ // as a 4-byte integer (offset from the region start shifted right by 4).
+ typedef u32 CompactPtrT;
+ static const uptr kCompactPtrScale = 4;
+ CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) {
+ return static_cast<CompactPtrT>((ptr - base) >> kCompactPtrScale);
+ }
+ uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) {
+ return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
+ }
+
+ void Init() {
+ uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
+ if (kUsingConstantSpaceBeg) {
+ CHECK_EQ(kSpaceBeg, reinterpret_cast<uptr>(
+ MmapFixedNoAccess(kSpaceBeg, TotalSpaceSize)));
+ } else {
+ NonConstSpaceBeg =
+ reinterpret_cast<uptr>(MmapNoAccess(TotalSpaceSize));
+ CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
+ }
+ MapWithCallback(SpaceEnd(), AdditionalSize());
+ }
+
+ void MapWithCallback(uptr beg, uptr size) {
+ CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
+ MapUnmapCallback().OnMap(beg, size);
+ }
+
+ void UnmapWithCallback(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ static bool CanAllocate(uptr size, uptr alignment) {
+ return size <= SizeClassMap::kMaxSize &&
+ alignment <= SizeClassMap::kMaxSize;
+ }
+
+ NOINLINE void ReturnToAllocator(AllocatorStats *stat, uptr class_id,
+ const CompactPtrT *chunks, uptr n_chunks) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr region_beg = GetRegionBeginBySizeClass(class_id);
+ CompactPtrT *free_array = GetFreeArray(region_beg);
+
+ BlockingMutexLock l(&region->mutex);
+ uptr old_num_chunks = region->num_freed_chunks;
+ uptr new_num_freed_chunks = old_num_chunks + n_chunks;
+ EnsureFreeArraySpace(region, region_beg, new_num_freed_chunks);
+ for (uptr i = 0; i < n_chunks; i++)
+ free_array[old_num_chunks + i] = chunks[i];
+ region->num_freed_chunks = new_num_freed_chunks;
+ region->n_freed += n_chunks;
+ }
+
+ NOINLINE void GetFromAllocator(AllocatorStats *stat, uptr class_id,
+ CompactPtrT *chunks, uptr n_chunks) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr region_beg = GetRegionBeginBySizeClass(class_id);
+ CompactPtrT *free_array = GetFreeArray(region_beg);
+
+ BlockingMutexLock l(&region->mutex);
+ if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
+ PopulateFreeArray(stat, class_id, region,
+ n_chunks - region->num_freed_chunks);
+ CHECK_GE(region->num_freed_chunks, n_chunks);
+ }
+ region->num_freed_chunks -= n_chunks;
+ uptr base_idx = region->num_freed_chunks;
+ for (uptr i = 0; i < n_chunks; i++)
+ chunks[i] = free_array[base_idx + i];
+ region->n_allocated += n_chunks;
+ }
+
+
+ bool PointerIsMine(const void *p) {
+ uptr P = reinterpret_cast<uptr>(p);
+ if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0)
+ return P / kSpaceSize == kSpaceBeg / kSpaceSize;
+ return P >= SpaceBeg() && P < SpaceEnd();
+ }
+
+ uptr GetRegionBegin(const void *p) {
+ if (kUsingConstantSpaceBeg)
+ return reinterpret_cast<uptr>(p) & ~(kRegionSize - 1);
+ uptr space_beg = SpaceBeg();
+ return ((reinterpret_cast<uptr>(p) - space_beg) & ~(kRegionSize - 1)) +
+ space_beg;
+ }
+
+ uptr GetRegionBeginBySizeClass(uptr class_id) {
+ return SpaceBeg() + kRegionSize * class_id;
+ }
+
+ uptr GetSizeClass(const void *p) {
+ if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0)
+ return ((reinterpret_cast<uptr>(p)) / kRegionSize) % kNumClassesRounded;
+ return ((reinterpret_cast<uptr>(p) - SpaceBeg()) / kRegionSize) %
+ kNumClassesRounded;
+ }
+
+ void *GetBlockBegin(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = ClassIdToSize(class_id);
+ if (!size) return nullptr;
+ uptr chunk_idx = GetChunkIdx((uptr)p, size);
+ uptr reg_beg = GetRegionBegin(p);
+ uptr beg = chunk_idx * size;
+ uptr next_beg = beg + size;
+ if (class_id >= kNumClasses) return nullptr;
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user >= next_beg)
+ return reinterpret_cast<void*>(reg_beg + beg);
+ return nullptr;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ CHECK(PointerIsMine(p));
+ return ClassIdToSize(GetSizeClass(p));
+ }
+
+ uptr ClassID(uptr size) { return SizeClassMap::ClassID(size); }
+
+ void *GetMetaData(const void *p) {
+ uptr class_id = GetSizeClass(p);
+ uptr size = ClassIdToSize(class_id);
+ uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), size);
+ uptr region_beg = GetRegionBeginBySizeClass(class_id);
+ return reinterpret_cast<void *>(GetMetadataEnd(region_beg) -
+ (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() {
+ UnmapWithCallback(SpaceBeg(), kSpaceSize + AdditionalSize());
+ }
+
+ static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
+ uptr stats_size) {
+ for (uptr class_id = 0; class_id < stats_size; class_id++)
+ if (stats[class_id] == start)
+ stats[class_id] = rss;
+ }
+
+ void PrintStats(uptr class_id, uptr rss) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ if (region->mapped_user == 0) return;
+ uptr in_use = region->n_allocated - region->n_freed;
+ uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id);
+ Printf(
+ " %02zd (%zd): mapped: %zdK allocs: %zd frees: %zd inuse: %zd "
+ "num_freed_chunks %zd"
+ " avail: %zd rss: %zdK releases: %zd\n",
+ class_id, ClassIdToSize(class_id), region->mapped_user >> 10,
+ region->n_allocated, region->n_freed, in_use,
+ region->num_freed_chunks, avail_chunks, rss >> 10,
+ region->rtoi.num_releases);
+ }
+
+ void PrintStats() {
+ uptr total_mapped = 0;
+ uptr n_allocated = 0;
+ uptr n_freed = 0;
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ total_mapped += region->mapped_user;
+ n_allocated += region->n_allocated;
+ n_freed += region->n_freed;
+ }
+ Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
+ "remains %zd\n",
+ total_mapped >> 20, n_allocated, n_allocated - n_freed);
+ uptr rss_stats[kNumClasses];
+ for (uptr class_id = 0; class_id < kNumClasses; class_id++)
+ rss_stats[class_id] = SpaceBeg() + kRegionSize * class_id;
+ GetMemoryProfile(FillMemoryProfile, rss_stats, kNumClasses);
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++)
+ PrintStats(class_id, rss_stats[class_id]);
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetRegionInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+ GetRegionInfo(i)->mutex.Unlock();
+ }
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr chunk_size = ClassIdToSize(class_id);
+ uptr region_beg = SpaceBeg() + class_id * kRegionSize;
+ for (uptr chunk = region_beg;
+ chunk < region_beg + region->allocated_user;
+ chunk += chunk_size) {
+ // Too slow: CHECK_EQ((void *)chunk, GetBlockBegin((void *)chunk));
+ callback(chunk, arg);
+ }
+ }
+ }
+
+ static uptr ClassIdToSize(uptr class_id) {
+ return SizeClassMap::Size(class_id);
+ }
+
+ static uptr AdditionalSize() {
+ return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+ GetPageSizeCached());
+ }
+
+ void ReleaseToOS() {
+ for (uptr class_id = 1; class_id < kNumClasses; class_id++)
+ ReleaseToOS(class_id);
+ }
+
+ typedef SizeClassMap SizeClassMapT;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+ static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
+
+ private:
+ static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
+ // FreeArray is the array of free-d chunks (stored as 4-byte offsets).
+ // In the worst case it may reguire kRegionSize/SizeClassMap::kMinSize
+ // elements, but in reality this will not happen. For simplicity we
+ // dedicate 1/8 of the region's virtual space to FreeArray.
+ static const uptr kFreeArraySize = kRegionSize / 8;
+
+ static const bool kUsingConstantSpaceBeg = kSpaceBeg != ~(uptr)0;
+ uptr NonConstSpaceBeg;
+ uptr SpaceBeg() const {
+ return kUsingConstantSpaceBeg ? kSpaceBeg : NonConstSpaceBeg;
+ }
+ uptr SpaceEnd() const { return SpaceBeg() + kSpaceSize; }
+ // kRegionSize must be >= 2^32.
+ COMPILER_CHECK((kRegionSize) >= (1ULL << (SANITIZER_WORDSIZE / 2)));
+ // kRegionSize must be <= 2^36, see CompactPtrT.
+ COMPILER_CHECK((kRegionSize) <= (1ULL << (SANITIZER_WORDSIZE / 2 + 4)));
+ // Call mmap for user memory with at least this size.
+ static const uptr kUserMapSize = 1 << 16;
+ // Call mmap for metadata memory with at least this size.
+ static const uptr kMetaMapSize = 1 << 16;
+ // Call mmap for free array memory with at least this size.
+ static const uptr kFreeArrayMapSize = 1 << 16;
+ // Granularity of ReleaseToOs (aka madvise).
+ static const uptr kReleaseToOsGranularity = 1 << 12;
+
+ struct ReleaseToOsInfo {
+ uptr n_freed_at_last_release;
+ uptr num_releases;
+ };
+
+ struct RegionInfo {
+ BlockingMutex mutex;
+ uptr num_freed_chunks; // Number of elements in the freearray.
+ uptr mapped_free_array; // Bytes mapped for freearray.
+ uptr allocated_user; // Bytes allocated for user memory.
+ uptr allocated_meta; // Bytes allocated for metadata.
+ uptr mapped_user; // Bytes mapped for user memory.
+ uptr mapped_meta; // Bytes mapped for metadata.
+ u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks.
+ uptr n_allocated, n_freed; // Just stats.
+ ReleaseToOsInfo rtoi;
+ };
+ COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
+
+ u32 Rand(u32 *state) { // ANSI C linear congruential PRNG.
+ return (*state = *state * 1103515245 + 12345) >> 16;
+ }
+
+ u32 RandN(u32 *state, u32 n) { return Rand(state) % n; } // [0, n)
+
+ void RandomShuffle(u32 *a, u32 n, u32 *rand_state) {
+ if (n <= 1) return;
+ for (u32 i = n - 1; i > 0; i--)
+ Swap(a[i], a[RandN(rand_state, i + 1)]);
+ }
+
+ RegionInfo *GetRegionInfo(uptr class_id) {
+ CHECK_LT(class_id, kNumClasses);
+ RegionInfo *regions =
+ reinterpret_cast<RegionInfo *>(SpaceBeg() + kSpaceSize);
+ return &regions[class_id];
+ }
+
+ uptr GetMetadataEnd(uptr region_beg) {
+ return region_beg + kRegionSize - kFreeArraySize;
+ }
+
+ uptr GetChunkIdx(uptr chunk, uptr size) {
+ if (!kUsingConstantSpaceBeg)
+ chunk -= SpaceBeg();
+
+ uptr offset = chunk % kRegionSize;
+ // Here we divide by a non-constant. This is costly.
+ // size always fits into 32-bits. If the offset fits too, use 32-bit div.
+ if (offset >> (SANITIZER_WORDSIZE / 2))
+ return offset / size;
+ return (u32)offset / (u32)size;
+ }
+
+ CompactPtrT *GetFreeArray(uptr region_beg) {
+ return reinterpret_cast<CompactPtrT *>(region_beg + kRegionSize -
+ kFreeArraySize);
+ }
+
+ void EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
+ uptr num_freed_chunks) {
+ uptr needed_space = num_freed_chunks * sizeof(CompactPtrT);
+ if (region->mapped_free_array < needed_space) {
+ CHECK_LE(needed_space, kFreeArraySize);
+ uptr new_mapped_free_array = RoundUpTo(needed_space, kFreeArrayMapSize);
+ uptr current_map_end = reinterpret_cast<uptr>(GetFreeArray(region_beg)) +
+ region->mapped_free_array;
+ uptr new_map_size = new_mapped_free_array - region->mapped_free_array;
+ MapWithCallback(current_map_end, new_map_size);
+ region->mapped_free_array = new_mapped_free_array;
+ }
+ }
+
+
+ NOINLINE void PopulateFreeArray(AllocatorStats *stat, uptr class_id,
+ RegionInfo *region, uptr requested_count) {
+ // region->mutex is held.
+ uptr size = ClassIdToSize(class_id);
+ uptr beg_idx = region->allocated_user;
+ uptr end_idx = beg_idx + requested_count * size;
+ uptr region_beg = GetRegionBeginBySizeClass(class_id);
+ if (end_idx > region->mapped_user) {
+ if (!kUsingConstantSpaceBeg && region->mapped_user == 0)
+ region->rand_state = static_cast<u32>(region_beg >> 12); // From ASLR.
+ // Do the mmap for the user memory.
+ uptr map_size = kUserMapSize;
+ while (end_idx > region->mapped_user + map_size)
+ map_size += kUserMapSize;
+ CHECK_GE(region->mapped_user + map_size, end_idx);
+ MapWithCallback(region_beg + region->mapped_user, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ region->mapped_user += map_size;
+ }
+ CompactPtrT *free_array = GetFreeArray(region_beg);
+ uptr total_count = (region->mapped_user - beg_idx) / size;
+ uptr num_freed_chunks = region->num_freed_chunks;
+ EnsureFreeArraySpace(region, region_beg, num_freed_chunks + total_count);
+ for (uptr i = 0; i < total_count; i++) {
+ uptr chunk = beg_idx + i * size;
+ free_array[num_freed_chunks + total_count - 1 - i] =
+ PointerToCompactPtr(0, chunk);
+ }
+ if (kRandomShuffleChunks)
+ RandomShuffle(&free_array[num_freed_chunks], total_count,
+ &region->rand_state);
+ region->num_freed_chunks += total_count;
+ region->allocated_user += total_count * size;
+ CHECK_LE(region->allocated_user, region->mapped_user);
+
+ region->allocated_meta += total_count * kMetadataSize;
+ if (region->allocated_meta > region->mapped_meta) {
+ uptr map_size = kMetaMapSize;
+ while (region->allocated_meta > region->mapped_meta + map_size)
+ map_size += kMetaMapSize;
+ // Do the mmap for the metadata.
+ CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
+ MapWithCallback(GetMetadataEnd(region_beg) -
+ region->mapped_meta - map_size, map_size);
+ region->mapped_meta += map_size;
+ }
+ CHECK_LE(region->allocated_meta, region->mapped_meta);
+ if (region->mapped_user + region->mapped_meta >
+ kRegionSize - kFreeArraySize) {
+ Printf("%s: Out of memory. Dying. ", SanitizerToolName);
+ Printf("The process has exhausted %zuMB for size class %zu.\n",
+ kRegionSize / 1024 / 1024, size);
+ Die();
+ }
+ }
+
+ bool MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size,
+ CompactPtrT first, CompactPtrT last) {
+ uptr beg_ptr = CompactPtrToPointer(region_beg, first);
+ uptr end_ptr = CompactPtrToPointer(region_beg, last) + chunk_size;
+ CHECK_GE(end_ptr - beg_ptr, kReleaseToOsGranularity);
+ beg_ptr = RoundUpTo(beg_ptr, kReleaseToOsGranularity);
+ end_ptr = RoundDownTo(end_ptr, kReleaseToOsGranularity);
+ if (end_ptr == beg_ptr) return false;
+ ReleaseMemoryToOS(beg_ptr, end_ptr - beg_ptr);
+ return true;
+ }
+
+ // Releases some RAM back to OS.
+ // Algorithm:
+ // * Lock the region.
+ // * Sort the chunks.
+ // * Find ranges fully covered by free-d chunks
+ // * Release them to OS with madvise.
+ //
+ // TODO(kcc): make sure we don't do it too frequently.
+ void ReleaseToOS(uptr class_id) {
+ RegionInfo *region = GetRegionInfo(class_id);
+ uptr region_beg = GetRegionBeginBySizeClass(class_id);
+ CompactPtrT *free_array = GetFreeArray(region_beg);
+ uptr chunk_size = ClassIdToSize(class_id);
+ uptr scaled_chunk_size = chunk_size >> kCompactPtrScale;
+ const uptr kScaledGranularity = kReleaseToOsGranularity >> kCompactPtrScale;
+ BlockingMutexLock l(&region->mutex);
+ uptr n = region->num_freed_chunks;
+ if (n * chunk_size < kReleaseToOsGranularity)
+ return; // No chance to release anything.
+ if ((region->rtoi.n_freed_at_last_release - region->n_freed) * chunk_size <
+ kReleaseToOsGranularity)
+ return; // Nothing new to release.
+ SortArray(free_array, n);
+ uptr beg = free_array[0];
+ uptr prev = free_array[0];
+ for (uptr i = 1; i < n; i++) {
+ uptr chunk = free_array[i];
+ CHECK_GT(chunk, prev);
+ if (chunk - prev != scaled_chunk_size) {
+ CHECK_GT(chunk - prev, scaled_chunk_size);
+ if (prev + scaled_chunk_size - beg >= kScaledGranularity) {
+ MaybeReleaseChunkRange(region_beg, chunk_size, beg, prev);
+ region->rtoi.n_freed_at_last_release = region->n_freed;
+ region->rtoi.num_releases++;
+ }
+ beg = chunk;
+ }
+ prev = chunk;
+ }
+ }
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
new file mode 100644
index 00000000000..91c2ecc5b26
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
@@ -0,0 +1,271 @@
+//===-- sanitizer_allocator_secondary.h -------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// 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).
+template <class MapUnmapCallback = NoOpMapUnmapCallback>
+class LargeMmapAllocator {
+ public:
+ void InitLinkerInitialized(bool may_return_null) {
+ page_size_ = GetPageSizeCached();
+ atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
+ }
+
+ void Init(bool may_return_null) {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized(may_return_null);
+ }
+
+ void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = RoundUpMapSize(size);
+ if (alignment > page_size_)
+ map_size += alignment;
+ // Overflow.
+ if (map_size < size) return ReturnNullOrDieOnBadRequest();
+ uptr map_beg = reinterpret_cast<uptr>(
+ MmapOrDie(map_size, "LargeMmapAllocator"));
+ CHECK(IsAligned(map_beg, page_size_));
+ MapUnmapCallback().OnMap(map_beg, map_size);
+ uptr map_end = map_beg + map_size;
+ uptr res = map_beg + page_size_;
+ if (res & (alignment - 1)) // Align.
+ res += alignment - (res & (alignment - 1));
+ CHECK(IsAligned(res, alignment));
+ CHECK(IsAligned(res, page_size_));
+ CHECK_GE(res + size, map_beg);
+ CHECK_LE(res + size, map_end);
+ Header *h = GetHeader(res);
+ h->size = size;
+ h->map_beg = map_beg;
+ h->map_size = map_size;
+ uptr size_log = MostSignificantSetBitIndex(map_size);
+ CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = n_chunks_++;
+ chunks_sorted_ = false;
+ CHECK_LT(idx, kMaxNumChunks);
+ h->chunk_idx = idx;
+ chunks_[idx] = h;
+ stats.n_allocs++;
+ stats.currently_allocated += map_size;
+ stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
+ stats.by_size_log[size_log]++;
+ stat->Add(AllocatorStatAllocated, map_size);
+ stat->Add(AllocatorStatMapped, map_size);
+ }
+ return reinterpret_cast<void*>(res);
+ }
+
+ bool MayReturnNull() const {
+ return atomic_load(&may_return_null_, memory_order_acquire);
+ }
+
+ void *ReturnNullOrDieOnBadRequest() {
+ if (MayReturnNull()) return nullptr;
+ ReportAllocatorCannotReturnNull(false);
+ }
+
+ void *ReturnNullOrDieOnOOM() {
+ if (MayReturnNull()) return nullptr;
+ ReportAllocatorCannotReturnNull(true);
+ }
+
+ void SetMayReturnNull(bool may_return_null) {
+ atomic_store(&may_return_null_, may_return_null, memory_order_release);
+ }
+
+ void Deallocate(AllocatorStats *stat, void *p) {
+ Header *h = GetHeader(p);
+ {
+ SpinMutexLock l(&mutex_);
+ uptr idx = h->chunk_idx;
+ CHECK_EQ(chunks_[idx], h);
+ CHECK_LT(idx, n_chunks_);
+ chunks_[idx] = chunks_[n_chunks_ - 1];
+ chunks_[idx]->chunk_idx = idx;
+ n_chunks_--;
+ chunks_sorted_ = false;
+ stats.n_frees++;
+ stats.currently_allocated -= h->map_size;
+ stat->Sub(AllocatorStatAllocated, h->map_size);
+ stat->Sub(AllocatorStatMapped, h->map_size);
+ }
+ MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
+ UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
+ }
+
+ uptr TotalMemoryUsed() {
+ SpinMutexLock l(&mutex_);
+ uptr res = 0;
+ for (uptr i = 0; i < n_chunks_; i++) {
+ Header *h = chunks_[i];
+ CHECK_EQ(h->chunk_idx, i);
+ res += RoundUpMapSize(h->size);
+ }
+ return res;
+ }
+
+ bool PointerIsMine(const void *p) {
+ return GetBlockBegin(p) != nullptr;
+ }
+
+ uptr GetActuallyAllocatedSize(void *p) {
+ return RoundUpTo(GetHeader(p)->size, page_size_);
+ }
+
+ // At least page_size_/2 metadata bytes is available.
+ void *GetMetaData(const void *p) {
+ // Too slow: CHECK_EQ(p, GetBlockBegin(p));
+ if (!IsAligned(reinterpret_cast<uptr>(p), page_size_)) {
+ Printf("%s: bad pointer %p\n", SanitizerToolName, p);
+ CHECK(IsAligned(reinterpret_cast<uptr>(p), page_size_));
+ }
+ return GetHeader(p) + 1;
+ }
+
+ void *GetBlockBegin(const void *ptr) {
+ uptr p = reinterpret_cast<uptr>(ptr);
+ SpinMutexLock l(&mutex_);
+ uptr nearest_chunk = 0;
+ // Cache-friendly linear search.
+ for (uptr i = 0; i < n_chunks_; i++) {
+ uptr ch = reinterpret_cast<uptr>(chunks_[i]);
+ if (p < ch) continue; // p is at left to this chunk, skip it.
+ if (p - ch < p - nearest_chunk)
+ nearest_chunk = ch;
+ }
+ if (!nearest_chunk)
+ return nullptr;
+ Header *h = reinterpret_cast<Header *>(nearest_chunk);
+ CHECK_GE(nearest_chunk, h->map_beg);
+ CHECK_LT(nearest_chunk, h->map_beg + h->map_size);
+ CHECK_LE(nearest_chunk, p);
+ if (h->map_beg + h->map_size <= p)
+ return nullptr;
+ return GetUser(h);
+ }
+
+ // This function does the same as GetBlockBegin, but is much faster.
+ // Must be called with the allocator locked.
+ void *GetBlockBeginFastLocked(void *ptr) {
+ mutex_.CheckLocked();
+ uptr p = reinterpret_cast<uptr>(ptr);
+ uptr n = n_chunks_;
+ if (!n) return nullptr;
+ if (!chunks_sorted_) {
+ // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
+ SortArray(reinterpret_cast<uptr*>(chunks_), n);
+ for (uptr i = 0; i < n; i++)
+ chunks_[i]->chunk_idx = i;
+ chunks_sorted_ = true;
+ min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+ max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
+ chunks_[n - 1]->map_size;
+ }
+ if (p < min_mmap_ || p >= max_mmap_)
+ return nullptr;
+ uptr beg = 0, end = n - 1;
+ // This loop is a log(n) lower_bound. It does not check for the exact match
+ // to avoid expensive cache-thrashing loads.
+ while (end - beg >= 2) {
+ uptr mid = (beg + end) / 2; // Invariant: mid >= beg + 1
+ if (p < reinterpret_cast<uptr>(chunks_[mid]))
+ end = mid - 1; // We are not interested in chunks_[mid].
+ else
+ beg = mid; // chunks_[mid] may still be what we want.
+ }
+
+ if (beg < end) {
+ CHECK_EQ(beg + 1, end);
+ // There are 2 chunks left, choose one.
+ if (p >= reinterpret_cast<uptr>(chunks_[end]))
+ beg = end;
+ }
+
+ Header *h = chunks_[beg];
+ if (h->map_beg + h->map_size <= p || p < h->map_beg)
+ return nullptr;
+ return GetUser(h);
+ }
+
+ void PrintStats() {
+ Printf("Stats: LargeMmapAllocator: allocated %zd times, "
+ "remains %zd (%zd K) max %zd M; by size logs: ",
+ stats.n_allocs, stats.n_allocs - stats.n_frees,
+ stats.currently_allocated >> 10, stats.max_allocated >> 20);
+ for (uptr i = 0; i < ARRAY_SIZE(stats.by_size_log); i++) {
+ uptr c = stats.by_size_log[i];
+ if (!c) continue;
+ Printf("%zd:%zd; ", i, c);
+ }
+ Printf("\n");
+ }
+
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ mutex_.Lock();
+ }
+
+ void ForceUnlock() {
+ mutex_.Unlock();
+ }
+
+ // Iterate over all existing chunks.
+ // The allocator must be locked when calling this function.
+ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+ for (uptr i = 0; i < n_chunks_; i++)
+ callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
+ }
+
+ private:
+ static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
+ struct Header {
+ uptr map_beg;
+ uptr map_size;
+ uptr size;
+ uptr chunk_idx;
+ };
+
+ Header *GetHeader(uptr p) {
+ CHECK(IsAligned(p, page_size_));
+ return reinterpret_cast<Header*>(p - page_size_);
+ }
+ Header *GetHeader(const void *p) {
+ return GetHeader(reinterpret_cast<uptr>(p));
+ }
+
+ void *GetUser(Header *h) {
+ CHECK(IsAligned((uptr)h, page_size_));
+ return reinterpret_cast<void*>(reinterpret_cast<uptr>(h) + page_size_);
+ }
+
+ uptr RoundUpMapSize(uptr size) {
+ return RoundUpTo(size, page_size_) + page_size_;
+ }
+
+ uptr page_size_;
+ Header *chunks_[kMaxNumChunks];
+ uptr n_chunks_;
+ uptr min_mmap_, max_mmap_;
+ bool chunks_sorted_;
+ struct Stats {
+ uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
+ } stats;
+ atomic_uint8_t may_return_null_;
+ SpinMutex mutex_;
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
new file mode 100644
index 00000000000..4cda021a947
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
@@ -0,0 +1,215 @@
+//===-- sanitizer_allocator_size_class_map.h --------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// SizeClassMap maps allocation sizes into size classes and back.
+// Class 0 always corresponds to size 0.
+// The other sizes are controlled by the template parameters:
+// kMinSizeLog: defines the class 1 as 2^kMinSizeLog.
+// kMaxSizeLog: defines the last class as 2^kMaxSizeLog.
+// kMidSizeLog: the classes starting from 1 increase with step
+// 2^kMinSizeLog until 2^kMidSizeLog.
+// kNumBits: the number of non-zero bits in sizes after 2^kMidSizeLog.
+// E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
+// look like 0b1xx0..0, where x is either 0 or 1.
+//
+// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
+//
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
+// Next 4 classes: 256 + i * 64 (i = 1 to 4).
+// Next 4 classes: 512 + i * 128 (i = 1 to 4).
+// ...
+// Next 4 classes: 2^k + i * 2^(k-2) (i = 1 to 4).
+// Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
+//
+// This structure of the size class map gives us:
+// - Efficient table-free class-to-size and size-to-class functions.
+// - Difference between two consequent size classes is between 14% and 25%
+//
+// This class also gives a hint to a thread-caching allocator about the amount
+// of chunks that need to be cached per-thread:
+// - kMaxNumCachedHint is a hint for maximal number of chunks per size class.
+// The actual number is computed in TransferBatch.
+// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
+//
+// Part of output of SizeClassMap::Print():
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
+//
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
+//
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 320 diff: +64 25% l 8 cached: 204 65280; id 17
+// c18 => s: 384 diff: +64 20% l 8 cached: 170 65280; id 18
+// c19 => s: 448 diff: +64 16% l 8 cached: 146 65408; id 19
+//
+// c20 => s: 512 diff: +64 14% l 9 cached: 128 65536; id 20
+// c21 => s: 640 diff: +128 25% l 9 cached: 102 65280; id 21
+// c22 => s: 768 diff: +128 20% l 9 cached: 85 65280; id 22
+// c23 => s: 896 diff: +128 16% l 9 cached: 73 65408; id 23
+//
+// c24 => s: 1024 diff: +128 14% l 10 cached: 64 65536; id 24
+// c25 => s: 1280 diff: +256 25% l 10 cached: 51 65280; id 25
+// c26 => s: 1536 diff: +256 20% l 10 cached: 42 64512; id 26
+// c27 => s: 1792 diff: +256 16% l 10 cached: 36 64512; id 27
+//
+// ...
+//
+// c48 => s: 65536 diff: +8192 14% l 16 cached: 1 65536; id 48
+// c49 => s: 81920 diff: +16384 25% l 16 cached: 1 81920; id 49
+// c50 => s: 98304 diff: +16384 20% l 16 cached: 1 98304; id 50
+// c51 => s: 114688 diff: +16384 16% l 16 cached: 1 114688; id 51
+//
+// c52 => s: 131072 diff: +16384 14% l 17 cached: 1 131072; id 52
+//
+//
+// Another example (kNumBits=2):
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 32 diff: +32 00% l 5 cached: 64 2048; id 1
+// c02 => s: 64 diff: +32 100% l 6 cached: 64 4096; id 2
+// c03 => s: 96 diff: +32 50% l 6 cached: 64 6144; id 3
+// c04 => s: 128 diff: +32 33% l 7 cached: 64 8192; id 4
+// c05 => s: 160 diff: +32 25% l 7 cached: 64 10240; id 5
+// c06 => s: 192 diff: +32 20% l 7 cached: 64 12288; id 6
+// c07 => s: 224 diff: +32 16% l 7 cached: 64 14336; id 7
+// c08 => s: 256 diff: +32 14% l 8 cached: 64 16384; id 8
+// c09 => s: 384 diff: +128 50% l 8 cached: 42 16128; id 9
+// c10 => s: 512 diff: +128 33% l 9 cached: 32 16384; id 10
+// c11 => s: 768 diff: +256 50% l 9 cached: 21 16128; id 11
+// c12 => s: 1024 diff: +256 33% l 10 cached: 16 16384; id 12
+// c13 => s: 1536 diff: +512 50% l 10 cached: 10 15360; id 13
+// c14 => s: 2048 diff: +512 33% l 11 cached: 8 16384; id 14
+// c15 => s: 3072 diff: +1024 50% l 11 cached: 5 15360; id 15
+// c16 => s: 4096 diff: +1024 33% l 12 cached: 4 16384; id 16
+// c17 => s: 6144 diff: +2048 50% l 12 cached: 2 12288; id 17
+// c18 => s: 8192 diff: +2048 33% l 13 cached: 2 16384; id 18
+// c19 => s: 12288 diff: +4096 50% l 13 cached: 1 12288; id 19
+// c20 => s: 16384 diff: +4096 33% l 14 cached: 1 16384; id 20
+// c21 => s: 24576 diff: +8192 50% l 14 cached: 1 24576; id 21
+// c22 => s: 32768 diff: +8192 33% l 15 cached: 1 32768; id 22
+// c23 => s: 49152 diff: +16384 50% l 15 cached: 1 49152; id 23
+// c24 => s: 65536 diff: +16384 33% l 16 cached: 1 65536; id 24
+// c25 => s: 98304 diff: +32768 50% l 16 cached: 1 98304; id 25
+// c26 => s: 131072 diff: +32768 33% l 17 cached: 1 131072; id 26
+
+template <uptr kNumBits, uptr kMinSizeLog, uptr kMidSizeLog, uptr kMaxSizeLog,
+ uptr kMaxNumCachedHintT, uptr kMaxBytesCachedLog>
+class SizeClassMap {
+ static const uptr kMinSize = 1 << kMinSizeLog;
+ static const uptr kMidSize = 1 << kMidSizeLog;
+ static const uptr kMidClass = kMidSize / kMinSize;
+ static const uptr S = kNumBits - 1;
+ static const uptr M = (1 << S) - 1;
+
+ public:
+ // kMaxNumCachedHintT is a power of two. It serves as a hint
+ // for the size of TransferBatch, the actual size could be a bit smaller.
+ static const uptr kMaxNumCachedHint = kMaxNumCachedHintT;
+ COMPILER_CHECK((kMaxNumCachedHint & (kMaxNumCachedHint - 1)) == 0);
+
+ static const uptr kMaxSize = 1UL << kMaxSizeLog;
+ static const uptr kNumClasses =
+ kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
+ static const uptr kLargestClassID = kNumClasses - 2;
+ COMPILER_CHECK(kNumClasses >= 16 && kNumClasses <= 256);
+ static const uptr kNumClassesRounded =
+ kNumClasses <= 32 ? 32 :
+ kNumClasses <= 64 ? 64 :
+ kNumClasses <= 128 ? 128 : 256;
+
+ static uptr Size(uptr class_id) {
+ if (class_id <= kMidClass)
+ return kMinSize * class_id;
+ class_id -= kMidClass;
+ uptr t = kMidSize << (class_id >> S);
+ return t + (t >> S) * (class_id & M);
+ }
+
+ static uptr ClassID(uptr size) {
+ if (size <= kMidSize)
+ return (size + kMinSize - 1) >> kMinSizeLog;
+ if (size > kMaxSize) return 0;
+ uptr l = MostSignificantSetBitIndex(size);
+ uptr hbits = (size >> (l - S)) & M;
+ uptr lbits = size & ((1 << (l - S)) - 1);
+ uptr l1 = l - kMidSizeLog;
+ return kMidClass + (l1 << S) + hbits + (lbits > 0);
+ }
+
+ static uptr MaxCachedHint(uptr class_id) {
+ if (class_id == 0) return 0;
+ uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
+ return Max<uptr>(1, Min(kMaxNumCachedHint, n));
+ }
+
+ static void Print() {
+ uptr prev_s = 0;
+ uptr total_cached = 0;
+ for (uptr i = 0; i < kNumClasses; i++) {
+ uptr s = Size(i);
+ if (s >= kMidSize / 2 && (s & (s - 1)) == 0)
+ Printf("\n");
+ uptr d = s - prev_s;
+ uptr p = prev_s ? (d * 100 / prev_s) : 0;
+ uptr l = s ? MostSignificantSetBitIndex(s) : 0;
+ uptr cached = MaxCachedHint(i) * s;
+ Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
+ "cached: %zd %zd; id %zd\n",
+ i, Size(i), d, p, l, MaxCachedHint(i), cached, ClassID(s));
+ total_cached += cached;
+ prev_s = s;
+ }
+ Printf("Total cached: %zd\n", total_cached);
+ }
+
+ static void Validate() {
+ for (uptr c = 1; c < kNumClasses; c++) {
+ // Printf("Validate: c%zd\n", c);
+ uptr s = Size(c);
+ CHECK_NE(s, 0U);
+ CHECK_EQ(ClassID(s), c);
+ if (c != kNumClasses - 1)
+ CHECK_EQ(ClassID(s + 1), c + 1);
+ CHECK_EQ(ClassID(s - 1), c);
+ if (c)
+ CHECK_GT(Size(c), Size(c-1));
+ }
+ CHECK_EQ(ClassID(kMaxSize + 1), 0);
+
+ for (uptr s = 1; s <= kMaxSize; s++) {
+ uptr c = ClassID(s);
+ // Printf("s%zd => c%zd\n", s, c);
+ CHECK_LT(c, kNumClasses);
+ CHECK_GE(Size(c), s);
+ if (c > 0)
+ CHECK_LT(Size(c-1), s);
+ }
+ }
+};
+
+typedef SizeClassMap<3, 4, 8, 17, 128, 16> DefaultSizeClassMap;
+typedef SizeClassMap<3, 4, 8, 17, 64, 14> CompactSizeClassMap;
+typedef SizeClassMap<2, 5, 9, 16, 64, 14> VeryCompactSizeClassMap;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_stats.h b/libsanitizer/sanitizer_common/sanitizer_allocator_stats.h
new file mode 100644
index 00000000000..e336b5d365a
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_stats.h
@@ -0,0 +1,103 @@
+//===-- sanitizer_allocator_stats.h -----------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the Sanitizer Allocator.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_ALLOCATOR_H
+#error This file must be included inside sanitizer_allocator.h
+#endif
+
+// Memory allocator statistics
+enum AllocatorStat {
+ AllocatorStatAllocated,
+ AllocatorStatMapped,
+ AllocatorStatCount
+};
+
+typedef uptr AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+ void InitLinkerInitialized() {}
+
+ void Add(AllocatorStat i, uptr v) {
+ v += atomic_load(&stats_[i], memory_order_relaxed);
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Sub(AllocatorStat i, uptr v) {
+ v = atomic_load(&stats_[i], memory_order_relaxed) - v;
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Set(AllocatorStat i, uptr v) {
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ uptr Get(AllocatorStat i) const {
+ return atomic_load(&stats_[i], memory_order_relaxed);
+ }
+
+ private:
+ friend class AllocatorGlobalStats;
+ AllocatorStats *next_;
+ AllocatorStats *prev_;
+ atomic_uintptr_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+ void InitLinkerInitialized() {
+ next_ = this;
+ prev_ = this;
+ }
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ InitLinkerInitialized();
+ }
+
+ void Register(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->next_ = next_;
+ s->prev_ = this;
+ next_->prev_ = s;
+ next_ = s;
+ }
+
+ void Unregister(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->prev_->next_ = s->next_;
+ s->next_->prev_ = s->prev_;
+ for (int i = 0; i < AllocatorStatCount; i++)
+ Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+ }
+
+ void Get(AllocatorStatCounters s) const {
+ internal_memset(s, 0, AllocatorStatCount * sizeof(uptr));
+ SpinMutexLock l(&mu_);
+ const AllocatorStats *stats = this;
+ for (;;) {
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] += stats->Get(AllocatorStat(i));
+ stats = stats->next_;
+ if (stats == this)
+ break;
+ }
+ // All stats must be non-negative.
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0;
+ }
+
+ private:
+ mutable SpinMutex mu_;
+};
diff --git a/libsanitizer/sanitizer_common/sanitizer_asm.h b/libsanitizer/sanitizer_common/sanitizer_asm.h
index 985f59c23c2..737ccbb716d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_asm.h
+++ b/libsanitizer/sanitizer_common/sanitizer_asm.h
@@ -40,3 +40,17 @@
# define CFI_DEF_CFA(reg, n)
# define CFI_RESTORE(reg)
#endif
+
+#if !defined(__APPLE__)
+# define ASM_HIDDEN(symbol) .hidden symbol
+# define ASM_TYPE_FUNCTION(symbol) .type symbol, @function
+# define ASM_SIZE(symbol) .size symbol, .-symbol
+# define ASM_TSAN_SYMBOL(symbol) symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) symbol
+#else
+# define ASM_HIDDEN(symbol)
+# define ASM_TYPE_FUNCTION(symbol)
+# define ASM_SIZE(symbol)
+# define ASM_TSAN_SYMBOL(symbol) _##symbol
+# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
index 4ac3b90769f..4ae87142d46 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
@@ -31,6 +31,10 @@ extern "C" long _InterlockedExchange( // NOLINT
extern "C" long _InterlockedExchangeAdd( // NOLINT
long volatile * Addend, long Value); // NOLINT
#pragma intrinsic(_InterlockedExchangeAdd)
+extern "C" char _InterlockedCompareExchange8( // NOLINT
+ char volatile *Destination, // NOLINT
+ char Exchange, char Comparand); // NOLINT
+#pragma intrinsic(_InterlockedCompareExchange8)
extern "C" short _InterlockedCompareExchange16( // NOLINT
short volatile *Destination, // NOLINT
short Exchange, short Comparand); // NOLINT
@@ -169,8 +173,6 @@ INLINE u32 atomic_exchange(volatile atomic_uint32_t *a,
return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v);
}
-#ifndef _WIN64
-
INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
u8 *cmp,
u8 xchgv,
@@ -178,6 +180,10 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
(void)mo;
DCHECK(!((uptr)a % sizeof(*a)));
u8 cmpv = *cmp;
+#ifdef _WIN64
+ u8 prev = (u8)_InterlockedCompareExchange8(
+ (volatile char*)&a->val_dont_use, (char)xchgv, (char)cmpv);
+#else
u8 prev;
__asm {
mov al, cmpv
@@ -186,14 +192,13 @@ INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
lock cmpxchg [ecx], dl
mov prev, al
}
+#endif
if (prev == cmpv)
return true;
*cmp = prev;
return false;
}
-#endif
-
INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
uptr *cmp,
uptr xchg,
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc
index 4529e63eba9..b445f613b85 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cc
@@ -10,6 +10,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_allocator_interface.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
@@ -22,13 +23,7 @@ namespace __sanitizer {
const char *SanitizerToolName = "SanitizerTool";
atomic_uint32_t current_verbosity;
-
-uptr GetPageSizeCached() {
- static uptr PageSize;
- if (!PageSize)
- PageSize = GetPageSize();
- return PageSize;
-}
+uptr PageSizeCached;
StaticSpinMutex report_file_mu;
ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
@@ -103,70 +98,13 @@ uptr stoptheworld_tracer_pid = 0;
// writing to the same log file.
uptr stoptheworld_tracer_ppid = 0;
-static const int kMaxNumOfInternalDieCallbacks = 5;
-static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
-
-bool AddDieCallback(DieCallbackType callback) {
- for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
- if (InternalDieCallbacks[i] == nullptr) {
- InternalDieCallbacks[i] = callback;
- return true;
- }
- }
- return false;
-}
-
-bool RemoveDieCallback(DieCallbackType callback) {
- for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
- if (InternalDieCallbacks[i] == callback) {
- internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
- sizeof(InternalDieCallbacks[0]) *
- (kMaxNumOfInternalDieCallbacks - i - 1));
- InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
- return true;
- }
- }
- return false;
-}
-
-static DieCallbackType UserDieCallback;
-void SetUserDieCallback(DieCallbackType callback) {
- UserDieCallback = callback;
-}
-
-void NORETURN Die() {
- if (UserDieCallback)
- UserDieCallback();
- for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
- if (InternalDieCallbacks[i])
- InternalDieCallbacks[i]();
- }
- if (common_flags()->abort_on_error)
- Abort();
- internal__exit(common_flags()->exitcode);
-}
-
-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 (%lld, %lld)\n", file, line, cond,
- v1, v2);
- Die();
-}
-
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
- const char *mmap_type, error_t err) {
+ const char *mmap_type, error_t err,
+ bool raw_report) {
static int recursion_count;
- if (recursion_count) {
+ if (raw_report || recursion_count) {
+ // If raw report is requested or we went into recursion, just die.
// The Report() and CHECK calls below may call mmap recursively and fail.
- // If we went into recursion, just die.
RawWrite("ERROR: Failed to mmap\n");
Die();
}
@@ -174,7 +112,7 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
Report("ERROR: %s failed to "
"%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
SanitizerToolName, mmap_type, size, size, mem_type, err);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
DumpProcessMap();
#endif
UNREACHABLE("unable to mmap");
@@ -217,6 +155,7 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
}
typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
+typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
template<class T>
static inline bool CompareLess(const T &a, const T &b) {
@@ -227,25 +166,8 @@ void SortArray(uptr *array, uptr size) {
InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
}
-// We want to map a chunk of address space aligned to 'alignment'.
-// We do it by maping a bit more and then unmaping redundant pieces.
-// We probably can do it with fewer syscalls in some OS-dependent way.
-void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
-// uptr PageSize = GetPageSizeCached();
- CHECK(IsPowerOfTwo(size));
- CHECK(IsPowerOfTwo(alignment));
- uptr map_size = size + alignment;
- uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
- uptr map_end = map_res + map_size;
- uptr res = map_res;
- if (res & (alignment - 1)) // Not aligned.
- res = (map_res + alignment) & ~(alignment - 1);
- uptr end = res + size;
- if (res != map_res)
- UnmapOrDie((void*)map_res, res - map_res);
- if (end != map_end)
- UnmapOrDie((void*)end, map_end - end);
- return (void*)res;
+void SortArray(u32 *array, uptr size) {
+ InternalSort<u32*, U32ComparisonFunction>(&array, size, CompareLess);
}
const char *StripPathPrefix(const char *filepath,
@@ -283,7 +205,7 @@ void ReportErrorSummary(const char *error_message) {
__sanitizer_report_error_summary(buff.data());
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
if (!common_flags()->print_summary)
return;
@@ -295,6 +217,40 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
}
#endif
+// Removes the ANSI escape sequences from the input string (in-place).
+void RemoveANSIEscapeSequencesFromString(char *str) {
+ if (!str)
+ return;
+
+ // We are going to remove the escape sequences in place.
+ char *s = str;
+ char *z = str;
+ while (*s != '\0') {
+ CHECK_GE(s, z);
+ // Skip over ANSI escape sequences with pointer 's'.
+ if (*s == '\033' && *(s + 1) == '[') {
+ s = internal_strchrnul(s, 'm');
+ if (*s == '\0') {
+ break;
+ }
+ s++;
+ continue;
+ }
+ // 's' now points at a character we want to keep. Copy over the buffer
+ // content if the escape sequence has been perviously skipped andadvance
+ // both pointers.
+ if (s != z)
+ *z = *s;
+
+ // If we have not seen an escape sequence, just advance both pointers.
+ z++;
+ s++;
+ }
+
+ // Null terminate the string.
+ *z = '\0';
+}
+
void LoadedModule::set(const char *module_name, uptr base_address) {
clear();
full_name_ = internal_strdup(module_name);
@@ -318,9 +274,8 @@ void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
}
bool LoadedModule::containsAddress(uptr address) const {
- for (Iterator iter = ranges(); iter.hasNext();) {
- const AddressRange *r = iter.next();
- if (r->beg <= address && address < r->end)
+ for (const AddressRange &r : ranges()) {
+ if (r.beg <= address && address < r.end)
return true;
}
return false;
@@ -387,6 +342,10 @@ bool TemplateMatch(const char *templ, const char *str) {
static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
char *FindPathToBinary(const char *name) {
+ if (FileExists(name)) {
+ return internal_strdup(name);
+ }
+
const char *path = GetEnv("PATH");
if (!path)
return nullptr;
@@ -451,6 +410,53 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
return name_len;
}
+void PrintCmdline() {
+ char **argv = GetArgv();
+ if (!argv) return;
+ Printf("\nCommand: ");
+ for (uptr i = 0; argv[i]; ++i)
+ Printf("%s ", argv[i]);
+ Printf("\n\n");
+}
+
+// Malloc hooks.
+static const int kMaxMallocFreeHooks = 5;
+struct MallocFreeHook {
+ void (*malloc_hook)(const void *, uptr);
+ void (*free_hook)(const void *);
+};
+
+static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
+
+void RunMallocHooks(const void *ptr, uptr size) {
+ for (int i = 0; i < kMaxMallocFreeHooks; i++) {
+ auto hook = MFHooks[i].malloc_hook;
+ if (!hook) return;
+ hook(ptr, size);
+ }
+}
+
+void RunFreeHooks(const void *ptr) {
+ for (int i = 0; i < kMaxMallocFreeHooks; i++) {
+ auto hook = MFHooks[i].free_hook;
+ if (!hook) return;
+ hook(ptr);
+ }
+}
+
+static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
+ void (*free_hook)(const void *)) {
+ if (!malloc_hook || !free_hook) return 0;
+ for (int i = 0; i < kMaxMallocFreeHooks; i++) {
+ if (MFHooks[i].malloc_hook == nullptr) {
+ MFHooks[i].malloc_hook = malloc_hook;
+ MFHooks[i].free_hook = free_hook;
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
@@ -460,6 +466,11 @@ void __sanitizer_set_report_path(const char *path) {
report_file.SetReportPath(path);
}
+void __sanitizer_set_report_fd(void *fd) {
+ report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
+ report_file.fd_pid = internal_getpid();
+}
+
void __sanitizer_report_error_summary(const char *error_summary) {
Printf("%s\n", error_summary);
}
@@ -468,4 +479,18 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_death_callback(void (*callback)(void)) {
SetUserDieCallback(callback);
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
+ uptr),
+ void (*free_hook)(const void *)) {
+ return InstallMallocFreeHooks(malloc_hook, free_hook);
+}
+
+#if !SANITIZER_GO && !SANITIZER_SUPPORTS_WEAK_HOOKS
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_print_memory_profile(int top_percent) {
+ (void)top_percent;
+}
+#endif
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 6fb2dd882aa..3e079ab7ad1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -21,7 +21,7 @@
#include "sanitizer_list.h"
#include "sanitizer_mutex.h"
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
extern "C" void _ReadWriteBarrier();
#pragma intrinsic(_ReadWriteBarrier)
#endif
@@ -42,11 +42,10 @@ const uptr kWordSizeInBits = 8 * kWordSize;
const uptr kMaxPathLength = 4096;
-// 16K loaded modules should be enough for everyone.
-static const uptr kMaxNumberOfModules = 1 << 14;
-
const uptr kMaxThreadStackSize = 1 << 30; // 1Gb
+static const uptr kErrorMessageBufferSize = 1 << 16;
+
// Denotes fake PC values that come from JIT/JAVA/etc.
// For such PC values __tsan_symbolize_external() will be called.
const u64 kExternalPCBit = 1ULL << 60;
@@ -62,7 +61,12 @@ INLINE int Verbosity() {
}
uptr GetPageSize();
-uptr GetPageSizeCached();
+extern uptr PageSizeCached;
+INLINE uptr GetPageSizeCached() {
+ if (!PageSizeCached)
+ PageSizeCached = GetPageSize();
+ return PageSizeCached;
+}
uptr GetMmapGranularity();
uptr GetMaxVirtualAddress();
// Threads
@@ -74,22 +78,30 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size);
// Memory management
-void *MmapOrDie(uptr size, const char *mem_type);
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
+INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
+ return MmapOrDie(size, mem_type, /*raw_report*/ true);
+}
void UnmapOrDie(void *addr, uptr size);
void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
const char *name = nullptr);
void *MmapNoReserveOrDie(uptr size, const char *mem_type);
void *MmapFixedOrDie(uptr fixed_addr, uptr size);
-void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr);
+void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr);
+void *MmapNoAccess(uptr size);
// Map aligned chunk of address space; size and alignment are powers of two.
void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
-// Disallow access to a memory range. Use MmapNoAccess to allocate an
+// Disallow access to a memory range. Use MmapFixedNoAccess to allocate an
// unaccessible memory.
bool MprotectNoAccess(uptr addr, uptr size);
+bool MprotectReadOnly(uptr addr, uptr size);
+
+// Find an available address space.
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding);
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
-void FlushUnneededShadowMemory(uptr addr, uptr size);
+void ReleaseMemoryToOS(uptr addr, uptr size);
void IncreaseTotalMmap(uptr size);
void DecreaseTotalMmap(uptr size);
uptr GetRSS();
@@ -97,21 +109,21 @@ void NoHugePagesInRegion(uptr addr, uptr length);
void DontDumpShadowMemory(uptr addr, uptr length);
// Check if the built VMA size matches the runtime one.
void CheckVMASize();
+void RunMallocHooks(const void *ptr, uptr size);
+void RunFreeHooks(const void *ptr);
// 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>
+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));
+ 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); }
@@ -119,9 +131,11 @@ class InternalScopedBuffer {
private:
T *ptr_;
uptr cnt_;
- // Disallow evil constructors.
- InternalScopedBuffer(const InternalScopedBuffer&);
- void operator=(const InternalScopedBuffer&);
+ // Disallow copies and moves.
+ InternalScopedBuffer(const InternalScopedBuffer &) = delete;
+ InternalScopedBuffer &operator=(const InternalScopedBuffer &) = delete;
+ InternalScopedBuffer(InternalScopedBuffer &&) = delete;
+ InternalScopedBuffer &operator=(InternalScopedBuffer &&) = delete;
};
class InternalScopedString : public InternalScopedBuffer<char> {
@@ -160,6 +174,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
// IO
void RawWrite(const char *buffer);
bool ColorizeReports();
+void RemoveANSIEscapeSequencesFromString(char *buffer);
void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
@@ -271,10 +286,27 @@ const char *GetPwd();
char *FindPathToBinary(const char *name);
bool IsPathSeparator(const char c);
bool IsAbsolutePath(const char *path);
+// Starts a subprocess and returs its pid.
+// If *_fd parameters are not kInvalidFd their corresponding input/output
+// streams will be redirect to the file. The files will always be closed
+// in parent process even in case of an error.
+// The child process will close all fds after STDERR_FILENO
+// before passing control to a program.
+pid_t StartSubprocess(const char *filename, const char *const argv[],
+ fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
+ fd_t stderr_fd = kInvalidFd);
+// Checks if specified process is still running
+bool IsProcessRunning(pid_t pid);
+// Waits for the process to finish and returns its exit code.
+// Returns -1 in case of an error.
+int WaitForProcess(pid_t pid);
u32 GetUid();
void ReExec();
+char **GetArgv();
+void PrintCmdline();
bool StackSizeIsUnlimited();
+uptr GetStackSizeLimitInBytes();
void SetStackSizeLimitInBytes(uptr limit);
bool AddressSpaceIsUnlimited();
void SetAddressSpaceUnlimited();
@@ -299,6 +331,7 @@ void SleepForMillis(int millis);
u64 NanoTime();
int Atexit(void (*function)(void));
void SortArray(uptr *array, uptr size);
+void SortArray(u32 *array, uptr size);
bool TemplateMatch(const char *templ, const char *str);
// Exit
@@ -307,7 +340,8 @@ void NORETURN Die();
void NORETURN
CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
- const char *mmap_type, error_t err);
+ const char *mmap_type, error_t err,
+ bool raw_report = false);
// Set the name of the current thread to 'name', return true on succees.
// The name may be truncated to a system-dependent limit.
@@ -339,9 +373,15 @@ void SetCheckFailedCallback(CheckFailedCallbackType callback);
// The callback should be registered once at the tool init time.
void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
+// Callback to be called when we want to try releasing unused allocator memory
+// back to the OS.
+typedef void (*AllocatorReleaseToOSCallback)();
+// The callback should be registered once at the tool init time.
+void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback);
+
// Functions related to signal handling.
typedef void (*SignalHandlerType)(int, void *, void *);
-bool IsDeadlySignal(int signum);
+bool IsHandledDeadlySignal(int signum);
void InstallDeadlySignalHandlers(SignalHandlerType handler);
// Alternative signal stack (POSIX-only).
void SetAlternateSignalStack();
@@ -357,7 +397,7 @@ void ReportErrorSummary(const char *error_message);
// error_type file:line[:column][ function]
void ReportErrorSummary(const char *error_type, const AddressInfo &info);
// Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
-void ReportErrorSummary(const char *error_type, StackTrace *trace);
+void ReportErrorSummary(const char *error_type, const StackTrace *trace);
// Math
#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
@@ -414,13 +454,13 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) {
if (IsPowerOfTwo(size)) return size;
uptr up = MostSignificantSetBitIndex(size);
- CHECK(size < (1ULL << (up + 1)));
- CHECK(size > (1ULL << up));
+ CHECK_LT(size, (1ULL << (up + 1)));
+ CHECK_GT(size, (1ULL << up));
return 1ULL << (up + 1);
}
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
- CHECK(IsPowerOfTwo(boundary));
+ RAW_CHECK(IsPowerOfTwo(boundary));
return (size + boundary - 1) & ~(boundary - 1);
}
@@ -487,7 +527,7 @@ class InternalMmapVectorNoCtor {
uptr new_capacity = RoundUpToPowerOfTwo(size_ + 1);
Resize(new_capacity);
}
- data_[size_++] = element;
+ internal_memcpy(&data_[size_++], &element, sizeof(T));
}
T &back() {
CHECK_GT(size_, 0);
@@ -513,6 +553,19 @@ class InternalMmapVectorNoCtor {
void clear() { size_ = 0; }
bool empty() const { return size() == 0; }
+ const T *begin() const {
+ return data();
+ }
+ T *begin() {
+ return data();
+ }
+ const T *end() const {
+ return data() + size();
+ }
+ T *end() {
+ return data() + size();
+ }
+
private:
void Resize(uptr new_capacity) {
CHECK_GT(new_capacity, 0);
@@ -619,8 +672,7 @@ class LoadedModule {
: next(nullptr), beg(beg), end(end), executable(executable) {}
};
- typedef IntrusiveList<AddressRange>::ConstIterator Iterator;
- Iterator ranges() const { return Iterator(&ranges_); }
+ const IntrusiveList<AddressRange> &ranges() const { return ranges_; }
private:
char *full_name_; // Owned.
@@ -628,13 +680,33 @@ class LoadedModule {
IntrusiveList<AddressRange> ranges_;
};
-// OS-dependent function that fills array with descriptions of at most
-// "max_modules" currently loaded modules. Returns the number of
-// initialized modules. If filter is nonzero, ignores modules for which
-// filter(full_name) is false.
-typedef bool (*string_predicate_t)(const char *);
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter);
+// List of LoadedModules. OS-dependent implementation is responsible for
+// filling this information.
+class ListOfModules {
+ public:
+ ListOfModules() : modules_(kInitialCapacity) {}
+ ~ListOfModules() { clear(); }
+ void init();
+ const LoadedModule *begin() const { return modules_.begin(); }
+ LoadedModule *begin() { return modules_.begin(); }
+ const LoadedModule *end() const { return modules_.end(); }
+ LoadedModule *end() { return modules_.end(); }
+ uptr size() const { return modules_.size(); }
+ const LoadedModule &operator[](uptr i) const {
+ CHECK_LT(i, modules_.size());
+ return modules_[i];
+ }
+
+ private:
+ void clear() {
+ for (auto &module : modules_) module.clear();
+ modules_.clear();
+ }
+
+ InternalMmapVector<LoadedModule> modules_;
+ // We rarely have more than 16K loaded modules.
+ static const uptr kInitialCapacity = 1 << 14;
+};
// Callback type for iterating over a set of memory ranges.
typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
@@ -646,22 +718,34 @@ enum AndroidApiLevel {
ANDROID_POST_LOLLIPOP = 23
};
+void WriteToSyslog(const char *buffer);
+
+#if SANITIZER_MAC
+void LogFullErrorReport(const char *buffer);
+#else
+INLINE void LogFullErrorReport(const char *buffer) {}
+#endif
+
+#if SANITIZER_LINUX || SANITIZER_MAC
+void WriteOneLineToSyslog(const char *s);
+void LogMessageOnPrintf(const char *str);
+#else
+INLINE void WriteOneLineToSyslog(const char *s) {}
+INLINE void LogMessageOnPrintf(const char *str) {}
+#endif
+
#if SANITIZER_LINUX
// Initialize Android logging. Any writes before this are silently lost.
void AndroidLogInit();
-void WriteToSyslog(const char *buffer);
#else
INLINE void AndroidLogInit() {}
-INLINE void WriteToSyslog(const char *buffer) {}
#endif
#if SANITIZER_ANDROID
-void GetExtraActivationFlags(char *buf, uptr size);
void SanitizerInitializeUnwinder();
AndroidApiLevel AndroidGetApiLevel();
#else
INLINE void AndroidLogWrite(const char *buffer_unused) {}
-INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; }
INLINE void SanitizerInitializeUnwinder() {}
INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; }
#endif
@@ -686,7 +770,7 @@ void MaybeStartBackgroudThread();
// compiler from recognising it and turning it into an actual call to
// memset/memcpy/etc.
static inline void SanitizerBreakOptimization(void *arg) {
-#if _MSC_VER && !defined(__clang__)
+#if defined(_MSC_VER) && !defined(__clang__)
_ReadWriteBarrier();
#else
__asm__ __volatile__("" : : "r" (arg) : "memory");
@@ -699,27 +783,68 @@ struct SignalContext {
uptr pc;
uptr sp;
uptr bp;
+ bool is_memory_access;
- SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp) :
- context(context), addr(addr), pc(pc), sp(sp), bp(bp) {
- }
+ enum WriteFlag { UNKNOWN, READ, WRITE } write_flag;
+
+ SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp,
+ bool is_memory_access, WriteFlag write_flag)
+ : context(context),
+ addr(addr),
+ pc(pc),
+ sp(sp),
+ bp(bp),
+ is_memory_access(is_memory_access),
+ write_flag(write_flag) {}
// Creates signal context in a platform-specific manner.
static SignalContext Create(void *siginfo, void *context);
+
+ // Returns true if the "context" indicates a memory write.
+ static WriteFlag GetWriteFlag(void *context);
};
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
-} // namespace __sanitizer
+void MaybeReexec();
-inline void *operator new(__sanitizer::operator_new_size_type size,
- __sanitizer::LowLevelAllocator &alloc) {
- return alloc.Allocate(size);
+template <typename Fn>
+class RunOnDestruction {
+ public:
+ explicit RunOnDestruction(Fn fn) : fn_(fn) {}
+ ~RunOnDestruction() { fn_(); }
+
+ private:
+ Fn fn_;
+};
+
+// A simple scope guard. Usage:
+// auto cleanup = at_scope_exit([]{ do_cleanup; });
+template <typename Fn>
+RunOnDestruction<Fn> at_scope_exit(Fn fn) {
+ return RunOnDestruction<Fn>(fn);
}
+// Linux on 64-bit s390 had a nasty bug that crashes the whole machine
+// if a process uses virtual memory over 4TB (as many sanitizers like
+// to do). This function will abort the process if running on a kernel
+// that looks vulnerable.
+#if SANITIZER_LINUX && SANITIZER_S390_64
+void AvoidCVE_2016_2143();
+#else
+INLINE void AvoidCVE_2016_2143() {}
+#endif
+
struct StackDepotStats {
uptr n_uniq_ids;
uptr allocated;
};
+} // namespace __sanitizer
+
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ __sanitizer::LowLevelAllocator &alloc) {
+ return alloc.Allocate(size);
+}
+
#endif // SANITIZER_COMMON_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 8223778cac4..38390ed9621 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -9,7 +9,7 @@
// ThreadSanitizer, MemorySanitizer, etc.
//
// This file should be included into the tool's interceptor file,
-// which has to define it's own macros:
+// which has to define its own macros:
// COMMON_INTERCEPTOR_ENTER
// COMMON_INTERCEPTOR_ENTER_NOIGNORE
// COMMON_INTERCEPTOR_READ_RANGE
@@ -89,6 +89,10 @@
#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
#endif
+#ifndef COMMON_INTERCEPTOR_MUTEX_INVALID
+#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) {}
+#endif
+
#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
#endif
@@ -141,6 +145,22 @@
#define COMMON_INTERCEPTOR_RELEASE(ctx, u) {}
#endif
+#ifndef COMMON_INTERCEPTOR_USER_CALLBACK_START
+#define COMMON_INTERCEPTOR_USER_CALLBACK_START() {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_USER_CALLBACK_END
+#define COMMON_INTERCEPTOR_USER_CALLBACK_END() {}
+#endif
+
+#ifdef SANITIZER_NLDBL_VERSION
+#define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \
+ COMMON_INTERCEPT_FUNCTION_VER(fn, SANITIZER_NLDBL_VERSION)
+#else
+#define COMMON_INTERCEPT_FUNCTION_LDBL(fn) \
+ COMMON_INTERCEPT_FUNCTION(fn)
+#endif
+
struct FileMetadata {
// For open_memstream().
char **addr;
@@ -190,6 +210,40 @@ UNUSED static void DeleteInterceptorMetadata(void *addr) {
}
#endif // SI_NOT_WINDOWS
+#if SANITIZER_INTERCEPT_STRLEN
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+ // Sometimes strlen is called prior to InitializeCommonInterceptors,
+ // in which case the REAL(strlen) typically used in
+ // COMMON_INTERCEPTOR_ENTER will fail. We use internal_strlen here
+ // to handle that.
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strlen(s);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strlen, s);
+ SIZE_T result = REAL(strlen)(s);
+ if (common_flags()->intercept_strlen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, result + 1);
+ return result;
+}
+#define INIT_STRLEN COMMON_INTERCEPT_FUNCTION(strlen)
+#else
+#define INIT_STRLEN
+#endif
+
+#if SANITIZER_INTERCEPT_STRNLEN
+INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strnlen, s, maxlen);
+ SIZE_T length = REAL(strnlen)(s, maxlen);
+ if (common_flags()->intercept_strlen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, Min(length + 1, maxlen));
+ return length;
+}
+#define INIT_STRNLEN COMMON_INTERCEPT_FUNCTION(strnlen)
+#else
+#define INIT_STRNLEN
+#endif
+
#if SANITIZER_INTERCEPT_TEXTDOMAIN
INTERCEPTOR(char*, textdomain, const char *domainname) {
void *ctx;
@@ -212,13 +266,11 @@ static inline int CharCmpX(unsigned char c1, unsigned char c2) {
}
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc,
- const char *s1, const char *s2)
+ const char *s1, const char *s2, int result)
INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
- CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
- s2);
unsigned char c1, c2;
uptr i;
for (i = 0;; i++) {
@@ -228,19 +280,21 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
}
COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
- return CharCmpX(c1, c2);
+ int result = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1,
+ s2, result);
+ return result;
}
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc,
- const char *s1, const char *s2, uptr n)
+ const char *s1, const char *s2, uptr n,
+ int result)
INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strncmp(s1, s2, size);
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size);
- CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
- s2, size);
unsigned char c1 = 0, c2 = 0;
uptr i;
for (i = 0; i < size; i++) {
@@ -248,9 +302,12 @@ INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
c2 = (unsigned char)s2[i];
if (c1 != c2 || c1 == '\0') break;
}
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
- return CharCmpX(c1, c2);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, Min(i + 1, size));
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s2, Min(i + 1, size));
+ int result = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
+ s2, size, result);
+ return result;
}
#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
@@ -267,6 +324,9 @@ static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
return c1_low - c2_low;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, uptr called_pc,
+ const char *s1, const char *s2, int result)
+
INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
@@ -279,9 +339,16 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
}
COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1);
COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1);
- return CharCaseCmp(c1, c2);
+ int result = CharCaseCmp(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, GET_CALLER_PC(),
+ s1, s2, result);
+ return result;
}
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc,
+ const char *s1, const char *s2, uptr n,
+ int result)
+
INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
@@ -294,7 +361,10 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
- return CharCaseCmp(c1, c2);
+ int result = CharCaseCmp(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, GET_CALLER_PC(),
+ s1, s2, n, result);
+ return result;
}
#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
@@ -316,6 +386,10 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1,
#endif
#if SANITIZER_INTERCEPT_STRSTR
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, uptr called_pc,
+ const char *s1, const char *s2, char *result)
+
INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strstr(s1, s2);
@@ -324,6 +398,8 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
char *r = REAL(strstr)(s1, s2);
if (common_flags()->intercept_strstr)
StrstrCheck(ctx, r, s1, s2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, GET_CALLER_PC(), s1,
+ s2, r);
return r;
}
@@ -333,12 +409,18 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
#endif
#if SANITIZER_INTERCEPT_STRCASESTR
+
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, uptr called_pc,
+ const char *s1, const char *s2, char *result)
+
INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2);
char *r = REAL(strcasestr)(s1, s2);
if (common_flags()->intercept_strstr)
StrstrCheck(ctx, r, s1, s2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, GET_CALLER_PC(),
+ s1, s2, r);
return r;
}
@@ -347,6 +429,79 @@ INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
#define INIT_STRCASESTR
#endif
+#if SANITIZER_INTERCEPT_MEMMEM
+DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc,
+ const void *s1, SIZE_T len1, const void *s2,
+ SIZE_T len2, void *result)
+
+INTERCEPTOR(void*, memmem, const void *s1, SIZE_T len1, const void *s2,
+ SIZE_T len2) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memmem, s1, len1, s2, len2);
+ void *r = REAL(memmem)(s1, len1, s2, len2);
+ if (common_flags()->intercept_memmem) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, len1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2);
+ }
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, GET_CALLER_PC(),
+ s1, len1, s2, len2, r);
+ return r;
+}
+
+#define INIT_MEMMEM COMMON_INTERCEPT_FUNCTION(memmem);
+#else
+#define INIT_MEMMEM
+#endif // SANITIZER_INTERCEPT_MEMMEM
+
+#if SANITIZER_INTERCEPT_STRCHR
+INTERCEPTOR(char*, strchr, const char *s, int c) {
+ void *ctx;
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strchr(s, c);
+ COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c);
+ char *result = REAL(strchr)(s, c);
+ uptr len = internal_strlen(s);
+ uptr n = result ? result - s + 1 : len + 1;
+ if (common_flags()->intercept_strchr)
+ COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n);
+ return result;
+}
+#define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr)
+#else
+#define INIT_STRCHR
+#endif
+
+#if SANITIZER_INTERCEPT_STRCHRNUL
+INTERCEPTOR(char*, strchrnul, const char *s, int c) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strchrnul, s, c);
+ char *result = REAL(strchrnul)(s, c);
+ uptr len = result - s + 1;
+ if (common_flags()->intercept_strchr)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s, len);
+ return result;
+}
+#define INIT_STRCHRNUL COMMON_INTERCEPT_FUNCTION(strchrnul)
+#else
+#define INIT_STRCHRNUL
+#endif
+
+#if SANITIZER_INTERCEPT_STRRCHR
+INTERCEPTOR(char*, strrchr, const char *s, int c) {
+ void *ctx;
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_strrchr(s, c);
+ COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c);
+ uptr len = internal_strlen(s);
+ if (common_flags()->intercept_strchr)
+ COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1);
+ return REAL(strrchr)(s, c);
+}
+#define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr)
+#else
+#define INIT_STRRCHR
+#endif
+
#if SANITIZER_INTERCEPT_STRSPN
INTERCEPTOR(SIZE_T, strspn, const char *s1, const char *s2) {
void *ctx;
@@ -395,18 +550,75 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) {
#define INIT_STRPBRK
#endif
+#if SANITIZER_INTERCEPT_MEMSET
+INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memset(dst, v, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size);
+ if (common_flags()->intercept_intrin)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
+ return REAL(memset)(dst, v, size);
+}
+
+#define INIT_MEMSET COMMON_INTERCEPT_FUNCTION(memset)
+#else
+#define INIT_MEMSET
+#endif
+
+#if SANITIZER_INTERCEPT_MEMMOVE
+INTERCEPTOR(void*, memmove, void *dst, const void *src, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+ return internal_memmove(dst, src, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size);
+ if (common_flags()->intercept_intrin) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size);
+ }
+ return REAL(memmove)(dst, src, size);
+}
+
+#define INIT_MEMMOVE COMMON_INTERCEPT_FUNCTION(memmove)
+#else
+#define INIT_MEMMOVE
+#endif
+
+#if SANITIZER_INTERCEPT_MEMCPY
+INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
+ // On OS X, calling internal_memcpy here will cause memory corruptions,
+ // because memcpy and memmove are actually aliases of the same
+ // implementation. We need to use internal_memmove here.
+ return internal_memmove(dst, src, size);
+ }
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size);
+ if (common_flags()->intercept_intrin) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size);
+ }
+ // N.B.: If we switch this to internal_ we'll have to use internal_memmove
+ // due to memcpy being an alias of memmove on OS X.
+ return REAL(memcpy)(dst, src, size);
+}
+
+#define INIT_MEMCPY COMMON_INTERCEPT_FUNCTION(memcpy)
+#else
+#define INIT_MEMCPY
+#endif
+
#if SANITIZER_INTERCEPT_MEMCMP
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc,
- const void *s1, const void *s2, uptr n)
+ const void *s1, const void *s2, uptr n,
+ int result)
INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_memcmp(a1, a2, size);
- CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1,
- a2, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size);
if (common_flags()->intercept_memcmp) {
if (common_flags()->strict_memcmp) {
// Check the entire regions even if the first bytes of the buffers are
@@ -426,10 +638,16 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) {
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size));
- return CharCmpX(c1, c2);
+ int r = CharCmpX(c1, c2);
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(),
+ a1, a2, size, r);
+ return r;
}
}
- return REAL(memcmp(a1, a2, size));
+ int result = REAL(memcmp(a1, a2, size));
+ CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1,
+ a2, size, result);
+ return result;
}
#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp)
@@ -443,7 +661,16 @@ INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) {
return internal_memchr(s, c, n);
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n);
+#if SANITIZER_WINDOWS
+ void *res;
+ if (REAL(memchr)) {
+ res = REAL(memchr)(s, c, n);
+ } else {
+ res = internal_memchr(s, c, n);
+ }
+#else
void *res = REAL(memchr)(s, c, n);
+#endif
uptr len = res ? (char *)res - (const char *)s + 1 : n;
COMMON_INTERCEPTOR_READ_RANGE(ctx, s, len);
return res;
@@ -488,7 +715,7 @@ INTERCEPTOR(float, frexpf, float x, int *exp) {
COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(frexpf)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -499,7 +726,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(frexpl)(x, exp);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp));
return res;
@@ -507,7 +734,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
#define INIT_FREXPF_FREXPL \
COMMON_INTERCEPT_FUNCTION(frexpf); \
- COMMON_INTERCEPT_FUNCTION(frexpl)
+ COMMON_INTERCEPT_FUNCTION_LDBL(frexpl)
#else
#define INIT_FREXPF_FREXPL
#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
@@ -540,7 +767,7 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(read)(fd, ptr, count);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -558,7 +785,7 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -576,7 +803,7 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -823,7 +1050,7 @@ INTERCEPTOR(char *, ctime, unsigned long *timep) {
COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ctime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -836,7 +1063,7 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ctime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
@@ -849,7 +1076,7 @@ INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(asctime)(tm);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -862,7 +1089,7 @@ INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(asctime_r)(tm, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
@@ -906,7 +1133,7 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(strptime)(s, format, tm);
COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0);
if (res && tm) {
@@ -1043,7 +1270,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
@@ -1060,7 +1287,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
@@ -1077,7 +1304,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
// FIXME: under ASan the REAL() call below may write to freed memory and
// corrupt its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
{ \
VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
@@ -1362,7 +1589,7 @@ INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd,
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_passwd(ctx, *result);
@@ -1377,7 +1604,7 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_passwd(ctx, *result);
@@ -1393,7 +1620,7 @@ INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp,
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrnam_r)(name, grp, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_group(ctx, *result);
@@ -1408,7 +1635,7 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
if (!res) {
if (result && *result) unpoison_group(ctx, *result);
@@ -1477,7 +1704,7 @@ INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
@@ -1492,7 +1719,7 @@ INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp);
@@ -1507,7 +1734,7 @@ INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen,
COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
@@ -1522,7 +1749,7 @@ INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf,
COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp);
if (!res) {
if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp);
@@ -1579,7 +1806,7 @@ INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(clock_getres)(clk_id, tp);
if (!res && tp) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -1591,7 +1818,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(clock_gettime)(clk_id, tp);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz);
@@ -1618,7 +1845,7 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) {
COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getitimer)(which, curr_value);
if (!res && curr_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz);
@@ -1632,7 +1859,7 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(setitimer)(which, new_value, old_value);
if (!res && old_value) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz);
@@ -1689,16 +1916,19 @@ static int wrapped_gl_stat(const char *s, void *st) {
return pglob_copy->gl_stat(s, st);
}
+static const __sanitizer_glob_t kGlobCopy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+
INTERCEPTOR(int, glob, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
- __sanitizer_glob_t glob_copy = {
- 0, 0, 0,
- 0, wrapped_gl_closedir, wrapped_gl_readdir,
- wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -1726,10 +1956,8 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
- __sanitizer_glob_t glob_copy = {
- 0, 0, 0,
- 0, wrapped_gl_closedir, wrapped_gl_readdir,
- wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy;
+ internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy));
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -1766,7 +1994,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
COMMON_INTERCEPTOR_ENTER(ctx, wait, status);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait)(status);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1784,7 +2012,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(waitid)(idtype, id, infop, options);
if (res != -1 && infop)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
@@ -1795,7 +2023,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(waitpid)(pid, status, options);
if (res != -1 && status)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1806,7 +2034,7 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait3)(status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1820,7 +2048,7 @@ INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(__wait4)(pid, status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1835,7 +2063,7 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wait4)(pid, status, options, rusage);
if (res != -1) {
if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
@@ -1864,7 +2092,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
// FIXME: figure out read size based on the address family.
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(inet_ntop)(af, src, dst, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -1876,7 +2104,7 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
// FIXME: figure out read size based on the address family.
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(inet_pton)(af, src, dst);
if (res == 1) {
uptr sz = __sanitizer_in_addr_sz(af);
@@ -1898,7 +2126,7 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(inet_aton)(cp, dst);
if (res != 0) {
uptr sz = __sanitizer_in_addr_sz(af_inet);
@@ -1917,7 +2145,7 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_getschedparam)(thread, policy, param);
if (res == 0) {
if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy));
@@ -1944,7 +2172,7 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getaddrinfo)(node, service, hints, out);
if (res == 0 && out) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out));
@@ -1976,7 +2204,7 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
// There is padding in in_addr that may make this too noisy
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags);
if (res == 0) {
@@ -2000,7 +2228,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
int addrlen_in = *addrlen;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getsockname)(sock_fd, addr, addrlen);
if (res == 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen));
@@ -2086,7 +2314,7 @@ INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop);
if (result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2109,7 +2337,7 @@ INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf,
h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop);
if (result) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2135,7 +2363,7 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type,
COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result,
h_errnop);
if (result) {
@@ -2161,7 +2389,7 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
result, h_errnop);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop);
if (result) {
@@ -2187,7 +2415,7 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen);
if (res == 0)
if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
@@ -2231,7 +2459,7 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int fd2 = REAL(accept4)(fd, addr, addrlen, f);
if (fd2 >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
@@ -2251,7 +2479,7 @@ INTERCEPTOR(double, modf, double x, double *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(modf)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2263,7 +2491,7 @@ INTERCEPTOR(float, modff, float x, float *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(modff)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2275,7 +2503,7 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(modfl)(x, iptr);
if (iptr) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr));
@@ -2285,7 +2513,7 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
#define INIT_MODF \
COMMON_INTERCEPT_FUNCTION(modf); \
COMMON_INTERCEPT_FUNCTION(modff); \
- COMMON_INTERCEPT_FUNCTION(modfl);
+ COMMON_INTERCEPT_FUNCTION_LDBL(modfl);
#else
#define INIT_MODF
#endif
@@ -2310,7 +2538,7 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
if (res >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
@@ -2326,6 +2554,75 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
#define INIT_RECVMSG
#endif
+#if SANITIZER_INTERCEPT_SENDMSG
+static void read_msghdr_control(void *ctx, void *control, uptr controllen) {
+ const unsigned kCmsgDataOffset =
+ RoundUpTo(sizeof(__sanitizer_cmsghdr), sizeof(uptr));
+
+ char *p = (char *)control;
+ char *const control_end = p + controllen;
+ while (true) {
+ if (p + sizeof(__sanitizer_cmsghdr) > control_end) break;
+ __sanitizer_cmsghdr *cmsg = (__sanitizer_cmsghdr *)p;
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_len, sizeof(cmsg->cmsg_len));
+
+ if (p + RoundUpTo(cmsg->cmsg_len, sizeof(uptr)) > control_end) break;
+
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_level,
+ sizeof(cmsg->cmsg_level));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &cmsg->cmsg_type,
+ sizeof(cmsg->cmsg_type));
+
+ if (cmsg->cmsg_len > kCmsgDataOffset) {
+ char *data = p + kCmsgDataOffset;
+ unsigned data_len = cmsg->cmsg_len - kCmsgDataOffset;
+ if (data_len > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, data_len);
+ }
+
+ p += RoundUpTo(cmsg->cmsg_len, sizeof(uptr));
+ }
+}
+
+static void read_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
+ SSIZE_T maxlen) {
+#define R(f) \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, &msg->msg_##f, sizeof(msg->msg_##f))
+ R(name);
+ R(namelen);
+ R(iov);
+ R(iovlen);
+ R(control);
+ R(controllen);
+ R(flags);
+#undef R
+ if (msg->msg_name && msg->msg_namelen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_name, msg->msg_namelen);
+ if (msg->msg_iov && msg->msg_iovlen)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, msg->msg_iov,
+ sizeof(*msg->msg_iov) * msg->msg_iovlen);
+ read_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
+ if (msg->msg_control && msg->msg_controllen)
+ read_msghdr_control(ctx, msg->msg_control, msg->msg_controllen);
+}
+
+INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg,
+ int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sendmsg, fd, msg, flags);
+ if (fd >= 0) {
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ }
+ SSIZE_T res = REAL(sendmsg)(fd, msg, flags);
+ if (common_flags()->intercept_send && res >= 0 && msg)
+ read_msghdr(ctx, msg, res);
+ return res;
+}
+#define INIT_SENDMSG COMMON_INTERCEPT_FUNCTION(sendmsg);
+#else
+#define INIT_SENDMSG
+#endif
+
#if SANITIZER_INTERCEPT_GETPEERNAME
INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
void *ctx;
@@ -2334,7 +2631,7 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
if (addrlen) addr_sz = *addrlen;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getpeername)(sockfd, addr, addrlen);
if (!res && addr && addrlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
@@ -2350,7 +2647,7 @@ INTERCEPTOR(int, sysinfo, void *info) {
void *ctx;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info);
int res = REAL(sysinfo)(info);
if (!res && info)
@@ -2378,7 +2675,7 @@ INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_dirent *res = REAL(readdir)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -2390,7 +2687,7 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(readdir_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2414,7 +2711,7 @@ INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_dirent64 *res = REAL(readdir64)(dirp);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
@@ -2426,7 +2723,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(readdir64_r)(dirp, entry, result);
if (!res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -2473,7 +2770,7 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
uptr res = REAL(ptrace)(request, pid, addr, data);
if (!res && data) {
@@ -2528,7 +2825,7 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(getcwd)(buf, size);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -2544,7 +2841,7 @@ INTERCEPTOR(char *, get_current_dir_name, int fake) {
COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(get_current_dir_name)(fake);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -2593,7 +2890,7 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) {
COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *real_endptr;
INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base);
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
@@ -2605,7 +2902,7 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *real_endptr;
INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base);
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
@@ -2625,7 +2922,7 @@ INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbstowcs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -2642,7 +2939,7 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
if (res != (SIZE_T)(-1) && dest && src) {
// This function, and several others, may or may not write the terminating
@@ -2672,7 +2969,7 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
if (res != (SIZE_T)(-1) && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -2692,7 +2989,7 @@ INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcstombs)(dest, src, len);
if (res != (SIZE_T) - 1 && dest) {
SIZE_T write_cnt = res + (res < len);
@@ -2709,7 +3006,7 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
if (res != (SIZE_T) - 1 && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -2737,7 +3034,7 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
if (res != ((SIZE_T)-1) && dest && src) {
SIZE_T write_cnt = res + !*src;
@@ -2759,7 +3056,7 @@ INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(wcrtomb)(dest, src, ps);
if (res != ((SIZE_T)-1) && dest) {
SIZE_T write_cnt = res;
@@ -2779,7 +3076,7 @@ INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(tcgetattr)(fd, termios_p);
if (!res && termios_p)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz);
@@ -2836,7 +3133,7 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(confstr)(name, buf, len);
if (buf && res)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
@@ -2853,7 +3150,7 @@ INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
return res;
@@ -2895,7 +3192,7 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(strerror_r)(errnum, buf, buflen);
// There are 2 versions of strerror_r:
// * POSIX version returns 0 on success, negative error code on failure,
@@ -2926,7 +3223,7 @@ INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
// This version always returns a null-terminated string.
if (buf && buflen)
@@ -2971,7 +3268,7 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
scandir_compar = compar;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(scandir)(dirp, namelist,
filter ? wrapped_scandir_filter : nullptr,
compar ? wrapped_scandir_compar : nullptr);
@@ -3024,7 +3321,7 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
scandir64_compar = compar;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res =
REAL(scandir64)(dirp, namelist,
filter ? wrapped_scandir64_filter : nullptr,
@@ -3051,7 +3348,7 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) {
COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getgroups)(size, lst);
if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
return res;
@@ -3117,7 +3414,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(wordexp)(s, p, flags);
if (!res && p) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -3143,7 +3440,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigwait)(set, sig);
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
return res;
@@ -3160,7 +3457,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigwaitinfo)(set, info);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -3179,7 +3476,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigtimedwait)(set, info, timeout);
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
@@ -3195,7 +3492,7 @@ INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigemptyset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3206,7 +3503,7 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigfillset)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3224,7 +3521,7 @@ INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigpending)(set);
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
@@ -3242,7 +3539,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
// FIXME: read sigset_t when all of sigemptyset, etc are intercepted
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(sigprocmask)(how, set, oldset);
if (!res && oldset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
@@ -3259,7 +3556,7 @@ INTERCEPTOR(int, backtrace, void **buffer, int size) {
COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(backtrace)(buffer, size);
if (res && buffer)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer));
@@ -3273,7 +3570,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char **res = REAL(backtrace_symbols)(buffer, size);
if (res && size) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
@@ -3293,7 +3590,9 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
INTERCEPTOR(void, _exit, int status) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, _exit, status);
+ COMMON_INTERCEPTOR_USER_CALLBACK_START();
int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx);
+ COMMON_INTERCEPTOR_USER_CALLBACK_END();
if (status == 0) status = status1;
REAL(_exit)(status);
}
@@ -3311,6 +3610,8 @@ INTERCEPTOR(int, pthread_mutex_lock, void *m) {
COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
if (res == 0 || res == errno_EOWNERDEAD)
COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ if (res == errno_EINVAL)
+ COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
return res;
}
@@ -3318,7 +3619,10 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
- return REAL(pthread_mutex_unlock)(m);
+ int res = REAL(pthread_mutex_unlock)(m);
+ if (res == errno_EINVAL)
+ COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
+ return res;
}
#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
@@ -3381,7 +3685,7 @@ INTERCEPTOR(int, statfs, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -3391,7 +3695,7 @@ INTERCEPTOR(int, fstatfs, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
return res;
@@ -3410,7 +3714,7 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -3420,7 +3724,7 @@ INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
return res;
@@ -3439,7 +3743,7 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statvfs)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -3449,7 +3753,7 @@ INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatvfs)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
return res;
@@ -3468,7 +3772,7 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(statvfs64)(path, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -3478,7 +3782,7 @@ INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(fstatvfs64)(fd, buf);
if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
return res;
@@ -3534,7 +3838,7 @@ INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_ntohost)(hostname, addr);
if (!res && hostname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
@@ -3547,7 +3851,7 @@ INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_hostton)(hostname, addr);
if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
return res;
@@ -3559,7 +3863,7 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ether_line)(line, addr, hostname);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -3583,7 +3887,7 @@ INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(ether_ntoa_r)(addr, buf);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
@@ -3595,7 +3899,7 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
return res;
@@ -3613,7 +3917,7 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(shmctl)(shmid, cmd, buf);
if (res >= 0) {
unsigned sz = 0;
@@ -3638,7 +3942,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(random_r)(buf, result);
if (!res && result)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
@@ -3651,7 +3955,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) {
// FIXME: under ASan the REAL() call below may write to freed memory and corrupt
// its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \
SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \
@@ -3690,7 +3994,7 @@ INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_attr_getstack)(attr, addr, size);
if (!res) {
if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
@@ -3739,7 +4043,7 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
cpuset);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
if (!res && cpusetsize && cpuset)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
@@ -3849,7 +4153,7 @@ INTERCEPTOR(char *, tmpnam, char *s) {
if (s)
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
else
COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
@@ -3867,7 +4171,7 @@ INTERCEPTOR(char *, tmpnam_r, char *s) {
COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(tmpnam_r)(s);
if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
return res;
@@ -3877,6 +4181,20 @@ INTERCEPTOR(char *, tmpnam_r, char *s) {
#define INIT_TMPNAM_R
#endif
+#if SANITIZER_INTERCEPT_TTYNAME_R
+INTERCEPTOR(int, ttyname_r, int fd, char *name, SIZE_T namesize) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ttyname_r, fd, name, namesize);
+ int res = REAL(ttyname_r)(fd, name, namesize);
+ if (res == 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, REAL(strlen)(name) + 1);
+ return res;
+}
+#define INIT_TTYNAME_R COMMON_INTERCEPT_FUNCTION(ttyname_r);
+#else
+#define INIT_TTYNAME_R
+#endif
+
#if SANITIZER_INTERCEPT_TEMPNAM
INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
void *ctx;
@@ -3911,7 +4229,7 @@ INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincos)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3921,7 +4239,7 @@ INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincosf)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3931,7 +4249,7 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(sincosl)(x, sin, cos);
if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
@@ -3939,7 +4257,7 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
#define INIT_SINCOS \
COMMON_INTERCEPT_FUNCTION(sincos); \
COMMON_INTERCEPT_FUNCTION(sincosf); \
- COMMON_INTERCEPT_FUNCTION(sincosl);
+ COMMON_INTERCEPT_FUNCTION_LDBL(sincosl);
#else
#define INIT_SINCOS
#endif
@@ -3950,7 +4268,7 @@ INTERCEPTOR(double, remquo, double x, double y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(remquo)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3960,7 +4278,7 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(remquof)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3970,7 +4288,7 @@ INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(remquol)(x, y, quo);
if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
return res;
@@ -3978,7 +4296,7 @@ INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
#define INIT_REMQUO \
COMMON_INTERCEPT_FUNCTION(remquo); \
COMMON_INTERCEPT_FUNCTION(remquof); \
- COMMON_INTERCEPT_FUNCTION(remquol);
+ COMMON_INTERCEPT_FUNCTION_LDBL(remquol);
#else
#define INIT_REMQUO
#endif
@@ -4009,7 +4327,7 @@ INTERCEPTOR(long double, lgammal, long double x) {
#define INIT_LGAMMA \
COMMON_INTERCEPT_FUNCTION(lgamma); \
COMMON_INTERCEPT_FUNCTION(lgammaf); \
- COMMON_INTERCEPT_FUNCTION(lgammal);
+ COMMON_INTERCEPT_FUNCTION_LDBL(lgammal);
#else
#define INIT_LGAMMA
#endif
@@ -4020,7 +4338,7 @@ INTERCEPTOR(double, lgamma_r, double x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
double res = REAL(lgamma_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -4030,7 +4348,7 @@ INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
float res = REAL(lgammaf_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
@@ -4048,12 +4366,12 @@ INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
long double res = REAL(lgammal_r)(x, signp);
if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
return res;
}
-#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION(lgammal_r);
+#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION_LDBL(lgammal_r);
#else
#define INIT_LGAMMAL_R
#endif
@@ -4064,7 +4382,7 @@ INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(drand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -4074,7 +4392,7 @@ INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(lrand48_r)(buffer, result);
if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
return res;
@@ -4104,7 +4422,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(getline)(lineptr, n, stream);
if (res > 0) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
@@ -4116,7 +4434,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
// FIXME: under ASan the call below may write to freed memory and corrupt its
// metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define GETDELIM_INTERCEPTOR_IMPL(vname) \
{ \
void *ctx; \
@@ -4163,7 +4481,7 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
void *outbuf_orig = outbuf ? *outbuf : nullptr;
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
@@ -4182,7 +4500,7 @@ INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_clock_t res = REAL(times)(tms);
if (res != (__sanitizer_clock_t)-1 && tms)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
@@ -4194,6 +4512,7 @@ INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
#endif
#if SANITIZER_INTERCEPT_TLS_GET_ADDR
+#if !SANITIZER_S390
#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr)
// If you see any crashes around this functions, there are 2 known issues with
// it: 1. __tls_get_addr can be called with mis-aligned stack due to:
@@ -4214,6 +4533,67 @@ INTERCEPTOR(void *, __tls_get_addr, void *arg) {
}
return res;
}
+#if SANITIZER_PPC
+// On PowerPC, we also need to intercept __tls_get_addr_opt, which has
+// mostly the same semantics as __tls_get_addr, but its presence enables
+// some optimizations in linker (which are safe to ignore here).
+extern "C" __attribute__((alias("__interceptor___tls_get_addr"),
+ visibility("default")))
+void *__tls_get_addr_opt(void *arg);
+#endif
+#else // SANITIZER_S390
+// On s390, we have to intercept two functions here:
+// - __tls_get_addr_internal, which is a glibc-internal function that is like
+// the usual __tls_get_addr, but returns a TP-relative offset instead of
+// a proper pointer. It is used by dlsym for TLS symbols.
+// - __tls_get_offset, which is like the above, but also takes a GOT-relative
+// descriptor offset as an argument instead of a pointer. GOT address
+// is passed in r12, so it's necessary to write it in assembly. This is
+// the function used by the compiler.
+#define INIT_TLS_GET_ADDR COMMON_INTERCEPT_FUNCTION(__tls_get_addr_internal)
+INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr_internal, arg);
+ uptr res = REAL(__tls_get_addr_internal)(arg);
+ uptr tp = reinterpret_cast<uptr>(__builtin_thread_pointer());
+ void *ptr = reinterpret_cast<void *>(res + tp);
+ uptr tls_begin, tls_end;
+ COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end);
+ DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, ptr, tls_begin, tls_end);
+ if (dtv) {
+ // New DTLS block has been allocated.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size);
+ }
+ return res;
+}
+// We need a protected symbol aliasing the above, so that we can jump
+// directly to it from the assembly below.
+extern "C" __attribute__((alias("__interceptor___tls_get_addr_internal"),
+ visibility("protected")))
+uptr __interceptor___tls_get_addr_internal_protected(void *arg);
+// Now carefully intercept __tls_get_offset.
+asm(
+ ".text\n"
+ ".global __tls_get_offset\n"
+ "__tls_get_offset:\n"
+// The __intercept_ version has to exist, so that gen_dynamic_list.py
+// exports our symbol.
+ ".global __interceptor___tls_get_offset\n"
+ "__interceptor___tls_get_offset:\n"
+#ifdef __s390x__
+ "la %r2, 0(%r2,%r12)\n"
+ "jg __interceptor___tls_get_addr_internal_protected\n"
+#else
+ "basr %r3,0\n"
+ "0: la %r2,0(%r2,%r12)\n"
+ "l %r4,1f-0b(%r3)\n"
+ "b 0(%r4,%r3)\n"
+ "1: .long __interceptor___tls_get_addr_internal_protected - 0b\n"
+#endif
+ ".type __tls_get_offset, @function\n"
+ ".size __tls_get_offset, .-__tls_get_offset\n"
+);
+#endif // SANITIZER_S390
#else
#define INIT_TLS_GET_ADDR
#endif
@@ -4225,7 +4605,7 @@ INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(listxattr)(path, list, size);
// Here and below, size == 0 is a special case where nothing is written to the
// buffer, and res contains the desired buffer size.
@@ -4238,7 +4618,7 @@ INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(llistxattr)(path, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
@@ -4248,7 +4628,7 @@ INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(flistxattr)(fd, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
@@ -4270,7 +4650,7 @@ INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(getxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4283,7 +4663,7 @@ INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4295,7 +4675,7 @@ INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
@@ -4314,7 +4694,7 @@ INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) {
COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getresuid)(ruid, euid, suid);
if (res >= 0) {
if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz);
@@ -4328,7 +4708,7 @@ INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) {
COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getresgid)(rgid, egid, sgid);
if (res >= 0) {
if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz);
@@ -4353,7 +4733,7 @@ INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) {
COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(getifaddrs)(ifap);
if (res == 0 && ifap) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *));
@@ -4389,7 +4769,7 @@ INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) {
COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
char *res = REAL(if_indextoname)(ifindex, ifname);
if (res && ifname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1);
@@ -4417,7 +4797,7 @@ INTERCEPTOR(int, capget, void *hdrp, void *datap) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(capget)(hdrp, datap);
if (res == 0 && datap)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
@@ -4518,7 +4898,7 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) {
COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(ftime)(tp);
if (tp)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp));
@@ -4536,7 +4916,7 @@ INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr,
COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(xdrmem_create)(xdrs, addr, size, op);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
if (op == __sanitizer_XDR_ENCODE) {
@@ -4551,14 +4931,14 @@ INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) {
COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
REAL(xdrstdio_create)(xdrs, file, op);
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs));
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
-// https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+// https://github.com/google/sanitizers/issues/321.
#define XDR_INTERCEPTOR(F, T) \
INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \
void *ctx; \
@@ -4612,7 +4992,7 @@ INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep,
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize);
if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -4632,7 +5012,7 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
}
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
int res = REAL(xdr_string)(xdrs, p, maxsize);
if (p && xdrs->x_op == __sanitizer_XDR_DECODE) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p));
@@ -4684,7 +5064,7 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp,
COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
void *res = REAL(tsearch)(key, rootp, compar);
if (res && *(void **)res == key)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *));
@@ -4766,7 +5146,7 @@ INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) {
INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1);
__sanitizer_FILE *res = REAL(fopen)(path, mode);
COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path);
@@ -4837,7 +5217,7 @@ INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) {
COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc);
if (res) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr));
@@ -4868,7 +5248,7 @@ INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size,
COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode);
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=321.
+ // https://github.com/google/sanitizers/issues/321.
__sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode);
if (res) unpoison_file(res);
return res;
@@ -5282,22 +5662,245 @@ INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov,
#define INIT_PROCESS_VM_READV
#endif
+#if SANITIZER_INTERCEPT_CTERMID
+INTERCEPTOR(char *, ctermid, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctermid, s);
+ char *res = REAL(ctermid)(s);
+ if (res) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_CTERMID COMMON_INTERCEPT_FUNCTION(ctermid);
+#else
+#define INIT_CTERMID
+#endif
+
+#if SANITIZER_INTERCEPT_CTERMID_R
+INTERCEPTOR(char *, ctermid_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ctermid_r, s);
+ char *res = REAL(ctermid_r)(s);
+ if (res) {
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_CTERMID_R COMMON_INTERCEPT_FUNCTION(ctermid_r);
+#else
+#define INIT_CTERMID_R
+#endif
+
+#if SANITIZER_INTERCEPT_RECV_RECVFROM
+INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, recv, fd, buf, len, flags);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SSIZE_T res = REAL(recv)(fd, buf, len, flags);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
+ }
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ return res;
+}
+
+INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
+ void *srcaddr, int *addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, recvfrom, fd, buf, len, flags, srcaddr,
+ addrlen);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ SIZE_T srcaddr_sz;
+ if (srcaddr) srcaddr_sz = *addrlen;
+ (void)srcaddr_sz; // prevent "set but not used" warning
+ SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
+ if (srcaddr)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
+ Min((SIZE_T)*addrlen, srcaddr_sz));
+ }
+ return res;
+}
+#define INIT_RECV_RECVFROM \
+ COMMON_INTERCEPT_FUNCTION(recv); \
+ COMMON_INTERCEPT_FUNCTION(recvfrom);
+#else
+#define INIT_RECV_RECVFROM
+#endif
+
+#if SANITIZER_INTERCEPT_SEND_SENDTO
+INTERCEPTOR(SSIZE_T, send, int fd, void *buf, SIZE_T len, int flags) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, send, fd, buf, len, flags);
+ if (fd >= 0) {
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ }
+ SSIZE_T res = REAL(send)(fd, buf, len, flags);
+ if (common_flags()->intercept_send && res > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len));
+ return res;
+}
+
+INTERCEPTOR(SSIZE_T, sendto, int fd, void *buf, SIZE_T len, int flags,
+ void *dstaddr, int addrlen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sendto, fd, buf, len, flags, dstaddr, addrlen);
+ if (fd >= 0) {
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ }
+ // Can't check dstaddr as it may have uninitialized padding at the end.
+ SSIZE_T res = REAL(sendto)(fd, buf, len, flags, dstaddr, addrlen);
+ if (common_flags()->intercept_send && res > 0)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len));
+ return res;
+}
+#define INIT_SEND_SENDTO \
+ COMMON_INTERCEPT_FUNCTION(send); \
+ COMMON_INTERCEPT_FUNCTION(sendto);
+#else
+#define INIT_SEND_SENDTO
+#endif
+
+#if SANITIZER_INTERCEPT_EVENTFD_READ_WRITE
+INTERCEPTOR(int, eventfd_read, int fd, u64 *value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, eventfd_read, fd, value);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ int res = REAL(eventfd_read)(fd, value);
+ if (res == 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, sizeof(*value));
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ }
+ return res;
+}
+INTERCEPTOR(int, eventfd_write, int fd, u64 value) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, eventfd_write, fd, value);
+ if (fd >= 0) {
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ }
+ int res = REAL(eventfd_write)(fd, value);
+ return res;
+}
+#define INIT_EVENTFD_READ_WRITE \
+ COMMON_INTERCEPT_FUNCTION(eventfd_read); \
+ COMMON_INTERCEPT_FUNCTION(eventfd_write)
+#else
+#define INIT_EVENTFD_READ_WRITE
+#endif
+
+#if SANITIZER_INTERCEPT_STAT
+INTERCEPTOR(int, stat, const char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, stat, path, buf);
+ if (common_flags()->intercept_stat)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+ int res = REAL(stat)(path, buf);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define INIT_STAT COMMON_INTERCEPT_FUNCTION(stat)
+#else
+#define INIT_STAT
+#endif
+
+#if SANITIZER_INTERCEPT___XSTAT
+INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xstat, version, path, buf);
+ if (common_flags()->intercept_stat)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+ int res = REAL(__xstat)(version, path, buf);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define INIT___XSTAT COMMON_INTERCEPT_FUNCTION(__xstat)
+#else
+#define INIT___XSTAT
+#endif
+
+#if SANITIZER_INTERCEPT___XSTAT64
+INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xstat64, version, path, buf);
+ if (common_flags()->intercept_stat)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+ int res = REAL(__xstat64)(version, path, buf);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define INIT___XSTAT64 COMMON_INTERCEPT_FUNCTION(__xstat64)
+#else
+#define INIT___XSTAT64
+#endif
+
+#if SANITIZER_INTERCEPT___LXSTAT
+INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __lxstat, version, path, buf);
+ if (common_flags()->intercept_stat)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+ int res = REAL(__lxstat)(version, path, buf);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat_sz);
+ return res;
+}
+#define INIT___LXSTAT COMMON_INTERCEPT_FUNCTION(__lxstat)
+#else
+#define INIT___LXSTAT
+#endif
+
+#if SANITIZER_INTERCEPT___LXSTAT64
+INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __lxstat64, version, path, buf);
+ if (common_flags()->intercept_stat)
+ COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0);
+ int res = REAL(__lxstat64)(version, path, buf);
+ if (!res)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer::struct_stat64_sz);
+ return res;
+}
+#define INIT___LXSTAT64 COMMON_INTERCEPT_FUNCTION(__lxstat64)
+#else
+#define INIT___LXSTAT64
+#endif
+
+// FIXME: add other *stat interceptor
+
static void InitializeCommonInterceptors() {
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
INIT_TEXTDOMAIN;
+ INIT_STRLEN;
+ INIT_STRNLEN;
INIT_STRCMP;
INIT_STRNCMP;
INIT_STRCASECMP;
INIT_STRNCASECMP;
INIT_STRSTR;
INIT_STRCASESTR;
+ INIT_STRCHR;
+ INIT_STRCHRNUL;
+ INIT_STRRCHR;
INIT_STRSPN;
INIT_STRPBRK;
+ INIT_MEMSET;
+ INIT_MEMMOVE;
+ INIT_MEMCPY;
INIT_MEMCHR;
INIT_MEMCMP;
INIT_MEMRCHR;
+ INIT_MEMMEM;
INIT_READ;
INIT_PREAD;
INIT_PREAD64;
@@ -5347,6 +5950,7 @@ static void InitializeCommonInterceptors() {
INIT_ACCEPT4;
INIT_MODF;
INIT_RECVMSG;
+ INIT_SENDMSG;
INIT_GETPEERNAME;
INIT_IOCTL;
INIT_INET_ATON;
@@ -5416,6 +6020,7 @@ static void InitializeCommonInterceptors() {
INIT_PTHREAD_BARRIERATTR_GETPSHARED;
INIT_TMPNAM;
INIT_TMPNAM_R;
+ INIT_TTYNAME_R;
INIT_TEMPNAM;
INIT_PTHREAD_SETNAME_NP;
INIT_SINCOS;
@@ -5456,4 +6061,15 @@ static void InitializeCommonInterceptors() {
INIT_PTHREAD_SETCANCEL;
INIT_MINCORE;
INIT_PROCESS_VM_READV;
+ INIT_CTERMID;
+ INIT_CTERMID_R;
+ INIT_RECV_RECVFROM;
+ INIT_SEND_SENDTO;
+ INIT_STAT;
+ INIT_EVENTFD_READ_WRITE;
+ INIT___XSTAT;
+ INIT___XSTAT64;
+ INIT___LXSTAT;
+ INIT___LXSTAT64;
+ // FIXME: add other *stat interceptors.
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 6c5fda09fbf..a68534c5a0a 100755
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -51,25 +51,9 @@ static void ioctl_table_fill() {
_(FIONBIO, READ, sizeof(int));
_(FIONCLEX, NONE, 0);
_(FIOSETOWN, READ, sizeof(int));
- _(SIOCADDMULTI, READ, struct_ifreq_sz);
_(SIOCATMARK, WRITE, sizeof(int));
- _(SIOCDELMULTI, READ, struct_ifreq_sz);
- _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
- _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
_(SIOCGIFCONF, CUSTOM, 0);
- _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
- _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
- _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
- _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
- _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
_(SIOCGPGRP, WRITE, sizeof(int));
- _(SIOCSIFADDR, READ, struct_ifreq_sz);
- _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
- _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
- _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
- _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
- _(SIOCSIFMTU, READ, struct_ifreq_sz);
- _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
_(SIOCSPGRP, READ, sizeof(int));
_(TIOCCONS, NONE, 0);
_(TIOCEXCL, NONE, 0);
@@ -90,6 +74,25 @@ static void ioctl_table_fill() {
_(TIOCSTI, READ, sizeof(char));
_(TIOCSWINSZ, READ, struct_winsize_sz);
+#if !SANITIZER_IOS
+ _(SIOCADDMULTI, READ, struct_ifreq_sz);
+ _(SIOCDELMULTI, READ, struct_ifreq_sz);
+ _(SIOCGIFADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFBRDADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFDSTADDR, WRITE, struct_ifreq_sz);
+ _(SIOCGIFFLAGS, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMETRIC, WRITE, struct_ifreq_sz);
+ _(SIOCGIFMTU, WRITE, struct_ifreq_sz);
+ _(SIOCGIFNETMASK, WRITE, struct_ifreq_sz);
+ _(SIOCSIFADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFBRDADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFDSTADDR, READ, struct_ifreq_sz);
+ _(SIOCSIFFLAGS, READ, struct_ifreq_sz);
+ _(SIOCSIFMETRIC, READ, struct_ifreq_sz);
+ _(SIOCSIFMTU, READ, struct_ifreq_sz);
+ _(SIOCSIFNETMASK, READ, struct_ifreq_sz);
+#endif
+
#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
_(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
_(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
@@ -578,7 +581,8 @@ static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d,
return;
if (request == IOCTL_SIOCGIFCONF) {
struct __sanitizer_ifconf *ifc = (__sanitizer_ifconf *)arg;
- COMMON_INTERCEPTOR_READ_RANGE(ctx, &ifc->ifc_len, sizeof(ifc->ifc_len));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, (char*)&ifc->ifc_len,
+ sizeof(ifc->ifc_len));
}
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
index 5a76c4ebd8b..8c9fa98f835 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
@@ -10,6 +10,8 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+
+#include "sanitizer_allocator_interface.h"
#include "sanitizer_flags.h"
#include "sanitizer_stackdepot.h"
#include "sanitizer_stacktrace.h"
@@ -43,7 +45,8 @@ void SetSandboxingCallback(void (*f)()) {
sandboxing_callback = f;
}
-void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+void ReportErrorSummary(const char *error_type, const StackTrace *stack) {
+#if !SANITIZER_GO
if (!common_flags()->print_summary)
return;
if (stack->size == 0) {
@@ -56,6 +59,7 @@ void ReportErrorSummary(const char *error_type, StackTrace *stack) {
SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
ReportErrorSummary(error_type, frame->info);
frame->ClearAll();
+#endif
}
static void (*SoftRssLimitExceededCallback)(bool exceeded);
@@ -64,12 +68,22 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
SoftRssLimitExceededCallback = Callback;
}
+static AllocatorReleaseToOSCallback ReleseCallback;
+void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback) {
+ CHECK_EQ(ReleseCallback, nullptr);
+ ReleseCallback = Callback;
+}
+
+#if SANITIZER_LINUX && !SANITIZER_GO
void BackgroundThread(void *arg) {
uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
+ bool heap_profile = common_flags()->heap_profile;
+ bool allocator_release_to_os = common_flags()->allocator_release_to_os;
uptr prev_reported_rss = 0;
uptr prev_reported_stack_depot_size = 0;
bool reached_soft_rss_limit = false;
+ uptr rss_during_last_reported_profile = 0;
while (true) {
SleepForMillis(100);
uptr current_rss_mb = GetRSS() >> 20;
@@ -111,14 +125,43 @@ void BackgroundThread(void *arg) {
SoftRssLimitExceededCallback(false);
}
}
+ if (allocator_release_to_os && ReleseCallback) ReleseCallback();
+ if (heap_profile &&
+ current_rss_mb > rss_during_last_reported_profile * 1.1) {
+ Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
+ __sanitizer_print_memory_profile(90);
+ rss_during_last_reported_profile = current_rss_mb;
+ }
}
}
+#endif
+
+void WriteToSyslog(const char *msg) {
+ InternalScopedString msg_copy(kErrorMessageBufferSize);
+ msg_copy.append("%s", msg);
+ char *p = msg_copy.data();
+ char *q;
+
+ // Print one line at a time.
+ // syslog, at least on Android, has an implicit message length limit.
+ do {
+ q = internal_strchr(p, '\n');
+ if (q)
+ *q = '\0';
+ WriteOneLineToSyslog(p);
+ if (q)
+ p = q + 1;
+ } while (q);
+}
void MaybeStartBackgroudThread() {
-#if SANITIZER_LINUX // Need to implement/test on other platforms.
+#if SANITIZER_LINUX && \
+ !SANITIZER_GO // Need to implement/test on other platforms.
// Start the background thread if one of the rss limits is given.
if (!common_flags()->hard_rss_limit_mb &&
- !common_flags()->soft_rss_limit_mb) return;
+ !common_flags()->soft_rss_limit_mb &&
+ !common_flags()->allocator_release_to_os &&
+ !common_flags()->heap_profile) return;
if (!&real_pthread_create) return; // Can't spawn the thread anyway.
internal_start_thread(BackgroundThread, nullptr);
#endif
@@ -128,7 +171,7 @@ void MaybeStartBackgroudThread() {
void NOINLINE
__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
- PrepareForSandboxing(args);
- if (sandboxing_callback)
- sandboxing_callback();
+ __sanitizer::PrepareForSandboxing(args);
+ if (__sanitizer::sandboxing_callback)
+ __sanitizer::sandboxing_callback();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
index 5e83ce9786c..6fd5ef74274 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
@@ -1235,17 +1235,15 @@ POST_SYSCALL(fcntl64)(long res, long fd, long cmd, long arg) {}
PRE_SYSCALL(pipe)(void *fildes) {}
POST_SYSCALL(pipe)(long res, void *fildes) {
- if (res >= 0) {
- if (fildes) POST_WRITE(fildes, sizeof(int));
- }
+ if (res >= 0)
+ if (fildes) POST_WRITE(fildes, sizeof(int) * 2);
}
PRE_SYSCALL(pipe2)(void *fildes, long flags) {}
POST_SYSCALL(pipe2)(long res, void *fildes, long flags) {
- if (res >= 0) {
- if (fildes) POST_WRITE(fildes, sizeof(int));
- }
+ if (res >= 0)
+ if (fildes) POST_WRITE(fildes, sizeof(int) * 2);
}
PRE_SYSCALL(dup)(long fildes) {}
@@ -1878,13 +1876,11 @@ PRE_SYSCALL(socket)(long arg0, long arg1, long arg2) {}
POST_SYSCALL(socket)(long res, long arg0, long arg1, long arg2) {}
-PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, void *arg3) {}
+PRE_SYSCALL(socketpair)(long arg0, long arg1, long arg2, int *sv) {}
-POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2,
- void *arg3) {
- if (res >= 0) {
- if (arg3) POST_WRITE(arg3, sizeof(int));
- }
+POST_SYSCALL(socketpair)(long res, long arg0, long arg1, long arg2, int *sv) {
+ if (res >= 0)
+ if (sv) POST_WRITE(sv, sizeof(int) * 2);
}
PRE_SYSCALL(socketcall)(long call, void *args) {}
@@ -2299,7 +2295,7 @@ POST_SYSCALL(ni_syscall)(long res) {}
PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
#if !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__) || defined(__aarch64__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__))
if (data) {
if (request == ptrace_setregs) {
PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2320,7 +2316,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
#if !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__) || defined(__aarch64__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__))
if (res >= 0 && data) {
// Note that this is different from the interceptor in
// sanitizer_common_interceptors.inc.
@@ -2842,6 +2838,40 @@ PRE_SYSCALL(vfork)() {
POST_SYSCALL(vfork)(long res) {
COMMON_SYSCALL_POST_FORK(res);
}
+
+PRE_SYSCALL(sigaction)(long signum, const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact) {
+ if (act) {
+ PRE_READ(&act->sigaction, sizeof(act->sigaction));
+ PRE_READ(&act->sa_flags, sizeof(act->sa_flags));
+ PRE_READ(&act->sa_mask, sizeof(act->sa_mask));
+ }
+}
+
+POST_SYSCALL(sigaction)(long res, long signum,
+ const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact) {
+ if (res >= 0 && oldact) POST_WRITE(oldact, sizeof(*oldact));
+}
+
+PRE_SYSCALL(rt_sigaction)(long signum,
+ const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) {
+ if (act) {
+ PRE_READ(&act->sigaction, sizeof(act->sigaction));
+ PRE_READ(&act->sa_flags, sizeof(act->sa_flags));
+ PRE_READ(&act->sa_mask, sz);
+ }
+}
+
+POST_SYSCALL(rt_sigaction)(long res, long signum,
+ const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact, SIZE_T sz) {
+ if (res >= 0 && oldact) {
+ SIZE_T oldact_sz = ((char *)&oldact->sa_mask) - ((char *)oldact) + sz;
+ POST_WRITE(oldact, oldact_sz);
+ }
+}
} // extern "C"
#undef PRE_SYSCALL
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
index c67880468b8..dd8620beaac 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -45,8 +45,12 @@
#include "sanitizer_symbolizer.h"
#include "sanitizer_flags.h"
+using namespace __sanitizer;
+
static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL;
static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
+static const uptr kNumWordsForMagic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
+static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
@@ -94,7 +98,7 @@ class CoverageData {
void DumpAll();
ALWAYS_INLINE
- void TraceBasicBlock(s32 *id);
+ void TraceBasicBlock(u32 *id);
void InitializeGuardArray(s32 *guards);
void InitializeGuards(s32 *guards, uptr n, const char *module_name,
@@ -105,17 +109,23 @@ class CoverageData {
uptr Update8bitCounterBitsetAndClearCounters(u8 *bitset);
uptr *data();
- uptr size();
+ uptr size() const;
private:
+ struct NamedPcRange {
+ const char *copied_module_name;
+ uptr beg, end; // elements [beg,end) in pc_array.
+ };
+
void DirectOpen();
void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end);
+ void GetRangeOffsets(const NamedPcRange& r, Symbolizer* s,
+ InternalMmapVector<uptr>* offsets) const;
// Maximal size pc array may ever grow.
// We MmapNoReserve this space to ensure that the array is contiguous.
- static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(
- 1 << (SANITIZER_ANDROID ? 24 : (SANITIZER_WINDOWS ? 27 : 26)),
- 1 << 27);
+ static const uptr kPcArrayMaxSize =
+ FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
// The amount file mapping for the pc array is grown by.
static const uptr kPcArrayMmapSize = 64 * 1024;
@@ -134,11 +144,6 @@ class CoverageData {
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
- struct NamedPcRange {
- const char *copied_module_name;
- uptr beg, end; // elements [beg,end) in pc_array.
- };
-
// Vector of module and compilation unit pc ranges.
InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec;
InternalMmapVectorNoCtor<NamedPcRange> module_name_vec;
@@ -510,7 +515,7 @@ uptr *CoverageData::data() {
return pc_array;
}
-uptr CoverageData::size() {
+uptr CoverageData::size() const {
return atomic_load(&pc_array_index, memory_order_relaxed);
}
@@ -680,11 +685,11 @@ void CoverageData::DumpCallerCalleePairs() {
// it once and then cache in the provided 'cache' storage.
//
// This function will eventually be inlined by the compiler.
-void CoverageData::TraceBasicBlock(s32 *id) {
+void CoverageData::TraceBasicBlock(u32 *id) {
// Will trap here if
// 1. coverage is not enabled at run-time.
// 2. The array tr_event_array is full.
- *tr_event_pointer = static_cast<u32>(*id - 1);
+ *tr_event_pointer = *id - 1;
tr_event_pointer++;
}
@@ -740,41 +745,96 @@ void CoverageData::DumpAsBitSet() {
}
}
+
+void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym,
+ InternalMmapVector<uptr>* offsets) const {
+ offsets->clear();
+ for (uptr i = 0; i < kNumWordsForMagic; i++)
+ offsets->push_back(0);
+ CHECK(r.copied_module_name);
+ CHECK_LE(r.beg, r.end);
+ CHECK_LE(r.end, size());
+ for (uptr i = r.beg; i < r.end; i++) {
+ uptr pc = UnbundlePc(pc_array[i]);
+ uptr counter = UnbundleCounter(pc_array[i]);
+ if (!pc) continue; // Not visited.
+ uptr offset = 0;
+ sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
+ offsets->push_back(BundlePcAndCounter(offset, counter));
+ }
+
+ CHECK_GE(offsets->size(), kNumWordsForMagic);
+ SortArray(offsets->data(), offsets->size());
+ for (uptr i = 0; i < offsets->size(); i++)
+ (*offsets)[i] = UnbundlePc((*offsets)[i]);
+}
+
+static void GenerateHtmlReport(const InternalMmapVector<char *> &cov_files) {
+ if (!common_flags()->html_cov_report) {
+ return;
+ }
+ char *sancov_path = FindPathToBinary(common_flags()->sancov_path);
+ if (sancov_path == nullptr) {
+ return;
+ }
+
+ InternalMmapVector<char *> sancov_argv(cov_files.size() * 2 + 3);
+ sancov_argv.push_back(sancov_path);
+ sancov_argv.push_back(internal_strdup("-html-report"));
+ auto argv_deleter = at_scope_exit([&] {
+ for (uptr i = 0; i < sancov_argv.size(); ++i) {
+ InternalFree(sancov_argv[i]);
+ }
+ });
+
+ for (const auto &cov_file : cov_files) {
+ sancov_argv.push_back(internal_strdup(cov_file));
+ }
+
+ {
+ ListOfModules modules;
+ modules.init();
+ for (const LoadedModule &module : modules) {
+ sancov_argv.push_back(internal_strdup(module.full_name()));
+ }
+ }
+
+ InternalScopedString report_path(kMaxPathLength);
+ fd_t report_fd =
+ CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html");
+ int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(),
+ kInvalidFd /* stdin */, report_fd /* std_out */);
+ if (pid > 0) {
+ int result = WaitForProcess(pid);
+ if (result == 0)
+ Printf("coverage report generated to %s\n", report_path.data());
+ }
+}
+
void CoverageData::DumpOffsets() {
auto sym = Symbolizer::GetOrInit();
if (!common_flags()->coverage_pcs) return;
CHECK_NE(sym, nullptr);
InternalMmapVector<uptr> offsets(0);
InternalScopedString path(kMaxPathLength);
- for (uptr m = 0; m < module_name_vec.size(); m++) {
- offsets.clear();
- uptr num_words_for_magic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
- for (uptr i = 0; i < num_words_for_magic; i++)
- offsets.push_back(0);
- auto r = module_name_vec[m];
- CHECK(r.copied_module_name);
- CHECK_LE(r.beg, r.end);
- CHECK_LE(r.end, size());
- for (uptr i = r.beg; i < r.end; i++) {
- uptr pc = UnbundlePc(pc_array[i]);
- uptr counter = UnbundleCounter(pc_array[i]);
- if (!pc) continue; // Not visited.
- uptr offset = 0;
- sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
- offsets.push_back(BundlePcAndCounter(offset, counter));
+
+ InternalMmapVector<char *> cov_files(module_name_vec.size());
+ auto cov_files_deleter = at_scope_exit([&] {
+ for (uptr i = 0; i < cov_files.size(); ++i) {
+ InternalFree(cov_files[i]);
}
+ });
- CHECK_GE(offsets.size(), num_words_for_magic);
- SortArray(offsets.data(), offsets.size());
- for (uptr i = 0; i < offsets.size(); i++)
- offsets[i] = UnbundlePc(offsets[i]);
+ for (uptr m = 0; m < module_name_vec.size(); m++) {
+ auto r = module_name_vec[m];
+ GetRangeOffsets(r, sym, &offsets);
- uptr num_offsets = offsets.size() - num_words_for_magic;
+ uptr num_offsets = offsets.size() - kNumWordsForMagic;
u64 *magic_p = reinterpret_cast<u64*>(offsets.data());
CHECK_EQ(*magic_p, 0ULL);
// FIXME: we may want to write 32-bit offsets even in 64-mode
// if all the offsets are small enough.
- *magic_p = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
+ *magic_p = kMagic;
const char *module_name = StripModuleName(r.copied_module_name);
if (cov_sandboxed) {
@@ -789,11 +849,14 @@ void CoverageData::DumpOffsets() {
if (fd == kInvalidFd) continue;
WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
CloseFile(fd);
+ cov_files.push_back(internal_strdup(path.data()));
VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
}
}
if (cov_fd != kInvalidFd)
CloseFile(cov_fd);
+
+ GenerateHtmlReport(cov_files);
}
void CoverageData::DumpAll() {
@@ -918,11 +981,13 @@ uptr __sanitizer_get_total_unique_caller_callee_pairs() {
}
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_func_enter(s32 *id) {
+void __sanitizer_cov_trace_func_enter(u32 *id) {
+ __sanitizer_cov_with_check(id);
coverage_data.TraceBasicBlock(id);
}
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_basic_block(s32 *id) {
+void __sanitizer_cov_trace_basic_block(u32 *id) {
+ __sanitizer_cov_with_check(id);
coverage_data.TraceBasicBlock(id);
}
SANITIZER_INTERFACE_ATTRIBUTE
@@ -949,8 +1014,30 @@ uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) {
return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset);
}
// Default empty implementations (weak). Users should redefine them.
+#if !SANITIZER_WINDOWS // weak does not work on Windows.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_cov_trace_cmp() {}
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_cmp1() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_cmp2() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_cmp4() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_cmp8() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_cov_trace_switch() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_div4() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_div8() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_gep() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_pc_guard() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_pc_indir() {}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_cov_trace_pc_guard_init() {}
+#endif // !SANITIZER_WINDOWS
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
index ebac6812881..b2e724ab221 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
@@ -70,26 +70,21 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
InternalScopedString text(kMaxTextSize);
{
- InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
- CHECK(modules.data());
- int n_modules = GetListOfModules(modules.data(), kMaxNumberOfModules,
- /* filter */ nullptr);
-
text.append("%d\n", sizeof(uptr) * 8);
- for (int i = 0; i < n_modules; ++i) {
- const char *module_name = StripModuleName(modules[i].full_name());
- uptr base = modules[i].base_address();
- for (auto iter = modules[i].ranges(); iter.hasNext();) {
- const auto *range = iter.next();
- if (range->executable) {
- uptr start = range->beg;
- uptr end = range->end;
+ ListOfModules modules;
+ modules.init();
+ for (const LoadedModule &module : modules) {
+ const char *module_name = StripModuleName(module.full_name());
+ uptr base = module.base_address();
+ for (const auto &range : module.ranges()) {
+ if (range.executable) {
+ uptr start = range.beg;
+ uptr end = range.end;
text.append("%zx %zx %zx %s\n", start, end, base, module_name);
if (caller_pc && caller_pc >= start && caller_pc < end)
cached_mapping.SetModuleRange(start, end);
}
}
- modules[i].clear();
}
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cc b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cc
index 7a318c963f7..e2aedc24da9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector1.cc
@@ -117,11 +117,16 @@ void DD::MutexBeforeLock(DDCallback *cb,
void DD::ReportDeadlock(DDCallback *cb, DDMutex *m) {
DDLogicalThread *lt = cb->lt;
- uptr path[10];
+ uptr path[20];
uptr len = dd.findPathToLock(&lt->dd, m->id, path, ARRAY_SIZE(path));
- CHECK_GT(len, 0U); // Hm.. cycle of 10 locks? I'd like to see that.
+ if (len == 0U) {
+ // A cycle of 20+ locks? Well, that's a bit odd...
+ Printf("WARNING: too long mutex cycle found\n");
+ return;
+ }
CHECK_EQ(m->id, path[0]);
lt->report_pending = true;
+ len = Min<uptr>(len, DDReport::kMaxLoopSize);
DDReport *rep = &lt->rep;
rep->n = len;
for (uptr i = 0; i < len; i++) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector_interface.h b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector_interface.h
index 07c3755155f..f8da20612db 100644
--- a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector_interface.h
+++ b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector_interface.h
@@ -49,7 +49,7 @@ struct DDFlags {
};
struct DDReport {
- enum { kMaxLoopSize = 8 };
+ enum { kMaxLoopSize = 20 };
int n; // number of entries in loop
struct {
u64 thr_ctx; // user thread context
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cc b/libsanitizer/sanitizer_common/sanitizer_flags.cc
index a24ff900011..5f69e58ffb2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.cc
@@ -28,11 +28,6 @@ struct FlagDescription {
IntrusiveList<FlagDescription> flag_descriptions;
-// If set, the tool will install its own SEGV signal handler by default.
-#ifndef SANITIZER_NEEDS_SEGV
-# define SANITIZER_NEEDS_SEGV 1
-#endif
-
void CommonFlags::SetDefaults() {
#define COMMON_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "sanitizer_flags.inc"
@@ -43,17 +38,44 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
internal_memcpy(this, &other, sizeof(*this));
}
-// Copy the string from "s" to "out", replacing "%b" with the binary basename.
-static void SubstituteBinaryName(const char *s, char *out, uptr out_size) {
+// Copy the string from "s" to "out", making the following substitutions:
+// %b = binary basename
+// %p = pid
+void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
char *out_end = out + out_size;
while (*s && out < out_end - 1) {
- if (s[0] != '%' || s[1] != 'b') { *out++ = *s++; continue; }
- const char *base = GetProcessName();
- CHECK(base);
- while (*base && out < out_end - 1)
- *out++ = *base++;
- s += 2; // skip "%b"
+ if (s[0] != '%') {
+ *out++ = *s++;
+ continue;
+ }
+ switch (s[1]) {
+ case 'b': {
+ const char *base = GetProcessName();
+ CHECK(base);
+ while (*base && out < out_end - 1)
+ *out++ = *base++;
+ s += 2; // skip "%b"
+ break;
+ }
+ case 'p': {
+ int pid = internal_getpid();
+ char buf[32];
+ char *buf_pos = buf + 32;
+ do {
+ *--buf_pos = (pid % 10) + '0';
+ pid /= 10;
+ } while (pid);
+ while (buf_pos < buf + 32 && out < out_end - 1)
+ *out++ = *buf_pos++;
+ s += 2; // skip "%p"
+ break;
+ }
+ default:
+ *out++ = *s++;
+ break;
+ }
}
+ CHECK(out < out_end - 1);
*out = '\0';
}
@@ -67,7 +89,7 @@ class FlagHandlerInclude : public FlagHandlerBase {
bool Parse(const char *value) final {
if (internal_strchr(value, '%')) {
char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude");
- SubstituteBinaryName(value, buf, kMaxPathLength);
+ SubstituteForFlagValue(value, buf, kMaxPathLength);
bool res = parser_->ParseFile(buf, ignore_missing_);
UnmapOrDie(buf, kMaxPathLength);
return res;
@@ -97,4 +119,10 @@ void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) {
RegisterIncludeFlags(parser, cf);
}
+void InitializeCommonFlags(CommonFlags *cf) {
+ // need to record coverage to generate coverage report.
+ cf->coverage |= cf->html_cov_report;
+ SetVerbosity(cf->verbosity);
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.h b/libsanitizer/sanitizer_common/sanitizer_flags.h
index f1b872b79e2..ff64af10ff5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.h
@@ -44,10 +44,17 @@ inline void OverrideCommonFlags(const CommonFlags &cf) {
common_flags_dont_use.CopyFrom(cf);
}
+void SubstituteForFlagValue(const char *s, char *out, uptr out_size);
+
class FlagParser;
void RegisterCommonFlags(FlagParser *parser,
CommonFlags *cf = &common_flags_dont_use);
void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf);
+
+// Should be called after parsing all flags. Sets up common flag values
+// and perform initializations common to all sanitizers (e.g. setting
+// verbosity).
+void InitializeCommonFlags(CommonFlags *cf = &common_flags_dont_use);
} // namespace __sanitizer
#endif // SANITIZER_FLAGS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
index bca1c4b4d0f..ccc0e416f4a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
@@ -54,7 +54,7 @@ COMMON_FLAG(
"Mention name of executable when reporting error and "
"append executable name to logs (as in \"log_path.exe_name.pid\").")
COMMON_FLAG(
- bool, log_to_syslog, SANITIZER_ANDROID,
+ bool, log_to_syslog, SANITIZER_ANDROID || SANITIZER_MAC,
"Write all sanitizer output to syslog in addition to other means of "
"logging.")
COMMON_FLAG(
@@ -73,10 +73,12 @@ COMMON_FLAG(bool, print_summary, true,
"If false, disable printing error summaries in addition to error "
"reports.")
COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
-COMMON_FLAG(bool, handle_segv, SANITIZER_NEEDS_SEGV,
+COMMON_FLAG(bool, handle_segv, true,
"If set, registers the tool's custom SIGSEGV/SIGBUS handler.")
COMMON_FLAG(bool, handle_abort, false,
"If set, registers the tool's custom SIGABRT handler.")
+COMMON_FLAG(bool, handle_sigill, false,
+ "If set, registers the tool's custom SIGILL handler.")
COMMON_FLAG(bool, handle_sigfpe, true,
"If set, registers the tool's custom SIGFPE handler.")
COMMON_FLAG(bool, allow_user_segv_handler, false,
@@ -114,6 +116,10 @@ COMMON_FLAG(uptr, soft_rss_limit_mb, 0,
" until the RSS goes below the soft limit."
" This limit does not affect memory allocations other than"
" malloc/new.")
+COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only")
+COMMON_FLAG(bool, allocator_release_to_os, false,
+ "Experimental. If true, try to periodically release unused"
+ " memory to the OS.\n")
COMMON_FLAG(bool, can_use_proc_maps_statm, true,
"If false, do not attempt to read /proc/maps/statm."
" Mostly useful for testing sanitizers.")
@@ -146,10 +152,10 @@ COMMON_FLAG(bool, full_address_space, false,
COMMON_FLAG(bool, print_suppressions, true,
"Print matched suppressions at exit.")
COMMON_FLAG(
- bool, disable_coredump, (SANITIZER_WORDSIZE == 64),
- "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
- "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
- "default and for sanitizers that don't reserve lots of virtual memory.")
+ bool, disable_coredump, (SANITIZER_WORDSIZE == 64) && !SANITIZER_GO,
+ "Disable core dumping. By default, disable_coredump=1 on 64-bit to avoid"
+ " dumping a 16T+ core file. Ignored on OSes that don't dump core by"
+ " default and for sanitizers that don't reserve lots of virtual memory.")
COMMON_FLAG(bool, use_madv_dontdump, true,
"If set, instructs kernel to not store the (huge) shadow "
"in core file.")
@@ -158,6 +164,11 @@ COMMON_FLAG(bool, symbolize_inline_frames, true,
COMMON_FLAG(bool, symbolize_vs_style, false,
"Print file locations in Visual Studio style (e.g: "
" file(10,42): ...")
+COMMON_FLAG(int, dedup_token_length, 0,
+ "If positive, after printing a stack trace also print a short "
+ "string token based on this number of frames that will simplify "
+ "deduplication of the reports. "
+ "Example: 'DEDUP_TOKEN: foo-bar-main'. Default is 0.")
COMMON_FLAG(const char *, stack_trace_format, "DEFAULT",
"Format string used to render stack frames. "
"See sanitizer_stacktrace_printer.h for the format description. "
@@ -175,18 +186,42 @@ COMMON_FLAG(bool, intercept_strspn, true,
COMMON_FLAG(bool, intercept_strpbrk, true,
"If set, uses custom wrappers for strpbrk function "
"to find more errors.")
+COMMON_FLAG(bool, intercept_strlen, true,
+ "If set, uses custom wrappers for strlen and strnlen functions "
+ "to find more errors.")
+COMMON_FLAG(bool, intercept_strchr, true,
+ "If set, uses custom wrappers for strchr, strchrnul, and strrchr "
+ "functions to find more errors.")
COMMON_FLAG(bool, intercept_memcmp, true,
"If set, uses custom wrappers for memcmp function "
"to find more errors.")
COMMON_FLAG(bool, strict_memcmp, true,
"If true, assume that memcmp(p1, p2, n) always reads n bytes before "
"comparing p1 and p2.")
+COMMON_FLAG(bool, intercept_memmem, true,
+ "If set, uses a wrapper for memmem() to find more errors.")
+COMMON_FLAG(bool, intercept_intrin, true,
+ "If set, uses custom wrappers for memset/memcpy/memmove "
+ "intrinsics to find more errors.")
+COMMON_FLAG(bool, intercept_stat, true,
+ "If set, uses custom wrappers for *stat functions "
+ "to find more errors.")
+COMMON_FLAG(bool, intercept_send, true,
+ "If set, uses custom wrappers for send* functions "
+ "to find more errors.")
COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer "
"mappings in /proc/self/maps with "
"user-readable names")
COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool "
"found an error")
COMMON_FLAG(
- bool, abort_on_error, SANITIZER_MAC,
+ bool, abort_on_error, SANITIZER_ANDROID || SANITIZER_MAC,
"If set, the tool calls abort() instead of _exit() after printing the "
"error report.")
+COMMON_FLAG(bool, suppress_equal_pcs, true,
+ "Deduplicate multiple reports for single source location in "
+ "halt_on_error=false mode (asan only).")
+COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash "
+ "(asan only).")
+COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.")
+COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.")
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index 0547f9927cb..34e80c3b50f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -23,6 +23,10 @@ extern "C" {
// The special values are "stdout" and "stderr".
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_report_path(const char *path);
+ // Tell the tools to write their reports to the provided file descriptor
+ // (casted to void *).
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_set_report_fd(void *fd);
typedef struct {
int coverage_sandboxed;
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index d76ed7570a7..b9c906669de 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -22,7 +22,7 @@
# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
// FIXME find out what we need on Windows, if anything.
# define SANITIZER_WEAK_ATTRIBUTE
-#elif defined(SANITIZER_GO)
+#elif SANITIZER_GO
# define SANITIZER_INTERFACE_ATTRIBUTE
# define SANITIZER_WEAK_ATTRIBUTE
#else
@@ -30,7 +30,7 @@
# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
#endif
-#if (SANITIZER_LINUX || SANITIZER_WINDOWS) && !defined(SANITIZER_GO)
+#if (SANITIZER_LINUX || SANITIZER_WINDOWS) && !SANITIZER_GO
# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
#else
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
@@ -87,6 +87,7 @@ typedef unsigned error_t;
typedef int fd_t;
typedef int error_t;
#endif
+typedef int pid_t;
// WARNING: OFF_T may be different from OS type off_t, depending on the value of
// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
@@ -103,19 +104,25 @@ typedef u64 OFF64_T;
#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
typedef uptr operator_new_size_type;
#else
+# if defined(__s390__) && !defined(__s390x__)
+// Special case: 31-bit s390 has unsigned long as size_t.
+typedef unsigned long operator_new_size_type;
+# else
typedef u32 operator_new_size_type;
+# endif
#endif
-} // namespace __sanitizer
-using namespace __sanitizer; // NOLINT
// ----------- ATTENTION -------------
// This header should NOT include any other headers to avoid portability issues.
// Common defs.
#define INLINE inline
#define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-#define WEAK SANITIZER_WEAK_ATTRIBUTE
+#define SANITIZER_WEAK_DEFAULT_IMPL \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
+#define SANITIZER_WEAK_CXX_DEFAULT_IMPL \
+ extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
// Platform-specific defs.
#if defined(_MSC_VER)
@@ -129,7 +136,7 @@ using namespace __sanitizer; // NOLINT
# define THREADLOCAL __declspec(thread)
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
-# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */
+# define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ (void)0
#else // _MSC_VER
# define ALWAYS_INLINE inline __attribute__((always_inline))
# define ALIAS(x) __attribute__((alias(x)))
@@ -173,7 +180,9 @@ typedef ALIGNED(1) s32 us32;
typedef ALIGNED(1) s64 us64;
#if SANITIZER_WINDOWS
+} // namespace __sanitizer
typedef unsigned long DWORD; // NOLINT
+namespace __sanitizer {
typedef DWORD thread_return_t;
# define THREAD_CALLING_CONV __stdcall
#else // _WIN32
@@ -183,14 +192,12 @@ typedef void* thread_return_t;
typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
// NOTE: Functions below must be defined in each run-time.
-namespace __sanitizer {
void NORETURN Die();
// FIXME: No, this shouldn't be in the sanitizer interface.
SANITIZER_INTERFACE_ATTRIBUTE
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 { \
@@ -282,14 +289,23 @@ 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)
+inline void Trap() {
+ __builtin_trap();
+}
#else
extern "C" void* _ReturnAddress(void);
+extern "C" void* _AddressOfReturnAddress(void);
# pragma intrinsic(_ReturnAddress)
+# pragma intrinsic(_AddressOfReturnAddress)
# 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
+# define GET_CURRENT_FRAME() (((uptr)_AddressOfReturnAddress()) + sizeof(uptr))
+
+extern "C" void __ud2(void);
+# pragma intrinsic(__ud2)
+inline void Trap() {
+ __ud2();
+}
#endif
#define HANDLE_EINTR(res, f) \
@@ -308,4 +324,19 @@ extern "C" void* _ReturnAddress(void);
(void)enable_fp; \
} while (0)
+} // namespace __sanitizer
+
+namespace __asan { using namespace __sanitizer; } // NOLINT
+namespace __dsan { using namespace __sanitizer; } // NOLINT
+namespace __dfsan { using namespace __sanitizer; } // NOLINT
+namespace __esan { using namespace __sanitizer; } // NOLINT
+namespace __lsan { using namespace __sanitizer; } // NOLINT
+namespace __msan { using namespace __sanitizer; } // NOLINT
+namespace __tsan { using namespace __sanitizer; } // NOLINT
+namespace __scudo { using namespace __sanitizer; } // NOLINT
+namespace __ubsan { using namespace __sanitizer; } // NOLINT
+namespace __xray { using namespace __sanitizer; } // NOLINT
+namespace __interception { using namespace __sanitizer; } // NOLINT
+
+
#endif // SANITIZER_DEFS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.cc b/libsanitizer/sanitizer_common/sanitizer_libc.cc
index 05fdca622e4..82d37675e47 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.cc
@@ -72,7 +72,7 @@ void *internal_memmove(void *dest, const void *src, uptr n) {
// Semi-fast bzero for 16-aligned data. Still far from peak performance.
void internal_bzero_aligned16(void *s, uptr n) {
- struct S16 { u64 a, b; } ALIGNED(16);
+ struct ALIGNED(16) S16 { u64 a, b; };
CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
p->a = p->b = 0;
@@ -173,6 +173,19 @@ uptr internal_strlen(const char *s) {
return i;
}
+uptr internal_strlcat(char *dst, const char *src, uptr maxlen) {
+ const uptr srclen = internal_strlen(src);
+ const uptr dstlen = internal_strnlen(dst, maxlen);
+ if (dstlen == maxlen) return maxlen + srclen;
+ if (srclen < maxlen - dstlen) {
+ internal_memmove(dst + dstlen, src, srclen + 1);
+ } else {
+ internal_memmove(dst + dstlen, src, maxlen - dstlen - 1);
+ dst[maxlen - 1] = '\0';
+ }
+ return dstlen + srclen;
+}
+
char *internal_strncat(char *dst, const char *src, uptr n) {
uptr len = internal_strlen(dst);
uptr i;
@@ -182,6 +195,17 @@ char *internal_strncat(char *dst, const char *src, uptr n) {
return dst;
}
+uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) {
+ const uptr srclen = internal_strlen(src);
+ if (srclen < maxlen) {
+ internal_memmove(dst, src, srclen + 1);
+ } else if (maxlen != 0) {
+ internal_memmove(dst, src, maxlen - 1);
+ dst[maxlen - 1] = '\0';
+ }
+ return srclen;
+}
+
char *internal_strncpy(char *dst, const char *src, uptr n) {
uptr i;
for (i = 0; i < n && src[i]; i++)
@@ -208,6 +232,12 @@ char *internal_strstr(const char *haystack, const char *needle) {
return nullptr;
}
+uptr internal_wcslen(const wchar_t *s) {
+ uptr i = 0;
+ while (s[i]) i++;
+ return i;
+}
+
s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
CHECK_EQ(base, 10);
while (IsSpace(*nptr)) nptr++;
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
index 1b3f8edfadb..d26ec8704c0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
@@ -41,12 +41,15 @@ uptr internal_strcspn(const char *s, const char *reject);
char *internal_strdup(const char *s);
char *internal_strndup(const char *s, uptr n);
uptr internal_strlen(const char *s);
+uptr internal_strlcat(char *dst, const char *src, uptr maxlen);
char *internal_strncat(char *dst, const char *src, uptr n);
int internal_strncmp(const char *s1, const char *s2, uptr n);
+uptr internal_strlcpy(char *dst, const char *src, uptr maxlen);
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.
+uptr internal_wcslen(const wchar_t *s);
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);
@@ -57,15 +60,18 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...);
bool mem_is_zero(const char *mem, uptr size);
// I/O
-const fd_t kInvalidFd = (fd_t)-1;
-const fd_t kStdinFd = 0;
-const fd_t kStdoutFd = (fd_t)1;
-const fd_t kStderrFd = (fd_t)2;
+// Define these as macros so we can use them in linker initialized global
+// structs without dynamic initialization.
+#define kInvalidFd ((fd_t)-1)
+#define kStdinFd ((fd_t)0)
+#define kStdoutFd ((fd_t)1)
+#define kStderrFd ((fd_t)2)
uptr internal_ftruncate(fd_t fd, uptr size);
// OS
void NORETURN internal__exit(int exitcode);
+unsigned int internal_sleep(unsigned int seconds);
uptr internal_getpid();
uptr internal_getppid();
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc
index 2cefa20a5f0..806fcd5e284 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc
@@ -58,7 +58,10 @@
#include <unistd.h>
#if SANITIZER_FREEBSD
+#include <sys/exec.h>
#include <sys/sysctl.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
#include <machine/atomic.h>
extern "C" {
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
@@ -87,12 +90,19 @@ const int FUTEX_WAKE = 1;
// Are we using 32-bit or 64-bit Linux syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
// but it still needs to use 64-bit syscalls.
-#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
+ SANITIZER_WORDSIZE == 64)
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
#else
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
#endif
+#if defined(__x86_64__) || SANITIZER_MIPS64
+extern "C" {
+extern void internal_sigreturn();
+}
+#endif
+
namespace __sanitizer {
#if SANITIZER_LINUX && defined(__x86_64__)
@@ -104,6 +114,7 @@ namespace __sanitizer {
#endif
// --------------- sanitizer_libc.h
+#if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
OFF_T offset) {
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
@@ -116,6 +127,7 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
offset / 4096);
#endif
}
+#endif // !SANITIZER_S390
uptr internal_munmap(void *addr, uptr length) {
return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
@@ -238,7 +250,15 @@ uptr internal_lstat(const char *path, void *buf) {
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
(uptr)buf, AT_SYMLINK_NOFOLLOW);
#elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
+# if SANITIZER_MIPS64
+ // For mips64, lstat syscall fills buffer in the format of kernel_stat
+ struct kernel_stat kbuf;
+ int res = internal_syscall(SYSCALL(lstat), path, &kbuf);
+ kernel_stat_to_stat(&kbuf, (struct stat *)buf);
+ return res;
+# else
return internal_syscall(SYSCALL(lstat), (uptr)path, (uptr)buf);
+# endif
#else
struct stat64 buf64;
int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
@@ -249,7 +269,15 @@ uptr internal_lstat(const char *path, void *buf) {
uptr internal_fstat(fd_t fd, void *buf) {
#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+# if SANITIZER_MIPS64
+ // For mips64, fstat syscall fills buffer in the format of kernel_stat
+ struct kernel_stat kbuf;
+ int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
+ kernel_stat_to_stat(&kbuf, (struct stat *)buf);
+ return res;
+# else
return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
+# endif
#else
struct stat64 buf64;
int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
@@ -312,6 +340,15 @@ void internal__exit(int exitcode) {
Die(); // Unreachable.
}
+unsigned int internal_sleep(unsigned int seconds) {
+ struct timespec ts;
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts);
+ if (res) return ts.tv_sec;
+ return 0;
+}
+
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]) {
return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
@@ -392,11 +429,13 @@ const char *GetEnv(const char *name) {
#endif
}
+#if !SANITIZER_FREEBSD
extern "C" {
SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
}
+#endif
-#if !SANITIZER_GO
+#if !SANITIZER_GO && !SANITIZER_FREEBSD
static void ReadNullSepFileToArray(const char *path, char ***arr,
int arr_size) {
char *buff;
@@ -421,7 +460,8 @@ static void ReadNullSepFileToArray(const char *path, char ***arr,
}
#endif
-static void GetArgsAndEnv(char*** argv, char*** envp) {
+static void GetArgsAndEnv(char ***argv, char ***envp) {
+#if !SANITIZER_FREEBSD
#if !SANITIZER_GO
if (&__libc_stack_end) {
#endif
@@ -436,6 +476,25 @@ static void GetArgsAndEnv(char*** argv, char*** envp) {
ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
}
#endif
+#else
+ // On FreeBSD, retrieving the argument and environment arrays is done via the
+ // kern.ps_strings sysctl, which returns a pointer to a structure containing
+ // this information. See also <sys/exec.h>.
+ ps_strings *pss;
+ size_t sz = sizeof(pss);
+ if (sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) {
+ Printf("sysctl kern.ps_strings failed\n");
+ Die();
+ }
+ *argv = pss->ps_argvstr;
+ *envp = pss->ps_envstr;
+#endif
+}
+
+char **GetArgv() {
+ char **argv, **envp;
+ GetArgsAndEnv(&argv, &envp);
+ return argv;
}
void ReExec() {
@@ -561,7 +620,8 @@ int internal_fork() {
#if SANITIZER_LINUX
#define SA_RESTORER 0x04000000
-// Doesn't set sa_restorer, use with caution (see below).
+// Doesn't set sa_restorer if the caller did not set it, so use with caution
+//(see below).
int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
__sanitizer_kernel_sigaction_t k_act, k_oldact;
internal_memset(&k_act, 0, sizeof(__sanitizer_kernel_sigaction_t));
@@ -583,7 +643,9 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
// rt_sigaction, so we need to do the same (we'll need to reimplement the
// restorers; for x86_64 the restorer address can be obtained from
// oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
+#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
k_act.sa_restorer = u_act->sa_restorer;
+#endif
}
uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
@@ -597,10 +659,31 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
sizeof(__sanitizer_kernel_sigset_t));
u_oldact->sa_flags = k_oldact.sa_flags;
+#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
u_oldact->sa_restorer = k_oldact.sa_restorer;
+#endif
}
return result;
}
+
+// Invokes sigaction via a raw syscall with a restorer, but does not support
+// all platforms yet.
+// We disable for Go simply because we have not yet added to buildgo.sh.
+#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
+int internal_sigaction_syscall(int signum, const void *act, void *oldact) {
+ if (act == nullptr)
+ return internal_sigaction_norestorer(signum, act, oldact);
+ __sanitizer_sigaction u_adjust;
+ internal_memcpy(&u_adjust, act, sizeof(u_adjust));
+#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
+ if (u_adjust.sa_restorer == nullptr) {
+ u_adjust.sa_restorer = internal_sigreturn;
+ }
+#endif
+ return internal_sigaction_norestorer(signum, (const void *)&u_adjust,
+ oldact);
+}
+#endif // defined(__x86_64__) && !SANITIZER_GO
#endif // SANITIZER_LINUX
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
@@ -620,6 +703,10 @@ void internal_sigfillset(__sanitizer_sigset_t *set) {
internal_memset(set, 0xff, sizeof(*set));
}
+void internal_sigemptyset(__sanitizer_sigset_t *set) {
+ internal_memset(set, 0, sizeof(*set));
+}
+
#if SANITIZER_LINUX
void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
signum -= 1;
@@ -630,6 +717,16 @@ void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
k_set->sig[idx] &= ~(1 << bit);
}
+
+bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
+ signum -= 1;
+ CHECK_GE(signum, 0);
+ CHECK_LT(signum, sizeof(*set) * 8);
+ __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
+ const uptr idx = signum / (sizeof(k_set->sig[0]) * 8);
+ const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
+ return k_set->sig[idx] & (1 << bit);
+}
#endif // SANITIZER_LINUX
// ThreadLister implementation.
@@ -701,7 +798,10 @@ bool ThreadLister::GetDirectoryEntries() {
}
uptr GetPageSize() {
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
+// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
+#if SANITIZER_ANDROID
+ return 4096;
+#elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
return EXEC_PAGESIZE;
#else
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
@@ -908,8 +1008,18 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
"bnez $2,1f;\n"
/* Call "fn(arg)". */
+#if SANITIZER_WORDSIZE == 32
+#ifdef __BIG_ENDIAN__
+ "lw $25,4($29);\n"
+ "lw $4,12($29);\n"
+#else
+ "lw $25,0($29);\n"
+ "lw $4,8($29);\n"
+#endif
+#else
"ld $25,0($29);\n"
"ld $4,8($29);\n"
+#endif
"jal $25;\n"
/* Call _exit($v0). */
@@ -981,18 +1091,91 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "x30", "memory");
return res;
}
-#endif // defined(__x86_64__) && SANITIZER_LINUX
+#elif defined(__powerpc64__)
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ long long res;
+/* Stack frame offsets. */
+#if _CALL_ELF != 2
+#define FRAME_MIN_SIZE 112
+#define FRAME_TOC_SAVE 40
+#else
+#define FRAME_MIN_SIZE 32
+#define FRAME_TOC_SAVE 24
+#endif
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
+ ((unsigned long long *)child_stack)[0] = (uptr)fn;
+ ((unsigned long long *)child_stack)[1] = (uptr)arg;
-#if SANITIZER_ANDROID
-#define PROP_VALUE_MAX 92
-extern "C" SANITIZER_WEAK_ATTRIBUTE int __system_property_get(const char *name,
- char *value);
-void GetExtraActivationFlags(char *buf, uptr size) {
- CHECK(size > PROP_VALUE_MAX);
- CHECK(&__system_property_get);
- __system_property_get("asan.options", buf);
+ register int (*__fn)(void *) __asm__("r3") = fn;
+ register void *__cstack __asm__("r4") = child_stack;
+ register int __flags __asm__("r5") = flags;
+ register void * __arg __asm__("r6") = arg;
+ register int * __ptidptr __asm__("r7") = parent_tidptr;
+ register void * __newtls __asm__("r8") = newtls;
+ register int * __ctidptr __asm__("r9") = child_tidptr;
+
+ __asm__ __volatile__(
+ /* fn, arg, child_stack are saved acrVoss the syscall */
+ "mr 28, %5\n\t"
+ "mr 29, %6\n\t"
+ "mr 27, %8\n\t"
+
+ /* syscall
+ r3 == flags
+ r4 == child_stack
+ r5 == parent_tidptr
+ r6 == newtls
+ r7 == child_tidptr */
+ "mr 3, %7\n\t"
+ "mr 5, %9\n\t"
+ "mr 6, %10\n\t"
+ "mr 7, %11\n\t"
+ "li 0, %3\n\t"
+ "sc\n\t"
+
+ /* Test if syscall was successful */
+ "cmpdi cr1, 3, 0\n\t"
+ "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
+ "bne- cr1, 1f\n\t"
+
+ /* Do the function call */
+ "std 2, %13(1)\n\t"
+#if _CALL_ELF != 2
+ "ld 0, 0(28)\n\t"
+ "ld 2, 8(28)\n\t"
+ "mtctr 0\n\t"
+#else
+ "mr 12, 28\n\t"
+ "mtctr 12\n\t"
+#endif
+ "mr 3, 27\n\t"
+ "bctrl\n\t"
+ "ld 2, %13(1)\n\t"
+
+ /* Call _exit(r3) */
+ "li 0, %4\n\t"
+ "sc\n\t"
+
+ /* Return to parent */
+ "1:\n\t"
+ "mr %0, 3\n\t"
+ : "=r" (res)
+ : "0" (-1), "i" (EINVAL),
+ "i" (__NR_clone), "i" (__NR_exit),
+ "r" (__fn), "r" (__cstack), "r" (__flags),
+ "r" (__arg), "r" (__ptidptr), "r" (__newtls),
+ "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE)
+ : "cr0", "cr1", "memory", "ctr",
+ "r0", "r29", "r27", "r28");
+ return res;
}
+#endif // defined(__x86_64__) && SANITIZER_LINUX
+#if SANITIZER_ANDROID
#if __ANDROID_API__ < 21
extern "C" __attribute__((weak)) int dl_iterate_phdr(
int (*)(struct dl_phdr_info *, size_t, void *), void *);
@@ -1035,15 +1218,17 @@ AndroidApiLevel AndroidGetApiLevel() {
#endif
-bool IsDeadlySignal(int signum) {
+bool IsHandledDeadlySignal(int signum) {
if (common_flags()->handle_abort && signum == SIGABRT)
return true;
+ if (common_flags()->handle_sigill && signum == SIGILL)
+ return true;
if (common_flags()->handle_sigfpe && signum == SIGFPE)
return true;
return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void *internal_start_thread(void(*func)(void *arg), void *arg) {
// Start the thread with signals blocked, otherwise it can steal user signals.
__sanitizer_sigset_t set, old;
@@ -1069,6 +1254,54 @@ void *internal_start_thread(void (*func)(void *), void *arg) { return 0; }
void internal_join_thread(void *th) {}
#endif
+#if defined(__aarch64__)
+// Android headers in the older NDK releases miss this definition.
+struct __sanitizer_esr_context {
+ struct _aarch64_ctx head;
+ uint64_t esr;
+};
+
+static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
+ static const u32 kEsrMagic = 0x45535201;
+ u8 *aux = ucontext->uc_mcontext.__reserved;
+ while (true) {
+ _aarch64_ctx *ctx = (_aarch64_ctx *)aux;
+ if (ctx->size == 0) break;
+ if (ctx->magic == kEsrMagic) {
+ *esr = ((__sanitizer_esr_context *)ctx)->esr;
+ return true;
+ }
+ aux += ctx->size;
+ }
+ return false;
+}
+#endif
+
+SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
+ ucontext_t *ucontext = (ucontext_t *)context;
+#if defined(__x86_64__) || defined(__i386__)
+ static const uptr PF_WRITE = 1U << 1;
+#if SANITIZER_FREEBSD
+ uptr err = ucontext->uc_mcontext.mc_err;
+#else
+ uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
+#endif
+ return err & PF_WRITE ? WRITE : READ;
+#elif defined(__arm__)
+ static const uptr FSR_WRITE = 1U << 11;
+ uptr fsr = ucontext->uc_mcontext.error_code;
+ return fsr & FSR_WRITE ? WRITE : READ;
+#elif defined(__aarch64__)
+ static const u64 ESR_ELx_WNR = 1U << 6;
+ u64 esr;
+ if (!Aarch64GetESR(ucontext, &esr)) return UNKNOWN;
+ return esr & ESR_ELx_WNR ? WRITE : READ;
+#else
+ (void)ucontext;
+ return UNKNOWN; // FIXME: Implement.
+#endif
+}
+
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
@@ -1136,11 +1369,29 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.pc;
*bp = ucontext->uc_mcontext.gregs[30];
*sp = ucontext->uc_mcontext.gregs[29];
+#elif defined(__s390__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+# if defined(__s390x__)
+ *pc = ucontext->uc_mcontext.psw.addr;
+# else
+ *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff;
+# endif
+ *bp = ucontext->uc_mcontext.gregs[11];
+ *sp = ucontext->uc_mcontext.gregs[15];
#else
# error "Unsupported arch"
#endif
}
+void MaybeReexec() {
+ // No need to re-exec on Linux.
+}
+
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+ UNREACHABLE("FindAvailableMemoryRange is not available");
+ return 0;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index 44977020bce..895bfc18195 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -32,7 +32,6 @@ uptr internal_sigaltstack(const struct sigaltstack* ss,
struct sigaltstack* oss);
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset);
-void internal_sigfillset(__sanitizer_sigset_t *set);
// Linux-only syscalls.
#if SANITIZER_LINUX
@@ -41,8 +40,13 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
// (like the process-wide error reporting SEGV handler) must use
// internal_sigaction instead.
int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
+#if (defined(__x86_64__) || SANITIZER_MIPS64) && !SANITIZER_GO
+// Uses a raw system call to avoid interceptors.
+int internal_sigaction_syscall(int signum, const void *act, void *oldact);
+#endif
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
+ || defined(__powerpc64__) || defined(__s390__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
index ff69664e7b9..63e70660cf3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -32,6 +32,7 @@
#include <pthread.h>
#include <signal.h>
#include <sys/resource.h>
+#include <syslog.h>
#if SANITIZER_FREEBSD
#include <pthread_np.h>
@@ -49,8 +50,6 @@
#if SANITIZER_ANDROID && __ANDROID_API__ < 21
#include <android/log.h>
-#else
-#include <syslog.h>
#endif
#if !SANITIZER_ANDROID
@@ -156,7 +155,6 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
static uptr g_tls_size;
-#endif
#ifdef __i386__
# define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
@@ -164,26 +162,7 @@ static uptr g_tls_size;
# define DL_INTERNAL_FUNCTION
#endif
-#if defined(__mips__) || defined(__powerpc64__)
-// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
-// head structure. It lies before the static tls blocks.
-static uptr TlsPreTcbSize() {
-# if defined(__mips__)
- const uptr kTcbHead = 16; // sizeof (tcbhead_t)
-# elif defined(__powerpc64__)
- const uptr kTcbHead = 88; // sizeof (tcbhead_t)
-# endif
- const uptr kTlsAlign = 16;
- const uptr kTlsPreTcbSize =
- (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
- InitTlsSize();
- g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1);
- return kTlsPreTcbSize;
-}
-#endif
-
void InitTlsSize() {
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
// all current supported platforms have 16 bytes stack alignment
const size_t kStackAlign = 16;
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
@@ -199,11 +178,13 @@ void InitTlsSize() {
if (tls_align < kStackAlign)
tls_align = kStackAlign;
g_tls_size = RoundUpTo(tls_size, tls_align);
-#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
}
+#else
+void InitTlsSize() { }
+#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
- || defined(__aarch64__) || defined(__powerpc64__)) \
+ || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \
&& SANITIZER_LINUX && !SANITIZER_ANDROID
// sizeof(struct pthread) from glibc.
static atomic_uintptr_t kThreadDescriptorSize;
@@ -220,6 +201,11 @@ uptr ThreadDescriptorSize() {
char *end;
int minor = internal_simple_strtoll(buf + 8, &end, 10);
if (end != buf + 8 && (*end == '\0' || *end == '.')) {
+ int patch = 0;
+ if (*end == '.')
+ // strtoll will return 0 if no valid conversion could be performed
+ patch = internal_simple_strtoll(end + 1, nullptr, 10);
+
/* sizeof(struct pthread) values from various glibc versions. */
if (SANITIZER_X32)
val = 1728; // Assume only one particular version for x32.
@@ -233,9 +219,9 @@ uptr ThreadDescriptorSize() {
val = FIRST_32_SECOND_64(1136, 1712);
else if (minor == 10)
val = FIRST_32_SECOND_64(1168, 1776);
- else if (minor <= 12)
+ else if (minor == 11 || (minor == 12 && patch == 1))
val = FIRST_32_SECOND_64(1168, 2288);
- else if (minor == 13)
+ else if (minor <= 13)
val = FIRST_32_SECOND_64(1168, 2304);
else
val = FIRST_32_SECOND_64(1216, 2304);
@@ -260,6 +246,9 @@ uptr ThreadDescriptorSize() {
val = 1776; // from glibc.ppc64le 2.20-8.fc21
atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
return val;
+#elif defined(__s390__)
+ val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
#endif
return 0;
}
@@ -271,6 +260,24 @@ uptr ThreadSelfOffset() {
return kThreadSelfOffset;
}
+#if defined(__mips__) || defined(__powerpc64__)
+// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
+// head structure. It lies before the static tls blocks.
+static uptr TlsPreTcbSize() {
+# if defined(__mips__)
+ const uptr kTcbHead = 16; // sizeof (tcbhead_t)
+# elif defined(__powerpc64__)
+ const uptr kTcbHead = 88; // sizeof (tcbhead_t)
+# endif
+ const uptr kTlsAlign = 16;
+ const uptr kTlsPreTcbSize =
+ (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
+ InitTlsSize();
+ g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1);
+ return kTlsPreTcbSize;
+}
+#endif
+
uptr ThreadSelf() {
uptr descr_addr;
# if defined(__i386__)
@@ -290,6 +297,9 @@ uptr ThreadSelf() {
.set pop" : "=r" (thread_pointer));
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
# elif defined(__aarch64__)
+ descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
+ ThreadDescriptorSize();
+# elif defined(__s390__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
# elif defined(__powerpc64__)
// PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
@@ -330,7 +340,7 @@ uptr ThreadSelf() {
#if !SANITIZER_GO
static void GetTls(uptr *addr, uptr *size) {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
-# if defined(__x86_64__) || defined(__i386__)
+# if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
*addr = ThreadSelf();
*size = GetTlsSize();
*addr -= *size;
@@ -410,17 +420,12 @@ typedef ElfW(Phdr) Elf_Phdr;
# endif
struct DlIteratePhdrData {
- LoadedModule *modules;
- uptr current_n;
+ InternalMmapVector<LoadedModule> *modules;
bool first;
- uptr max_n;
- string_predicate_t filter;
};
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;
InternalScopedString module_name(kMaxPathLength);
if (data->first) {
data->first = false;
@@ -431,20 +436,18 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
}
if (module_name[0] == '\0')
return 0;
- if (data->filter && !data->filter(module_name.data()))
- return 0;
- LoadedModule *cur_module = &data->modules[data->current_n];
- cur_module->set(module_name.data(), info->dlpi_addr);
- data->current_n++;
+ LoadedModule cur_module;
+ cur_module.set(module_name.data(), info->dlpi_addr);
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;
bool executable = phdr->p_flags & PF_X;
- cur_module->addAddressRange(cur_beg, cur_end, executable);
+ cur_module.addAddressRange(cur_beg, cur_end, executable);
}
}
+ data->modules->push_back(cur_module);
return 0;
}
@@ -453,8 +456,8 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr(
int (*)(struct dl_phdr_info *, size_t, void *), void *);
#endif
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
+void ListOfModules::init() {
+ clear();
#if SANITIZER_ANDROID && __ANDROID_API__ <= 22
u32 api_level = AndroidGetApiLevel();
// Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
@@ -462,13 +465,12 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
// both K and L (and future) Android releases.
if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier
MemoryMappingLayout memory_mapping(false);
- return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+ memory_mapping.DumpListOfModules(&modules_);
+ return;
}
#endif
- CHECK(modules);
- DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
+ DlIteratePhdrData data = {&modules_, true};
dl_iterate_phdr(dl_iterate_phdr_cb, &data);
- return data.current_n;
}
// getrusage does not give us the current RSS, only the max RSS.
@@ -519,19 +521,20 @@ uptr GetRSS() {
static atomic_uint8_t android_log_initialized;
void AndroidLogInit() {
+ openlog(GetProcessName(), 0, LOG_USER);
atomic_store(&android_log_initialized, 1, memory_order_release);
}
-static bool IsSyslogAvailable() {
+static bool ShouldLogAfterPrintf() {
return atomic_load(&android_log_initialized, memory_order_acquire);
}
#else
void AndroidLogInit() {}
-static bool IsSyslogAvailable() { return true; }
+static bool ShouldLogAfterPrintf() { return true; }
#endif // SANITIZER_ANDROID
-static void WriteOneLineToSyslog(const char *s) {
+void WriteOneLineToSyslog(const char *s) {
#if SANITIZER_ANDROID &&__ANDROID_API__ < 21
__android_log_write(ANDROID_LOG_INFO, NULL, s);
#else
@@ -539,24 +542,11 @@ static void WriteOneLineToSyslog(const char *s) {
#endif
}
-void WriteToSyslog(const char *buffer) {
- if (!IsSyslogAvailable())
- return;
- char *copy = internal_strdup(buffer);
- char *p = copy;
- char *q;
- // syslog, at least on Android, has an implicit message length limit.
- // Print one line at a time.
- do {
- q = internal_strchr(p, '\n');
- if (q)
- *q = '\0';
- WriteOneLineToSyslog(p);
- if (q)
- p = q + 1;
- } while (q);
- InternalFree(copy);
+void LogMessageOnPrintf(const char *str) {
+ if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
+ WriteToSyslog(str);
}
+
#endif // SANITIZER_LINUX
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S b/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S
new file mode 100644
index 00000000000..0b76f3a473a
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S
@@ -0,0 +1,21 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Avoid being marked as needing an executable stack:
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+// Further contents are mips64 only:
+#if defined(__linux__) && defined(__mips64)
+
+.section .text
+.set noreorder
+.globl internal_sigreturn
+.type internal_sigreturn, @function
+internal_sigreturn:
+
+ li $v0,5211 // #5211 is for SYS_rt_sigreturn
+ syscall
+
+.size internal_sigreturn, .-internal_sigreturn
+
+#endif // defined(__linux__) && defined(__mips64)
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc
new file mode 100644
index 00000000000..c7d647528ab
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc
@@ -0,0 +1,189 @@
+//===-- sanitizer_linux_s390.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 s390-linux-specific functions from
+// sanitizer_libc.h.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX && SANITIZER_S390
+
+#include "sanitizer_libc.h"
+#include "sanitizer_linux.h"
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+namespace __sanitizer {
+
+// --------------- sanitizer_libc.h
+uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
+ OFF_T offset) {
+ struct s390_mmap_params {
+ unsigned long addr;
+ unsigned long length;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+ } params = {
+ (unsigned long)addr,
+ (unsigned long)length,
+ (unsigned long)prot,
+ (unsigned long)flags,
+ (unsigned long)fd,
+# ifdef __s390x__
+ (unsigned long)offset,
+# else
+ (unsigned long)(offset / 4096),
+# endif
+ };
+# ifdef __s390x__
+ return syscall(__NR_mmap, &params);
+# else
+ return syscall(__NR_mmap2, &params);
+# endif
+}
+
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ // Minimum frame size.
+#ifdef __s390x__
+ child_stack = (char *)child_stack - 160;
+#else
+ child_stack = (char *)child_stack - 96;
+#endif
+ // Terminate unwind chain.
+ ((unsigned long *)child_stack)[0] = 0;
+ // And pass parameters.
+ ((unsigned long *)child_stack)[1] = (uptr)fn;
+ ((unsigned long *)child_stack)[2] = (uptr)arg;
+ register long res __asm__("r2");
+ register void *__cstack __asm__("r2") = child_stack;
+ register int __flags __asm__("r3") = flags;
+ register int * __ptidptr __asm__("r4") = parent_tidptr;
+ register int * __ctidptr __asm__("r5") = child_tidptr;
+ register void * __newtls __asm__("r6") = newtls;
+
+ __asm__ __volatile__(
+ /* Clone. */
+ "svc %1\n"
+
+ /* if (%r2 != 0)
+ * return;
+ */
+#ifdef __s390x__
+ "cghi %%r2, 0\n"
+#else
+ "chi %%r2, 0\n"
+#endif
+ "jne 1f\n"
+
+ /* Call "fn(arg)". */
+#ifdef __s390x__
+ "lmg %%r1, %%r2, 8(%%r15)\n"
+#else
+ "lm %%r1, %%r2, 4(%%r15)\n"
+#endif
+ "basr %%r14, %%r1\n"
+
+ /* Call _exit(%r2). */
+ "svc %2\n"
+
+ /* Return to parent. */
+ "1:\n"
+ : "=r" (res)
+ : "i"(__NR_clone), "i"(__NR_exit),
+ "r"(__cstack),
+ "r"(__flags),
+ "r"(__ptidptr),
+ "r"(__ctidptr),
+ "r"(__newtls)
+ : "memory", "cc");
+ return res;
+}
+
+#if SANITIZER_S390_64
+static bool FixedCVE_2016_2143() {
+ // Try to determine if the running kernel has a fix for CVE-2016-2143,
+ // return false if in doubt (better safe than sorry). Distros may want to
+ // adjust this for their own kernels.
+ struct utsname buf;
+ unsigned int major, minor, patch = 0;
+ // This should never fail, but just in case...
+ if (uname(&buf))
+ return false;
+ char *ptr = buf.release;
+ major = internal_simple_strtoll(ptr, &ptr, 10);
+ // At least first 2 should be matched.
+ if (ptr[0] != '.')
+ return false;
+ minor = internal_simple_strtoll(ptr+1, &ptr, 10);
+ // Third is optional.
+ if (ptr[0] == '.')
+ patch = internal_simple_strtoll(ptr+1, &ptr, 10);
+ if (major < 3) {
+ // <3.0 is bad.
+ return false;
+ } else if (major == 3) {
+ // 3.2.79+ is OK.
+ if (minor == 2 && patch >= 79)
+ return true;
+ // 3.12.58+ is OK.
+ if (minor == 12 && patch >= 58)
+ return true;
+ // Otherwise, bad.
+ return false;
+ } else if (major == 4) {
+ // 4.1.21+ is OK.
+ if (minor == 1 && patch >= 21)
+ return true;
+ // 4.4.6+ is OK.
+ if (minor == 4 && patch >= 6)
+ return true;
+ // Otherwise, OK if 4.5+.
+ return minor >= 5;
+ } else {
+ // Linux 5 and up are fine.
+ return true;
+ }
+}
+
+void AvoidCVE_2016_2143() {
+ // Older kernels are affected by CVE-2016-2143 - they will crash hard
+ // if someone uses 4-level page tables (ie. virtual addresses >= 4TB)
+ // and fork() in the same process. Unfortunately, sanitizers tend to
+ // require such addresses. Since this is very likely to crash the whole
+ // machine (sanitizers themselves use fork() for llvm-symbolizer, for one),
+ // abort the process at initialization instead.
+ if (FixedCVE_2016_2143())
+ return;
+ if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
+ return;
+ Report(
+ "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143. Using ASan,\n"
+ "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
+ "machine, or worse.\n"
+ "\n"
+ "If you are certain your kernel is not vulnerable (you have compiled it\n"
+ "yourself, or are using an unrecognized distribution kernel), you can\n"
+ "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
+ "with any value.\n");
+ Die();
+}
+#endif
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LINUX && SANITIZER_S390
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S b/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S
new file mode 100644
index 00000000000..6b892116ff4
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S
@@ -0,0 +1,23 @@
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Avoid being marked as needing an executable stack:
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+// Further contents are x86_64-only:
+#if defined(__linux__) && defined(__x86_64__)
+
+#include "../builtins/assembly.h"
+
+// If the "naked" function attribute were supported for x86 we could
+// do this via inline asm.
+.text
+.balign 4
+DEFINE_COMPILERRT_FUNCTION(internal_sigreturn)
+ mov $0xf, %eax // 0xf == SYS_rt_sigreturn
+ mov %rcx, %r10
+ syscall
+ ret // Won't normally reach here.
+END_COMPILERRT_FUNCTION(internal_sigreturn)
+
+#endif // defined(__linux__) && defined(__x86_64__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_list.h b/libsanitizer/sanitizer_common/sanitizer_list.h
index 9216ede67fb..190c7e67cf0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_list.h
+++ b/libsanitizer/sanitizer_common/sanitizer_list.h
@@ -69,7 +69,9 @@ struct IntrusiveList {
}
Item *front() { return first_; }
+ const Item *front() const { return first_; }
Item *back() { return last_; }
+ const Item *back() const { return last_; }
void append_front(IntrusiveList<Item> *l) {
CHECK_NE(this, l);
@@ -114,24 +116,32 @@ struct IntrusiveList {
}
}
- template<class ListTy, class ItemTy>
+ template<class ItemTy>
class IteratorBase {
public:
- explicit IteratorBase(ListTy *list)
- : list_(list), current_(list->first_) { }
- ItemTy *next() {
- ItemTy *ret = current_;
- if (current_) current_ = current_->next;
- return ret;
+ explicit IteratorBase(ItemTy *current) : current_(current) {}
+ IteratorBase &operator++() {
+ current_ = current_->next;
+ return *this;
+ }
+ bool operator!=(IteratorBase other) const {
+ return current_ != other.current_;
+ }
+ ItemTy &operator*() {
+ return *current_;
}
- bool hasNext() const { return current_ != nullptr; }
private:
- ListTy *list_;
ItemTy *current_;
};
- typedef IteratorBase<IntrusiveList<Item>, Item> Iterator;
- typedef IteratorBase<const IntrusiveList<Item>, const Item> ConstIterator;
+ typedef IteratorBase<Item> Iterator;
+ typedef IteratorBase<const Item> ConstIterator;
+
+ Iterator begin() { return Iterator(first_); }
+ Iterator end() { return Iterator(0); }
+
+ ConstIterator begin() const { return ConstIterator(first_); }
+ ConstIterator end() const { return ConstIterator(0); }
// private, don't use directly.
uptr size_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc
index 159db76f01e..4408d1dccb9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc
@@ -11,6 +11,7 @@
#include "sanitizer_platform.h"
#if SANITIZER_MAC
+#include "sanitizer_mac.h"
// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
// the clients will most certainly use 64-bit ones as well.
@@ -23,7 +24,6 @@
#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
-#include "sanitizer_mac.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_limits_posix.h"
#include "sanitizer_procmaps.h"
@@ -34,6 +34,23 @@
extern char **environ;
#endif
+#if defined(__has_include) && __has_include(<os/trace.h>)
+#define SANITIZER_OS_TRACE 1
+#include <os/trace.h>
+#else
+#define SANITIZER_OS_TRACE 0
+#endif
+
+#if !SANITIZER_IOS
+#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
+#else
+extern "C" {
+ extern char ***_NSGetArgv(void);
+}
+#endif
+
+#include <asl.h>
+#include <dlfcn.h> // for dladdr()
#include <errno.h>
#include <fcntl.h>
#include <libkern/OSAtomic.h>
@@ -49,21 +66,45 @@ extern char **environ;
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
+#include <util.h>
+
+// From <crt_externs.h>, but we don't have that file on iOS.
+extern "C" {
+ extern char ***_NSGetArgv(void);
+ extern char ***_NSGetEnviron(void);
+}
+
+// From <mach/mach_vm.h>, but we don't have that file on iOS.
+extern "C" {
+ extern kern_return_t mach_vm_region_recurse(
+ vm_map_t target_task,
+ mach_vm_address_t *address,
+ mach_vm_size_t *size,
+ natural_t *nesting_depth,
+ vm_region_recurse_info_t info,
+ mach_msg_type_number_t *infoCnt);
+}
namespace __sanitizer {
#include "sanitizer_syscall_generic.inc"
+// Direct syscalls, don't call libmalloc hooks.
+extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,
+ off_t off);
+extern "C" int __munmap(void *, size_t);
+
// ---------------------- sanitizer_libc.h
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
int fd, u64 offset) {
if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
- return (uptr)mmap(addr, length, prot, flags, fd, offset);
+ return (uptr)__mmap(addr, length, prot, flags, fd, offset);
}
uptr internal_munmap(void *addr, uptr length) {
- return munmap(addr, length);
+ return __munmap(addr, length);
}
int internal_mprotect(void *addr, uptr length, int prot) {
@@ -129,6 +170,10 @@ void internal__exit(int exitcode) {
_exit(exitcode);
}
+unsigned int internal_sleep(unsigned int seconds) {
+ return sleep(seconds);
+}
+
uptr internal_getpid() {
return getpid();
}
@@ -145,9 +190,34 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
return sigprocmask(how, set, oldset);
}
+// Doesn't call pthread_atfork() handlers.
+extern "C" pid_t __fork(void);
+
int internal_fork() {
- // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
- return fork();
+ return __fork();
+}
+
+int internal_forkpty(int *amaster) {
+ int master, slave;
+ if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1;
+ int pid = __fork();
+ if (pid == -1) {
+ close(master);
+ close(slave);
+ return -1;
+ }
+ if (pid == 0) {
+ close(master);
+ if (login_tty(slave) != 0) {
+ // We already forked, there's not much we can do. Let's quit.
+ Report("login_tty failed (errno %d)\n", errno);
+ internal__exit(1);
+ }
+ } else {
+ *amaster = master;
+ close(slave);
+ }
+ return pid;
}
uptr internal_rename(const char *oldpath, const char *newpath) {
@@ -158,6 +228,15 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
return ftruncate(fd, size);
}
+uptr internal_execve(const char *filename, char *const argv[],
+ char *const envp[]) {
+ return execve(filename, argv, envp);
+}
+
+uptr internal_waitpid(int pid, int *status, int options) {
+ return waitpid(pid, status, options);
+}
+
// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
struct stat st;
@@ -168,7 +247,10 @@ bool FileExists(const char *filename) {
}
uptr GetTid() {
- return reinterpret_cast<uptr>(pthread_self());
+ // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes.
+ uint64_t tid;
+ pthread_threadid_np(nullptr, &tid);
+ return tid;
}
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -178,7 +260,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr stacksize = pthread_get_stacksize_np(pthread_self());
// pthread_get_stacksize_np() returns an incorrect stack size for the main
// thread on Mavericks. See
- // https://code.google.com/p/address-sanitizer/issues/detail?id=261
+ // https://github.com/google/sanitizers/issues/261
if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
stacksize == (1 << 19)) {
struct rlimit rl;
@@ -289,7 +371,7 @@ void InitTlsSize() {
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
uptr stack_top, stack_bottom;
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
*stk_addr = stack_bottom;
@@ -304,13 +386,18 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif
}
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
+void ListOfModules::init() {
+ clear();
MemoryMappingLayout memory_mapping(false);
- return memory_mapping.DumpListOfModules(modules, max_modules, filter);
+ memory_mapping.DumpListOfModules(&modules_);
}
-bool IsDeadlySignal(int signum) {
+bool IsHandledDeadlySignal(int signum) {
+ if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
+ // Handling fatal signals on watchOS and tvOS devices is disallowed.
+ return false;
+ if (common_flags()->handle_abort && signum == SIGABRT)
+ return true;
return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
}
@@ -382,6 +469,70 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) {
void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
+#if !SANITIZER_GO
+static BlockingMutex syslog_lock(LINKER_INITIALIZED);
+#endif
+
+void WriteOneLineToSyslog(const char *s) {
+#if !SANITIZER_GO
+ syslog_lock.CheckLocked();
+ asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
+#endif
+}
+
+void LogMessageOnPrintf(const char *str) {
+ // Log all printf output to CrashLog.
+ if (common_flags()->abort_on_error)
+ CRAppendCrashLogMessage(str);
+}
+
+void LogFullErrorReport(const char *buffer) {
+#if !SANITIZER_GO
+ // Log with os_trace. This will make it into the crash log.
+#if SANITIZER_OS_TRACE
+ if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) {
+ // os_trace requires the message (format parameter) to be a string literal.
+ if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
+ sizeof("AddressSanitizer") - 1) == 0)
+ os_trace("Address Sanitizer reported a failure.");
+ else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
+ sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
+ os_trace("Undefined Behavior Sanitizer reported a failure.");
+ else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
+ sizeof("ThreadSanitizer") - 1) == 0)
+ os_trace("Thread Sanitizer reported a failure.");
+ else
+ os_trace("Sanitizer tool reported a failure.");
+
+ if (common_flags()->log_to_syslog)
+ os_trace("Consult syslog for more information.");
+ }
+#endif
+
+ // Log to syslog.
+ // The logging on OS X may call pthread_create so we need the threading
+ // environment to be fully initialized. Also, this should never be called when
+ // holding the thread registry lock since that may result in a deadlock. If
+ // the reporting thread holds the thread registry mutex, and asl_log waits
+ // for GCD to dispatch a new thread, the process will deadlock, because the
+ // pthread_create wrapper needs to acquire the lock as well.
+ BlockingMutexLock l(&syslog_lock);
+ if (common_flags()->log_to_syslog)
+ WriteToSyslog(buffer);
+
+ // The report is added to CrashLog as part of logging all of Printf output.
+#endif
+}
+
+SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
+#if defined(__x86_64__) || defined(__i386__)
+ ucontext_t *ucontext = static_cast<ucontext_t*>(context);
+ return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ;
+#else
+ return UNKNOWN;
+#endif
+}
+
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
ucontext_t *ucontext = (ucontext_t*)context;
# if defined(__aarch64__)
@@ -409,6 +560,237 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif
}
+#if !SANITIZER_GO
+static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
+LowLevelAllocator allocator_for_env;
+
+// Change the value of the env var |name|, leaking the original value.
+// If |name_value| is NULL, the variable is deleted from the environment,
+// otherwise the corresponding "NAME=value" string is replaced with
+// |name_value|.
+void LeakyResetEnv(const char *name, const char *name_value) {
+ char **env = GetEnviron();
+ uptr name_len = internal_strlen(name);
+ while (*env != 0) {
+ uptr len = internal_strlen(*env);
+ if (len > name_len) {
+ const char *p = *env;
+ if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
+ // Match.
+ if (name_value) {
+ // Replace the old value with the new one.
+ *env = const_cast<char*>(name_value);
+ } else {
+ // Shift the subsequent pointers back.
+ char **del = env;
+ do {
+ del[0] = del[1];
+ } while (*del++);
+ }
+ }
+ }
+ env++;
+ }
+}
+
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+bool ReexecDisabled() {
+ return false;
+}
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber;
+static const double kMinDyldVersionWithAutoInterposition = 360.0;
+
+bool DyldNeedsEnvVariable() {
+ // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users
+ // still may want use them on older systems. On older Darwin platforms, dyld
+ // doesn't export dyldVersionNumber symbol and we simply return true.
+ if (!&dyldVersionNumber) return true;
+ // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if
+ // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via
+ // GetMacosVersion() doesn't work for the simulator. Let's instead check
+ // `dyldVersionNumber`, which is exported by dyld, against a known version
+ // number from the first OS release where this appeared.
+ return dyldVersionNumber < kMinDyldVersionWithAutoInterposition;
+}
+
+void MaybeReexec() {
+ if (ReexecDisabled()) return;
+
+ // Make sure the dynamic runtime library is preloaded so that the
+ // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+ // ourselves.
+ Dl_info info;
+ RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info));
+ char *dyld_insert_libraries =
+ const_cast<char*>(GetEnv(kDyldInsertLibraries));
+ uptr old_env_len = dyld_insert_libraries ?
+ internal_strlen(dyld_insert_libraries) : 0;
+ uptr fname_len = internal_strlen(info.dli_fname);
+ const char *dylib_name = StripModuleName(info.dli_fname);
+ uptr dylib_name_len = internal_strlen(dylib_name);
+
+ bool lib_is_in_env = dyld_insert_libraries &&
+ internal_strstr(dyld_insert_libraries, dylib_name);
+ if (DyldNeedsEnvVariable() && !lib_is_in_env) {
+ // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
+ // library.
+ InternalScopedString program_name(1024);
+ uint32_t buf_size = program_name.size();
+ _NSGetExecutablePath(program_name.data(), &buf_size);
+ char *new_env = const_cast<char*>(info.dli_fname);
+ if (dyld_insert_libraries) {
+ // Append the runtime dylib name to the existing value of
+ // DYLD_INSERT_LIBRARIES.
+ new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2);
+ internal_strncpy(new_env, dyld_insert_libraries, old_env_len);
+ new_env[old_env_len] = ':';
+ // Copy fname_len and add a trailing zero.
+ internal_strncpy(new_env + old_env_len + 1, info.dli_fname,
+ fname_len + 1);
+ // Ok to use setenv() since the wrappers don't depend on the value of
+ // asan_inited.
+ setenv(kDyldInsertLibraries, new_env, /*overwrite*/1);
+ } else {
+ // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
+ setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
+ }
+ VReport(1, "exec()-ing the program with\n");
+ VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env);
+ VReport(1, "to enable wrappers.\n");
+ execv(program_name.data(), *_NSGetArgv());
+
+ // We get here only if execv() failed.
+ Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, "
+ "which is required for the sanitizer to work. We tried to set the "
+ "environment variable and re-execute itself, but execv() failed, "
+ "possibly because of sandbox restrictions. Make sure to launch the "
+ "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env);
+ RAW_CHECK("execv failed" && 0);
+ }
+
+ // Verify that interceptors really work. We'll use dlsym to locate
+ // "pthread_create", if interceptors are working, it should really point to
+ // "wrap_pthread_create" within our own dylib.
+ Dl_info info_pthread_create;
+ void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create");
+ RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create));
+ if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) {
+ Report(
+ "ERROR: Interceptors are not working. This may be because %s is "
+ "loaded too late (e.g. via dlopen). Please launch the executable "
+ "with:\n%s=%s\n",
+ SanitizerToolName, kDyldInsertLibraries, info.dli_fname);
+ RAW_CHECK("interceptors not installed" && 0);
+ }
+
+ if (!lib_is_in_env)
+ return;
+
+ // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
+ // the dylib from the environment variable, because interceptors are installed
+ // and we don't want our children to inherit the variable.
+
+ uptr env_name_len = internal_strlen(kDyldInsertLibraries);
+ // Allocate memory to hold the previous env var name, its value, the '='
+ // sign and the '\0' char.
+ char *new_env = (char*)allocator_for_env.Allocate(
+ old_env_len + 2 + env_name_len);
+ RAW_CHECK(new_env);
+ internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
+ internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
+ new_env[env_name_len] = '=';
+ char *new_env_pos = new_env + env_name_len + 1;
+
+ // Iterate over colon-separated pieces of |dyld_insert_libraries|.
+ char *piece_start = dyld_insert_libraries;
+ char *piece_end = NULL;
+ char *old_env_end = dyld_insert_libraries + old_env_len;
+ do {
+ if (piece_start[0] == ':') piece_start++;
+ piece_end = internal_strchr(piece_start, ':');
+ if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
+ if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
+ uptr piece_len = piece_end - piece_start;
+
+ char *filename_start =
+ (char *)internal_memrchr(piece_start, '/', piece_len);
+ uptr filename_len = piece_len;
+ if (filename_start) {
+ filename_start += 1;
+ filename_len = piece_len - (filename_start - piece_start);
+ } else {
+ filename_start = piece_start;
+ }
+
+ // If the current piece isn't the runtime library name,
+ // append it to new_env.
+ if ((dylib_name_len != filename_len) ||
+ (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
+ if (new_env_pos != new_env + env_name_len + 1) {
+ new_env_pos[0] = ':';
+ new_env_pos++;
+ }
+ internal_strncpy(new_env_pos, piece_start, piece_len);
+ new_env_pos += piece_len;
+ }
+ // Move on to the next piece.
+ piece_start = piece_end;
+ } while (piece_start < old_env_end);
+
+ // Can't use setenv() here, because it requires the allocator to be
+ // initialized.
+ // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
+ // a separate function called after InitializeAllocator().
+ if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
+ LeakyResetEnv(kDyldInsertLibraries, new_env);
+}
+#endif // SANITIZER_GO
+
+char **GetArgv() {
+ return *_NSGetArgv();
+}
+
+uptr FindAvailableMemoryRange(uptr shadow_size,
+ uptr alignment,
+ uptr left_padding) {
+ typedef vm_region_submap_short_info_data_64_t RegionInfo;
+ enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
+ // Start searching for available memory region past PAGEZERO, which is
+ // 4KB on 32-bit and 4GB on 64-bit.
+ mach_vm_address_t start_address =
+ (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000;
+
+ mach_vm_address_t address = start_address;
+ mach_vm_address_t free_begin = start_address;
+ kern_return_t kr = KERN_SUCCESS;
+ while (kr == KERN_SUCCESS) {
+ mach_vm_size_t vmsize = 0;
+ natural_t depth = 0;
+ RegionInfo vminfo;
+ mach_msg_type_number_t count = kRegionInfoSize;
+ kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
+ (vm_region_info_t)&vminfo, &count);
+ if (free_begin != address) {
+ // We found a free region [free_begin..address-1].
+ uptr shadow_address = RoundUpTo((uptr)free_begin + left_padding,
+ alignment);
+ if (shadow_address + shadow_size < (uptr)address) {
+ return shadow_address;
+ }
+ }
+ // Move to the next region.
+ address += vmsize;
+ free_begin = address;
+ }
+
+ // We looked at all free regions and could not find one large enough.
+ return 0;
+}
+
+// FIXME implement on this platform.
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { }
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index 2aac83e3657..4bea069189f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
@@ -11,6 +11,7 @@
#ifndef SANITIZER_MAC_H
#define SANITIZER_MAC_H
+#include "sanitizer_common.h"
#include "sanitizer_platform.h"
#if SANITIZER_MAC
#include "sanitizer_posix.h"
@@ -35,5 +36,22 @@ char **GetEnviron();
} // namespace __sanitizer
+extern "C" {
+static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
+ {};
+static const char *__crashreporter_info__ __attribute__((__used__)) =
+ &__crashreporter_info_buff__[0];
+asm(".desc ___crashreporter_info__, 0x10");
+} // extern "C"
+
+namespace __sanitizer {
+static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
+
+INLINE void CRAppendCrashLogMessage(const char *msg) {
+ BlockingMutexLock l(&crashreporter_info_mutex);
+ internal_strlcat(__crashreporter_info_buff__, msg,
+ sizeof(__crashreporter_info_buff__)); }
+} // namespace __sanitizer
+
#endif // SANITIZER_MAC
#endif // SANITIZER_MAC_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
index 6ed0f69de97..93fb19e922c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
@@ -25,7 +25,7 @@
#include "sanitizer_common/sanitizer_mac.h"
// Similar code is used in Google Perftools,
-// http://code.google.com/p/google-perftools.
+// https://github.com/gperftools/gperftools.
static malloc_zone_t sanitizer_zone;
@@ -54,7 +54,7 @@ INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
// FIXME: ASan should support purgeable allocations.
- // https://code.google.com/p/address-sanitizer/issues/detail?id=139
+ // https://github.com/google/sanitizers/issues/139
COMMON_MALLOC_ENTER();
return &sanitizer_zone;
}
@@ -182,28 +182,18 @@ void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) {
return p;
}
-#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;
- // FIXME: need to retire this flag.
- if (!COMMON_MALLOC_IGNORE_INVALID_FREE) {
- COMMON_MALLOC_FREE(ptr);
- } else {
- GET_ZONE_FOR_PTR(ptr);
- COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name);
- }
-}
-
// TODO(glider): the allocation callbacks need to be refactored.
extern "C"
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
- free_common(zone, ptr);
+ if (!ptr) return;
+ COMMON_MALLOC_FREE(ptr);
}
+#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
+
extern "C"
SANITIZER_INTERFACE_ATTRIBUTE
void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index 7d0ff2896e9..428709d55ec 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -47,12 +47,30 @@
# define SANITIZER_IOSSIM 0
#endif
+#if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
+# define SANITIZER_WATCHOS 1
+#else
+# define SANITIZER_WATCHOS 0
+#endif
+
+#if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_TV
+# define SANITIZER_TVOS 1
+#else
+# define SANITIZER_TVOS 0
+#endif
+
#if defined(_WIN32)
# define SANITIZER_WINDOWS 1
#else
# define SANITIZER_WINDOWS 0
#endif
+#if defined(_WIN64)
+# define SANITIZER_WINDOWS64 1
+#else
+# define SANITIZER_WINDOWS64 0
+#endif
+
#if defined(__ANDROID__)
# define SANITIZER_ANDROID 1
#else
@@ -79,14 +97,67 @@
# define SANITIZER_X32 0
#endif
-// VMA size definition for architecture that support multiple sizes.
-// AArch64 has 3 VMA sizes: 39, 42 and 48.
-#if !defined(SANITIZER_AARCH64_VMA)
-# define SANITIZER_AARCH64_VMA 39
+#if defined(__mips__)
+# define SANITIZER_MIPS 1
+# if defined(__mips64)
+# define SANITIZER_MIPS32 0
+# define SANITIZER_MIPS64 1
+# else
+# define SANITIZER_MIPS32 1
+# define SANITIZER_MIPS64 0
+# endif
#else
-# if SANITIZER_AARCH64_VMA != 39 && SANITIZER_AARCH64_VMA != 42
-# error "invalid SANITIZER_AARCH64_VMA size"
+# define SANITIZER_MIPS 0
+# define SANITIZER_MIPS32 0
+# define SANITIZER_MIPS64 0
+#endif
+
+#if defined(__s390__)
+# define SANITIZER_S390 1
+# if defined(__s390x__)
+# define SANITIZER_S390_31 0
+# define SANITIZER_S390_64 1
+# else
+# define SANITIZER_S390_31 1
+# define SANITIZER_S390_64 0
+# endif
+#else
+# define SANITIZER_S390 0
+# define SANITIZER_S390_31 0
+# define SANITIZER_S390_64 0
+#endif
+
+#if defined(__powerpc__)
+# define SANITIZER_PPC 1
+# if defined(__powerpc64__)
+# define SANITIZER_PPC32 0
+# define SANITIZER_PPC64 1
+// 64-bit PPC has two ABIs (v1 and v2). The old powerpc64 target is
+// big-endian, and uses v1 ABI (known for its function descriptors),
+// while the new powerpc64le target is little-endian and uses v2.
+// In theory, you could convince gcc to compile for their evil twins
+// (eg. big-endian v2), but you won't find such combinations in the wild
+// (it'd require bootstrapping a whole system, which would be quite painful
+// - there's no target triple for that). LLVM doesn't support them either.
+# if _CALL_ELF == 2
+# define SANITIZER_PPC64V1 0
+# define SANITIZER_PPC64V2 1
+# else
+# define SANITIZER_PPC64V1 1
+# define SANITIZER_PPC64V2 0
+# endif
+# else
+# define SANITIZER_PPC32 1
+# define SANITIZER_PPC64 0
+# define SANITIZER_PPC64V1 0
+# define SANITIZER_PPC64V2 0
# endif
+#else
+# define SANITIZER_PPC 0
+# define SANITIZER_PPC32 0
+# define SANITIZER_PPC64 0
+# define SANITIZER_PPC64V1 0
+# define SANITIZER_PPC64V2 0
#endif
// By default we allow to use SizeClassAllocator64 on 64-bit platform.
@@ -95,7 +166,9 @@
// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
#ifndef SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__mips64) || defined(__aarch64__)
+# if SANITIZER_ANDROID && defined(__aarch64__)
+# define SANITIZER_CAN_USE_ALLOCATOR64 1
+# elif defined(__mips64) || defined(__aarch64__)
# define SANITIZER_CAN_USE_ALLOCATOR64 0
# else
# define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
@@ -107,6 +180,8 @@
// will still work but will consume more memory for TwoLevelByteMap.
#if defined(__mips__)
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40)
+#elif defined(__aarch64__)
+# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
#else
# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
#endif
@@ -135,10 +210,8 @@
#define SANITIZER_USES_UID16_SYSCALLS 0
#endif
-#if defined(__mips__) || (defined(__aarch64__) && SANITIZER_AARCH64_VMA == 39)
+#if defined(__mips__)
# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
-#elif defined(__aarch64__) && SANITIZER_AARCH64_VMA == 42
-# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 11)
#else
# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
#endif
@@ -160,4 +233,22 @@
# define MSC_PREREQ(version) 0
#endif
+#if defined(__arm64__) && SANITIZER_IOS
+# define SANITIZER_NON_UNIQUE_TYPEINFO 1
+#else
+# define SANITIZER_NON_UNIQUE_TYPEINFO 0
+#endif
+
+// On linux, some architectures had an ABI transition from 64-bit long double
+// (ie. same as double) to 128-bit long double. On those, glibc symbols
+// involving long doubles come in two versions, and we need to pass the
+// correct one to dlvsym when intercepting them.
+#if SANITIZER_LINUX && (SANITIZER_S390 || SANITIZER_PPC32 || SANITIZER_PPC64V1)
+#define SANITIZER_NLDBL_VERSION "GLIBC_2.4"
+#endif
+
+#if SANITIZER_GO == 0
+# define SANITIZER_GO 0
+#endif
+
#endif // SANITIZER_PLATFORM_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 040e030e088..2a886058187 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -27,6 +27,12 @@
# define SI_LINUX_NOT_ANDROID 0
#endif
+#if SANITIZER_ANDROID
+# define SI_ANDROID 1
+#else
+# define SI_ANDROID 0
+#endif
+
#if SANITIZER_FREEBSD
# define SI_FREEBSD 1
#else
@@ -41,8 +47,10 @@
#if SANITIZER_MAC
# define SI_MAC 1
+# define SI_NOT_MAC 0
#else
# define SI_MAC 0
+# define SI_NOT_MAC 1
#endif
#if SANITIZER_IOS
@@ -51,14 +59,30 @@
# define SI_IOS 0
#endif
+#if !SANITIZER_WINDOWS && !SANITIZER_MAC
+# define SI_UNIX_NOT_MAC 1
+#else
+# define SI_UNIX_NOT_MAC 0
+#endif
+
+#define SANITIZER_INTERCEPT_STRLEN 1
+#define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC
#define SANITIZER_INTERCEPT_STRCMP 1
#define SANITIZER_INTERCEPT_STRSTR 1
#define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRCHR 1
+#define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC
+#define SANITIZER_INTERCEPT_STRRCHR 1
#define SANITIZER_INTERCEPT_STRSPN 1
#define SANITIZER_INTERCEPT_STRPBRK 1
#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MEMSET 1
+#define SANITIZER_INTERCEPT_MEMMOVE 1
+#define SANITIZER_INTERCEPT_MEMCPY 1
#define SANITIZER_INTERCEPT_MEMCMP 1
+// FIXME: enable memmem on Windows.
+#define SANITIZER_INTERCEPT_MEMMEM SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_MEMCHR 1
#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX
@@ -123,15 +147,21 @@
#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SENDMSG SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
+#if SI_LINUX_NOT_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+ defined(__s390__))
+#define SANITIZER_INTERCEPT_PTRACE 1
+#else
+#define SANITIZER_INTERCEPT_PTRACE 0
+#endif
#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
@@ -203,6 +233,7 @@
#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_TTYNAME_R SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_SINCOS SI_LINUX
#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
@@ -235,7 +266,11 @@
#define SANITIZER_INTERCEPT_IF_INDEXTONAME \
SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__)
+#if SI_LINUX && defined(__arm__)
+#define SANITIZER_INTERCEPT_AEABI_MEM 1
+#else
+#define SANITIZER_INTERCEPT_AEABI_MEM 0
+#endif
#define SANITIZER_INTERCEPT___BZERO SI_MAC
#define SANITIZER_INTERCEPT_FTIME !SI_FREEBSD && SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID
@@ -247,8 +282,12 @@
#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
+
+#ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+#endif
+
#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
@@ -258,7 +297,17 @@
#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_MINCORE SI_LINUX
#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX
+#define SANITIZER_INTERCEPT_CTERMID SI_LINUX || SI_MAC || SI_FREEBSD
+#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD
#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX
+#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SEND_SENDTO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
+#define SANITIZER_INTERCEPT_STAT (SI_FREEBSD || SI_MAC || SI_ANDROID)
+#define SANITIZER_INTERCEPT___XSTAT !SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT
+#define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
index a1f04325033..23a014823c4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -26,7 +26,7 @@
// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
// are not defined anywhere in userspace headers. Fake them. This seems to work
// fine with newer headers, too.
-#include <asm/posix_types.h>
+#include <linux/posix_types.h>
#if defined(__x86_64__) || defined(__mips__)
#include <sys/stat.h>
#else
@@ -54,6 +54,8 @@
#include <linux/perf_event.h>
#endif
+using namespace __sanitizer;
+
namespace __sanitizer {
#if !SANITIZER_ANDROID
unsigned struct_statfs64_sz = sizeof(struct statfs64);
@@ -61,7 +63,8 @@ namespace __sanitizer {
} // namespace __sanitizer
#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\
- && !defined(__mips__) && !defined(__sparc__)
+ && !defined(__mips__) && !defined(__s390__)\
+ && !defined(__sparc__)
COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
index 9866cc9e17a..7bf76c4e715 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -121,6 +121,10 @@
# include <asm/ptrace.h>
# ifdef __arm__
typedef struct user_fpregs elf_fpregset_t;
+# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/)
+# if !defined(ARM_VFPREGS_SIZE)
+# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN
+# endif
# endif
# endif
# include <semaphore.h>
@@ -305,23 +309,28 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+ defined(__s390__))
#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
#elif defined(__aarch64__)
unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state);
+#elif defined(__s390__)
+ unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct);
+ unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct);
#else
unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
#endif // __mips64 || __powerpc64__ || __aarch64__
#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
- defined(__aarch64__) || defined(__arm__)
+ defined(__aarch64__) || defined(__arm__) || defined(__s390__)
unsigned struct_user_fpxregs_struct_sz = 0;
#else
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__
+// || __s390__
#ifdef __arm__
unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
#else
@@ -926,6 +935,8 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
const int si_SEGV_ACCERR = SEGV_ACCERR;
} // namespace __sanitizer
+using namespace __sanitizer;
+
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
@@ -1049,8 +1060,15 @@ COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
// Can't write checks for sa_handler and sa_sigaction due to them being
// preprocessor macros.
CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+#if !defined(__s390x__) || __GLIBC_PREREQ (2, 20)
+// On s390x glibc 2.19 and earlier sa_flags was unsigned long, and sa_resv
+// didn't exist.
CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
-#if SANITIZER_LINUX
+#endif
+#if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32)
CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
#endif
@@ -1121,9 +1139,6 @@ CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
-#ifndef __GLIBC_PREREQ
-#define __GLIBC_PREREQ(x, y) 0
-#endif
#if !defined(__aarch64__) || !SANITIZER_LINUX || __GLIBC_PREREQ (2, 21)
/* On aarch64 glibc 2.20 and earlier provided incorrect mode field. */
CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
@@ -1262,4 +1277,8 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
CHECK_TYPE_SIZE(sem_t);
#endif
+#if SANITIZER_LINUX && defined(__arm__)
+COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN);
+#endif
+
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index b6f90eb3a74..d1a30516997 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -18,7 +18,7 @@
#if SANITIZER_FREEBSD
// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
-// incroporates the map structure.
+// incorporates the map structure.
# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544)))
#else
@@ -75,12 +75,16 @@ namespace __sanitizer {
const unsigned struct_kernel_stat_sz = 144;
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__mips__)
- #if SANITIZER_WORDSIZE == 64
- const unsigned struct_kernel_stat_sz = 216;
- #else
- const unsigned struct_kernel_stat_sz = 144;
- #endif
+ const unsigned struct_kernel_stat_sz =
+ SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) :
+ FIRST_32_SECOND_64(144, 216);
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__s390__) && !defined(__s390x__)
+ const unsigned struct_kernel_stat_sz = 64;
const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__s390x__)
+ const unsigned struct_kernel_stat_sz = 144;
+ const unsigned struct_kernel_stat64_sz = 0;
#elif defined(__sparc__) && defined(__arch64__)
const unsigned struct___old_kernel_stat_sz = 0;
const unsigned struct_kernel_stat_sz = 104;
@@ -109,7 +113,7 @@ namespace __sanitizer {
#if SANITIZER_LINUX || SANITIZER_FREEBSD
-#if defined(__powerpc64__)
+#if defined(__powerpc64__) || defined(__s390__)
const unsigned struct___old_kernel_stat_sz = 0;
#elif !defined(__sparc__)
const unsigned struct___old_kernel_stat_sz = 32;
@@ -196,7 +200,7 @@ namespace __sanitizer {
unsigned __seq;
u64 __unused1;
u64 __unused2;
-#elif defined(__mips__) || defined(__aarch64__)
+#elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__)
unsigned int mode;
unsigned short __seq;
unsigned short __pad1;
@@ -250,7 +254,7 @@ namespace __sanitizer {
unsigned long shm_nattch;
unsigned long __glibc_reserved1;
unsigned long __glibc_reserved2;
- #else
+ #else
#ifndef __powerpc__
uptr shm_segsz;
#elif !defined(__powerpc64__)
@@ -555,7 +559,11 @@ namespace __sanitizer {
};
#if SANITIZER_ANDROID
+# if SANITIZER_MIPS
+ typedef unsigned long __sanitizer_sigset_t[16/sizeof(unsigned long)];
+# else
typedef unsigned long __sanitizer_sigset_t;
+# endif
#elif SANITIZER_MAC
typedef unsigned __sanitizer_sigset_t;
#elif SANITIZER_LINUX
@@ -581,6 +589,15 @@ namespace __sanitizer {
__sanitizer_sigset_t sa_mask;
void (*sa_restorer)();
};
+#elif SANITIZER_ANDROID && SANITIZER_MIPS32 // check this before WORDSIZE == 32
+ struct __sanitizer_sigaction {
+ unsigned sa_flags;
+ union {
+ void (*sigaction)(int sig, void *siginfo, void *uctx);
+ void (*handler)(int sig);
+ };
+ __sanitizer_sigset_t sa_mask;
+ };
#elif SANITIZER_ANDROID && (SANITIZER_WORDSIZE == 32)
struct __sanitizer_sigaction {
union {
@@ -604,7 +621,11 @@ namespace __sanitizer {
int sa_flags;
__sanitizer_sigset_t sa_mask;
#else
+#if defined(__s390x__)
+ int sa_resv;
+#else
__sanitizer_sigset_t sa_mask;
+#endif
#ifndef __mips__
#if defined(__sparc__)
unsigned long sa_flags;
@@ -619,6 +640,9 @@ namespace __sanitizer {
#if defined(__mips__) && (SANITIZER_WORDSIZE == 32)
int sa_resv[1];
#endif
+#if defined(__s390x__)
+ __sanitizer_sigset_t sa_mask;
+#endif
};
#endif // !SANITIZER_ANDROID
@@ -626,7 +650,7 @@ namespace __sanitizer {
typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
#elif defined(__mips__)
struct __sanitizer_kernel_sigset_t {
- u8 sig[16];
+ uptr sig[2];
};
#else
struct __sanitizer_kernel_sigset_t {
@@ -635,6 +659,17 @@ namespace __sanitizer {
#endif
// Linux system headers define the 'sa_handler' and 'sa_sigaction' macros.
+#if SANITIZER_MIPS
+ struct __sanitizer_kernel_sigaction_t {
+ unsigned int sa_flags;
+ union {
+ void (*handler)(int signo);
+ void (*sigaction)(int signo, void *info, void *ctx);
+ };
+ __sanitizer_kernel_sigset_t sa_mask;
+ void (*sa_restorer)(void);
+ };
+#else
struct __sanitizer_kernel_sigaction_t {
union {
void (*handler)(int signo);
@@ -644,6 +679,7 @@ namespace __sanitizer {
void (*sa_restorer)(void);
__sanitizer_kernel_sigset_t sa_mask;
};
+#endif
extern uptr sig_ign;
extern uptr sig_dfl;
@@ -779,7 +815,8 @@ namespace __sanitizer {
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
- defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__))
+ defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+ defined(__s390__))
extern unsigned struct_user_regs_struct_sz;
extern unsigned struct_user_fpregs_struct_sz;
extern unsigned struct_user_fpxregs_struct_sz;
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc
index ed44633bc18..d10213d917f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc
@@ -87,7 +87,11 @@ static uptr GetKernelAreaSize() {
uptr GetMaxVirtualAddress() {
#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__) || defined(__aarch64__)
+# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
+ // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The
+ // upper bound can change depending on the device.
+ return 0x200000000 - 1;
+# elif defined(__powerpc64__) || defined(__aarch64__)
// On PowerPC64 we have two different address space layouts: 44- and 46-bit.
// We somehow need to figure out which one we are using now and choose
// one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
@@ -98,26 +102,32 @@ uptr GetMaxVirtualAddress() {
return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
# elif defined(__mips64)
return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
+# elif defined(__s390x__)
+ return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
# else
return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
# endif
#else // SANITIZER_WORDSIZE == 32
+# if defined(__s390__)
+ return (1ULL << 31) - 1; // 0x7fffffff;
+# else
uptr res = (1ULL << 32) - 1; // 0xffffffff;
if (!common_flags()->full_address_space)
res -= GetKernelAreaSize();
CHECK_LT(reinterpret_cast<uptr>(&res), res);
return res;
+# endif
#endif // SANITIZER_WORDSIZE
}
-void *MmapOrDie(uptr size, const char *mem_type) {
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
size = RoundUpTo(size, GetPageSizeCached());
uptr res = internal_mmap(nullptr, size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
int reserrno;
if (internal_iserror(res, &reserrno))
- ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
+ ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
IncreaseTotalMmap(size);
return (void *)res;
}
@@ -133,6 +143,26 @@ void UnmapOrDie(void *addr, uptr size) {
DecreaseTotalMmap(size);
}
+// We want to map a chunk of address space aligned to 'alignment'.
+// We do it by maping a bit more and then unmaping redundant pieces.
+// We probably can do it with fewer syscalls in some OS-dependent way.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+ CHECK(IsPowerOfTwo(size));
+ CHECK(IsPowerOfTwo(alignment));
+ uptr map_size = size + alignment;
+ uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
+ uptr map_end = map_res + map_size;
+ uptr res = map_res;
+ if (res & (alignment - 1)) // Not aligned.
+ res = (map_res + alignment) & ~(alignment - 1);
+ uptr end = res + size;
+ if (res != map_res)
+ UnmapOrDie((void*)map_res, res - map_res);
+ if (end != map_end)
+ UnmapOrDie((void*)end, map_end - end);
+ return (void*)res;
+}
+
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
uptr PageSize = GetPageSizeCached();
uptr p = internal_mmap(nullptr,
@@ -169,6 +199,10 @@ bool MprotectNoAccess(uptr addr, uptr size) {
return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
}
+bool MprotectReadOnly(uptr addr, uptr size) {
+ return 0 == internal_mprotect((void *)addr, size, PROT_READ);
+}
+
fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
int flags;
switch (mode) {
@@ -313,26 +347,13 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
}
SignalContext SignalContext::Create(void *siginfo, void *context) {
- uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
+ auto si = (siginfo_t *)siginfo;
+ uptr addr = (uptr)si->si_addr;
uptr pc, sp, bp;
GetPcSpBp(context, &pc, &sp, &bp);
- return SignalContext(context, addr, pc, sp, bp);
-}
-
-// This function check is the built VMA matches the runtime one for
-// architectures with multiple VMA size.
-void CheckVMASize() {
-#ifdef __aarch64__
- static const unsigned kBuiltVMA = SANITIZER_AARCH64_VMA;
- unsigned maxRuntimeVMA =
- (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
- if (kBuiltVMA != maxRuntimeVMA) {
- Printf("WARNING: %s runtime VMA is not the one built for.\n",
- SanitizerToolName);
- Printf("\tBuilt VMA: %u bits\n", kBuiltVMA);
- Printf("\tRuntime VMA: %u bits\n", maxRuntimeVMA);
- }
-#endif
+ WriteFlag write_flag = GetWriteFlag(context);
+ bool is_memory_access = si->si_signo == SIGSEGV;
+ return SignalContext(context, addr, pc, sp, bp, is_memory_access, write_flag);
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
index 8dd259e32ba..68b34babdeb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
@@ -14,6 +14,7 @@
// ----------- ATTENTION -------------
// This header should NOT include any other headers from sanitizer runtime.
#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
#if !SANITIZER_POSIX
// Make it hard to accidentally use any of functions declared in this file:
@@ -52,6 +53,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data);
uptr internal_waitpid(int pid, int *status, int options);
int internal_fork();
+int internal_forkpty(int *amaster);
// These functions call appropriate pthread_ functions directly, bypassing
// the interceptor. They are weak and may not be present in some tools.
@@ -74,8 +76,15 @@ int real_pthread_join(void *th, void **ret);
int my_pthread_attr_getstack(void *attr, void **addr, uptr *size);
+// A routine named real_sigaction() must be implemented by each sanitizer in
+// order for internal_sigaction() to bypass interceptors.
int internal_sigaction(int signum, const void *act, void *oldact);
+void internal_sigfillset(__sanitizer_sigset_t *set);
+void internal_sigemptyset(__sanitizer_sigset_t *set);
+bool internal_sigismember(__sanitizer_sigset_t *set, int signum);
+uptr internal_execve(const char *filename, char *const argv[],
+ char *const envp[]);
} // namespace __sanitizer
#endif // SANITIZER_POSIX_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
index 4b7273b4cc0..335aad1660e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#if SANITIZER_FREEBSD
@@ -41,6 +42,8 @@
#define MAP_NORESERVE 0
#endif
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+
namespace __sanitizer {
u32 GetUid() {
@@ -51,7 +54,7 @@ uptr GetThreadSelf() {
return (uptr)pthread_self();
}
-void FlushUnneededShadowMemory(uptr addr, uptr size) {
+void ReleaseMemoryToOS(uptr addr, uptr size) {
madvise((void*)addr, size, MADV_DONTNEED);
}
@@ -95,6 +98,10 @@ bool StackSizeIsUnlimited() {
return (stack_size == RLIM_INFINITY);
}
+uptr GetStackSizeLimitInBytes() {
+ return (uptr)getlim(RLIMIT_STACK);
+}
+
void SetStackSizeLimitInBytes(uptr limit) {
setlim(RLIMIT_STACK, (rlim_t)limit);
CHECK(!StackSizeIsUnlimited());
@@ -119,11 +126,21 @@ void SleepForMillis(int millis) {
}
void Abort() {
+#if !SANITIZER_GO
+ // If we are handling SIGABRT, unhandle it first.
+ if (IsHandledDeadlySignal(SIGABRT)) {
+ struct sigaction sigact;
+ internal_memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
+ internal_sigaction(SIGABRT, &sigact, nullptr);
+ }
+#endif
+
abort();
}
int Atexit(void (*function)(void)) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
return atexit(function);
#else
return 0;
@@ -134,7 +151,7 @@ bool SupportsColoredOutput(fd_t fd) {
return isatty(fd) != 0;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// TODO(glider): different tools may require different altstack size.
static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough.
@@ -163,10 +180,9 @@ void UnsetAlternateSignalStack() {
UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
}
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
static void MaybeInstallSigaction(int signum,
SignalHandlerType handler) {
- if (!IsDeadlySignal(signum))
+ if (!IsHandledDeadlySignal(signum))
return;
struct sigaction sigact;
internal_memset(&sigact, 0, sizeof(sigact));
@@ -188,6 +204,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
MaybeInstallSigaction(SIGBUS, handler);
MaybeInstallSigaction(SIGABRT, handler);
MaybeInstallSigaction(SIGFPE, handler);
+ MaybeInstallSigaction(SIGILL, handler);
}
#endif // SANITIZER_GO
@@ -266,7 +283,7 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
return (void *)p;
}
-void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
+void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
int fd = name ? GetNamedMappingFd(name, size) : -1;
unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE;
if (fd == -1) flags |= MAP_ANON;
@@ -275,6 +292,11 @@ void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
0);
}
+void *MmapNoAccess(uptr size) {
+ unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE;
+ return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0);
+}
+
// This function is defined elsewhere if we intercepted pthread_attr_getstack.
extern "C" {
SANITIZER_WEAK_ATTRIBUTE int
@@ -317,6 +339,79 @@ void AdjustStackSize(void *attr_) {
}
#endif // !SANITIZER_GO
+pid_t StartSubprocess(const char *program, const char *const argv[],
+ fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+ auto file_closer = at_scope_exit([&] {
+ if (stdin_fd != kInvalidFd) {
+ internal_close(stdin_fd);
+ }
+ if (stdout_fd != kInvalidFd) {
+ internal_close(stdout_fd);
+ }
+ if (stderr_fd != kInvalidFd) {
+ internal_close(stderr_fd);
+ }
+ });
+
+ int pid = internal_fork();
+
+ if (pid < 0) {
+ int rverrno;
+ if (internal_iserror(pid, &rverrno)) {
+ Report("WARNING: failed to fork (errno %d)\n", rverrno);
+ }
+ return pid;
+ }
+
+ if (pid == 0) {
+ // Child subprocess
+ if (stdin_fd != kInvalidFd) {
+ internal_close(STDIN_FILENO);
+ internal_dup2(stdin_fd, STDIN_FILENO);
+ internal_close(stdin_fd);
+ }
+ if (stdout_fd != kInvalidFd) {
+ internal_close(STDOUT_FILENO);
+ internal_dup2(stdout_fd, STDOUT_FILENO);
+ internal_close(stdout_fd);
+ }
+ if (stderr_fd != kInvalidFd) {
+ internal_close(STDERR_FILENO);
+ internal_dup2(stderr_fd, STDERR_FILENO);
+ internal_close(stderr_fd);
+ }
+
+ for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
+
+ execv(program, const_cast<char **>(&argv[0]));
+ internal__exit(1);
+ }
+
+ return pid;
+}
+
+bool IsProcessRunning(pid_t pid) {
+ int process_status;
+ uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG);
+ int local_errno;
+ if (internal_iserror(waitpid_status, &local_errno)) {
+ VReport(1, "Waiting on the process failed (errno %d).\n", local_errno);
+ return false;
+ }
+ return waitpid_status == 0;
+}
+
+int WaitForProcess(pid_t pid) {
+ int process_status;
+ uptr waitpid_status = internal_waitpid(pid, &process_status, 0);
+ int local_errno;
+ if (internal_iserror(waitpid_status, &local_errno)) {
+ VReport(1, "Waiting on the process failed (errno %d).\n", local_errno);
+ return -1;
+ }
+ return process_status;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc
index 6688610bf0f..c11113da244 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc
@@ -211,7 +211,7 @@ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void OnPrint(const char *str) {
(void)str;
}
-#elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS)
+#elif SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS)
void OnPrint(const char *str);
#else
void OnPrint(const char *str) {
@@ -276,9 +276,12 @@ static void SharedPrintfCode(bool append_pid, const char *format,
# undef CHECK_NEEDED_LENGTH
}
RawWrite(buffer);
- if (common_flags()->log_to_syslog)
- WriteToSyslog(buffer);
+
+ // Remove color sequences from the message.
+ RemoveANSIEscapeSequencesFromString(buffer);
CallPrintfAndReportCallback(buffer);
+ LogMessageOnPrintf(buffer);
+
// If we had mapped any memory, clean up.
if (buffer != local_buffer)
UnmapOrDie((void *)buffer, buffer_size);
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
index 7477abf30b6..0183a094111 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
@@ -41,9 +41,8 @@ class MemoryMappingLayout {
// instead of aborting.
static void CacheMemoryMappings();
- // Stores the list of mapped objects into an array.
- uptr DumpListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter);
+ // Adds all mapped objects into a vector.
+ void DumpListOfModules(InternalMmapVector<LoadedModule> *modules);
// Memory protection masks.
static const uptr kProtectionRead = 1;
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
index 1cf3f8510fb..c725c2e7b66 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
@@ -114,22 +114,17 @@ void MemoryMappingLayout::LoadFromCache() {
}
}
-uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
- uptr max_modules,
- string_predicate_t filter) {
+void MemoryMappingLayout::DumpListOfModules(
+ InternalMmapVector<LoadedModule> *modules) {
Reset();
uptr cur_beg, cur_end, cur_offset, prot;
InternalScopedString module_name(kMaxPathLength);
- uptr n_modules = 0;
- for (uptr i = 0; n_modules < max_modules &&
- Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
- module_name.size(), &prot);
+ for (uptr i = 0; Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
+ module_name.size(), &prot);
i++) {
const char *cur_name = module_name.data();
if (cur_name[0] == '\0')
continue;
- if (filter && !filter(cur_name))
- continue;
// Don't subtract 'cur_beg' from 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
@@ -142,12 +137,11 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
// shadow memory of the tool), so the module can't be the
// first entry.
uptr base_address = (i ? cur_beg : 0) - cur_offset;
- LoadedModule *cur_module = &modules[n_modules];
- cur_module->set(cur_name, base_address);
- cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
- n_modules++;
+ LoadedModule cur_module;
+ cur_module.set(cur_name, base_address);
+ cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ modules->push_back(cur_module);
}
- return n_modules;
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
index e77e33fb2d7..10918e54398 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -65,7 +65,7 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
while (IsDecimal(*current_))
current_++;
// Qemu may lack the trailing space.
- // http://code.google.com/p/address-sanitizer/issues/detail?id=160
+ // https://github.com/google/sanitizers/issues/160
// CHECK_EQ(*current_++, ' ');
// Skip spaces.
while (current_ < next_line && *current_ == ' ')
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
index 393243b7c28..81829a7c284 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -63,7 +63,7 @@ void MemoryMappingLayout::LoadFromCache() {
}
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
-// Google Perftools, http://code.google.com/p/google-perftools.
+// Google Perftools, https://github.com/gperftools/gperftools.
// NextSegmentLoad scans the current image for the next segment load command
// and returns the start and end addresses and file offset of the corresponding
@@ -153,34 +153,28 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
return false;
}
-uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
- uptr max_modules,
- string_predicate_t filter) {
+void MemoryMappingLayout::DumpListOfModules(
+ InternalMmapVector<LoadedModule> *modules) {
Reset();
uptr cur_beg, cur_end, prot;
InternalScopedString module_name(kMaxPathLength);
- uptr n_modules = 0;
- for (uptr i = 0; n_modules < max_modules &&
- Next(&cur_beg, &cur_end, 0, module_name.data(),
- module_name.size(), &prot);
+ for (uptr i = 0; Next(&cur_beg, &cur_end, 0, module_name.data(),
+ module_name.size(), &prot);
i++) {
const char *cur_name = module_name.data();
if (cur_name[0] == '\0')
continue;
- if (filter && !filter(cur_name))
- continue;
LoadedModule *cur_module = nullptr;
- if (n_modules > 0 &&
- 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
- cur_module = &modules[n_modules - 1];
+ if (!modules->empty() &&
+ 0 == internal_strcmp(cur_name, modules->back().full_name())) {
+ cur_module = &modules->back();
} else {
- cur_module = &modules[n_modules];
+ modules->push_back(LoadedModule());
+ cur_module = &modules->back();
cur_module->set(cur_name, cur_beg);
- n_modules++;
}
cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
}
- return n_modules;
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_quarantine.h b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
index a635871be45..9e9268f2a5d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_quarantine.h
+++ b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
@@ -99,10 +99,12 @@ class Quarantine {
void NOINLINE DoRecycle(Cache *c, Callback cb) {
while (QuarantineBatch *b = c->DequeueBatch()) {
const uptr kPrefetch = 16;
+ CHECK(kPrefetch <= ARRAY_SIZE(b->batch));
for (uptr i = 0; i < kPrefetch; i++)
PREFETCH(b->batch[i]);
- for (uptr i = 0; i < b->count; i++) {
- PREFETCH(b->batch[i + kPrefetch]);
+ for (uptr i = 0, count = b->count; i < count; i++) {
+ if (i + kPrefetch < count)
+ PREFETCH(b->batch[i + kPrefetch]);
cb.Recycle((Node*)b->batch[i]);
}
cb.Deallocate(b);
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
index 796d472a1eb..cbb3af270b6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
@@ -38,11 +38,6 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
top_frame_bp = 0;
}
-// Check if given pointer points into allocated stack area.
-static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
- return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
-}
-
// In GCC on ARM bp points to saved lr, not fp, so we should check the next
// cell in stack to be a saved frame pointer. GetCanonicFrame returns the
// pointer to saved frame pointer in any case.
@@ -69,6 +64,7 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
uptr stack_bottom, u32 max_depth) {
+ const uptr kPageSize = GetPageSizeCached();
CHECK_GE(max_depth, 2);
trace_buffer[0] = pc;
size = 1;
@@ -90,9 +86,16 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
!IsAligned((uptr)caller_frame, sizeof(uhwptr)))
break;
uhwptr pc1 = caller_frame[2];
+#elif defined(__s390__)
+ uhwptr pc1 = frame[14];
#else
uhwptr pc1 = frame[1];
#endif
+ // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
+ // x86_64) is invalid and stop unwinding here. If we're adding support for
+ // a platform where this isn't true, we need to reconsider this check.
+ if (pc1 < kPageSize)
+ break;
if (pc1 != pc) {
trace_buffer[size++] = (uptr) pc1;
}
@@ -116,7 +119,7 @@ void BufferedStackTrace::PopStackFrames(uptr count) {
uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
// Use threshold to find PC in stack trace, as PC we want to unwind from may
// slightly differ from return address in the actual unwinded stack trace.
- const int kPcThreshold = 304;
+ const int kPcThreshold = 350;
for (uptr i = 0; i < size; ++i) {
if (MatchPc(pc, trace[i], kPcThreshold))
return i;
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index 7f22455ac9e..c59dbd55883 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -27,7 +27,7 @@ static const u32 kStackTraceMax = 256;
// Fast unwind is the only option on Mac for now; we will need to
// revisit this macro when slow unwind works on Mac, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+// https://github.com/google/sanitizers/issues/137
#if SANITIZER_MAC
# define SANITIZER_CAN_SLOW_UNWIND 0
#else
@@ -108,6 +108,11 @@ struct BufferedStackTrace : public StackTrace {
void operator=(const BufferedStackTrace &);
};
+// Check if given pointer points into allocated stack area.
+static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
+ return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
+}
+
} // namespace __sanitizer
// Use this macro if you want to print stack trace with the caller
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index addf44f7327..ac3ee3a019c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -23,6 +23,8 @@ void StackTrace::Print() const {
return;
}
InternalScopedString frame_desc(GetPageSizeCached() * 2);
+ InternalScopedString dedup_token(GetPageSizeCached());
+ int dedup_frames = common_flags()->dedup_token_length;
uptr frame_num = 0;
for (uptr i = 0; i < size && trace[i]; i++) {
// PCs in stack traces are actually the return addresses, that is,
@@ -36,11 +38,18 @@ void StackTrace::Print() const {
cur->info, common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
Printf("%s\n", frame_desc.data());
+ if (dedup_frames-- > 0) {
+ if (dedup_token.length())
+ dedup_token.append("--");
+ dedup_token.append(cur->info.function);
+ }
}
frames->ClearAll();
}
// Always print a trailing empty line after stack trace.
Printf("\n");
+ if (dedup_token.length())
+ Printf("DEDUP_TOKEN: %s\n", dedup_token.data());
}
void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
@@ -72,3 +81,38 @@ void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
}
} // namespace __sanitizer
+using namespace __sanitizer;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
+ uptr out_buf_size) {
+ if (!out_buf_size) return;
+ pc = StackTrace::GetPreviousInstructionPc(pc);
+ SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
+ if (!frame) {
+ internal_strncpy(out_buf, "<can't symbolize>", out_buf_size);
+ out_buf[out_buf_size - 1] = 0;
+ return;
+ }
+ InternalScopedString frame_desc(GetPageSizeCached());
+ RenderFrame(&frame_desc, fmt, 0, frame->info,
+ common_flags()->symbolize_vs_style,
+ common_flags()->strip_path_prefix);
+ internal_strncpy(out_buf, frame_desc.data(), out_buf_size);
+ out_buf[out_buf_size - 1] = 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
+ char *out_buf, uptr out_buf_size) {
+ if (!out_buf_size) return;
+ out_buf[0] = 0;
+ DataInfo DI;
+ if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
+ InternalScopedString data_desc(GetPageSizeCached());
+ RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
+ internal_strncpy(out_buf, data_desc.data(), out_buf_size);
+ out_buf[out_buf_size - 1] = 0;
+}
+} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
index bcc9de78ec1..de78c7ac8d1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -114,6 +114,35 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
}
}
+void RenderData(InternalScopedString *buffer, const char *format,
+ const DataInfo *DI, const char *strip_path_prefix) {
+ for (const char *p = format; *p != '\0'; p++) {
+ if (*p != '%') {
+ buffer->append("%c", *p);
+ continue;
+ }
+ p++;
+ switch (*p) {
+ case '%':
+ buffer->append("%%");
+ break;
+ case 's':
+ buffer->append("%s", StripPathPrefix(DI->file, strip_path_prefix));
+ break;
+ case 'l':
+ buffer->append("%d", DI->line);
+ break;
+ case 'g':
+ buffer->append("%s", DI->name);
+ break;
+ default:
+ Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n", *p,
+ *p);
+ Die();
+ }
+ }
+}
+
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
index a553568ea6f..6726f141f22 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -57,6 +57,13 @@ void RenderSourceLocation(InternalScopedString *buffer, const char *file,
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
uptr offset, const char *strip_path_prefix);
+// Same as RenderFrame, but for data section (global variables).
+// Accepts %s, %l from above.
+// Also accepts:
+// %g - name of the global variable.
+void RenderData(InternalScopedString *buffer, const char *format,
+ const DataInfo *DI, const char *strip_path_prefix = "");
+
} // namespace __sanitizer
#endif // SANITIZER_STACKTRACE_PRINTER_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index c919e4f6e97..891386dc0ba 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -13,7 +13,8 @@
#include "sanitizer_platform.h"
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
- defined(__aarch64__))
+ defined(__aarch64__) || defined(__powerpc64__) || \
+ defined(__s390__))
#include "sanitizer_stoptheworld.h"
@@ -36,6 +37,9 @@
# include <asm/ptrace.h>
# endif
# include <sys/user.h> // for user_regs_struct
+# if SANITIZER_ANDROID && SANITIZER_MIPS
+# include <asm/reg.h> // for mips SP register in sys/user.h
+# endif
#endif
#include <sys/wait.h> // for signal-related stuff
@@ -73,10 +77,10 @@
// thread-local variables used by libc will be shared between the tracer task
// and the thread which spawned it.
-COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
-
namespace __sanitizer {
+COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
+
// Structure for passing arguments into the tracer thread.
struct TracerThreadArgument {
StopTheWorldCallback callback;
@@ -184,6 +188,7 @@ void ThreadSuspender::KillAllThreads() {
bool ThreadSuspender::SuspendAllThreads() {
ThreadLister thread_lister(pid_);
bool added_threads;
+ bool first_iteration = true;
do {
// Run through the directory entries once.
added_threads = false;
@@ -193,12 +198,13 @@ bool ThreadSuspender::SuspendAllThreads() {
added_threads = true;
tid = thread_lister.GetNextTID();
}
- if (thread_lister.error()) {
+ if (thread_lister.error() || (first_iteration && !added_threads)) {
// Detach threads and fail.
ResumeAllThreads();
return false;
}
thread_lister.Reset();
+ first_iteration = false;
} while (added_threads);
return true;
}
@@ -227,8 +233,8 @@ static void TracerThreadDieCallback() {
// Signal handler to wake up suspended threads when the tracer thread dies.
static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
SignalContext ctx = SignalContext::Create(siginfo, uctx);
- VPrintf(1, "Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n",
- signum, ctx.addr, ctx.pc, ctx.sp);
+ Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum,
+ ctx.addr, ctx.pc, ctx.sp);
ThreadSuspender *inst = thread_suspender_instance;
if (inst) {
if (signum == SIGABRT)
@@ -465,13 +471,22 @@ typedef pt_regs regs_struct;
#elif defined(__mips__)
typedef struct user regs_struct;
-#define REG_SP regs[EF_REG29]
+# if SANITIZER_ANDROID
+# define REG_SP regs[EF_R29]
+# else
+# define REG_SP regs[EF_REG29]
+# endif
#elif defined(__aarch64__)
typedef struct user_pt_regs regs_struct;
#define REG_SP sp
#define ARCH_IOVEC_FOR_GETREGSET
+#elif defined(__s390__)
+typedef _user_regs_struct regs_struct;
+#define REG_SP gprs[15]
+#define ARCH_IOVEC_FOR_GETREGSET
+
#else
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
@@ -509,5 +524,6 @@ uptr SuspendedThreadsList::RegisterCount() {
}
} // namespace __sanitizer
-#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
- // || defined(__aarch64__)
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
+ // || defined(__aarch64__) || defined(__powerpc64__)
+ // || defined(__s390__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
index 2b6a78155fd..bfdff59a35c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
@@ -125,7 +125,7 @@ void SuppressionContext::Parse(const char *str) {
Printf("%s: failed to parse suppressions\n", SanitizerToolName);
Die();
}
- Suppression s = {};
+ Suppression s;
s.type = suppression_types_[type];
s.templ = (char*)InternalAlloc(end2 - line + 1);
internal_memcpy(s.templ, line, end2 - line);
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.h b/libsanitizer/sanitizer_common/sanitizer_suppressions.h
index efec926476b..ed6d7baae84 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.h
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.h
@@ -18,6 +18,7 @@
namespace __sanitizer {
struct Suppression {
+ Suppression() { internal_memset(this, 0, sizeof(*this)); }
const char *type;
char *templ;
atomic_uint32_t hit_count;
@@ -40,7 +41,7 @@ class SuppressionContext {
void GetMatched(InternalMmapVector<Suppression *> *matched);
private:
- static const int kMaxSuppressionTypes = 16;
+ static const int kMaxSuppressionTypes = 32;
const char **const suppression_types_;
const int suppression_types_num_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
index 0e58d5fed6e..3557415aeab 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
@@ -58,6 +58,7 @@ DataInfo::DataInfo() {
void DataInfo::Clear() {
InternalFree(module);
+ InternalFree(file);
InternalFree(name);
internal_memset(this, 0, sizeof(DataInfo));
}
@@ -94,7 +95,7 @@ const char *Symbolizer::ModuleNameOwner::GetOwnedCopy(const char *str) {
}
Symbolizer::Symbolizer(IntrusiveList<SymbolizerTool> tools)
- : module_names_(&mu_), n_modules_(0), modules_fresh_(false), tools_(tools),
+ : module_names_(&mu_), modules_(), modules_fresh_(false), tools_(tools),
start_hook_(0), end_hook_(0) {}
Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index 0a443a70115..2b90b42e2ba 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -63,6 +63,8 @@ struct DataInfo {
// (de)allocated using sanitizer internal allocator.
char *module;
uptr module_offset;
+ char *file;
+ uptr line;
char *name;
uptr start;
uptr size;
@@ -78,6 +80,7 @@ class Symbolizer final {
/// Initialize and return platform-specific implementation of symbolizer
/// (if it wasn't already initialized).
static Symbolizer *GetOrInit();
+ static void LateInitialize();
// Returns a list of symbolized frames for a given address (containing
// all inlined functions, if necessary).
SymbolizedStack *SymbolizePC(uptr address);
@@ -111,6 +114,8 @@ class Symbolizer final {
void AddHooks(StartSymbolizationHook start_hook,
EndSymbolizationHook end_hook);
+ const LoadedModule *FindModuleForAddress(uptr address);
+
private:
// GetModuleNameAndOffsetForPC has to return a string to the caller.
// Since the corresponding module might get unloaded later, we should create
@@ -137,9 +142,7 @@ class Symbolizer final {
bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
uptr *module_offset);
- LoadedModule *FindModuleForAddress(uptr address);
- LoadedModule modules_[kMaxNumberOfModules];
- uptr n_modules_;
+ ListOfModules modules_;
// If stale, need to reload the modules before looking up addresses.
bool modules_fresh_;
@@ -155,7 +158,6 @@ class Symbolizer final {
// always synchronized.
BlockingMutex mu_;
- typedef IntrusiveList<SymbolizerTool>::Iterator Iterator;
IntrusiveList<SymbolizerTool> tools_;
explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);
@@ -173,6 +175,10 @@ class Symbolizer final {
};
};
+#ifdef SANITIZER_WINDOWS
+void InitializeDbgHelpIfNeeded();
+#endif
+
} // namespace __sanitizer
#endif // SANITIZER_SYMBOLIZER_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
index a87964b4636..119cb688463 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -26,7 +26,7 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result);
const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter,
char **result);
-const char *DemangleCXXABI(const char *name);
+const char *DemangleSwiftAndCXX(const char *name);
// SymbolizerTool is an interface that is implemented by individual "tools"
// that can perform symbolication (external llvm-symbolizer, libbacktrace,
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index 4264b5e3ddc..45eb11a4d3b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -67,10 +67,9 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
return res;
// Always fill data about module name and offset.
res->info.FillModuleInfo(module_name, module_offset);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
+ for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
- if (tool->SymbolizePC(addr, res)) {
+ if (tool.SymbolizePC(addr, res)) {
return res;
}
}
@@ -86,10 +85,9 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
info->Clear();
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
+ for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
- if (tool->SymbolizeData(addr, info)) {
+ if (tool.SymbolizeData(addr, info)) {
return true;
}
}
@@ -111,19 +109,17 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
void Symbolizer::Flush() {
BlockingMutexLock l(&mu_);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
+ for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
- tool->Flush();
+ tool.Flush();
}
}
const char *Symbolizer::Demangle(const char *name) {
BlockingMutexLock l(&mu_);
- for (auto iter = Iterator(&tools_); iter.hasNext();) {
- auto *tool = iter.next();
+ for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
- if (const char *demangled = tool->Demangle(name))
+ if (const char *demangled = tool.Demangle(name))
return demangled;
}
return PlatformDemangle(name);
@@ -137,27 +133,23 @@ void Symbolizer::PrepareForSandboxing() {
bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
const char **module_name,
uptr *module_offset) {
- LoadedModule *module = FindModuleForAddress(address);
- if (module == 0)
+ const LoadedModule *module = FindModuleForAddress(address);
+ if (module == nullptr)
return false;
*module_name = module->full_name();
*module_offset = address - module->base_address();
return true;
}
-LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
+const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
bool modules_were_reloaded = false;
if (!modules_fresh_) {
- for (uptr i = 0; i < n_modules_; i++)
- modules_[i].clear();
- n_modules_ =
- GetListOfModules(modules_, kMaxNumberOfModules, /* filter */ nullptr);
- CHECK_GT(n_modules_, 0);
- CHECK_LT(n_modules_, kMaxNumberOfModules);
+ modules_.init();
+ RAW_CHECK(modules_.size() > 0);
modules_fresh_ = true;
modules_were_reloaded = true;
}
- for (uptr i = 0; i < n_modules_; i++) {
+ for (uptr i = 0; i < modules_.size(); i++) {
if (modules_[i].containsAddress(address)) {
return &modules_[i];
}
@@ -211,10 +203,18 @@ class LLVMSymbolizerProcess : public SymbolizerProcess {
const char* const kSymbolizerArch = "--default-arch=x86_64";
#elif defined(__i386__)
const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+#elif defined(__aarch64__)
+ const char* const kSymbolizerArch = "--default-arch=arm64";
+#elif defined(__arm__)
+ const char* const kSymbolizerArch = "--default-arch=arm";
+#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
const char* const kSymbolizerArch = "--default-arch=powerpc64";
-#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+#elif defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
const char* const kSymbolizerArch = "--default-arch=powerpc64le";
+#elif defined(__s390x__)
+ const char* const kSymbolizerArch = "--default-arch=s390x";
+#elif defined(__s390__)
+ const char* const kSymbolizerArch = "--default-arch=s390";
#else
const char* const kSymbolizerArch = "--default-arch=unknown";
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
index e65976c18d0..249ccdf8377 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc
@@ -17,8 +17,6 @@
#include "sanitizer_mac.h"
#include "sanitizer_symbolizer_mac.h"
-namespace __sanitizer {
-
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
@@ -26,11 +24,14 @@ namespace __sanitizer {
#include <unistd.h>
#include <util.h>
+namespace __sanitizer {
+
bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
Dl_info info;
int result = dladdr((const void *)addr, &info);
if (!result) return false;
- const char *demangled = DemangleCXXABI(info.dli_sname);
+ const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
+ if (!demangled) return false;
stack->info.function = internal_strdup(demangled);
return true;
}
@@ -39,7 +40,7 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
Dl_info info;
int result = dladdr((const void *)addr, &info);
if (!result) return false;
- const char *demangled = DemangleCXXABI(info.dli_sname);
+ const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
datainfo->name = internal_strdup(demangled);
datainfo->start = (uptr)info.dli_saddr;
return true;
@@ -77,23 +78,6 @@ class AtosSymbolizerProcess : public SymbolizerProcess {
char pid_str_[16];
};
-static const char *kAtosErrorMessages[] = {
- "atos cannot examine process",
- "unable to get permission to examine process",
- "An admin user name and password is required",
- "could not load inserted library",
- "architecture mismatch between analysis process",
-};
-
-static bool IsAtosErrorMessage(const char *str) {
- for (uptr i = 0; i < ARRAY_SIZE(kAtosErrorMessages); i++) {
- if (internal_strstr(str, kAtosErrorMessages[i])) {
- return true;
- }
- }
- return false;
-}
-
static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
char **out_module, char **out_file, uptr *line,
uptr *start_address) {
@@ -110,15 +94,15 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name,
// 0xdeadbeef (in library.dylib)
// 0xdeadbeef
- if (IsAtosErrorMessage(trim)) {
- Report("atos returned an error: %s\n", trim);
+ const char *rest = trim;
+ char *symbol_name;
+ rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
+ if (rest[0] == '\0') {
+ InternalFree(symbol_name);
InternalFree(trim);
return false;
}
- const char *rest = trim;
- char *symbol_name;
- rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name);
if (internal_strncmp(symbol_name, "0x", 2) != 0)
*out_name = symbol_name;
else
@@ -149,6 +133,7 @@ AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator)
bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
if (!process_) return false;
+ if (addr == 0) return false;
char command[32];
internal_snprintf(command, sizeof(command), "0x%zx\n", addr);
const char *buf = process_->SendCommand(command);
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index e4ff525d6b0..3fcd7d04880 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -24,7 +24,9 @@
#include "sanitizer_symbolizer_libbacktrace.h"
#include "sanitizer_symbolizer_mac.h"
+#include <dlfcn.h> // for dlsym()
#include <errno.h>
+#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -59,6 +61,44 @@ const char *DemangleCXXABI(const char *name) {
return name;
}
+// As of now, there are no headers for the Swift runtime. Once they are
+// present, we will weakly link since we do not require Swift runtime to be
+// linked.
+typedef char *(*swift_demangle_ft)(const char *mangledName,
+ size_t mangledNameLength, char *outputBuffer,
+ size_t *outputBufferSize, uint32_t flags);
+static swift_demangle_ft swift_demangle_f;
+
+// This must not happen lazily at symbolication time, because dlsym uses
+// malloc and thread-local storage, which is not a good thing to do during
+// symbolication.
+static void InitializeSwiftDemangler() {
+ swift_demangle_f = (swift_demangle_ft)dlsym(RTLD_DEFAULT, "swift_demangle");
+}
+
+// Attempts to demangle a Swift name. The demangler will return nullptr if a
+// non-Swift name is passed in.
+const char *DemangleSwift(const char *name) {
+ if (!name) return nullptr;
+
+ // Check if we are dealing with a Swift mangled name first.
+ if (name[0] != '_' || name[1] != 'T') {
+ return nullptr;
+ }
+
+ if (swift_demangle_f)
+ return swift_demangle_f(name, internal_strlen(name), 0, 0, 0);
+
+ return nullptr;
+}
+
+const char *DemangleSwiftAndCXX(const char *name) {
+ if (!name) return nullptr;
+ if (const char *swift_demangled_name = DemangleSwift(name))
+ return swift_demangled_name;
+ return DemangleCXXABI(name);
+}
+
bool SymbolizerProcess::StartSymbolizerSubprocess() {
if (!FileExists(path_)) {
if (!reported_invalid_path_) {
@@ -72,8 +112,15 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
if (use_forkpty_) {
#if SANITIZER_MAC
fd_t fd = kInvalidFd;
+
+ // forkpty redirects stdout and stderr into a single stream, so we would
+ // receive error messages as standard replies. To avoid that, let's dup
+ // stderr and restore it in the child.
+ int saved_stderr = dup(STDERR_FILENO);
+ CHECK_GE(saved_stderr, 0);
+
// Use forkpty to disable buffering in the new terminal.
- pid = forkpty(&fd, 0, 0, 0);
+ pid = internal_forkpty(&fd);
if (pid == -1) {
// forkpty() failed.
Report("WARNING: failed to fork external symbolizer (errno: %d)\n",
@@ -81,6 +128,11 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return false;
} else if (pid == 0) {
// Child subprocess.
+
+ // Restore stderr.
+ CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0);
+ close(saved_stderr);
+
const char *argv[kArgVMax];
GetArgV(path_, argv);
execv(path_, const_cast<char **>(&argv[0]));
@@ -90,6 +142,8 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
// Continue execution in parent process.
input_fd_ = output_fd_ = fd;
+ close(saved_stderr);
+
// Disable echo in the new terminal, disable CR.
struct termios termflags;
tcgetattr(fd, &termflags);
@@ -135,47 +189,23 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
CHECK(infd);
CHECK(outfd);
- // Real fork() may call user callbacks registered with pthread_atfork().
- pid = internal_fork();
- if (pid == -1) {
- // Fork() failed.
+ const char *argv[kArgVMax];
+ GetArgV(path_, argv);
+ pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
+ /* stdout */ infd[1]);
+ if (pid < 0) {
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 = sysconf(_SC_OPEN_MAX); fd > 2; fd--)
- internal_close(fd);
- const char *argv[kArgVMax];
- GetArgV(path_, argv);
- execv(path_, const_cast<char **>(&argv[0]));
- internal__exit(1);
}
- // Continue execution in parent process.
- internal_close(outfd[0]);
- internal_close(infd[1]);
input_fd_ = infd[0];
output_fd_ = outfd[1];
}
// Check that symbolizer subprocess started successfully.
- int pid_status;
SleepForMillis(kSymbolizerStartupTimeMillis);
- int exited_pid = waitpid(pid, &pid_status, WNOHANG);
- if (exited_pid != 0) {
+ if (!IsProcessRunning(pid)) {
// Either waitpid failed, or child has already exited.
Report("WARNING: external symbolizer didn't start up correctly!\n");
return false;
@@ -372,7 +402,7 @@ class InternalSymbolizer : public SymbolizerTool {
#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
const char *Symbolizer::PlatformDemangle(const char *name) {
- return DemangleCXXABI(name);
+ return DemangleSwiftAndCXX(name);
}
void Symbolizer::PlatformPrepareForSandboxing() {}
@@ -431,7 +461,9 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
VReport(2, "Symbolizer is disabled.\n");
return;
}
- if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
+ if (IsReportingOOM()) {
+ VReport(2, "Cannot use internal symbolizer: out of memory\n");
+ } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
VReport(2, "Using internal symbolizer.\n");
list->push_back(tool);
return;
@@ -450,10 +482,6 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
VReport(2, "Using dladdr symbolizer.\n");
list->push_back(new(*allocator) DlAddrSymbolizer());
#endif // SANITIZER_MAC
-
- if (list->size() == 0) {
- Report("WARNING: no internal or external symbolizer found.\n");
- }
}
Symbolizer *Symbolizer::PlatformInit() {
@@ -463,6 +491,11 @@ Symbolizer *Symbolizer::PlatformInit() {
return new(symbolizer_allocator_) Symbolizer(list);
}
+void Symbolizer::LateInitialize() {
+ Symbolizer::GetOrInit();
+ InitializeSwiftDemangler();
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
index dadb0eaaf6e..95fda7ec42e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -40,6 +40,8 @@ bool TrySymInitialize() {
// FIXME: We don't call SymCleanup() on exit yet - should we?
}
+} // namespace
+
// Initializes DbgHelp library, if it's not yet initialized. Calls to this
// function should be synchronized with respect to other calls to DbgHelp API
// (e.g. from WinSymbolizerTool).
@@ -95,8 +97,6 @@ void InitializeDbgHelpIfNeeded() {
}
}
-} // namespace
-
bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
InitializeDbgHelpIfNeeded();
@@ -277,6 +277,10 @@ Symbolizer *Symbolizer::PlatformInit() {
return new(symbolizer_allocator_) Symbolizer(list);
}
+void Symbolizer::LateInitialize() {
+ Symbolizer::GetOrInit();
+}
+
} // namespace __sanitizer
#endif // _WIN32
diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cc b/libsanitizer/sanitizer_common/sanitizer_termination.cc
new file mode 100644
index 00000000000..6d7335112b3
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_termination.cc
@@ -0,0 +1,84 @@
+//===-- sanitizer_termination.cc --------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file contains the Sanitizer termination functions CheckFailed and Die,
+/// and the callback functionalities associated with them.
+///
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+static const int kMaxNumOfInternalDieCallbacks = 5;
+static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
+
+bool AddDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == nullptr) {
+ InternalDieCallbacks[i] = callback;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool RemoveDieCallback(DieCallbackType callback) {
+ for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
+ if (InternalDieCallbacks[i] == callback) {
+ internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
+ sizeof(InternalDieCallbacks[0]) *
+ (kMaxNumOfInternalDieCallbacks - i - 1));
+ InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
+ return true;
+ }
+ }
+ return false;
+}
+
+static DieCallbackType UserDieCallback;
+void SetUserDieCallback(DieCallbackType callback) {
+ UserDieCallback = callback;
+}
+
+void NORETURN Die() {
+ if (UserDieCallback)
+ UserDieCallback();
+ for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
+ if (InternalDieCallbacks[i])
+ InternalDieCallbacks[i]();
+ }
+ if (common_flags()->abort_on_error)
+ Abort();
+ internal__exit(common_flags()->exitcode);
+}
+
+static CheckFailedCallbackType CheckFailedCallback;
+void SetCheckFailedCallback(CheckFailedCallbackType callback) {
+ CheckFailedCallback = callback;
+}
+
+const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
+
+void NORETURN CheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ static atomic_uint32_t num_calls;
+ if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
+ SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
+ Trap();
+ }
+
+ if (CheckFailedCallback) {
+ CheckFailedCallback(file, line, cond, v1, v2);
+ }
+ Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
+ v1, v2);
+ Die();
+}
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
index bfa610443c1..c865d2cad84 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
@@ -129,7 +129,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
tctx = context_factory_(tid);
threads_[tid] = tctx;
} else {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
SanitizerToolName, max_threads_);
#else
@@ -275,6 +275,8 @@ void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
}
void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
+ if (tctx->tid == 0)
+ return; // Don't reuse the main thread. It's a special snowflake.
dead_threads_.push_back(tctx);
if (dead_threads_.size() <= thread_quarantine_size_)
return;
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
index 7c6ef4f9028..229225d95dd 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -76,7 +76,7 @@ void DTLS_Destroy() {
DTLS_Deallocate(dtls.dtv, s);
}
-#if defined(__powerpc64__)
+#if defined(__powerpc64__) || defined(__mips__)
// This is glibc's TLS_DTV_OFFSET:
// "Dynamic thread vector pointers point 0x8000 past the start of each
// TLS block."
diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
index 408c21c913b..eb1c133e4f4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
@@ -46,6 +46,11 @@ unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch;
#if SANITIZER_ANDROID
void SanitizerInitializeUnwinder() {
+ if (AndroidGetApiLevel() >= ANDROID_LOLLIPOP_MR1) return;
+
+ // Pre-lollipop Android can not unwind through signal handler frames with
+ // libgcc unwinder, but it has a libcorkscrew.so library with the necessary
+ // workarounds.
void *p = dlopen("libcorkscrew.so", RTLD_LAZY);
if (!p) {
VReport(1,
@@ -101,6 +106,11 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
UnwindTraceArg *arg = (UnwindTraceArg*)param;
CHECK_LT(arg->stack->size, arg->max_depth);
uptr pc = Unwind_GetIP(ctx);
+ const uptr kPageSize = GetPageSizeCached();
+ // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
+ // x86_64) is invalid and stop unwinding here. If we're adding support for
+ // a platform where this isn't true, we need to reconsider this check.
+ if (pc < kPageSize) return UNWIND_STOP;
arg->stack->trace_buffer[arg->stack->size++] = pc;
if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
return UNWIND_CONTINUE;
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc
index 0c0a29cea44..785883ce767 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cc
@@ -25,7 +25,9 @@
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
+#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
namespace __sanitizer {
@@ -33,13 +35,15 @@ namespace __sanitizer {
// --------------------- sanitizer_common.h
uptr GetPageSize() {
- // FIXME: there is an API for getting the system page size (GetSystemInfo or
- // GetNativeSystemInfo), but if we use it here we get test failures elsewhere.
- return 1U << 14;
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwPageSize;
}
uptr GetMmapGranularity() {
- return 1U << 16; // FIXME: is this configurable?
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwAllocationGranularity;
}
uptr GetMaxVirtualAddress() {
@@ -81,10 +85,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
}
#endif // #if !SANITIZER_GO
-void *MmapOrDie(uptr size, const char *mem_type) {
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (rv == 0)
- ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
+ ReportMmapFailureAndDie(size, mem_type, "allocate",
+ GetLastError(), raw_report);
return rv;
}
@@ -92,20 +97,90 @@ void UnmapOrDie(void *addr, uptr size) {
if (!size || !addr)
return;
- if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
- Report("ERROR: %s failed to "
- "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
- SanitizerToolName, size, size, addr, GetLastError());
- CHECK("unable to unmap" && 0);
+ MEMORY_BASIC_INFORMATION mbi;
+ CHECK(VirtualQuery(addr, &mbi, sizeof(mbi)));
+
+ // MEM_RELEASE can only be used to unmap whole regions previously mapped with
+ // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that
+ // fails try MEM_DECOMMIT.
+ if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
+ if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
+ Report("ERROR: %s failed to "
+ "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
+ SanitizerToolName, size, size, addr, GetLastError());
+ CHECK("unable to unmap" && 0);
+ }
}
}
+// We want to map a chunk of address space aligned to 'alignment'.
+void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+ CHECK(IsPowerOfTwo(size));
+ CHECK(IsPowerOfTwo(alignment));
+
+ // Windows will align our allocations to at least 64K.
+ alignment = Max(alignment, GetMmapGranularity());
+
+ uptr mapped_addr =
+ (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!mapped_addr)
+ ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
+
+ // If we got it right on the first try, return. Otherwise, unmap it and go to
+ // the slow path.
+ if (IsAligned(mapped_addr, alignment))
+ return (void*)mapped_addr;
+ if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
+ ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
+
+ // If we didn't get an aligned address, overallocate, find an aligned address,
+ // unmap, and try to allocate at that aligned address.
+ int retries = 0;
+ const int kMaxRetries = 10;
+ for (; retries < kMaxRetries &&
+ (mapped_addr == 0 || !IsAligned(mapped_addr, alignment));
+ retries++) {
+ // Overallocate size + alignment bytes.
+ mapped_addr =
+ (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
+ if (!mapped_addr)
+ ReportMmapFailureAndDie(size, mem_type, "allocate aligned",
+ GetLastError());
+
+ // Find the aligned address.
+ uptr aligned_addr = RoundUpTo(mapped_addr, alignment);
+
+ // Free the overallocation.
+ if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
+ ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
+
+ // Attempt to allocate exactly the number of bytes we need at the aligned
+ // address. This may fail for a number of reasons, in which case we continue
+ // the loop.
+ mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ }
+
+ // Fail if we can't make this work quickly.
+ if (retries == kMaxRetries && mapped_addr == 0)
+ ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
+
+ return (void *)mapped_addr;
+}
+
void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
// FIXME: is this really "NoReserve"? On Win32 this does not matter much,
// but on Win64 it does.
- (void)name; // unsupported
- void *p = VirtualAlloc((LPVOID)fixed_addr, size,
- MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ (void)name; // unsupported
+#if !SANITIZER_GO && SANITIZER_WINDOWS64
+ // On asan/Windows64, use MEM_COMMIT would result in error
+ // 1455:ERROR_COMMITMENT_LIMIT.
+ // Asan uses exception handler to commit page on demand.
+ void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE);
+#else
+ void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT,
+ PAGE_READWRITE);
+#endif
if (p == 0)
Report("ERROR: %s failed to "
"allocate %p (%zd) bytes at %p (error code: %d)\n",
@@ -113,8 +188,18 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
return p;
}
+// Memory space mapped by 'MmapFixedOrDie' must have been reserved by
+// 'MmapFixedNoAccess'.
void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
- return MmapFixedNoReserve(fixed_addr, size);
+ void *p = VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_COMMIT, PAGE_READWRITE);
+ if (p == 0) {
+ char mem_type[30];
+ internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
+ fixed_addr);
+ ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
+ }
+ return p;
}
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
@@ -122,10 +207,10 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
return MmapOrDie(size, mem_type);
}
-void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
+void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
(void)name; // unsupported
void *res = VirtualAlloc((LPVOID)fixed_addr, size,
- MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
+ MEM_RESERVE, PAGE_NOACCESS);
if (res == 0)
Report("WARNING: %s failed to "
"mprotect %p (%zd) bytes at %p (error code: %d)\n",
@@ -133,19 +218,28 @@ void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
return res;
}
+void *MmapNoAccess(uptr size) {
+ void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS);
+ if (res == 0)
+ Report("WARNING: %s failed to "
+ "mprotect %p (%zd) bytes (error code: %d)\n",
+ SanitizerToolName, size, size, GetLastError());
+ return res;
+}
+
bool MprotectNoAccess(uptr addr, uptr size) {
DWORD old_protection;
return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
}
-void FlushUnneededShadowMemory(uptr addr, uptr size) {
+void ReleaseMemoryToOS(uptr addr, uptr size) {
// This is almost useless on 32-bits.
// FIXME: add madvise-analog when we move to 64-bits.
}
void NoHugePagesInRegion(uptr addr, uptr size) {
- // FIXME: probably similar to FlushUnneededShadowMemory.
+ // FIXME: probably similar to ReleaseMemoryToOS.
}
void DontDumpShadowMemory(uptr addr, uptr length) {
@@ -153,6 +247,26 @@ void DontDumpShadowMemory(uptr addr, uptr length) {
// FIXME: add madvise-analog when we move to 64-bits.
}
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+ uptr address = 0;
+ while (true) {
+ MEMORY_BASIC_INFORMATION info;
+ if (!::VirtualQuery((void*)address, &info, sizeof(info)))
+ return 0;
+
+ if (info.State == MEM_FREE) {
+ uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding,
+ alignment);
+ if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize)
+ return shadow_address;
+ }
+
+ // Move to the next region.
+ address = (uptr)info.BaseAddress + info.RegionSize;
+ }
+ return 0;
+}
+
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MEMORY_BASIC_INFORMATION mbi;
CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
@@ -218,7 +332,7 @@ struct ModuleInfo {
uptr end_address;
};
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
int CompareModulesBase(const void *pl, const void *pr) {
const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
if (l->base_address < r->base_address)
@@ -228,18 +342,18 @@ int CompareModulesBase(const void *pl, const void *pr) {
#endif
} // namespace
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void DumpProcessMap() {
Report("Dumping process modules:\n");
- InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
- uptr num_modules =
- GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
+ ListOfModules modules;
+ modules.init();
+ uptr num_modules = modules.size();
InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
for (size_t i = 0; i < num_modules; ++i) {
module_infos[i].filepath = modules[i].full_name();
- module_infos[i].base_address = modules[i].base_address();
- module_infos[i].end_address = modules[i].ranges().next()->end;
+ module_infos[i].base_address = modules[i].ranges().front()->beg;
+ module_infos[i].end_address = modules[i].ranges().back()->end;
}
qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
CompareModulesBase);
@@ -314,6 +428,7 @@ void Abort() {
internal__exit(3);
}
+#if !SANITIZER_GO
// Read the file to extract the ImageBase field from the PE header. If ASLR is
// disabled and this virtual address is available, the loader will typically
// load the image at this address. Therefore, we call it the preferred base. Any
@@ -366,9 +481,8 @@ static uptr GetPreferredBase(const char *modname) {
return (uptr)pe_header->ImageBase;
}
-#ifndef SANITIZER_GO
-uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
- string_predicate_t filter) {
+void ListOfModules::init() {
+ clear();
HANDLE cur_process = GetCurrentProcess();
// Query the list of modules. Start by assuming there are no more than 256
@@ -390,10 +504,8 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
}
// |num_modules| is the number of modules actually present,
- // |count| is the number of modules we return.
- size_t nun_modules = bytes_required / sizeof(HMODULE),
- count = 0;
- for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
+ size_t num_modules = bytes_required / sizeof(HMODULE);
+ for (size_t i = 0; i < num_modules; ++i) {
HMODULE handle = hmodules[i];
MODULEINFO mi;
if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
@@ -411,9 +523,6 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
&module_name[0], kMaxPathLength, NULL, NULL);
module_name[module_name_len] = '\0';
- if (filter && !filter(module_name))
- continue;
-
uptr base_address = (uptr)mi.lpBaseOfDll;
uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
@@ -424,15 +533,13 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
uptr preferred_base = GetPreferredBase(&module_name[0]);
uptr adjusted_base = base_address - preferred_base;
- LoadedModule *cur_module = &modules[count];
- cur_module->set(module_name, adjusted_base);
+ LoadedModule cur_module;
+ cur_module.set(module_name, adjusted_base);
// We add the whole module as one single address range.
- cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
- count++;
+ cur_module.addAddressRange(base_address, end_address, /*executable*/ true);
+ modules_.push_back(cur_module);
}
UnmapOrDie(hmodules, modules_buffer_size);
-
- return count;
};
// We can't use atexit() directly at __asan_init time as the CRT is not fully
@@ -459,14 +566,15 @@ __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
// ------------------ sanitizer_libc.h
fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
+ // FIXME: Use the wide variants to handle Unicode filenames.
fd_t res;
if (mode == RdOnly) {
- res = CreateFile(filename, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ res = CreateFileA(filename, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
} else if (mode == WrOnly) {
- res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, nullptr);
+ res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, nullptr);
} else {
UNIMPLEMENTED();
}
@@ -613,7 +721,7 @@ void InitTlsSize() {
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
-#ifdef SANITIZER_GO
+#if SANITIZER_GO
*stk_addr = 0;
*stk_size = 0;
*tls_addr = 0;
@@ -634,7 +742,7 @@ void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
// FIXME: CaptureStackBackTrace might be too slow for us.
// FIXME: Compare with StackWalk64.
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
- size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
+ size = CaptureStackBackTrace(1, Min(max_depth, kStackTraceMax),
(void**)trace, 0);
if (size == 0)
return;
@@ -649,6 +757,9 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
CONTEXT ctx = *(CONTEXT *)context;
STACKFRAME64 stack_frame;
memset(&stack_frame, 0, sizeof(stack_frame));
+
+ InitializeDbgHelpIfNeeded();
+
size = 0;
#if defined(_WIN64)
int machine_type = IMAGE_FILE_MACHINE_AMD64;
@@ -697,7 +808,7 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
// FIXME: Decide what to do on Windows.
}
-bool IsDeadlySignal(int signum) {
+bool IsHandledDeadlySignal(int signum) {
// FIXME: Decide what to do on Windows.
return false;
}
@@ -728,8 +839,8 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
}
SignalContext SignalContext::Create(void *siginfo, void *context) {
- EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
- CONTEXT *context_record = (CONTEXT*)context;
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
+ CONTEXT *context_record = (CONTEXT *)context;
uptr pc = (uptr)exception_record->ExceptionAddress;
#ifdef _WIN64
@@ -741,7 +852,19 @@ SignalContext SignalContext::Create(void *siginfo, void *context) {
#endif
uptr access_addr = exception_record->ExceptionInformation[1];
- return SignalContext(context, access_addr, pc, sp, bp);
+ // The contents of this array are documented at
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
+ // The first element indicates read as 0, write as 1, or execute as 8. The
+ // second element is the faulting address.
+ WriteFlag write_flag = SignalContext::UNKNOWN;
+ switch (exception_record->ExceptionInformation[0]) {
+ case 0: write_flag = SignalContext::READ; break;
+ case 1: write_flag = SignalContext::WRITE; break;
+ case 8: write_flag = SignalContext::UNKNOWN; break;
+ }
+ bool is_memory_access = write_flag != SignalContext::UNKNOWN;
+ return SignalContext(context, access_addr, pc, sp, bp, is_memory_access,
+ write_flag);
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
@@ -759,6 +882,49 @@ void CheckVMASize() {
// Do nothing.
}
+void MaybeReexec() {
+ // No need to re-exec on Windows.
+}
+
+char **GetArgv() {
+ // FIXME: Actually implement this function.
+ return 0;
+}
+
+pid_t StartSubprocess(const char *program, const char *const argv[],
+ fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
+ // FIXME: implement on this platform
+ // Should be implemented based on
+ // SymbolizerProcess::StarAtSymbolizerSubprocess
+ // from lib/sanitizer_common/sanitizer_symbolizer_win.cc.
+ return -1;
+}
+
+bool IsProcessRunning(pid_t pid) {
+ // FIXME: implement on this platform.
+ return false;
+}
+
+int WaitForProcess(pid_t pid) { return -1; }
+
+// FIXME implement on this platform.
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { }
+
+
} // namespace __sanitizer
+#if !SANITIZER_GO
+// Workaround to implement weak hooks on Windows. COFF doesn't directly support
+// weak symbols, but it does support /alternatename, which is similar. If the
+// user does not override the hook, we will use this default definition instead
+// of null.
+extern "C" void __sanitizer_print_memory_profile(int top_percent) {}
+
+#ifdef _WIN64
+#pragma comment(linker, "/alternatename:__sanitizer_print_memory_profile=__sanitizer_default_print_memory_profile") // NOLINT
+#else
+#pragma comment(linker, "/alternatename:___sanitizer_print_memory_profile=___sanitizer_default_print_memory_profile") // NOLINT
+#endif
+#endif
+
#endif // _WIN32
diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am
index 9833de20bd8..7a0c2971143 100644
--- a/libsanitizer/tsan/Makefile.am
+++ b/libsanitizer/tsan/Makefile.am
@@ -10,13 +10,16 @@ AM_CXXFLAGS += -std=gnu++11
ACLOCAL_AMFLAGS = -I m4
toolexeclib_LTLIBRARIES = libtsan.la
+nodist_toolexeclib_HEADERS = libtsan_preinit.o
tsan_files = \
tsan_clock.cc \
+ tsan_debugging.cc \
tsan_fd.cc \
tsan_flags.cc \
tsan_ignoreset.cc \
tsan_interceptors.cc \
+ tsan_interceptors_mac.cc \
tsan_interface_ann.cc \
tsan_interface_atomic.cc \
tsan_interface.cc \
@@ -35,6 +38,7 @@ tsan_files = \
tsan_report.cc \
tsan_rtl.cc \
tsan_rtl_mutex.cc \
+ tsan_rtl_proc.cc \
tsan_rtl_report.cc \
tsan_rtl_thread.cc \
tsan_stack_trace.cc \
@@ -44,7 +48,7 @@ tsan_files = \
tsan_sync.cc
libtsan_la_SOURCES = $(tsan_files)
-EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S
+EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S
libtsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
libtsan_la_DEPENDENCIES = $(top_builddir)/sanitizer_common/libsanitizer_common.la $(top_builddir)/interception/libinterception.la $(TSAN_TARGET_DEPENDENT_OBJECTS)
if LIBBACKTRACE_SUPPORTED
@@ -54,6 +58,9 @@ endif
libtsan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS)
libtsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libtsan)
+libtsan_preinit.o: tsan_preinit.o
+ cp $< $@
+
# 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.
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index de8de7c6674..4d4ec47becc 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -15,6 +15,7 @@
@SET_MAKE@
+
VPATH = @srcdir@
am__make_dryrun = \
{ \
@@ -101,20 +102,22 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
+am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
+ "$(DESTDIR)$(toolexeclibdir)"
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
am__DEPENDENCIES_1 =
-am__objects_1 = tsan_clock.lo tsan_fd.lo tsan_flags.lo \
- tsan_ignoreset.lo tsan_interceptors.lo tsan_interface_ann.lo \
+am__objects_1 = tsan_clock.lo tsan_debugging.lo tsan_fd.lo \
+ tsan_flags.lo tsan_ignoreset.lo tsan_interceptors.lo \
+ tsan_interceptors_mac.lo tsan_interface_ann.lo \
tsan_interface_atomic.lo tsan_interface.lo \
tsan_interface_java.lo tsan_libdispatch_mac.lo \
tsan_malloc_mac.lo tsan_md5.lo tsan_mman.lo tsan_mutex.lo \
tsan_mutexset.lo tsan_new_delete.lo tsan_platform_linux.lo \
tsan_platform_mac.lo tsan_platform_posix.lo \
tsan_platform_windows.lo tsan_report.lo tsan_rtl.lo \
- tsan_rtl_mutex.lo tsan_rtl_report.lo tsan_rtl_thread.lo \
- tsan_stack_trace.lo tsan_stat.lo tsan_suppressions.lo \
- tsan_symbolize.lo tsan_sync.lo
+ tsan_rtl_mutex.lo tsan_rtl_proc.lo tsan_rtl_report.lo \
+ tsan_rtl_thread.lo tsan_stack_trace.lo tsan_stat.lo \
+ tsan_suppressions.lo tsan_symbolize.lo tsan_sync.lo
am_libtsan_la_OBJECTS = $(am__objects_1)
libtsan_la_OBJECTS = $(am_libtsan_la_OBJECTS)
libtsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -153,6 +156,7 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
+HEADERS = $(nodist_toolexeclib_HEADERS)
ETAGS = etags
CTAGS = ctags
ACLOCAL = @ACLOCAL@
@@ -225,6 +229,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -309,12 +314,15 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
-std=gnu++11
ACLOCAL_AMFLAGS = -I m4
toolexeclib_LTLIBRARIES = libtsan.la
+nodist_toolexeclib_HEADERS = libtsan_preinit.o
tsan_files = \
tsan_clock.cc \
+ tsan_debugging.cc \
tsan_fd.cc \
tsan_flags.cc \
tsan_ignoreset.cc \
tsan_interceptors.cc \
+ tsan_interceptors_mac.cc \
tsan_interface_ann.cc \
tsan_interface_atomic.cc \
tsan_interface.cc \
@@ -333,6 +341,7 @@ tsan_files = \
tsan_report.cc \
tsan_rtl.cc \
tsan_rtl_mutex.cc \
+ tsan_rtl_proc.cc \
tsan_rtl_report.cc \
tsan_rtl_thread.cc \
tsan_stack_trace.cc \
@@ -342,7 +351,7 @@ tsan_files = \
tsan_sync.cc
libtsan_la_SOURCES = $(tsan_files)
-EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S
+EXTRA_libtsan_la_SOURCES = tsan_rtl_amd64.S tsan_rtl_aarch64.S tsan_rtl_mips64.S tsan_rtl_ppc64.S
libtsan_la_LIBADD = \
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
$(top_builddir)/interception/libinterception.la \
@@ -469,10 +478,12 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_clock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_debugging.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_fd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_ignoreset.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_ann.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_atomic.Plo@am__quote@
@@ -492,7 +503,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_aarch64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_amd64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_mips64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_mutex.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_ppc64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_proc.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_report.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_thread.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_stack_trace.Plo@am__quote@
@@ -548,6 +562,27 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
+install-nodist_toolexeclibHEADERS: $(nodist_toolexeclib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_toolexeclib_HEADERS)'; test -n "$(toolexeclibdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(toolexeclibdir)" || exit $$?; \
+ done
+
+uninstall-nodist_toolexeclibHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_toolexeclib_HEADERS)'; test -n "$(toolexeclibdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(toolexeclibdir)'; $(am__uninstall_files_from_dir)
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -602,9 +637,9 @@ distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
check-am: all-am
check: check-am
-all-am: Makefile $(LTLIBRARIES)
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
installdirs:
- for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -666,7 +701,8 @@ install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-toolexeclibLTLIBRARIES
+install-exec-am: install-nodist_toolexeclibHEADERS \
+ install-toolexeclibLTLIBRARIES
install-html: install-html-am
@@ -706,7 +742,8 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-toolexeclibLTLIBRARIES
+uninstall-am: uninstall-nodist_toolexeclibHEADERS \
+ uninstall-toolexeclibLTLIBRARIES
.MAKE: install-am install-strip
@@ -717,13 +754,18 @@ uninstall-am: uninstall-toolexeclibLTLIBRARIES
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
-
+ install-nodist_toolexeclibHEADERS 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-nodist_toolexeclibHEADERS \
+ uninstall-toolexeclibLTLIBRARIES
+
+
+libtsan_preinit.o: tsan_preinit.o
+ cp $< $@
# 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.
diff --git a/libsanitizer/tsan/tsan_clock.cc b/libsanitizer/tsan/tsan_clock.cc
index 037afc83fc6..23f9228a672 100644
--- a/libsanitizer/tsan/tsan_clock.cc
+++ b/libsanitizer/tsan/tsan_clock.cc
@@ -80,7 +80,7 @@
// We don't have ThreadState in these methods, so this is an ugly hack that
// works only in C++.
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
# define CPP_STAT_INC(typ) StatInc(cur_thread(), typ)
#else
# define CPP_STAT_INC(typ) (void)0
diff --git a/libsanitizer/tsan/tsan_debugging.cc b/libsanitizer/tsan/tsan_debugging.cc
new file mode 100644
index 00000000000..d26d4828b15
--- /dev/null
+++ b/libsanitizer/tsan/tsan_debugging.cc
@@ -0,0 +1,160 @@
+//===-- tsan_debugging.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 (TSan), a race detector.
+//
+// TSan debugging API implementation.
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_report.h"
+#include "tsan_rtl.h"
+
+using namespace __tsan;
+
+static const char *ReportTypeDescription(ReportType typ) {
+ if (typ == ReportTypeRace) return "data-race";
+ if (typ == ReportTypeVptrRace) return "data-race-vptr";
+ if (typ == ReportTypeUseAfterFree) return "heap-use-after-free";
+ if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free-vptr";
+ if (typ == ReportTypeThreadLeak) return "thread-leak";
+ if (typ == ReportTypeMutexDestroyLocked) return "locked-mutex-destroy";
+ if (typ == ReportTypeMutexDoubleLock) return "mutex-double-lock";
+ if (typ == ReportTypeMutexInvalidAccess) return "mutex-invalid-access";
+ if (typ == ReportTypeMutexBadUnlock) return "mutex-bad-unlock";
+ if (typ == ReportTypeMutexBadReadLock) return "mutex-bad-read-lock";
+ if (typ == ReportTypeMutexBadReadUnlock) return "mutex-bad-read-unlock";
+ if (typ == ReportTypeSignalUnsafe) return "signal-unsafe-call";
+ if (typ == ReportTypeErrnoInSignal) return "errno-in-signal-handler";
+ if (typ == ReportTypeDeadlock) return "lock-order-inversion";
+ return "";
+}
+
+static const char *ReportLocationTypeDescription(ReportLocationType typ) {
+ if (typ == ReportLocationGlobal) return "global";
+ if (typ == ReportLocationHeap) return "heap";
+ if (typ == ReportLocationStack) return "stack";
+ if (typ == ReportLocationTLS) return "tls";
+ if (typ == ReportLocationFD) return "fd";
+ return "";
+}
+
+static void CopyTrace(SymbolizedStack *first_frame, void **trace,
+ uptr trace_size) {
+ uptr i = 0;
+ for (SymbolizedStack *frame = first_frame; frame != nullptr;
+ frame = frame->next) {
+ trace[i++] = (void *)frame->info.address;
+ if (i >= trace_size) break;
+ }
+}
+
+// Meant to be called by the debugger.
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_get_current_report() {
+ return const_cast<ReportDesc*>(cur_thread()->current_report);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_data(void *report, const char **description, int *count,
+ int *stack_count, int *mop_count, int *loc_count,
+ int *mutex_count, int *thread_count,
+ int *unique_tid_count, void **sleep_trace,
+ uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ *description = ReportTypeDescription(rep->typ);
+ *count = rep->count;
+ *stack_count = rep->stacks.Size();
+ *mop_count = rep->mops.Size();
+ *loc_count = rep->locs.Size();
+ *mutex_count = rep->mutexes.Size();
+ *thread_count = rep->threads.Size();
+ *unique_tid_count = rep->unique_tids.Size();
+ if (rep->sleep) CopyTrace(rep->sleep->frames, sleep_trace, trace_size);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_stack(void *report, uptr idx, void **trace,
+ uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->stacks.Size());
+ ReportStack *stack = rep->stacks[idx];
+ if (stack) CopyTrace(stack->frames, trace, trace_size);
+ return stack ? 1 : 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,
+ int *size, int *write, int *atomic, void **trace,
+ uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->mops.Size());
+ ReportMop *mop = rep->mops[idx];
+ *tid = mop->tid;
+ *addr = (void *)mop->addr;
+ *size = mop->size;
+ *write = mop->write ? 1 : 0;
+ *atomic = mop->atomic ? 1 : 0;
+ if (mop->stack) CopyTrace(mop->stack->frames, trace, trace_size);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc(void *report, uptr idx, const char **type,
+ void **addr, uptr *start, uptr *size, int *tid,
+ int *fd, int *suppressable, void **trace,
+ uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->locs.Size());
+ ReportLocation *loc = rep->locs[idx];
+ *type = ReportLocationTypeDescription(loc->type);
+ *addr = (void *)loc->global.start;
+ *start = loc->heap_chunk_start;
+ *size = loc->heap_chunk_size;
+ *tid = loc->tid;
+ *fd = loc->fd;
+ *suppressable = loc->suppressable;
+ if (loc->stack) CopyTrace(loc->stack->frames, trace, trace_size);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
+ int *destroyed, void **trace, uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->mutexes.Size());
+ ReportMutex *mutex = rep->mutexes[idx];
+ *mutex_id = mutex->id;
+ *addr = (void *)mutex->addr;
+ *destroyed = mutex->destroyed;
+ if (mutex->stack) CopyTrace(mutex->stack->frames, trace, trace_size);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id,
+ int *running, const char **name, int *parent_tid,
+ void **trace, uptr trace_size) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->threads.Size());
+ ReportThread *thread = rep->threads[idx];
+ *tid = thread->id;
+ *os_id = thread->os_id;
+ *running = thread->running;
+ *name = thread->name;
+ *parent_tid = thread->parent_tid;
+ if (thread->stack) CopyTrace(thread->stack->frames, trace, trace_size);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->unique_tids.Size());
+ *tid = rep->unique_tids[idx];
+ return 1;
+}
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index 259b30bee5d..e540526caa2 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -27,27 +27,18 @@
#endif
#ifndef TSAN_CONTAINS_UBSAN
-# define TSAN_CONTAINS_UBSAN (CAN_SANITIZE_UB && !defined(SANITIZER_GO))
+# if CAN_SANITIZE_UB && !SANITIZER_GO
+# define TSAN_CONTAINS_UBSAN 1
+# else
+# define TSAN_CONTAINS_UBSAN 0
+# endif
#endif
namespace __tsan {
-#ifdef SANITIZER_GO
-const bool kGoMode = true;
-const bool kCppMode = false;
-const char *const kTsanOptionsEnv = "GORACE";
-// Go linker does not support weak symbols.
-#define CPP_WEAK
-#else
-const bool kGoMode = false;
-const bool kCppMode = true;
-const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
-#define CPP_WEAK WEAK
-#endif
-
const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
#else
const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory.
@@ -146,6 +137,7 @@ struct MD5Hash {
MD5Hash md5_hash(const void *data, uptr size);
+struct Processor;
struct ThreadState;
class ThreadContext;
struct Context;
diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
index 651c112c78a..780ff6f4c8e 100644
--- a/libsanitizer/tsan/tsan_dense_alloc.h
+++ b/libsanitizer/tsan/tsan_dense_alloc.h
@@ -106,7 +106,7 @@ class DenseSlabAlloc {
// Reserve 0 as invalid index.
IndexT start = fillpos_ == 0 ? 1 : 0;
for (IndexT i = start; i < kL2Size; i++) {
- new(batch + i) T();
+ new(batch + i) T;
*(IndexT*)(batch + i) = i + 1 + fillpos_ * kL2Size;
}
*(IndexT*)(batch + kL2Size - 1) = 0;
diff --git a/libsanitizer/tsan/tsan_flags.cc b/libsanitizer/tsan/tsan_flags.cc
index 4cec0ac09f4..5064a0fe653 100644
--- a/libsanitizer/tsan/tsan_flags.cc
+++ b/libsanitizer/tsan/tsan_flags.cc
@@ -27,8 +27,8 @@ Flags *flags() {
#ifdef TSAN_EXTERNAL_HOOKS
extern "C" const char* __tsan_default_options();
#else
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE
-const char *WEAK __tsan_default_options() {
+SANITIZER_WEAK_DEFAULT_IMPL
+const char *__tsan_default_options() {
return "";
}
#endif
@@ -59,7 +59,7 @@ void InitializeFlags(Flags *f, const char *env) {
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.allow_addr2line = true;
- if (kGoMode) {
+ if (SANITIZER_GO) {
// Does not work as expected for Go: runtime handles SIGABRT and crashes.
cf.abort_on_error = false;
// Go does not have mutexes.
@@ -69,6 +69,7 @@ void InitializeFlags(Flags *f, const char *env) {
cf.print_suppressions = false;
cf.stack_trace_format = " #%n %f %S %M";
cf.exitcode = 66;
+ cf.intercept_tls_get_addr = true;
OverrideCommonFlags(cf);
}
@@ -106,7 +107,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->report_signal_unsafe = false;
}
- SetVerbosity(common_flags()->verbosity);
+ InitializeCommonFlags();
if (Verbosity()) ReportUnrecognizedFlags();
diff --git a/libsanitizer/tsan/tsan_flags.inc b/libsanitizer/tsan/tsan_flags.inc
index 822e560b622..78f5e80fd5c 100644
--- a/libsanitizer/tsan/tsan_flags.inc
+++ b/libsanitizer/tsan/tsan_flags.inc
@@ -59,8 +59,9 @@ TSAN_FLAG(bool, stop_on_start, false,
"Stops on start until __tsan_resume() is called (for debugging).")
TSAN_FLAG(bool, running_on_valgrind, false,
"Controls whether RunningOnValgrind() returns true or false.")
+// There are a lot of goroutines in Go, so we use smaller history.
TSAN_FLAG(
- int, history_size, kGoMode ? 1 : 3, // There are a lot of goroutines in Go.
+ int, history_size, SANITIZER_GO ? 1 : 3,
"Per-thread history size, controls how many previous memory accesses "
"are remembered per thread. Possible values are [0..7]. "
"history_size=0 amounts to 32K memory accesses. Each next value doubles "
@@ -74,3 +75,7 @@ TSAN_FLAG(int, io_sync, 1,
TSAN_FLAG(bool, die_after_fork, true,
"Die after multi-threaded fork if the child creates new threads.")
TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
+TSAN_FLAG(bool, ignore_interceptors_accesses, false,
+ "Ignore reads and writes from all interceptors.")
+TSAN_FLAG(bool, shared_ptr_interceptor, true,
+ "Track atomic reference counting in libc++ shared_ptr and weak_ptr.")
diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc
index 0c71c008d70..bf5f2d5b66c 100644
--- a/libsanitizer/tsan/tsan_interceptors.cc
+++ b/libsanitizer/tsan/tsan_interceptors.cc
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "interception/interception.h"
#include "tsan_interceptors.h"
#include "tsan_interface.h"
@@ -38,14 +39,9 @@ using namespace __tsan; // NOLINT
#define stderr __stderrp
#endif
-#if SANITIZER_FREEBSD
-#define __libc_realloc __realloc
-#define __libc_calloc __calloc
-#elif SANITIZER_MAC
-#define __libc_malloc REAL(malloc)
-#define __libc_realloc REAL(realloc)
-#define __libc_calloc REAL(calloc)
-#define __libc_free REAL(free)
+#if SANITIZER_ANDROID
+#define __errno_location __errno
+#define mallopt(a, b)
#endif
#if SANITIZER_LINUX || SANITIZER_FREEBSD
@@ -77,9 +73,9 @@ struct ucontext_t {
};
#endif
-#if defined(__x86_64__) || defined(__mips__)
+#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1
#define PTHREAD_ABI_BASE "GLIBC_2.3.2"
-#elif defined(__aarch64__)
+#elif defined(__aarch64__) || SANITIZER_PPC64V2
#define PTHREAD_ABI_BASE "GLIBC_2.17"
#endif
@@ -90,10 +86,6 @@ extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
extern "C" int pthread_setspecific(unsigned key, const void *v);
DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
-extern "C" int pthread_sigmask(int how, const __sanitizer_sigset_t *set,
- __sanitizer_sigset_t *oldset);
-// REAL(sigfillset) defined in common interceptors.
-DECLARE_REAL(int, sigfillset, __sanitizer_sigset_t *set)
DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
@@ -101,19 +93,22 @@ extern "C" void *pthread_self();
extern "C" void _exit(int status);
extern "C" int *__errno_location();
extern "C" int fileno_unlocked(void *stream);
-extern "C" void *__libc_calloc(uptr size, uptr n);
-extern "C" void *__libc_realloc(void *ptr, uptr size);
extern "C" int dirfd(void *dirp);
-#if !SANITIZER_FREEBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID
extern "C" int mallopt(int param, int value);
#endif
extern __sanitizer_FILE *stdout, *stderr;
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC
const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
+#else
+const int PTHREAD_MUTEX_RECURSIVE = 2;
+const int PTHREAD_MUTEX_RECURSIVE_NP = 2;
+#endif
const int EINVAL = 22;
const int EBUSY = 16;
const int EOWNERDEAD = 130;
-#if !SANITIZER_MAC
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC
const int EPOLL_CTL_ADD = 1;
#endif
const int SIGILL = 4;
@@ -122,7 +117,7 @@ const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
const int SIGTERM = 15;
-#ifdef __mips__
+#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC
const int SIGBUS = 10;
const int SIGSYS = 12;
#else
@@ -147,6 +142,17 @@ typedef long long_t; // NOLINT
typedef void (*sighandler_t)(int sig);
typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx);
+#if SANITIZER_ANDROID
+struct sigaction_t {
+ u32 sa_flags;
+ union {
+ sighandler_t sa_handler;
+ sigactionhandler_t sa_sigaction;
+ };
+ __sanitizer_sigset_t sa_mask;
+ void (*sa_restorer)();
+};
+#else
struct sigaction_t {
#ifdef __mips__
u32 sa_flags;
@@ -158,6 +164,9 @@ struct sigaction_t {
#if SANITIZER_FREEBSD
int sa_flags;
__sanitizer_sigset_t sa_mask;
+#elif SANITIZER_MAC
+ __sanitizer_sigset_t sa_mask;
+ int sa_flags;
#else
__sanitizer_sigset_t sa_mask;
#ifndef __mips__
@@ -166,11 +175,12 @@ struct sigaction_t {
void (*sa_restorer)();
#endif
};
+#endif
const sighandler_t SIG_DFL = (sighandler_t)0;
const sighandler_t SIG_IGN = (sighandler_t)1;
const sighandler_t SIG_ERR = (sighandler_t)-1;
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC
const int SA_SIGINFO = 0x40;
const int SIG_SETMASK = 3;
#elif defined(__mips__)
@@ -199,6 +209,9 @@ struct ThreadSignalContext {
atomic_uintptr_t in_blocking_func;
atomic_uintptr_t have_pending_signals;
SignalDesc pending_signals[kSigCount];
+ // emptyset and oldset are too big for stack.
+ __sanitizer_sigset_t emptyset;
+ __sanitizer_sigset_t oldset;
};
// The object is 64-byte aligned, because we want hot data to be located in
@@ -231,26 +244,33 @@ static ThreadSignalContext *SigCtx(ThreadState *thr) {
return ctx;
}
+#if !SANITIZER_MAC
static unsigned g_thread_finalize_key;
+#endif
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
: thr_(thr)
, pc_(pc)
, in_ignored_lib_(false) {
- if (!thr_->ignore_interceptors) {
- Initialize(thr);
+ Initialize(thr);
+ if (!thr_->is_inited)
+ return;
+ if (!thr_->ignore_interceptors)
FuncEntry(thr, pc);
- }
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
in_ignored_lib_ = true;
thr_->in_ignored_lib = true;
ThreadIgnoreBegin(thr_, pc_);
}
+ if (flags()->ignore_interceptors_accesses) ThreadIgnoreBegin(thr_, pc_);
}
ScopedInterceptor::~ScopedInterceptor() {
+ if (!thr_->is_inited)
+ return;
+ if (flags()->ignore_interceptors_accesses) ThreadIgnoreEnd(thr_, pc_);
if (in_ignored_lib_) {
thr_->in_ignored_lib = false;
ThreadIgnoreEnd(thr_, pc_);
@@ -262,6 +282,22 @@ ScopedInterceptor::~ScopedInterceptor() {
}
}
+void ScopedInterceptor::UserCallbackStart() {
+ if (flags()->ignore_interceptors_accesses) ThreadIgnoreEnd(thr_, pc_);
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = false;
+ ThreadIgnoreEnd(thr_, pc_);
+ }
+}
+
+void ScopedInterceptor::UserCallbackEnd() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = true;
+ ThreadIgnoreBegin(thr_, pc_);
+ }
+ if (flags()->ignore_interceptors_accesses) ThreadIgnoreBegin(thr_, pc_);
+}
+
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
#if SANITIZER_FREEBSD
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
@@ -340,12 +376,13 @@ static void at_exit_wrapper(void *arg) {
Acquire(thr, pc, (uptr)arg);
AtExitCtx *ctx = (AtExitCtx*)arg;
((void(*)(void *arg))ctx->f)(ctx->arg);
- __libc_free(ctx);
+ InternalFree(ctx);
}
static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
void *arg, void *dso);
+#if !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
if (cur_thread()->in_symbolizer)
return 0;
@@ -354,6 +391,7 @@ TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(atexit, f);
return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
}
+#endif
TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
if (cur_thread()->in_symbolizer)
@@ -364,7 +402,7 @@ TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
void *arg, void *dso) {
- AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx));
ctx->f = f;
ctx->arg = arg;
Release(thr, pc, (uptr)ctx);
@@ -383,14 +421,14 @@ static void on_exit_wrapper(int status, void *arg) {
Acquire(thr, pc, (uptr)arg);
AtExitCtx *ctx = (AtExitCtx*)arg;
((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
- __libc_free(ctx);
+ InternalFree(ctx);
}
TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
if (cur_thread()->in_symbolizer)
return 0;
SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
- AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+ AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx));
ctx->f = (void(*)())f;
ctx->arg = arg;
Release(thr, pc, (uptr)ctx);
@@ -409,7 +447,7 @@ static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
JmpBuf *buf = &thr->jmp_bufs[i];
if (buf->sp <= sp) {
uptr sz = thr->jmp_bufs.Size();
- thr->jmp_bufs[i] = thr->jmp_bufs[sz - 1];
+ internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf));
thr->jmp_bufs.PopBack();
i--;
}
@@ -436,15 +474,19 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
}
static void LongJmp(ThreadState *thr, uptr *env) {
-#if SANITIZER_FREEBSD
+#ifdef __powerpc__
+ uptr mangled_sp = env[0];
+#elif SANITIZER_FREEBSD || SANITIZER_MAC
uptr mangled_sp = env[2];
#elif defined(SANITIZER_LINUX)
# ifdef __aarch64__
uptr mangled_sp = env[13];
+# elif defined(__mips64)
+ uptr mangled_sp = env[1];
# else
uptr mangled_sp = env[6];
# endif
-#endif // SANITIZER_FREEBSD
+#endif
// Find the saved buf by mangled_sp.
for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
JmpBuf *buf = &thr->jmp_bufs[i];
@@ -474,6 +516,11 @@ extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
SetJmp(cur_thread(), sp, mangled_sp);
}
+#if SANITIZER_MAC
+TSAN_INTERCEPTOR(int, setjmp, void *env);
+TSAN_INTERCEPTOR(int, _setjmp, void *env);
+TSAN_INTERCEPTOR(int, sigsetjmp, void *env);
+#else // SANITIZER_MAC
// Not called. Merely to satisfy TSAN_INTERCEPT().
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
int __interceptor_setjmp(void *env);
@@ -512,10 +559,14 @@ DEFINE_REAL(int, setjmp, void *env)
DEFINE_REAL(int, _setjmp, void *env)
DEFINE_REAL(int, sigsetjmp, void *env)
DEFINE_REAL(int, __sigsetjmp, void *env)
+#endif // SANITIZER_MAC
TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
+ // Note: if we call REAL(longjmp) in the context of ScopedInterceptor,
+ // bad things will happen. We will jump over ScopedInterceptor dtor and can
+ // leave thr->in_ignored_lib set.
{
- SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
+ SCOPED_INTERCEPTOR_RAW(longjmp, env, val);
}
LongJmp(cur_thread(), env);
REAL(longjmp)(env, val);
@@ -523,7 +574,7 @@ TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) {
TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
{
- SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
+ SCOPED_INTERCEPTOR_RAW(siglongjmp, env, val);
}
LongJmp(cur_thread(), env);
REAL(siglongjmp)(env, val);
@@ -532,7 +583,7 @@ TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
#if !SANITIZER_MAC
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
if (cur_thread()->in_symbolizer)
- return __libc_malloc(size);
+ return InternalAlloc(size);
void *p = 0;
{
SCOPED_INTERCEPTOR_RAW(malloc, size);
@@ -549,7 +600,7 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
if (cur_thread()->in_symbolizer)
- return __libc_calloc(size, n);
+ return InternalCalloc(size, n);
void *p = 0;
{
SCOPED_INTERCEPTOR_RAW(calloc, size, n);
@@ -561,7 +612,7 @@ TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
if (cur_thread()->in_symbolizer)
- return __libc_realloc(p, size);
+ return InternalRealloc(p, size);
if (p)
invoke_free_hook(p);
{
@@ -576,7 +627,7 @@ TSAN_INTERCEPTOR(void, free, void *p) {
if (p == 0)
return;
if (cur_thread()->in_symbolizer)
- return __libc_free(p);
+ return InternalFree(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(free, p);
user_free(thr, pc, p);
@@ -586,7 +637,7 @@ TSAN_INTERCEPTOR(void, cfree, void *p) {
if (p == 0)
return;
if (cur_thread()->in_symbolizer)
- return __libc_free(p);
+ return InternalFree(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(cfree, p);
user_free(thr, pc, p);
@@ -598,69 +649,6 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
}
#endif
-TSAN_INTERCEPTOR(uptr, strlen, const char *s) {
- SCOPED_TSAN_INTERCEPTOR(strlen, s);
- uptr len = internal_strlen(s);
- MemoryAccessRange(thr, pc, (uptr)s, len + 1, false);
- return len;
-}
-
-TSAN_INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
- // On FreeBSD we get here from libthr internals on thread initialization.
- if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
- SCOPED_TSAN_INTERCEPTOR(memset, dst, v, size);
- MemoryAccessRange(thr, pc, (uptr)dst, size, true);
- }
- return internal_memset(dst, v, size);
-}
-
-TSAN_INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
- // On FreeBSD we get here from libthr internals on thread initialization.
- if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
- SCOPED_TSAN_INTERCEPTOR(memcpy, dst, src, size);
- MemoryAccessRange(thr, pc, (uptr)dst, size, true);
- MemoryAccessRange(thr, pc, (uptr)src, size, false);
- }
- // On OS X, calling internal_memcpy here will cause memory corruptions,
- // because memcpy and memmove are actually aliases of the same implementation.
- // We need to use internal_memmove here.
- return internal_memmove(dst, src, size);
-}
-
-TSAN_INTERCEPTOR(void*, memmove, void *dst, void *src, uptr n) {
- if (!COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
- SCOPED_TSAN_INTERCEPTOR(memmove, dst, src, n);
- MemoryAccessRange(thr, pc, (uptr)dst, n, true);
- MemoryAccessRange(thr, pc, (uptr)src, n, false);
- }
- return REAL(memmove)(dst, src, n);
-}
-
-TSAN_INTERCEPTOR(char*, strchr, char *s, int c) {
- SCOPED_TSAN_INTERCEPTOR(strchr, s, c);
- char *res = REAL(strchr)(s, c);
- uptr len = internal_strlen(s);
- uptr n = res ? (char*)res - (char*)s + 1 : len + 1;
- READ_STRING_OF_LEN(thr, pc, s, len, n);
- return res;
-}
-
-#if !SANITIZER_MAC
-TSAN_INTERCEPTOR(char*, strchrnul, char *s, int c) {
- SCOPED_TSAN_INTERCEPTOR(strchrnul, s, c);
- char *res = REAL(strchrnul)(s, c);
- uptr len = (char*)res - (char*)s + 1;
- READ_STRING(thr, pc, s, len);
- return res;
-}
-#endif
-
-TSAN_INTERCEPTOR(char*, strrchr, char *s, int c) {
- SCOPED_TSAN_INTERCEPTOR(strrchr, s, c);
- MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s) + 1, false);
- return REAL(strrchr)(s, c);
-}
-
TSAN_INTERCEPTOR(char*, strcpy, char *dst, const char *src) { // NOLINT
SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src); // NOLINT
uptr srclen = internal_strlen(src);
@@ -706,7 +694,11 @@ TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags,
if (res != MAP_FAILED) {
if (fd > 0)
FdAccess(thr, pc, fd);
- MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+
+ if (thr->ignore_reads_and_writes == 0)
+ MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+ else
+ MemoryResetRange(thr, pc, (uptr)res, sz);
}
return res;
}
@@ -721,7 +713,11 @@ TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags,
if (res != MAP_FAILED) {
if (fd > 0)
FdAccess(thr, pc, fd);
- MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+
+ if (thr->ignore_reads_and_writes == 0)
+ MemoryRangeImitateWrite(thr, pc, (uptr)res, sz);
+ else
+ MemoryResetRange(thr, pc, (uptr)res, sz);
}
return res;
}
@@ -735,7 +731,8 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
if (sz != 0) {
// If sz == 0, munmap will return EINVAL and don't unmap any memory.
DontNeedShadowFor((uptr)addr, sz);
- ctx->metamap.ResetRange(thr, pc, (uptr)addr, (uptr)sz);
+ ScopedGlobalProcessor sgp;
+ ctx->metamap.ResetRange(thr->proc(), (uptr)addr, (uptr)sz);
}
int res = REAL(munmap)(addr, sz);
return res;
@@ -782,8 +779,25 @@ TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
}
#endif
+// __cxa_guard_acquire and friends need to be intercepted in a special way -
+// regular interceptors will break statically-linked libstdc++. Linux
+// interceptors are especially defined as weak functions (so that they don't
+// cause link errors when user defines them as well). So they silently
+// auto-disable themselves when such symbol is already present in the binary. If
+// we link libstdc++ statically, it will bring own __cxa_guard_acquire which
+// will silently replace our interceptor. That's why on Linux we simply export
+// these interceptors with INTERFACE_ATTRIBUTE.
+// On OS X, we don't support statically linking, so we just use a regular
+// interceptor.
+#if SANITIZER_MAC
+#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
+#else
+#define STDCXX_INTERCEPTOR(rettype, name, ...) \
+ extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__)
+#endif
+
// Used in thread-safe function static initialization.
-extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
for (;;) {
u32 cmp = atomic_load(g, memory_order_acquire);
@@ -799,13 +813,13 @@ extern "C" int INTERFACE_ATTRIBUTE __cxa_guard_acquire(atomic_uint32_t *g) {
}
}
-extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_release(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
Release(thr, pc, (uptr)g);
atomic_store(g, 1, memory_order_release);
}
-extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) {
+STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) {
SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g);
atomic_store(g, 0, memory_order_relaxed);
}
@@ -813,16 +827,21 @@ extern "C" void INTERFACE_ATTRIBUTE __cxa_guard_abort(atomic_uint32_t *g) {
namespace __tsan {
void DestroyThreadState() {
ThreadState *thr = cur_thread();
+ Processor *proc = thr->proc();
ThreadFinish(thr);
+ ProcUnwire(proc, thr);
+ ProcDestroy(proc);
ThreadSignalContext *sctx = thr->signal_ctx;
if (sctx) {
thr->signal_ctx = 0;
UnmapOrDie(sctx, sizeof(*sctx));
}
+ DTLS_Destroy();
cur_thread_finalize();
}
} // namespace __tsan
+#if !SANITIZER_MAC
static void thread_finalize(void *v) {
uptr iter = (uptr)v;
if (iter > 1) {
@@ -834,6 +853,7 @@ static void thread_finalize(void *v) {
}
DestroyThreadState();
}
+#endif
struct ThreadParam {
@@ -851,6 +871,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
ThreadState *thr = cur_thread();
// Thread-local state is not initialized yet.
ScopedIgnoreInterceptors ignore;
+#if !SANITIZER_MAC
ThreadIgnoreBegin(thr, 0);
if (pthread_setspecific(g_thread_finalize_key,
(void *)GetPthreadDestructorIterations())) {
@@ -858,8 +879,11 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
Die();
}
ThreadIgnoreEnd(thr, 0);
+#endif
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
internal_sched_yield();
+ Processor *proc = ProcCreate();
+ ProcWire(proc, thr);
ThreadStart(thr, tid, GetTid());
atomic_store(&p->tid, 0, memory_order_release);
}
@@ -1017,12 +1041,12 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
return REAL(pthread_cond_init)(cond, a);
}
-INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
- void *cond = init_cond(c);
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
+static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
+ int (*fn)(void *c, void *m, void *abstime), void *c,
+ void *m, void *t) {
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
MutexUnlock(thr, pc, (uptr)m);
- CondMutexUnlockCtx arg = {&si, thr, pc, m};
+ CondMutexUnlockCtx arg = {si, thr, pc, m};
int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
// See test/tsan/cond_cancel.cc.
@@ -1030,36 +1054,38 @@ INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
// Enable signal delivery while the thread is blocked.
BlockingCall bc(thr);
res = call_pthread_cancel_with_cleanup(
- (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
- cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+ fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
}
- if (res == errno_EOWNERDEAD)
- MutexRepair(thr, pc, (uptr)m);
+ if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
MutexLock(thr, pc, (uptr)m);
return res;
}
+INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
+ return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
+ pthread_cond_wait),
+ cond, m, 0);
+}
+
INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
- MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
- MutexUnlock(thr, pc, (uptr)m);
- CondMutexUnlockCtx arg = {&si, thr, pc, m};
- int res = 0;
- // This ensures that we handle mutex lock even in case of pthread_cancel.
- // See test/tsan/cond_cancel.cc.
- {
- BlockingCall bc(thr);
- res = call_pthread_cancel_with_cleanup(
- REAL(pthread_cond_timedwait), cond, m, abstime,
- (void(*)(void *arg))cond_mutex_unlock, &arg);
- }
- if (res == errno_EOWNERDEAD)
- MutexRepair(thr, pc, (uptr)m);
- MutexLock(thr, pc, (uptr)m);
- return res;
+ return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
+ abstime);
}
+#if SANITIZER_MAC
+INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
+ void *reltime) {
+ void *cond = init_cond(c);
+ SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
+ return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
+ m, reltime);
+}
+#endif
+
INTERCEPTOR(int, pthread_cond_signal, void *c) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond);
@@ -1316,97 +1342,7 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
return 0;
}
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__xstat)(version, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
-#else
-#define TSAN_MAYBE_INTERCEPT___XSTAT
-#endif
-
-TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_MAC
- SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(stat)(path, buf);
-#else
- SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__xstat)(0, path, buf);
-#endif
-}
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__xstat64)(version, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
-#else
-#define TSAN_MAYBE_INTERCEPT___XSTAT64
-#endif
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__xstat64)(0, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
-#else
-#define TSAN_MAYBE_INTERCEPT_STAT64
-#endif
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__lxstat)(version, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
-#else
-#define TSAN_MAYBE_INTERCEPT___LXSTAT
-#endif
-
-TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_MAC
- SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(lstat)(path, buf);
-#else
- SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__lxstat)(0, path, buf);
-#endif
-}
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__lxstat64)(version, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
-#else
-#define TSAN_MAYBE_INTERCEPT___LXSTAT64
-#endif
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
- SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
- READ_STRING(thr, pc, path, 0);
- return REAL(__lxstat64)(0, path, buf);
-}
-#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
-#else
-#define TSAN_MAYBE_INTERCEPT_LSTAT64
-#endif
-
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
if (fd > 0)
@@ -1419,7 +1355,7 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
#endif
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_MAC
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
@@ -1432,7 +1368,7 @@ TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
#endif
}
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
if (fd > 0)
@@ -1444,7 +1380,7 @@ TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
#define TSAN_MAYBE_INTERCEPT___FXSTAT64
#endif
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
if (fd > 0)
@@ -1623,32 +1559,6 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
return res;
}
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, epoll_create, int size) {
- SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
- int fd = REAL(epoll_create)(size);
- if (fd >= 0)
- FdPollCreate(thr, pc, fd);
- return fd;
-}
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create)
-#else
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
-#endif
-
-#if SANITIZER_LINUX
-TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
- SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
- int fd = REAL(epoll_create1)(flags);
- if (fd >= 0)
- FdPollCreate(thr, pc, fd);
- return fd;
-}
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1)
-#else
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1
-#endif
-
TSAN_INTERCEPTOR(int, close, int fd) {
SCOPED_TSAN_INTERCEPTOR(close, fd);
if (fd >= 0)
@@ -1669,7 +1579,7 @@ TSAN_INTERCEPTOR(int, __close, int fd) {
#endif
// glibc guts
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
int fds[64];
@@ -1703,37 +1613,6 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
}
#endif
-TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
- SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
- if (fd >= 0) {
- FdAccess(thr, pc, fd);
- FdRelease(thr, pc, fd);
- }
- int res = REAL(send)(fd, buf, len, flags);
- return res;
-}
-
-TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) {
- SCOPED_TSAN_INTERCEPTOR(sendmsg, fd, msg, flags);
- if (fd >= 0) {
- FdAccess(thr, pc, fd);
- FdRelease(thr, pc, fd);
- }
- int res = REAL(sendmsg)(fd, msg, flags);
- return res;
-}
-
-TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
- SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags);
- if (fd >= 0)
- FdAccess(thr, pc, fd);
- int res = REAL(recv)(fd, buf, len, flags);
- if (res >= 0 && fd >= 0) {
- FdAcquire(thr, pc, fd);
- }
- return res;
-}
-
TSAN_INTERCEPTOR(int, unlink, char *path) {
SCOPED_TSAN_INTERCEPTOR(unlink, path);
Release(thr, pc, File2addr(path));
@@ -1814,12 +1693,30 @@ TSAN_INTERCEPTOR(int, rmdir, char *path) {
TSAN_INTERCEPTOR(int, closedir, void *dirp) {
SCOPED_TSAN_INTERCEPTOR(closedir, dirp);
- int fd = dirfd(dirp);
- FdClose(thr, pc, fd);
+ if (dirp) {
+ int fd = dirfd(dirp);
+ FdClose(thr, pc, fd);
+ }
return REAL(closedir)(dirp);
}
#if SANITIZER_LINUX
+TSAN_INTERCEPTOR(int, epoll_create, int size) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
+ int fd = REAL(epoll_create)(size);
+ if (fd >= 0)
+ FdPollCreate(thr, pc, fd);
+ return fd;
+}
+
+TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
+ int fd = REAL(epoll_create1)(flags);
+ if (fd >= 0)
+ FdPollCreate(thr, pc, fd);
+ return fd;
+}
+
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
if (epfd >= 0)
@@ -1831,12 +1728,7 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
int res = REAL(epoll_ctl)(epfd, op, fd, ev);
return res;
}
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl)
-#else
-#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
-#endif
-#if SANITIZER_LINUX
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
if (epfd >= 0)
@@ -1846,17 +1738,72 @@ TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
FdAcquire(thr, pc, epfd);
return res;
}
-#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait)
+
+TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout,
+ void *sigmask) {
+ SCOPED_TSAN_INTERCEPTOR(epoll_pwait, epfd, ev, cnt, timeout, sigmask);
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
+ int res = BLOCK_REAL(epoll_pwait)(epfd, ev, cnt, timeout, sigmask);
+ if (res > 0 && epfd >= 0)
+ FdAcquire(thr, pc, epfd);
+ return res;
+}
+
+#define TSAN_MAYBE_INTERCEPT_EPOLL \
+ TSAN_INTERCEPT(epoll_create); \
+ TSAN_INTERCEPT(epoll_create1); \
+ TSAN_INTERCEPT(epoll_ctl); \
+ TSAN_INTERCEPT(epoll_wait); \
+ TSAN_INTERCEPT(epoll_pwait)
#else
-#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#define TSAN_MAYBE_INTERCEPT_EPOLL
#endif
+// The following functions are intercepted merely to process pending signals.
+// If program blocks signal X, we must deliver the signal before the function
+// returns. Similarly, if program unblocks a signal (or returns from sigsuspend)
+// it's better to deliver the signal straight away.
+TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) {
+ SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
+ return REAL(sigsuspend)(mask);
+}
+
+TSAN_INTERCEPTOR(int, sigblock, int mask) {
+ SCOPED_TSAN_INTERCEPTOR(sigblock, mask);
+ return REAL(sigblock)(mask);
+}
+
+TSAN_INTERCEPTOR(int, sigsetmask, int mask) {
+ SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask);
+ return REAL(sigsetmask)(mask);
+}
+
+TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set,
+ __sanitizer_sigset_t *oldset) {
+ SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset);
+ return REAL(pthread_sigmask)(how, set, oldset);
+}
+
namespace __tsan {
static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
bool sigact, int sig, my_siginfo_t *info, void *uctx) {
if (acquire)
Acquire(thr, 0, (uptr)&sigactions[sig]);
+ // Signals are generally asynchronous, so if we receive a signals when
+ // ignores are enabled we should disable ignores. This is critical for sync
+ // and interceptors, because otherwise we can miss syncronization and report
+ // false races.
+ int ignore_reads_and_writes = thr->ignore_reads_and_writes;
+ int ignore_interceptors = thr->ignore_interceptors;
+ int ignore_sync = thr->ignore_sync;
+ if (!ctx->after_multithreaded_fork) {
+ thr->ignore_reads_and_writes = 0;
+ thr->fast_state.ClearIgnoreBit();
+ thr->ignore_interceptors = 0;
+ thr->ignore_sync = 0;
+ }
// Ensure that the handler does not spoil errno.
const int saved_errno = errno;
errno = 99;
@@ -1872,6 +1819,13 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
else
((sighandler_t)pc)(sig);
}
+ if (!ctx->after_multithreaded_fork) {
+ thr->ignore_reads_and_writes = ignore_reads_and_writes;
+ if (ignore_reads_and_writes)
+ thr->fast_state.SetIgnoreBit();
+ thr->ignore_interceptors = ignore_interceptors;
+ thr->ignore_sync = ignore_sync;
+ }
// We do not detect errno spoiling for SIGTERM,
// because some SIGTERM handlers do spoil errno but reraise SIGTERM,
// tsan reports false positive in such case.
@@ -1901,10 +1855,9 @@ void ProcessPendingSignals(ThreadState *thr) {
return;
atomic_store(&sctx->have_pending_signals, 0, memory_order_relaxed);
atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
- // These are too big for stack.
- static THREADLOCAL __sanitizer_sigset_t emptyset, oldset;
- CHECK_EQ(0, REAL(sigfillset)(&emptyset));
- CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &emptyset, &oldset));
+ internal_sigfillset(&sctx->emptyset);
+ int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset);
+ CHECK_EQ(res, 0);
for (int sig = 0; sig < kSigCount; sig++) {
SignalDesc *signal = &sctx->pending_signals[sig];
if (signal->armed) {
@@ -1913,7 +1866,8 @@ void ProcessPendingSignals(ThreadState *thr) {
&signal->siginfo, &signal->ctx);
}
}
- CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &oldset, 0));
+ res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0);
+ CHECK_EQ(res, 0);
atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
}
@@ -1943,13 +1897,8 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
(sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed))) {
atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
if (sctx && atomic_load(&sctx->in_blocking_func, memory_order_relaxed)) {
- // We ignore interceptors in blocking functions,
- // temporary enbled them again while we are calling user function.
- int const i = thr->ignore_interceptors;
- thr->ignore_interceptors = 0;
atomic_store(&sctx->in_blocking_func, 0, memory_order_relaxed);
CallUserSignalHandler(thr, sync, true, sigact, sig, info, ctx);
- thr->ignore_interceptors = i;
atomic_store(&sctx->in_blocking_func, 1, memory_order_relaxed);
} else {
// Be very conservative with when we do acquire in this case.
@@ -1987,7 +1936,10 @@ static void rtl_sigaction(int sig, my_siginfo_t *info, void *ctx) {
}
TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
- SCOPED_TSAN_INTERCEPTOR(sigaction, sig, act, old);
+ // Note: if we call REAL(sigaction) directly for any reason without proxying
+ // the signal handler through rtl_sigaction, very bad things will happen.
+ // The handler will run synchronously and corrupt tsan per-thread state.
+ SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old);
if (old)
internal_memcpy(old, &sigactions[sig], sizeof(*old));
if (act == 0)
@@ -2002,12 +1954,12 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags;
internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask,
sizeof(sigactions[sig].sa_mask));
-#if !SANITIZER_FREEBSD
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC
sigactions[sig].sa_restorer = act->sa_restorer;
#endif
sigaction_t newact;
internal_memcpy(&newact, act, sizeof(newact));
- REAL(sigfillset)(&newact.sa_mask);
+ internal_sigfillset(&newact.sa_mask);
if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) {
if (newact.sa_flags & SA_SIGINFO)
newact.sa_sigaction = rtl_sigaction;
@@ -2022,7 +1974,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) {
sigaction_t act;
act.sa_handler = h;
- REAL(memset)(&act.sa_mask, -1, sizeof(act.sa_mask));
+ internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask));
act.sa_flags = 0;
sigaction_t old;
int res = sigaction(sig, &act, &old);
@@ -2031,11 +1983,6 @@ TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) {
return old.sa_handler;
}
-TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) {
- SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
- return REAL(sigsuspend)(mask);
-}
-
TSAN_INTERCEPTOR(int, raise, int sig) {
SCOPED_TSAN_INTERCEPTOR(raise, sig);
ThreadSignalContext *sctx = SigCtx(thr);
@@ -2103,7 +2050,13 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
return REAL(fork)(fake);
SCOPED_INTERCEPTOR_RAW(fork, fake);
ForkBefore(thr, pc);
- int pid = REAL(fork)(fake);
+ int pid;
+ {
+ // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
+ // we'll assert in CheckNoLocks() unless we ignore interceptors.
+ ScopedIgnoreInterceptors ignore;
+ pid = REAL(fork)(fake);
+ }
if (pid == 0) {
// child
ForkChildAfter(thr, pc);
@@ -2135,7 +2088,7 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
return WRAP(fork)(fake);
}
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
void *data);
struct dl_iterate_phdr_data {
@@ -2218,23 +2171,15 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
#undef SANITIZER_INTERCEPT_FGETPWENT
#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
-// __tls_get_addr can be called with mis-aligned stack due to:
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
-// There are two potential issues:
-// 1. Sanitizer code contains a MOVDQA spill (it does not seem to be the case
-// right now). or 2. ProcessPendingSignal calls user handler which contains
-// MOVDQA spill (this happens right now).
-// Since the interceptor only initializes memory for msan, the simplest solution
-// is to disable the interceptor in tsan (other sanitizers do not call
-// signal handlers from COMMON_INTERCEPTOR_ENTER).
-// As __tls_get_addr has been intercepted in the past, to avoid breaking
-// libtsan ABI, keep it around, but just call the real function.
+// We define our own.
#if SANITIZER_INTERCEPT_TLS_GET_ADDR
#define NEED_TLS_GET_ADDR
#endif
#undef SANITIZER_INTERCEPT_TLS_GET_ADDR
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
+ INTERCEPT_FUNCTION_VER(name, ver)
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \
@@ -2321,6 +2266,10 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \
+ MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
#if !SANITIZER_MAC
#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
@@ -2335,6 +2284,12 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
*begin = *end = 0; \
}
+#define COMMON_INTERCEPTOR_USER_CALLBACK_START() \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START()
+
+#define COMMON_INTERCEPTOR_USER_CALLBACK_END() \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END()
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define TSAN_SYSCALL() \
@@ -2357,7 +2312,7 @@ struct ScopedSyscall {
}
};
-#if !SANITIZER_MAC
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC
static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
TSAN_SYSCALL();
MemoryAccessRange(thr, pc, p, s, write);
@@ -2452,8 +2407,27 @@ static void syscall_post_fork(uptr pc, int pid) {
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#ifdef NEED_TLS_GET_ADDR
+// Define own interceptor instead of sanitizer_common's for three reasons:
+// 1. It must not process pending signals.
+// Signal handlers may contain MOVDQA instruction (see below).
+// 2. It must be as simple as possible to not contain MOVDQA.
+// 3. Sanitizer_common version uses COMMON_INTERCEPTOR_INITIALIZE_RANGE which
+// is empty for tsan (meant only for msan).
+// Note: __tls_get_addr can be called with mis-aligned stack due to:
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
+// So the interceptor must work with mis-aligned stack, in particular, does not
+// execute MOVDQA with stack addresses.
TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) {
- return REAL(__tls_get_addr)(arg);
+ void *res = REAL(__tls_get_addr)(arg);
+ ThreadState *thr = cur_thread();
+ if (!thr)
+ return res;
+ DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, thr->tls_size);
+ if (!dtv)
+ return res;
+ // New DTLS block has been allocated.
+ MemoryResetRange(thr, 0, dtv->beg, dtv->size);
+ return res;
}
#endif
@@ -2468,7 +2442,7 @@ static void finalize(void *arg) {
Die();
}
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
static void unreachable() {
Report("FATAL: ThreadSanitizer: unreachable called\n");
Die();
@@ -2517,13 +2491,6 @@ void InitializeInterceptors() {
TSAN_MAYBE_INTERCEPT_PVALLOC;
TSAN_INTERCEPT(posix_memalign);
- TSAN_INTERCEPT(strlen);
- TSAN_INTERCEPT(memset);
- TSAN_INTERCEPT(memcpy);
- TSAN_INTERCEPT(memmove);
- TSAN_INTERCEPT(strchr);
- TSAN_INTERCEPT(strchrnul);
- TSAN_INTERCEPT(strrchr);
TSAN_INTERCEPT(strcpy); // NOLINT
TSAN_INTERCEPT(strncpy);
TSAN_INTERCEPT(strdup);
@@ -2566,14 +2533,6 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_once);
- TSAN_INTERCEPT(stat);
- TSAN_MAYBE_INTERCEPT___XSTAT;
- TSAN_MAYBE_INTERCEPT_STAT64;
- TSAN_MAYBE_INTERCEPT___XSTAT64;
- TSAN_INTERCEPT(lstat);
- TSAN_MAYBE_INTERCEPT___LXSTAT;
- TSAN_MAYBE_INTERCEPT_LSTAT64;
- TSAN_MAYBE_INTERCEPT___LXSTAT64;
TSAN_INTERCEPT(fstat);
TSAN_MAYBE_INTERCEPT___FXSTAT;
TSAN_MAYBE_INTERCEPT_FSTAT64;
@@ -2594,18 +2553,13 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(connect);
TSAN_INTERCEPT(bind);
TSAN_INTERCEPT(listen);
- TSAN_MAYBE_INTERCEPT_EPOLL_CREATE;
- TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1;
+ TSAN_MAYBE_INTERCEPT_EPOLL;
TSAN_INTERCEPT(close);
TSAN_MAYBE_INTERCEPT___CLOSE;
TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
TSAN_INTERCEPT(pipe);
TSAN_INTERCEPT(pipe2);
- TSAN_INTERCEPT(send);
- TSAN_INTERCEPT(sendmsg);
- TSAN_INTERCEPT(recv);
-
TSAN_INTERCEPT(unlink);
TSAN_INTERCEPT(tmpfile);
TSAN_MAYBE_INTERCEPT_TMPFILE64;
@@ -2616,12 +2570,12 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(rmdir);
TSAN_INTERCEPT(closedir);
- TSAN_MAYBE_INTERCEPT_EPOLL_CTL;
- TSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
-
TSAN_INTERCEPT(sigaction);
TSAN_INTERCEPT(signal);
TSAN_INTERCEPT(sigsuspend);
+ TSAN_INTERCEPT(sigblock);
+ TSAN_INTERCEPT(sigsetmask);
+ TSAN_INTERCEPT(pthread_sigmask);
TSAN_INTERCEPT(raise);
TSAN_INTERCEPT(kill);
TSAN_INTERCEPT(pthread_kill);
@@ -2633,7 +2587,9 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(fork);
TSAN_INTERCEPT(vfork);
+#if !SANITIZER_ANDROID
TSAN_INTERCEPT(dl_iterate_phdr);
+#endif
TSAN_INTERCEPT(on_exit);
TSAN_INTERCEPT(__cxa_atexit);
TSAN_INTERCEPT(_exit);
@@ -2642,7 +2598,7 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(__tls_get_addr);
#endif
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
// Need to setup it, because interceptors check that the function is resolved.
// But atexit is emitted directly into the module, so can't be resolved.
REAL(atexit) = (int(*)(void(*)()))unreachable;
@@ -2653,12 +2609,50 @@ void InitializeInterceptors() {
Die();
}
+#if !SANITIZER_MAC
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
Printf("ThreadSanitizer: failed to create thread key\n");
Die();
}
+#endif
FdInit();
}
} // namespace __tsan
+
+// Invisible barrier for tests.
+// There were several unsuccessful iterations for this functionality:
+// 1. Initially it was implemented in user code using
+// REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on
+// MacOS. Futexes are linux-specific for this matter.
+// 2. Then we switched to atomics+usleep(10). But usleep produced parasitic
+// "as-if synchronized via sleep" messages in reports which failed some
+// output tests.
+// 3. Then we switched to atomics+sched_yield. But this produced tons of tsan-
+// visible events, which lead to "failed to restore stack trace" failures.
+// Note that no_sanitize_thread attribute does not turn off atomic interception
+// so attaching it to the function defined in user code does not help.
+// That's why we now have what we have.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_init(u64 *barrier, u32 count) {
+ if (count >= (1 << 8)) {
+ Printf("barrier_init: count is too large (%d)\n", count);
+ Die();
+ }
+ // 8 lsb is thread count, the remaining are count of entered threads.
+ *barrier = count;
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_testonly_barrier_wait(u64 *barrier) {
+ unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED);
+ unsigned old_epoch = (old >> 8) / (old & 0xff);
+ for (;;) {
+ unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED);
+ unsigned cur_epoch = (cur >> 8) / (cur & 0xff);
+ if (cur_epoch != old_epoch)
+ return;
+ internal_sched_yield();
+ }
+}
diff --git a/libsanitizer/tsan/tsan_interceptors.h b/libsanitizer/tsan/tsan_interceptors.h
index ed68eb96bf8..97fa5085a78 100644
--- a/libsanitizer/tsan/tsan_interceptors.h
+++ b/libsanitizer/tsan/tsan_interceptors.h
@@ -8,6 +8,8 @@ class ScopedInterceptor {
public:
ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
~ScopedInterceptor();
+ void UserCallbackStart();
+ void UserCallbackEnd();
private:
ThreadState *const thr_;
const uptr pc_;
@@ -30,18 +32,16 @@ class ScopedInterceptor {
Report("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
Die(); \
} \
- if (thr->ignore_interceptors || thr->in_ignored_lib) \
+ if (!thr->is_inited || thr->ignore_interceptors || thr->in_ignored_lib) \
return REAL(func)(__VA_ARGS__); \
/**/
-#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
+#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \
+ si.UserCallbackStart();
-#if SANITIZER_FREEBSD
-#define __libc_free __free
-#define __libc_malloc __malloc
-#endif
+#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \
+ si.UserCallbackEnd();
-extern "C" void __libc_free(void *ptr);
-extern "C" void *__libc_malloc(uptr size);
+#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
#endif // TSAN_INTERCEPTORS_H
diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cc b/libsanitizer/tsan/tsan_interceptors_mac.cc
new file mode 100644
index 00000000000..eaf866d6c75
--- /dev/null
+++ b/libsanitizer/tsan/tsan_interceptors_mac.cc
@@ -0,0 +1,357 @@
+//===-- tsan_interceptors_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 ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific interceptors.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "interception/interception.h"
+#include "tsan_interceptors.h"
+#include "tsan_interface.h"
+#include "tsan_interface_ann.h"
+
+#include <libkern/OSAtomic.h>
+#include <xpc/xpc.h>
+
+typedef long long_t; // NOLINT
+
+namespace __tsan {
+
+// The non-barrier versions of OSAtomic* functions are semantically mo_relaxed,
+// but the two variants (e.g. OSAtomicAdd32 and OSAtomicAdd32Barrier) are
+// actually aliases of each other, and we cannot have different interceptors for
+// them, because they're actually the same function. Thus, we have to stay
+// conservative and treat the non-barrier versions as mo_acq_rel.
+static const morder kMacOrderBarrier = mo_acq_rel;
+static const morder kMacOrderNonBarrier = mo_acq_rel;
+
+#define OSATOMIC_INTERCEPTOR(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+ TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, x, ptr); \
+ return tsan_atomic_f((volatile tsan_t *)ptr, x, mo); \
+ }
+
+#define OSATOMIC_INTERCEPTOR_PLUS_X(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+ TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, x, ptr); \
+ return tsan_atomic_f((volatile tsan_t *)ptr, x, mo) + x; \
+ }
+
+#define OSATOMIC_INTERCEPTOR_PLUS_1(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
+ TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, ptr); \
+ return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) + 1; \
+ }
+
+#define OSATOMIC_INTERCEPTOR_MINUS_1(return_t, t, tsan_t, f, tsan_atomic_f, \
+ mo) \
+ TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, ptr); \
+ return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) - 1; \
+ }
+
+#define OSATOMIC_INTERCEPTORS_ARITHMETIC(f, tsan_atomic_f, m) \
+ m(int32_t, int32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f, \
+ kMacOrderNonBarrier) \
+ m(int32_t, int32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f, \
+ kMacOrderBarrier) \
+ m(int64_t, int64_t, a64, f##64, __tsan_atomic64_##tsan_atomic_f, \
+ kMacOrderNonBarrier) \
+ m(int64_t, int64_t, a64, f##64##Barrier, __tsan_atomic64_##tsan_atomic_f, \
+ kMacOrderBarrier)
+
+#define OSATOMIC_INTERCEPTORS_BITWISE(f, tsan_atomic_f, m, m_orig) \
+ m(int32_t, uint32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f, \
+ kMacOrderNonBarrier) \
+ m(int32_t, uint32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f, \
+ kMacOrderBarrier) \
+ m_orig(int32_t, uint32_t, a32, f##32##Orig, __tsan_atomic32_##tsan_atomic_f, \
+ kMacOrderNonBarrier) \
+ m_orig(int32_t, uint32_t, a32, f##32##OrigBarrier, \
+ __tsan_atomic32_##tsan_atomic_f, kMacOrderBarrier)
+
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicAdd, fetch_add,
+ OSATOMIC_INTERCEPTOR_PLUS_X)
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicIncrement, fetch_add,
+ OSATOMIC_INTERCEPTOR_PLUS_1)
+OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicDecrement, fetch_sub,
+ OSATOMIC_INTERCEPTOR_MINUS_1)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicOr, fetch_or, OSATOMIC_INTERCEPTOR_PLUS_X,
+ OSATOMIC_INTERCEPTOR)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicAnd, fetch_and,
+ OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
+OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor,
+ OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
+
+#define OSATOMIC_INTERCEPTORS_CAS(f, tsan_atomic_f, tsan_t, t) \
+ TSAN_INTERCEPTOR(bool, f, t old_value, t new_value, t volatile *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, old_value, new_value, ptr); \
+ return tsan_atomic_f##_compare_exchange_strong( \
+ (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \
+ kMacOrderNonBarrier, kMacOrderNonBarrier); \
+ } \
+ \
+ TSAN_INTERCEPTOR(bool, f##Barrier, t old_value, t new_value, \
+ t volatile *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f##Barrier, old_value, new_value, ptr); \
+ return tsan_atomic_f##_compare_exchange_strong( \
+ (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \
+ kMacOrderBarrier, kMacOrderNonBarrier); \
+ }
+
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapInt, __tsan_atomic32, a32, int)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapLong, __tsan_atomic64, a64,
+ long_t)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapPtr, __tsan_atomic64, a64,
+ void *)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32,
+ int32_t)
+OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64,
+ int64_t)
+
+#define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo) \
+ TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) { \
+ SCOPED_TSAN_INTERCEPTOR(f, n, ptr); \
+ char *byte_ptr = ((char *)ptr) + (n >> 3); \
+ char bit = 0x80u >> (n & 7); \
+ char mask = clear ? ~bit : bit; \
+ char orig_byte = op((a8 *)byte_ptr, mask, mo); \
+ return orig_byte & bit; \
+ }
+
+#define OSATOMIC_INTERCEPTORS_BITOP(f, op, clear) \
+ OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, kMacOrderNonBarrier) \
+ OSATOMIC_INTERCEPTOR_BITOP(f##Barrier, op, clear, kMacOrderBarrier)
+
+OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndSet, __tsan_atomic8_fetch_or, false)
+OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndClear, __tsan_atomic8_fetch_and,
+ true)
+
+TSAN_INTERCEPTOR(void, OSAtomicEnqueue, OSQueueHead *list, void *item,
+ size_t offset) {
+ SCOPED_TSAN_INTERCEPTOR(OSAtomicEnqueue, list, item, offset);
+ __tsan_release(item);
+ REAL(OSAtomicEnqueue)(list, item, offset);
+}
+
+TSAN_INTERCEPTOR(void *, OSAtomicDequeue, OSQueueHead *list, size_t offset) {
+ SCOPED_TSAN_INTERCEPTOR(OSAtomicDequeue, list, offset);
+ void *item = REAL(OSAtomicDequeue)(list, offset);
+ if (item) __tsan_acquire(item);
+ return item;
+}
+
+// OSAtomicFifoEnqueue and OSAtomicFifoDequeue are only on OS X.
+#if !SANITIZER_IOS
+
+TSAN_INTERCEPTOR(void, OSAtomicFifoEnqueue, OSFifoQueueHead *list, void *item,
+ size_t offset) {
+ SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoEnqueue, list, item, offset);
+ __tsan_release(item);
+ REAL(OSAtomicFifoEnqueue)(list, item, offset);
+}
+
+TSAN_INTERCEPTOR(void *, OSAtomicFifoDequeue, OSFifoQueueHead *list,
+ size_t offset) {
+ SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoDequeue, list, offset);
+ void *item = REAL(OSAtomicFifoDequeue)(list, offset);
+ if (item) __tsan_acquire(item);
+ return item;
+}
+
+#endif
+
+TSAN_INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockLock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockLock, lock);
+ REAL(OSSpinLockLock)(lock);
+ Acquire(thr, pc, (uptr)lock);
+}
+
+TSAN_INTERCEPTOR(bool, OSSpinLockTry, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockTry)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockTry, lock);
+ bool result = REAL(OSSpinLockTry)(lock);
+ if (result)
+ Acquire(thr, pc, (uptr)lock);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, OSSpinLockUnlock, volatile OSSpinLock *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(OSSpinLockUnlock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(OSSpinLockUnlock, lock);
+ Release(thr, pc, (uptr)lock);
+ REAL(OSSpinLockUnlock)(lock);
+}
+
+TSAN_INTERCEPTOR(void, os_lock_lock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_lock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_lock, lock);
+ REAL(os_lock_lock)(lock);
+ Acquire(thr, pc, (uptr)lock);
+}
+
+TSAN_INTERCEPTOR(bool, os_lock_trylock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_trylock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_trylock, lock);
+ bool result = REAL(os_lock_trylock)(lock);
+ if (result)
+ Acquire(thr, pc, (uptr)lock);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) {
+ CHECK(!cur_thread()->is_dead);
+ if (!cur_thread()->is_inited) {
+ return REAL(os_lock_unlock)(lock);
+ }
+ SCOPED_TSAN_INTERCEPTOR(os_lock_unlock, lock);
+ Release(thr, pc, (uptr)lock);
+ REAL(os_lock_unlock)(lock);
+}
+
+TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler,
+ xpc_connection_t connection, xpc_handler_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(xpc_connection_set_event_handler, connection,
+ handler);
+ Release(thr, pc, (uptr)connection);
+ xpc_handler_t new_handler = ^(xpc_object_t object) {
+ {
+ SCOPED_INTERCEPTOR_RAW(xpc_connection_set_event_handler);
+ Acquire(thr, pc, (uptr)connection);
+ }
+ handler(object);
+ };
+ REAL(xpc_connection_set_event_handler)(connection, new_handler);
+}
+
+TSAN_INTERCEPTOR(void, xpc_connection_send_barrier, xpc_connection_t connection,
+ dispatch_block_t barrier) {
+ SCOPED_TSAN_INTERCEPTOR(xpc_connection_send_barrier, connection, barrier);
+ Release(thr, pc, (uptr)connection);
+ dispatch_block_t new_barrier = ^() {
+ {
+ SCOPED_INTERCEPTOR_RAW(xpc_connection_send_barrier);
+ Acquire(thr, pc, (uptr)connection);
+ }
+ barrier();
+ };
+ REAL(xpc_connection_send_barrier)(connection, new_barrier);
+}
+
+TSAN_INTERCEPTOR(void, xpc_connection_send_message_with_reply,
+ xpc_connection_t connection, xpc_object_t message,
+ dispatch_queue_t replyq, xpc_handler_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(xpc_connection_send_message_with_reply, connection,
+ message, replyq, handler);
+ Release(thr, pc, (uptr)connection);
+ xpc_handler_t new_handler = ^(xpc_object_t object) {
+ {
+ SCOPED_INTERCEPTOR_RAW(xpc_connection_send_message_with_reply);
+ Acquire(thr, pc, (uptr)connection);
+ }
+ handler(object);
+ };
+ REAL(xpc_connection_send_message_with_reply)
+ (connection, message, replyq, new_handler);
+}
+
+// On macOS, libc++ is always linked dynamically, so intercepting works the
+// usual way.
+#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
+
+namespace {
+struct fake_shared_weak_count {
+ volatile a64 shared_owners;
+ volatile a64 shared_weak_owners;
+ virtual void _unused_0x0() = 0;
+ virtual void _unused_0x8() = 0;
+ virtual void on_zero_shared() = 0;
+ virtual void _unused_0x18() = 0;
+ virtual void on_zero_shared_weak() = 0;
+};
+} // namespace
+
+// This adds a libc++ interceptor for:
+// void __shared_weak_count::__release_shared() _NOEXCEPT;
+// Shared and weak pointers in C++ maintain reference counts via atomics in
+// libc++.dylib, which are TSan-invisible, and this leads to false positives in
+// destructor code. This interceptor re-implements the whole function so that
+// the mo_acq_rel semantics of the atomic decrement are visible.
+//
+// Unfortunately, this interceptor cannot simply Acquire/Release some sync
+// object and call the original function, because it would have a race between
+// the sync and the destruction of the object. Calling both under a lock will
+// not work because the destructor can invoke this interceptor again (and even
+// in a different thread, so recursive locks don't help).
+STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
+ fake_shared_weak_count *o) {
+ if (!flags()->shared_ptr_interceptor)
+ return REAL(_ZNSt3__119__shared_weak_count16__release_sharedEv)(o);
+
+ SCOPED_TSAN_INTERCEPTOR(_ZNSt3__119__shared_weak_count16__release_sharedEv,
+ o);
+ if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
+ Acquire(thr, pc, (uptr)&o->shared_owners);
+ o->on_zero_shared();
+ if (__tsan_atomic64_fetch_add(&o->shared_weak_owners, -1, mo_release) ==
+ 0) {
+ Acquire(thr, pc, (uptr)&o->shared_weak_owners);
+ o->on_zero_shared_weak();
+ }
+ }
+}
+
+namespace {
+struct call_once_callback_args {
+ void (*orig_func)(void *arg);
+ void *orig_arg;
+ void *flag;
+};
+
+void call_once_callback_wrapper(void *arg) {
+ call_once_callback_args *new_args = (call_once_callback_args *)arg;
+ new_args->orig_func(new_args->orig_arg);
+ __tsan_release(new_args->flag);
+}
+} // namespace
+
+// This adds a libc++ interceptor for:
+// void __call_once(volatile unsigned long&, void*, void(*)(void*));
+// C++11 call_once is implemented via an internal function __call_once which is
+// inside libc++.dylib, and the atomic release store inside it is thus
+// TSan-invisible. To avoid false positives, this interceptor wraps the callback
+// function and performs an explicit Release after the user code has run.
+STDCXX_INTERCEPTOR(void, _ZNSt3__111__call_onceERVmPvPFvS2_E, void *flag,
+ void *arg, void (*func)(void *arg)) {
+ call_once_callback_args new_args = {func, arg, flag};
+ REAL(_ZNSt3__111__call_onceERVmPvPFvS2_E)(flag, &new_args,
+ call_once_callback_wrapper);
+}
+
+} // namespace __tsan
+
+#endif // SANITIZER_MAC
diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
index 4ff6fa1831e..066dde6f543 100644
--- a/libsanitizer/tsan/tsan_interface.h
+++ b/libsanitizer/tsan/tsan_interface.h
@@ -15,6 +15,7 @@
#define TSAN_INTERFACE_H
#include <sanitizer_common/sanitizer_internal_defs.h>
+using __sanitizer::uptr;
// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.
@@ -23,6 +24,8 @@
extern "C" {
#endif
+#if !SANITIZER_GO
+
// This function should be called at the very beginning of the process,
// before any instrumented code is executed and before any call to malloc.
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init();
@@ -73,8 +76,296 @@ void __tsan_read_range(void *addr, unsigned long size); // NOLINT
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_write_range(void *addr, unsigned long size); // NOLINT
+// User may provide function that would be called right when TSan detects
+// an error. The argument 'report' is an opaque pointer that can be used to
+// gather additional information using other TSan report API functions.
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_on_report(void *report);
+
+// If TSan is currently reporting a detected issue on the current thread,
+// returns an opaque pointer to the current report. Otherwise returns NULL.
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_get_current_report();
+
+// Returns a report's description (issue type), number of duplicate issues
+// found, counts of array data (stack traces, memory operations, locations,
+// mutexes, threads, unique thread IDs) and a stack trace of a sleep() call (if
+// one was involved in the issue).
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_data(void *report, const char **description, int *count,
+ int *stack_count, int *mop_count, int *loc_count,
+ int *mutex_count, int *thread_count,
+ int *unique_tid_count, void **sleep_trace,
+ uptr trace_size);
+
+// Returns information about stack traces included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_stack(void *report, uptr idx, void **trace,
+ uptr trace_size);
+
+// Returns information about memory operations included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_mop(void *report, uptr idx, int *tid, void **addr,
+ int *size, int *write, int *atomic, void **trace,
+ uptr trace_size);
+
+// Returns information about locations included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc(void *report, uptr idx, const char **type,
+ void **addr, uptr *start, uptr *size, int *tid,
+ int *fd, int *suppressable, void **trace,
+ uptr trace_size);
+
+// Returns information about mutexes included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
+ int *destroyed, void **trace, uptr trace_size);
+
+// Returns information about threads included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id,
+ int *running, const char **name, int *parent_tid,
+ void **trace, uptr trace_size);
+
+// Returns information about unique thread IDs included in the report.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid);
+
+#endif // SANITIZER_GO
+
#ifdef __cplusplus
} // extern "C"
#endif
+namespace __tsan {
+
+// These should match declarations from public tsan_interface_atomic.h header.
+typedef unsigned char a8;
+typedef unsigned short a16; // NOLINT
+typedef unsigned int a32;
+typedef unsigned long long a64; // NOLINT
+#if !SANITIZER_GO && (defined(__SIZEOF_INT128__) \
+ || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64)
+__extension__ typedef __int128 a128;
+# define __TSAN_HAS_INT128 1
+#else
+# define __TSAN_HAS_INT128 0
+#endif
+
+// Part of ABI, do not change.
+// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
+typedef enum {
+ mo_relaxed,
+ mo_consume,
+ mo_acquire,
+ mo_release,
+ mo_acq_rel,
+ mo_seq_cst
+} morder;
+
+struct ThreadState;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_load(const volatile a8 *a, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_load(const volatile a16 *a, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_load(const volatile a32 *a, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_load(const volatile a64 *a, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_load(const volatile a128 *a, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic8_store(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic16_store(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic32_store(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic64_store(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic128_store(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_exchange(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_exchange(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_exchange(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_exchange(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_exchange(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_add(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_add(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_add(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_add(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_add(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_sub(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_sub(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_sub(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_sub(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_sub(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_and(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_and(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_and(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_and(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_and(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_or(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_or(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_or(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_or(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_or(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_xor(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_xor(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_xor(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_xor(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_xor(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_fetch_nand(volatile a8 *a, a8 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_fetch_nand(volatile a16 *a, a16 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_fetch_nand(volatile a32 *a, a32 v, morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_fetch_nand(volatile a64 *a, a64 v, morder mo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_fetch_nand(volatile a128 *a, a128 v, morder mo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic8_compare_exchange_strong(volatile a8 *a, a8 *c, a8 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic16_compare_exchange_strong(volatile a16 *a, a16 *c, a16 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic32_compare_exchange_strong(volatile a32 *a, a32 *c, a32 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic64_compare_exchange_strong(volatile a64 *a, a64 *c, a64 v,
+ morder mo, morder fmo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic128_compare_exchange_strong(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic8_compare_exchange_weak(volatile a8 *a, a8 *c, a8 v, morder mo,
+ morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic16_compare_exchange_weak(volatile a16 *a, a16 *c, a16 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic32_compare_exchange_weak(volatile a32 *a, a32 *c, a32 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v,
+ morder mo, morder fmo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_atomic128_compare_exchange_weak(volatile a128 *a, a128 *c, a128 v,
+ morder mo, morder fmo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v, morder mo,
+ morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v,
+ morder mo, morder fmo);
+SANITIZER_INTERFACE_ATTRIBUTE
+a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
+ morder mo, morder fmo);
+#if __TSAN_HAS_INT128
+SANITIZER_INTERFACE_ATTRIBUTE
+a128 __tsan_atomic128_compare_exchange_val(volatile a128 *a, a128 c, a128 v,
+ morder mo, morder fmo);
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic_thread_fence(morder mo);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_atomic_signal_fence(morder mo);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
+ u8 *a);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
+ u8 *a);
+} // extern "C"
+
+} // namespace __tsan
+
#endif // TSAN_INTERFACE_H
diff --git a/libsanitizer/tsan/tsan_interface_atomic.cc b/libsanitizer/tsan/tsan_interface_atomic.cc
index 0ded1aa1099..5c5c34f3b87 100644
--- a/libsanitizer/tsan/tsan_interface_atomic.cc
+++ b/libsanitizer/tsan/tsan_interface_atomic.cc
@@ -21,39 +21,16 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "tsan_flags.h"
+#include "tsan_interface.h"
#include "tsan_rtl.h"
using namespace __tsan; // NOLINT
-// These should match declarations from public tsan_interface_atomic.h header.
-typedef unsigned char a8;
-typedef unsigned short a16; // NOLINT
-typedef unsigned int a32;
-typedef unsigned long long a64; // NOLINT
-#if !defined(SANITIZER_GO) && (defined(__SIZEOF_INT128__) \
- || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64)
-__extension__ typedef __int128 a128;
-# define __TSAN_HAS_INT128 1
-#else
-# define __TSAN_HAS_INT128 0
-#endif
-
-#if !defined(SANITIZER_GO) && __TSAN_HAS_INT128
+#if !SANITIZER_GO && __TSAN_HAS_INT128
// Protects emulation of 128-bit atomic operations.
static StaticSpinMutex mutex128;
#endif
-// Part of ABI, do not change.
-// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
-typedef enum {
- mo_relaxed,
- mo_consume,
- mo_acquire,
- mo_release,
- mo_acq_rel,
- mo_seq_cst
-} morder;
-
static bool IsLoadOrder(morder mo) {
return mo == mo_relaxed || mo == mo_consume
|| mo == mo_acquire || mo == mo_seq_cst;
@@ -123,7 +100,7 @@ template<typename T> T func_cas(volatile T *v, T cmp, T xch) {
// Atomic ops are executed under tsan internal mutex,
// here we assume that the atomic variables are not accessed
// from non-instrumented code.
-#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) \
+#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !SANITIZER_GO \
&& __TSAN_HAS_INT128
a128 func_xchg(volatile a128 *v, a128 op) {
SpinMutexLock lock(&mutex128);
@@ -197,7 +174,7 @@ static int SizeLog() {
// this leads to false negatives only in very obscure cases.
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static atomic_uint8_t *to_atomic(const volatile a8 *a) {
return reinterpret_cast<atomic_uint8_t *>(const_cast<a8 *>(a));
}
@@ -233,7 +210,7 @@ static T NoTsanAtomicLoad(const volatile T *a, morder mo) {
return atomic_load(to_atomic(a), to_mo(mo));
}
-#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+#if __TSAN_HAS_INT128 && !SANITIZER_GO
static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
SpinMutexLock lock(&mutex128);
return *a;
@@ -263,7 +240,7 @@ static void NoTsanAtomicStore(volatile T *a, T v, morder mo) {
atomic_store(to_atomic(a), v, to_mo(mo));
}
-#if __TSAN_HAS_INT128 && !defined(SANITIZER_GO)
+#if __TSAN_HAS_INT128 && !SANITIZER_GO
static void NoTsanAtomicStore(volatile a128 *a, a128 v, morder mo) {
SpinMutexLock lock(&mutex128);
*a = v;
@@ -455,7 +432,7 @@ static T AtomicCAS(ThreadState *thr, uptr pc,
return c;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static void NoTsanAtomicFence(morder mo) {
__sync_synchronize();
}
@@ -467,7 +444,7 @@ static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
#endif
// Interface functions follow.
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// C/C++
@@ -866,7 +843,7 @@ void __tsan_atomic_signal_fence(morder mo) {
}
} // extern "C"
-#else // #ifndef SANITIZER_GO
+#else // #if !SANITIZER_GO
// Go
@@ -949,4 +926,4 @@ void __tsan_go_atomic64_compare_exchange(
*(bool*)(a+24) = (cur == cmp);
}
} // extern "C"
-#endif // #ifndef SANITIZER_GO
+#endif // #if !SANITIZER_GO
diff --git a/libsanitizer/tsan/tsan_interface_java.cc b/libsanitizer/tsan/tsan_interface_java.cc
index 934ccc3ef9c..d1638f2aa9d 100644
--- a/libsanitizer/tsan/tsan_interface_java.cc
+++ b/libsanitizer/tsan/tsan_interface_java.cc
@@ -109,7 +109,7 @@ void __tsan_java_free(jptr ptr, jptr size) {
CHECK_GE(ptr, jctx->heap_begin);
CHECK_LE(ptr + size, jctx->heap_begin + jctx->heap_size);
- ctx->metamap.FreeRange(thr, pc, ptr, size);
+ ctx->metamap.FreeRange(thr->proc(), ptr, size);
}
void __tsan_java_move(jptr src, jptr dst, jptr size) {
diff --git a/libsanitizer/tsan/tsan_libdispatch_mac.cc b/libsanitizer/tsan/tsan_libdispatch_mac.cc
index 5b39665d5d2..10c70a831c6 100644
--- a/libsanitizer/tsan/tsan_libdispatch_mac.cc
+++ b/libsanitizer/tsan/tsan_libdispatch_mac.cc
@@ -19,11 +19,205 @@
#include "tsan_platform.h"
#include "tsan_rtl.h"
+#include <Block.h>
#include <dispatch/dispatch.h>
#include <pthread.h>
+typedef long long_t; // NOLINT
+
namespace __tsan {
+typedef struct {
+ dispatch_queue_t queue;
+ void *orig_context;
+ dispatch_function_t orig_work;
+ bool free_context_in_callback;
+ bool submitted_synchronously;
+ bool is_barrier_block;
+ uptr non_queue_sync_object;
+} tsan_block_context_t;
+
+// The offsets of different fields of the dispatch_queue_t structure, exported
+// by libdispatch.dylib.
+extern "C" struct dispatch_queue_offsets_s {
+ const uint16_t dqo_version;
+ const uint16_t dqo_label;
+ const uint16_t dqo_label_size;
+ const uint16_t dqo_flags;
+ const uint16_t dqo_flags_size;
+ const uint16_t dqo_serialnum;
+ const uint16_t dqo_serialnum_size;
+ const uint16_t dqo_width;
+ const uint16_t dqo_width_size;
+ const uint16_t dqo_running;
+ const uint16_t dqo_running_size;
+ const uint16_t dqo_suspend_cnt;
+ const uint16_t dqo_suspend_cnt_size;
+ const uint16_t dqo_target_queue;
+ const uint16_t dqo_target_queue_size;
+ const uint16_t dqo_priority;
+ const uint16_t dqo_priority_size;
+} dispatch_queue_offsets;
+
+static bool IsQueueSerial(dispatch_queue_t q) {
+ CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2);
+ uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width);
+ CHECK_NE(width, 0);
+ return width == 1;
+}
+
+static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) {
+ CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8);
+ dispatch_queue_t target_queue =
+ *(dispatch_queue_t *)(((uptr)source) +
+ dispatch_queue_offsets.dqo_target_queue);
+ CHECK_NE(target_queue, 0);
+ return target_queue;
+}
+
+static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
+ dispatch_queue_t queue,
+ void *orig_context,
+ dispatch_function_t orig_work) {
+ tsan_block_context_t *new_context =
+ (tsan_block_context_t *)user_alloc(thr, pc, sizeof(tsan_block_context_t));
+ new_context->queue = queue;
+ new_context->orig_context = orig_context;
+ new_context->orig_work = orig_work;
+ new_context->free_context_in_callback = true;
+ new_context->submitted_synchronously = false;
+ new_context->is_barrier_block = false;
+ return new_context;
+}
+
+static void dispatch_callback_wrap(void *param) {
+ SCOPED_INTERCEPTOR_RAW(dispatch_callback_wrap);
+ tsan_block_context_t *context = (tsan_block_context_t *)param;
+ bool is_queue_serial = context->queue && IsQueueSerial(context->queue);
+ uptr sync_ptr = (uptr)context->queue ?: context->non_queue_sync_object;
+
+ uptr serial_sync = (uptr)sync_ptr;
+ uptr concurrent_sync = ((uptr)sync_ptr) + sizeof(uptr);
+ uptr submit_sync = (uptr)context;
+ bool serial_task = context->is_barrier_block || is_queue_serial;
+
+ Acquire(thr, pc, submit_sync);
+ Acquire(thr, pc, serial_sync);
+ if (serial_task) Acquire(thr, pc, concurrent_sync);
+
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ context->orig_work(context->orig_context);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+
+ Release(thr, pc, serial_task ? serial_sync : concurrent_sync);
+ if (context->submitted_synchronously) Release(thr, pc, submit_sync);
+
+ if (context->free_context_in_callback) user_free(thr, pc, context);
+}
+
+static void invoke_block(void *param) {
+ dispatch_block_t block = (dispatch_block_t)param;
+ block();
+}
+
+static void invoke_and_release_block(void *param) {
+ dispatch_block_t block = (dispatch_block_t)param;
+ block();
+ Block_release(block);
+}
+
+#define DISPATCH_INTERCEPT_B(name, barrier) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ dispatch_block_t heap_block = Block_copy(block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ tsan_block_context_t *new_context = \
+ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block); \
+ new_context->is_barrier_block = barrier; \
+ Release(thr, pc, (uptr)new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name##_f)(q, new_context, dispatch_callback_wrap); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ }
+
+#define DISPATCH_INTERCEPT_SYNC_B(name, barrier) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ dispatch_block_t heap_block = Block_copy(block); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ tsan_block_context_t new_context = { \
+ q, heap_block, &invoke_and_release_block, false, true, barrier, 0}; \
+ Release(thr, pc, (uptr)&new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name##_f)(q, &new_context, dispatch_callback_wrap); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ Acquire(thr, pc, (uptr)&new_context); \
+ }
+
+#define DISPATCH_INTERCEPT_F(name, barrier) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \
+ dispatch_function_t work) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \
+ tsan_block_context_t *new_context = \
+ AllocContext(thr, pc, q, context, work); \
+ new_context->is_barrier_block = barrier; \
+ Release(thr, pc, (uptr)new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name)(q, new_context, dispatch_callback_wrap); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ }
+
+#define DISPATCH_INTERCEPT_SYNC_F(name, barrier) \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \
+ dispatch_function_t work) { \
+ SCOPED_TSAN_INTERCEPTOR(name, q, context, work); \
+ tsan_block_context_t new_context = { \
+ q, context, work, false, true, barrier, 0}; \
+ Release(thr, pc, (uptr)&new_context); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
+ REAL(name)(q, &new_context, dispatch_callback_wrap); \
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \
+ Acquire(thr, pc, (uptr)&new_context); \
+ }
+
+// We wrap dispatch_async, dispatch_sync and friends where we allocate a new
+// context, which is used to synchronize (we release the context before
+// submitting, and the callback acquires it before executing the original
+// callback).
+DISPATCH_INTERCEPT_B(dispatch_async, false)
+DISPATCH_INTERCEPT_B(dispatch_barrier_async, true)
+DISPATCH_INTERCEPT_F(dispatch_async_f, false)
+DISPATCH_INTERCEPT_F(dispatch_barrier_async_f, true)
+DISPATCH_INTERCEPT_SYNC_B(dispatch_sync, false)
+DISPATCH_INTERCEPT_SYNC_B(dispatch_barrier_sync, true)
+DISPATCH_INTERCEPT_SYNC_F(dispatch_sync_f, false)
+DISPATCH_INTERCEPT_SYNC_F(dispatch_barrier_sync_f, true)
+
+TSAN_INTERCEPTOR(void, dispatch_after, dispatch_time_t when,
+ dispatch_queue_t queue, dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_after, when, queue, block);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ dispatch_block_t heap_block = Block_copy(block);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ tsan_block_context_t *new_context =
+ AllocContext(thr, pc, queue, heap_block, &invoke_and_release_block);
+ Release(thr, pc, (uptr)new_context);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ REAL(dispatch_after_f)(when, queue, new_context, dispatch_callback_wrap);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+}
+
+TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
+ dispatch_queue_t queue, void *context,
+ dispatch_function_t work) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_after_f, when, queue, context, work);
+ WRAP(dispatch_after)(when, queue, ^(void) {
+ work(context);
+ });
+}
+
// GCD's dispatch_once implementation has a fast path that contains a racy read
// and it's inlined into user's code. Furthermore, this fast path doesn't
// establish a proper happens-before relations between the initialization and
@@ -39,12 +233,14 @@ namespace __tsan {
#undef dispatch_once
TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
dispatch_block_t block) {
- SCOPED_TSAN_INTERCEPTOR(dispatch_once, predicate, block);
+ SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block);
atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
u32 v = atomic_load(a, memory_order_acquire);
if (v == 0 &&
atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) {
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
block();
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
Release(thr, pc, (uptr)a);
atomic_store(a, 2, memory_order_release);
} else {
@@ -59,10 +255,423 @@ TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
#undef dispatch_once_f
TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate,
void *context, dispatch_function_t function) {
- SCOPED_TSAN_INTERCEPTOR(dispatch_once_f, predicate, context, function);
+ SCOPED_INTERCEPTOR_RAW(dispatch_once_f, predicate, context, function);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
WRAP(dispatch_once)(predicate, ^(void) {
function(context);
});
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal,
+ dispatch_semaphore_t dsema) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_signal, dsema);
+ Release(thr, pc, (uptr)dsema);
+ return REAL(dispatch_semaphore_signal)(dsema);
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema,
+ dispatch_time_t timeout) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_wait, dsema, timeout);
+ long_t result = REAL(dispatch_semaphore_wait)(dsema, timeout);
+ if (result == 0) Acquire(thr, pc, (uptr)dsema);
+ return result;
+}
+
+TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group,
+ dispatch_time_t timeout) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout);
+ long_t result = REAL(dispatch_group_wait)(group, timeout);
+ if (result == 0) Acquire(thr, pc, (uptr)group);
+ return result;
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group);
+ // Acquired in the group noticifaction callback in dispatch_group_notify[_f].
+ Release(thr, pc, (uptr)group);
+ REAL(dispatch_group_leave)(group);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group,
+ dispatch_queue_t queue, dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block);
+ dispatch_retain(group);
+ dispatch_group_enter(group);
+ __block dispatch_block_t block_copy = (dispatch_block_t)_Block_copy(block);
+ WRAP(dispatch_async)(queue, ^(void) {
+ block_copy();
+ _Block_release(block_copy);
+ WRAP(dispatch_group_leave)(group);
+ dispatch_release(group);
+ });
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+ dispatch_queue_t queue, void *context,
+ dispatch_function_t work) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work);
+ dispatch_retain(group);
+ dispatch_group_enter(group);
+ WRAP(dispatch_async)(queue, ^(void) {
+ work(context);
+ WRAP(dispatch_group_leave)(group);
+ dispatch_release(group);
+ });
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group,
+ dispatch_queue_t q, dispatch_block_t block) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block);
+
+ // To make sure the group is still available in the callback (otherwise
+ // it can be already destroyed). Will be released in the callback.
+ dispatch_retain(group);
+
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ dispatch_block_t heap_block = Block_copy(^(void) {
+ {
+ SCOPED_INTERCEPTOR_RAW(dispatch_read_callback);
+ // Released when leaving the group (dispatch_group_leave).
+ Acquire(thr, pc, (uptr)group);
+ }
+ dispatch_release(group);
+ block();
+ });
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ tsan_block_context_t *new_context =
+ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
+ new_context->is_barrier_block = true;
+ Release(thr, pc, (uptr)new_context);
+ REAL(dispatch_group_notify_f)(group, q, new_context, dispatch_callback_wrap);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group,
+ dispatch_queue_t q, void *context, dispatch_function_t work) {
+ WRAP(dispatch_group_notify)(group, q, ^(void) { work(context); });
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler,
+ dispatch_source_t source, dispatch_block_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_event_handler)(source, nullptr);
+ dispatch_queue_t q = GetTargetQueueFromSource(source);
+ __block tsan_block_context_t new_context = {
+ q, handler, &invoke_block, false, false, false, 0 };
+ dispatch_block_t new_handler = Block_copy(^(void) {
+ new_context.orig_context = handler; // To explicitly capture "handler".
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_source_set_event_handler)(source, new_handler);
+ Block_release(new_handler);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f,
+ dispatch_source_t source, dispatch_function_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler_f, source, handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_event_handler)(source, nullptr);
+ dispatch_block_t block = ^(void) {
+ handler(dispatch_get_context(source));
+ };
+ WRAP(dispatch_source_set_event_handler)(source, block);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler,
+ dispatch_source_t source, dispatch_block_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_cancel_handler)(source, nullptr);
+ dispatch_queue_t q = GetTargetQueueFromSource(source);
+ __block tsan_block_context_t new_context = {
+ q, handler, &invoke_block, false, false, false, 0};
+ dispatch_block_t new_handler = Block_copy(^(void) {
+ new_context.orig_context = handler; // To explicitly capture "handler".
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_source_set_cancel_handler)(source, new_handler);
+ Block_release(new_handler);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f,
+ dispatch_source_t source, dispatch_function_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler_f, source,
+ handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_cancel_handler)(source, nullptr);
+ dispatch_block_t block = ^(void) {
+ handler(dispatch_get_context(source));
+ };
+ WRAP(dispatch_source_set_cancel_handler)(source, block);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler,
+ dispatch_source_t source, dispatch_block_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler, source,
+ handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_registration_handler)(source, nullptr);
+ dispatch_queue_t q = GetTargetQueueFromSource(source);
+ __block tsan_block_context_t new_context = {
+ q, handler, &invoke_block, false, false, false, 0};
+ dispatch_block_t new_handler = Block_copy(^(void) {
+ new_context.orig_context = handler; // To explicitly capture "handler".
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_source_set_registration_handler)(source, new_handler);
+ Block_release(new_handler);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f,
+ dispatch_source_t source, dispatch_function_t handler) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler_f, source,
+ handler);
+ if (handler == nullptr)
+ return REAL(dispatch_source_set_registration_handler)(source, nullptr);
+ dispatch_block_t block = ^(void) {
+ handler(dispatch_get_context(source));
+ };
+ WRAP(dispatch_source_set_registration_handler)(source, block);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations,
+ dispatch_queue_t queue, void (^block)(size_t)) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block);
+
+ void *parent_to_child_sync = nullptr;
+ uptr parent_to_child_sync_uptr = (uptr)&parent_to_child_sync;
+ void *child_to_parent_sync = nullptr;
+ uptr child_to_parent_sync_uptr = (uptr)&child_to_parent_sync;
+
+ Release(thr, pc, parent_to_child_sync_uptr);
+ void (^new_block)(size_t) = ^(size_t iteration) {
+ SCOPED_INTERCEPTOR_RAW(dispatch_apply);
+ Acquire(thr, pc, parent_to_child_sync_uptr);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ block(iteration);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ Release(thr, pc, child_to_parent_sync_uptr);
+ };
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ REAL(dispatch_apply)(iterations, queue, new_block);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ Acquire(thr, pc, child_to_parent_sync_uptr);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations,
+ dispatch_queue_t queue, void *context,
+ void (*work)(void *, size_t)) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_apply_f, iterations, queue, context, work);
+ void (^new_block)(size_t) = ^(size_t iteration) {
+ work(context, iteration);
+ };
+ WRAP(dispatch_apply)(iterations, queue, new_block);
+}
+
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
+DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, long_t sz)
+
+TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer,
+ size_t size, dispatch_queue_t q, dispatch_block_t destructor) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor);
+ if ((q == nullptr) || (destructor == DISPATCH_DATA_DESTRUCTOR_DEFAULT))
+ return REAL(dispatch_data_create)(buffer, size, q, destructor);
+
+ if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE)
+ destructor = ^(void) { WRAP(free)((void *)buffer); };
+ else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP)
+ destructor = ^(void) { WRAP(munmap)((void *)buffer, size); };
+
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
+ dispatch_block_t heap_block = Block_copy(destructor);
+ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
+ tsan_block_context_t *new_context =
+ AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
+ uptr submit_sync = (uptr)new_context;
+ Release(thr, pc, submit_sync);
+ return REAL(dispatch_data_create)(buffer, size, q, ^(void) {
+ dispatch_callback_wrap(new_context);
+ });
+}
+
+typedef void (^fd_handler_t)(dispatch_data_t data, int error);
+typedef void (^cleanup_handler_t)(int error);
+
+TSAN_INTERCEPTOR(void, dispatch_read, dispatch_fd_t fd, size_t length,
+ dispatch_queue_t q, fd_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_read, fd, length, q, h);
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) {
+ new_context.orig_context = ^(void) {
+ h(data, error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_read)(fd, length, q, new_h);
+ Block_release(new_h);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_write, dispatch_fd_t fd, dispatch_data_t data,
+ dispatch_queue_t q, fd_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_write, fd, data, q, h);
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) {
+ new_context.orig_context = ^(void) {
+ h(data, error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_write)(fd, data, q, new_h);
+ Block_release(new_h);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_io_read, dispatch_io_t channel, off_t offset,
+ size_t length, dispatch_queue_t q, dispatch_io_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_read, channel, offset, length, q, h);
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ dispatch_io_handler_t new_h =
+ Block_copy(^(bool done, dispatch_data_t data, int error) {
+ new_context.orig_context = ^(void) {
+ h(done, data, error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_io_read)(channel, offset, length, q, new_h);
+ Block_release(new_h);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_io_write, dispatch_io_t channel, off_t offset,
+ dispatch_data_t data, dispatch_queue_t q,
+ dispatch_io_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_write, channel, offset, data, q, h);
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ dispatch_io_handler_t new_h =
+ Block_copy(^(bool done, dispatch_data_t data, int error) {
+ new_context.orig_context = ^(void) {
+ h(done, data, error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_io_write)(channel, offset, data, q, new_h);
+ Block_release(new_h);
+}
+
+TSAN_INTERCEPTOR(void, dispatch_io_barrier, dispatch_io_t channel,
+ dispatch_block_t barrier) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_barrier, channel, barrier);
+ __block tsan_block_context_t new_context = {
+ nullptr, nullptr, &invoke_block, false, false, false, 0};
+ new_context.non_queue_sync_object = (uptr)channel;
+ new_context.is_barrier_block = true;
+ dispatch_block_t new_block = Block_copy(^(void) {
+ new_context.orig_context = ^(void) {
+ barrier();
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ REAL(dispatch_io_barrier)(channel, new_block);
+ Block_release(new_block);
+}
+
+TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create, dispatch_io_type_t type,
+ dispatch_fd_t fd, dispatch_queue_t q, cleanup_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_create, type, fd, q, h);
+ __block dispatch_io_t new_channel = nullptr;
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ cleanup_handler_t new_h = Block_copy(^(int error) {
+ {
+ SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
+ Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close.
+ }
+ new_context.orig_context = ^(void) {
+ h(error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ new_channel = REAL(dispatch_io_create)(type, fd, q, new_h);
+ Block_release(new_h);
+ return new_channel;
+}
+
+TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_path,
+ dispatch_io_type_t type, const char *path, int oflag,
+ mode_t mode, dispatch_queue_t q, cleanup_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_path, type, path, oflag, mode,
+ q, h);
+ __block dispatch_io_t new_channel = nullptr;
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ cleanup_handler_t new_h = Block_copy(^(int error) {
+ {
+ SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
+ Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close.
+ }
+ new_context.orig_context = ^(void) {
+ h(error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ new_channel =
+ REAL(dispatch_io_create_with_path)(type, path, oflag, mode, q, new_h);
+ Block_release(new_h);
+ return new_channel;
+}
+
+TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_io,
+ dispatch_io_type_t type, dispatch_io_t io, dispatch_queue_t q,
+ cleanup_handler_t h) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_io, type, io, q, h);
+ __block dispatch_io_t new_channel = nullptr;
+ __block tsan_block_context_t new_context = {
+ q, nullptr, &invoke_block, false, false, false, 0};
+ cleanup_handler_t new_h = Block_copy(^(int error) {
+ {
+ SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
+ Acquire(thr, pc, (uptr)new_channel); // Release() in dispatch_io_close.
+ }
+ new_context.orig_context = ^(void) {
+ h(error);
+ };
+ dispatch_callback_wrap(&new_context);
+ });
+ uptr submit_sync = (uptr)&new_context;
+ Release(thr, pc, submit_sync);
+ new_channel = REAL(dispatch_io_create_with_io)(type, io, q, new_h);
+ Block_release(new_h);
+ return new_channel;
+}
+
+TSAN_INTERCEPTOR(void, dispatch_io_close, dispatch_io_t channel,
+ dispatch_io_close_flags_t flags) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_io_close, channel, flags);
+ Release(thr, pc, (uptr)channel); // Acquire() in dispatch_io_create[_*].
+ return REAL(dispatch_io_close)(channel, flags);
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_malloc_mac.cc b/libsanitizer/tsan/tsan_malloc_mac.cc
index 97090773ca7..cc1031a584f 100644
--- a/libsanitizer/tsan/tsan_malloc_mac.cc
+++ b/libsanitizer/tsan/tsan_malloc_mac.cc
@@ -25,41 +25,32 @@ using namespace __tsan;
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
void *p = \
user_alloc(cur_thread(), StackTrace::GetCurrentPc(), size, alignment)
-#define COMMON_MALLOC_MALLOC(size) \
- if (cur_thread()->in_symbolizer) \
- return REAL(malloc)(size); \
- SCOPED_INTERCEPTOR_RAW(malloc, size); \
+#define COMMON_MALLOC_MALLOC(size) \
+ if (cur_thread()->in_symbolizer) return InternalAlloc(size); \
+ SCOPED_INTERCEPTOR_RAW(malloc, size); \
void *p = user_alloc(thr, pc, size)
-#define COMMON_MALLOC_REALLOC(ptr, size) \
- if (cur_thread()->in_symbolizer) \
- return REAL(realloc)(ptr, size); \
- SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ if (cur_thread()->in_symbolizer) return InternalRealloc(ptr, size); \
+ SCOPED_INTERCEPTOR_RAW(realloc, ptr, size); \
void *p = user_realloc(thr, pc, ptr, size)
-#define COMMON_MALLOC_CALLOC(count, size) \
- if (cur_thread()->in_symbolizer) \
- return REAL(calloc)(count, size); \
- SCOPED_INTERCEPTOR_RAW(calloc, size, count); \
+#define COMMON_MALLOC_CALLOC(count, size) \
+ if (cur_thread()->in_symbolizer) return InternalCalloc(count, size); \
+ SCOPED_INTERCEPTOR_RAW(calloc, size, count); \
void *p = user_calloc(thr, pc, size, count)
-#define COMMON_MALLOC_VALLOC(size) \
- if (cur_thread()->in_symbolizer) \
- return REAL(valloc)(size); \
- SCOPED_INTERCEPTOR_RAW(valloc, size); \
+#define COMMON_MALLOC_VALLOC(size) \
+ if (cur_thread()->in_symbolizer) \
+ return InternalAlloc(size, nullptr, GetPageSizeCached()); \
+ SCOPED_INTERCEPTOR_RAW(valloc, size); \
void *p = user_alloc(thr, pc, size, GetPageSizeCached())
-#define COMMON_MALLOC_FREE(ptr) \
- if (cur_thread()->in_symbolizer) \
- return REAL(free)(ptr); \
- SCOPED_INTERCEPTOR_RAW(free, ptr); \
+#define COMMON_MALLOC_FREE(ptr) \
+ if (cur_thread()->in_symbolizer) return InternalFree(ptr); \
+ SCOPED_INTERCEPTOR_RAW(free, ptr); \
user_free(thr, pc, ptr)
-#define COMMON_MALLOC_SIZE(ptr) \
- uptr size = user_alloc_usable_size(ptr);
+#define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr);
#define COMMON_MALLOC_FILL_STATS(zone, stats)
#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
(void)zone_name; \
Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
-#define COMMON_MALLOC_IGNORE_INVALID_FREE false
-#define COMMON_MALLOC_REPORT_FREE_UNALLOCATED(ptr, zone_ptr, zone_name) \
- (void)zone_name; \
- Report("free_common(%p) -- attempting to free unallocated memory.\n", ptr);
#define COMMON_MALLOC_NAMESPACE __tsan
#include "sanitizer_common/sanitizer_malloc_mac.inc"
diff --git a/libsanitizer/tsan/tsan_mman.cc b/libsanitizer/tsan/tsan_mman.cc
index c8a5a6a264a..152c2de28d8 100644
--- a/libsanitizer/tsan/tsan_mman.cc
+++ b/libsanitizer/tsan/tsan_mman.cc
@@ -17,12 +17,14 @@
#include "tsan_flags.h"
// May be overriden by front-end.
-extern "C" void WEAK __sanitizer_malloc_hook(void *ptr, uptr size) {
+SANITIZER_WEAK_DEFAULT_IMPL
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
(void)ptr;
(void)size;
}
-extern "C" void WEAK __sanitizer_free_hook(void *ptr) {
+SANITIZER_WEAK_DEFAULT_IMPL
+void __sanitizer_free_hook(void *ptr) {
(void)ptr;
}
@@ -50,7 +52,7 @@ struct MapUnmapCallback {
diff = p + size - RoundDown(p + size, kPageSize);
if (diff != 0)
size -= diff;
- FlushUnneededShadowMemory((uptr)MemToMeta(p), size / kMetaRatio);
+ ReleaseMemoryToOS((uptr)MemToMeta(p), size / kMetaRatio);
}
};
@@ -59,18 +61,69 @@ Allocator *allocator() {
return reinterpret_cast<Allocator*>(&allocator_placeholder);
}
+struct GlobalProc {
+ Mutex mtx;
+ Processor *proc;
+
+ GlobalProc()
+ : mtx(MutexTypeGlobalProc, StatMtxGlobalProc)
+ , proc(ProcCreate()) {
+ }
+};
+
+static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
+GlobalProc *global_proc() {
+ return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
+}
+
+ScopedGlobalProcessor::ScopedGlobalProcessor() {
+ GlobalProc *gp = global_proc();
+ ThreadState *thr = cur_thread();
+ if (thr->proc())
+ return;
+ // If we don't have a proc, use the global one.
+ // There are currently only two known case where this path is triggered:
+ // __interceptor_free
+ // __nptl_deallocate_tsd
+ // start_thread
+ // clone
+ // and:
+ // ResetRange
+ // __interceptor_munmap
+ // __deallocate_stack
+ // start_thread
+ // clone
+ // Ideally, we destroy thread state (and unwire proc) when a thread actually
+ // exits (i.e. when we join/wait it). Then we would not need the global proc
+ gp->mtx.Lock();
+ ProcWire(gp->proc, thr);
+}
+
+ScopedGlobalProcessor::~ScopedGlobalProcessor() {
+ GlobalProc *gp = global_proc();
+ ThreadState *thr = cur_thread();
+ if (thr->proc() != gp->proc)
+ return;
+ ProcUnwire(gp->proc, thr);
+ gp->mtx.Unlock();
+}
+
void InitializeAllocator() {
allocator()->Init(common_flags()->allocator_may_return_null);
}
-void AllocatorThreadStart(ThreadState *thr) {
- allocator()->InitCache(&thr->alloc_cache);
- internal_allocator()->InitCache(&thr->internal_alloc_cache);
+void InitializeAllocatorLate() {
+ new(global_proc()) GlobalProc();
+}
+
+void AllocatorProcStart(Processor *proc) {
+ allocator()->InitCache(&proc->alloc_cache);
+ internal_allocator()->InitCache(&proc->internal_alloc_cache);
}
-void AllocatorThreadFinish(ThreadState *thr) {
- allocator()->DestroyCache(&thr->alloc_cache);
- internal_allocator()->DestroyCache(&thr->internal_alloc_cache);
+void AllocatorProcFinish(Processor *proc) {
+ allocator()->DestroyCache(&proc->alloc_cache);
+ internal_allocator()->DestroyCache(&proc->internal_alloc_cache);
}
void AllocatorPrintStats() {
@@ -93,8 +146,8 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
- return allocator()->ReturnNullOrDie();
- void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
+ return allocator()->ReturnNullOrDieOnBadRequest();
+ void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align);
if (p == 0)
return 0;
if (ctx && ctx->initialized)
@@ -106,7 +159,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
if (CallocShouldReturnNullDueToOverflow(size, n))
- return allocator()->ReturnNullOrDie();
+ return allocator()->ReturnNullOrDieOnBadRequest();
void *p = user_alloc(thr, pc, n * size);
if (p)
internal_memset(p, 0, n * size);
@@ -114,9 +167,10 @@ void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
}
void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
+ ScopedGlobalProcessor sgp;
if (ctx && ctx->initialized)
OnUserFree(thr, pc, (uptr)p, true);
- allocator()->Deallocate(&thr->alloc_cache, p);
+ allocator()->Deallocate(&thr->proc()->alloc_cache, p);
if (signal)
SignalUnsafeCall(thr, pc);
}
@@ -132,27 +186,23 @@ void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
CHECK_NE(p, (void*)0);
- uptr sz = ctx->metamap.FreeBlock(thr, pc, p);
+ uptr sz = ctx->metamap.FreeBlock(thr->proc(), p);
DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz);
if (write && thr->ignore_reads_and_writes == 0)
MemoryRangeFreed(thr, pc, (uptr)p, sz);
}
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
- void *p2 = 0;
// FIXME: Handle "shrinking" more efficiently,
// it seems that some software actually does this.
- if (sz) {
- p2 = user_alloc(thr, pc, sz);
- if (p2 == 0)
- return 0;
- if (p) {
- uptr oldsz = user_alloc_usable_size(p);
- internal_memcpy(p2, p, min(oldsz, sz));
- }
- }
- if (p)
+ void *p2 = user_alloc(thr, pc, sz);
+ if (p2 == 0)
+ return 0;
+ if (p) {
+ uptr oldsz = user_alloc_usable_size(p);
+ internal_memcpy(p2, p, min(oldsz, sz));
user_free(thr, pc, p);
+ }
return p2;
}
@@ -160,7 +210,11 @@ uptr user_alloc_usable_size(const void *p) {
if (p == 0)
return 0;
MBlock *b = ctx->metamap.GetBlock((uptr)p);
- return b ? b->siz : 0;
+ if (!b)
+ return 0; // Not a valid pointer.
+ if (b->siz == 0)
+ return 1; // Zero-sized allocations are actually 1 byte.
+ return b->siz;
}
void invoke_malloc_hook(void *ptr, uptr size) {
@@ -168,6 +222,7 @@ void invoke_malloc_hook(void *ptr, uptr size) {
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
__sanitizer_malloc_hook(ptr, size);
+ RunMallocHooks(ptr, size);
}
void invoke_free_hook(void *ptr) {
@@ -175,6 +230,7 @@ void invoke_free_hook(void *ptr) {
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return;
__sanitizer_free_hook(ptr);
+ RunFreeHooks(ptr);
}
void *internal_alloc(MBlockType typ, uptr sz) {
@@ -183,7 +239,7 @@ void *internal_alloc(MBlockType typ, uptr sz) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
}
- return InternalAlloc(sz, &thr->internal_alloc_cache);
+ return InternalAlloc(sz, &thr->proc()->internal_alloc_cache);
}
void internal_free(void *p) {
@@ -192,7 +248,7 @@ void internal_free(void *p) {
thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0);
}
- InternalFree(p, &thr->internal_alloc_cache);
+ InternalFree(p, &thr->proc()->internal_alloc_cache);
}
} // namespace __tsan
@@ -234,8 +290,8 @@ uptr __sanitizer_get_allocated_size(const void *p) {
void __tsan_on_thread_idle() {
ThreadState *thr = cur_thread();
- allocator()->SwallowCache(&thr->alloc_cache);
- internal_allocator()->SwallowCache(&thr->internal_alloc_cache);
- ctx->metamap.OnThreadIdle(thr);
+ allocator()->SwallowCache(&thr->proc()->alloc_cache);
+ internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache);
+ ctx->metamap.OnProcIdle(thr->proc());
}
} // extern "C"
diff --git a/libsanitizer/tsan/tsan_mman.h b/libsanitizer/tsan/tsan_mman.h
index a7c91fae5e1..d49c9a9e9f2 100644
--- a/libsanitizer/tsan/tsan_mman.h
+++ b/libsanitizer/tsan/tsan_mman.h
@@ -18,9 +18,10 @@ namespace __tsan {
const uptr kDefaultAlignment = 16;
void InitializeAllocator();
+void InitializeAllocatorLate();
void ReplaceSystemMalloc();
-void AllocatorThreadStart(ThreadState *thr);
-void AllocatorThreadFinish(ThreadState *thr);
+void AllocatorProcStart(Processor *proc);
+void AllocatorProcFinish(Processor *proc);
void AllocatorPrintStats();
// For user allocations.
diff --git a/libsanitizer/tsan/tsan_mutex.cc b/libsanitizer/tsan/tsan_mutex.cc
index 3d3f6cc82b9..9b105cf201b 100644
--- a/libsanitizer/tsan/tsan_mutex.cc
+++ b/libsanitizer/tsan/tsan_mutex.cc
@@ -41,6 +41,7 @@ static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
/*11 MutexTypeDDetector*/ {},
/*12 MutexTypeFired*/ {MutexTypeLeaf},
/*13 MutexTypeRacy*/ {MutexTypeLeaf},
+ /*14 MutexTypeGlobalProc*/ {},
};
static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
diff --git a/libsanitizer/tsan/tsan_mutex.h b/libsanitizer/tsan/tsan_mutex.h
index 9960eee9bc8..bd1000f0b29 100644
--- a/libsanitizer/tsan/tsan_mutex.h
+++ b/libsanitizer/tsan/tsan_mutex.h
@@ -32,6 +32,7 @@ enum MutexType {
MutexTypeDDetector,
MutexTypeFired,
MutexTypeRacy,
+ MutexTypeGlobalProc,
// This must be the last.
MutexTypeCount
diff --git a/libsanitizer/tsan/tsan_mutexset.h b/libsanitizer/tsan/tsan_mutexset.h
index d5406ae9f12..b2c60b9a826 100644
--- a/libsanitizer/tsan/tsan_mutexset.h
+++ b/libsanitizer/tsan/tsan_mutexset.h
@@ -41,7 +41,7 @@ class MutexSet {
}
private:
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
uptr size_;
Desc descs_[kMaxSize];
#endif
@@ -53,7 +53,7 @@ class MutexSet {
// Go does not have mutexes, so do not spend memory and time.
// (Go sync.Mutex is actually a semaphore -- can be unlocked
// in different goroutine).
-#ifdef SANITIZER_GO
+#if SANITIZER_GO
MutexSet::MutexSet() {}
void MutexSet::Add(u64 id, bool write, u64 epoch) {}
void MutexSet::Del(u64 id, bool write) {}
diff --git a/libsanitizer/tsan/tsan_new_delete.cc b/libsanitizer/tsan/tsan_new_delete.cc
index ba8474e0714..606cdd659f4 100644
--- a/libsanitizer/tsan/tsan_new_delete.cc
+++ b/libsanitizer/tsan/tsan_new_delete.cc
@@ -21,14 +21,10 @@ struct nothrow_t {};
DECLARE_REAL(void *, malloc, uptr size)
DECLARE_REAL(void, free, void *ptr)
-#if SANITIZER_MAC
-#define __libc_malloc REAL(malloc)
-#define __libc_free REAL(free)
-#endif
#define OPERATOR_NEW_BODY(mangled_name) \
if (cur_thread()->in_symbolizer) \
- return __libc_malloc(size); \
+ return InternalAlloc(size); \
void *p = 0; \
{ \
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
@@ -64,7 +60,7 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
#define OPERATOR_DELETE_BODY(mangled_name) \
if (ptr == 0) return; \
if (cur_thread()->in_symbolizer) \
- return __libc_free(ptr); \
+ return InternalFree(ptr); \
invoke_free_hook(ptr); \
SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
user_free(thr, pc, ptr);
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index f34f577ec03..368edc21ce4 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -22,38 +22,46 @@
namespace __tsan {
-#if !defined(SANITIZER_GO)
+#if !SANITIZER_GO
#if defined(__x86_64__)
/*
C/C++ on linux/x86_64 and freebsd/x86_64
-0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
-0100 0000 0000 - 0200 0000 0000: -
-0200 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 3000 0000 0000: -
+0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
+0040 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 2000 0000 0000: shadow
+2000 0000 0000 - 3000 0000 0000: -
3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 6000 0000 0000: -
+4000 0000 0000 - 5500 0000 0000: -
+5500 0000 0000 - 5680 0000 0000: pie binaries without ASLR or on 4.1+ kernels
+5680 0000 0000 - 6000 0000 0000: -
6000 0000 0000 - 6200 0000 0000: traces
6200 0000 0000 - 7d00 0000 0000: -
-7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7e80 0000 0000: -
+7b00 0000 0000 - 7c00 0000 0000: heap
+7c00 0000 0000 - 7e80 0000 0000: -
7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
*/
-const uptr kMetaShadowBeg = 0x300000000000ull;
-const uptr kMetaShadowEnd = 0x400000000000ull;
-const uptr kTraceMemBeg = 0x600000000000ull;
-const uptr kTraceMemEnd = 0x620000000000ull;
-const uptr kShadowBeg = 0x020000000000ull;
-const uptr kShadowEnd = 0x100000000000ull;
-const uptr kHeapMemBeg = 0x7d0000000000ull;
-const uptr kHeapMemEnd = 0x7e0000000000ull;
-const uptr kLoAppMemBeg = 0x000000001000ull;
-const uptr kLoAppMemEnd = 0x010000000000ull;
-const uptr kHiAppMemBeg = 0x7e8000000000ull;
-const uptr kHiAppMemEnd = 0x800000000000ull;
-const uptr kAppMemMsk = 0x7c0000000000ull;
-const uptr kAppMemXor = 0x020000000000ull;
-const uptr kVdsoBeg = 0xf000000000000000ull;
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x300000000000ull;
+ static const uptr kMetaShadowEnd = 0x340000000000ull;
+ static const uptr kTraceMemBeg = 0x600000000000ull;
+ static const uptr kTraceMemEnd = 0x620000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x200000000000ull;
+ static const uptr kHeapMemBeg = 0x7b0000000000ull;
+ static const uptr kHeapMemEnd = 0x7c0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000001000ull;
+ static const uptr kLoAppMemEnd = 0x008000000000ull;
+ static const uptr kMidAppMemBeg = 0x550000000000ull;
+ static const uptr kMidAppMemEnd = 0x568000000000ull;
+ static const uptr kHiAppMemBeg = 0x7e8000000000ull;
+ static const uptr kHiAppMemEnd = 0x800000000000ull;
+ static const uptr kAppMemMsk = 0x780000000000ull;
+ static const uptr kAppMemXor = 0x040000000000ull;
+ static const uptr kVdsoBeg = 0xf000000000000000ull;
+};
+
+#define TSAN_MID_APP_RANGE 1
#elif defined(__mips64)
/*
C/C++ on linux/mips64
@@ -69,129 +77,204 @@ fe00 0000 00 - ff00 0000 00: heap
ff00 0000 00 - ff80 0000 00: -
ff80 0000 00 - ffff ffff ff: modules and main thread stack
*/
-const uptr kMetaShadowBeg = 0x3000000000ull;
-const uptr kMetaShadowEnd = 0x4000000000ull;
-const uptr kTraceMemBeg = 0x6000000000ull;
-const uptr kTraceMemEnd = 0x6200000000ull;
-const uptr kShadowBeg = 0x1400000000ull;
-const uptr kShadowEnd = 0x2400000000ull;
-const uptr kHeapMemBeg = 0xfe00000000ull;
-const uptr kHeapMemEnd = 0xff00000000ull;
-const uptr kLoAppMemBeg = 0x0100000000ull;
-const uptr kLoAppMemEnd = 0x0200000000ull;
-const uptr kHiAppMemBeg = 0xff80000000ull;
-const uptr kHiAppMemEnd = 0xffffffffffull;
-const uptr kAppMemMsk = 0xfc00000000ull;
-const uptr kAppMemXor = 0x0400000000ull;
-const uptr kVdsoBeg = 0xfffff00000ull;
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x4000000000ull;
+ static const uptr kMetaShadowEnd = 0x5000000000ull;
+ static const uptr kTraceMemBeg = 0xb000000000ull;
+ static const uptr kTraceMemEnd = 0xb200000000ull;
+ static const uptr kShadowBeg = 0x2400000000ull;
+ static const uptr kShadowEnd = 0x4000000000ull;
+ static const uptr kHeapMemBeg = 0xfe00000000ull;
+ static const uptr kHeapMemEnd = 0xff00000000ull;
+ static const uptr kLoAppMemBeg = 0x0100000000ull;
+ static const uptr kLoAppMemEnd = 0x0200000000ull;
+ static const uptr kMidAppMemBeg = 0xaa00000000ull;
+ static const uptr kMidAppMemEnd = 0xab00000000ull;
+ static const uptr kHiAppMemBeg = 0xff80000000ull;
+ static const uptr kHiAppMemEnd = 0xffffffffffull;
+ static const uptr kAppMemMsk = 0xf800000000ull;
+ static const uptr kAppMemXor = 0x0800000000ull;
+ static const uptr kVdsoBeg = 0xfffff00000ull;
+};
+
+#define TSAN_MID_APP_RANGE 1
#elif defined(__aarch64__)
-# if SANITIZER_AARCH64_VMA == 39
+// AArch64 supports multiple VMA which leads to multiple address transformation
+// functions. To support these multiple VMAS transformations and mappings TSAN
+// runtime for AArch64 uses an external memory read (vmaSize) to select which
+// mapping to use. Although slower, it make a same instrumented binary run on
+// multiple kernels.
+
/*
C/C++ on linux/aarch64 (39-bit VMA)
-0000 4000 00 - 0200 0000 00: main binary
-2000 0000 00 - 4000 0000 00: shadow memory
-4000 0000 00 - 5000 0000 00: metainfo
-5000 0000 00 - 6000 0000 00: -
+0000 0010 00 - 0100 0000 00: main binary
+0100 0000 00 - 0800 0000 00: -
+0800 0000 00 - 2000 0000 00: shadow memory
+2000 0000 00 - 3100 0000 00: -
+3100 0000 00 - 3400 0000 00: metainfo
+3400 0000 00 - 5500 0000 00: -
+5500 0000 00 - 5600 0000 00: main binary (PIE)
+5600 0000 00 - 6000 0000 00: -
6000 0000 00 - 6200 0000 00: traces
6200 0000 00 - 7d00 0000 00: -
-7d00 0000 00 - 7e00 0000 00: heap
-7e00 0000 00 - 7fff ffff ff: modules and main thread stack
+7c00 0000 00 - 7d00 0000 00: heap
+7d00 0000 00 - 7fff ffff ff: modules and main thread stack
*/
-const uptr kLoAppMemBeg = 0x0000400000ull;
-const uptr kLoAppMemEnd = 0x0200000000ull;
-const uptr kShadowBeg = 0x2000000000ull;
-const uptr kShadowEnd = 0x4000000000ull;
-const uptr kMetaShadowBeg = 0x4000000000ull;
-const uptr kMetaShadowEnd = 0x5000000000ull;
-const uptr kTraceMemBeg = 0x6000000000ull;
-const uptr kTraceMemEnd = 0x6200000000ull;
-const uptr kHeapMemBeg = 0x7d00000000ull;
-const uptr kHeapMemEnd = 0x7e00000000ull;
-const uptr kHiAppMemBeg = 0x7e00000000ull;
-const uptr kHiAppMemEnd = 0x7fffffffffull;
-const uptr kAppMemMsk = 0x7800000000ull;
-const uptr kAppMemXor = 0x0800000000ull;
-const uptr kVdsoBeg = 0x7f00000000ull;
-# elif SANITIZER_AARCH64_VMA == 42
+struct Mapping39 {
+ static const uptr kLoAppMemBeg = 0x0000001000ull;
+ static const uptr kLoAppMemEnd = 0x0100000000ull;
+ static const uptr kShadowBeg = 0x0800000000ull;
+ static const uptr kShadowEnd = 0x2000000000ull;
+ static const uptr kMetaShadowBeg = 0x3100000000ull;
+ static const uptr kMetaShadowEnd = 0x3400000000ull;
+ static const uptr kMidAppMemBeg = 0x5500000000ull;
+ static const uptr kMidAppMemEnd = 0x5600000000ull;
+ static const uptr kTraceMemBeg = 0x6000000000ull;
+ static const uptr kTraceMemEnd = 0x6200000000ull;
+ static const uptr kHeapMemBeg = 0x7c00000000ull;
+ static const uptr kHeapMemEnd = 0x7d00000000ull;
+ static const uptr kHiAppMemBeg = 0x7e00000000ull;
+ static const uptr kHiAppMemEnd = 0x7fffffffffull;
+ static const uptr kAppMemMsk = 0x7800000000ull;
+ static const uptr kAppMemXor = 0x0200000000ull;
+ static const uptr kVdsoBeg = 0x7f00000000ull;
+};
+
/*
C/C++ on linux/aarch64 (42-bit VMA)
-00000 4000 00 - 01000 0000 00: main binary
+00000 0010 00 - 01000 0000 00: main binary
01000 0000 00 - 10000 0000 00: -
10000 0000 00 - 20000 0000 00: shadow memory
20000 0000 00 - 26000 0000 00: -
26000 0000 00 - 28000 0000 00: metainfo
-28000 0000 00 - 36200 0000 00: -
+28000 0000 00 - 2aa00 0000 00: -
+2aa00 0000 00 - 2ab00 0000 00: main binary (PIE)
+2ab00 0000 00 - 36200 0000 00: -
36200 0000 00 - 36240 0000 00: traces
36240 0000 00 - 3e000 0000 00: -
3e000 0000 00 - 3f000 0000 00: heap
-3c000 0000 00 - 3ff00 0000 00: -
-3ff00 0000 00 - 3ffff f000 00: modules and main thread stack
+3f000 0000 00 - 3ffff ffff ff: modules and main thread stack
*/
-const uptr kLoAppMemBeg = 0x00000400000ull;
-const uptr kLoAppMemEnd = 0x01000000000ull;
-const uptr kShadowBeg = 0x10000000000ull;
-const uptr kShadowEnd = 0x20000000000ull;
-const uptr kMetaShadowBeg = 0x26000000000ull;
-const uptr kMetaShadowEnd = 0x28000000000ull;
-const uptr kTraceMemBeg = 0x36200000000ull;
-const uptr kTraceMemEnd = 0x36400000000ull;
-const uptr kHeapMemBeg = 0x3e000000000ull;
-const uptr kHeapMemEnd = 0x3f000000000ull;
-const uptr kHiAppMemBeg = 0x3ff00000000ull;
-const uptr kHiAppMemEnd = 0x3fffff00000ull;
-const uptr kAppMemMsk = 0x3c000000000ull;
-const uptr kAppMemXor = 0x04000000000ull;
-const uptr kVdsoBeg = 0x37f00000000ull;
-# endif
-#endif
-
-ALWAYS_INLINE
-bool IsAppMem(uptr mem) {
- return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
- (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
- (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
-}
-
-ALWAYS_INLINE
-bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
-}
-
-ALWAYS_INLINE
-bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
-}
+struct Mapping42 {
+ static const uptr kLoAppMemBeg = 0x00000001000ull;
+ static const uptr kLoAppMemEnd = 0x01000000000ull;
+ static const uptr kShadowBeg = 0x10000000000ull;
+ static const uptr kShadowEnd = 0x20000000000ull;
+ static const uptr kMetaShadowBeg = 0x26000000000ull;
+ static const uptr kMetaShadowEnd = 0x28000000000ull;
+ static const uptr kMidAppMemBeg = 0x2aa00000000ull;
+ static const uptr kMidAppMemEnd = 0x2ab00000000ull;
+ static const uptr kTraceMemBeg = 0x36200000000ull;
+ static const uptr kTraceMemEnd = 0x36400000000ull;
+ static const uptr kHeapMemBeg = 0x3e000000000ull;
+ static const uptr kHeapMemEnd = 0x3f000000000ull;
+ static const uptr kHiAppMemBeg = 0x3f000000000ull;
+ static const uptr kHiAppMemEnd = 0x3ffffffffffull;
+ static const uptr kAppMemMsk = 0x3c000000000ull;
+ static const uptr kAppMemXor = 0x04000000000ull;
+ static const uptr kVdsoBeg = 0x37f00000000ull;
+};
-ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
- DCHECK(IsAppMem(x));
- return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
- ^ kAppMemXor) * kShadowCnt;
-}
+struct Mapping48 {
+ static const uptr kLoAppMemBeg = 0x0000000001000ull;
+ static const uptr kLoAppMemEnd = 0x0000200000000ull;
+ static const uptr kShadowBeg = 0x0002000000000ull;
+ static const uptr kShadowEnd = 0x0004000000000ull;
+ static const uptr kMetaShadowBeg = 0x0005000000000ull;
+ static const uptr kMetaShadowEnd = 0x0006000000000ull;
+ static const uptr kMidAppMemBeg = 0x0aaaa00000000ull;
+ static const uptr kMidAppMemEnd = 0x0aaaf00000000ull;
+ static const uptr kTraceMemBeg = 0x0f06000000000ull;
+ static const uptr kTraceMemEnd = 0x0f06200000000ull;
+ static const uptr kHeapMemBeg = 0x0ffff00000000ull;
+ static const uptr kHeapMemEnd = 0x0ffff00000000ull;
+ static const uptr kHiAppMemBeg = 0x0ffff00000000ull;
+ static const uptr kHiAppMemEnd = 0x1000000000000ull;
+ static const uptr kAppMemMsk = 0x0fff800000000ull;
+ static const uptr kAppMemXor = 0x0000800000000ull;
+ static const uptr kVdsoBeg = 0xffff000000000ull;
+};
-ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
- DCHECK(IsAppMem(x));
- return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
- ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
-}
+// Indicates the runtime will define the memory regions at runtime.
+#define TSAN_RUNTIME_VMA 1
+// Indicates that mapping defines a mid range memory segment.
+#define TSAN_MID_APP_RANGE 1
+#elif defined(__powerpc64__)
+// PPC64 supports multiple VMA which leads to multiple address transformation
+// functions. To support these multiple VMAS transformations and mappings TSAN
+// runtime for PPC64 uses an external memory read (vmaSize) to select which
+// mapping to use. Although slower, it make a same instrumented binary run on
+// multiple kernels.
-ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
- return (s / kShadowCnt) ^ kAppMemXor;
- else
- return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
-}
+/*
+C/C++ on linux/powerpc64 (44-bit VMA)
+0000 0000 0100 - 0001 0000 0000: main binary
+0001 0000 0000 - 0001 0000 0000: -
+0001 0000 0000 - 0b00 0000 0000: shadow
+0b00 0000 0000 - 0b00 0000 0000: -
+0b00 0000 0000 - 0d00 0000 0000: metainfo (memory blocks and sync objects)
+0d00 0000 0000 - 0d00 0000 0000: -
+0d00 0000 0000 - 0f00 0000 0000: traces
+0f00 0000 0000 - 0f00 0000 0000: -
+0f00 0000 0000 - 0f50 0000 0000: heap
+0f50 0000 0000 - 0f60 0000 0000: -
+0f60 0000 0000 - 1000 0000 0000: modules and main thread stack
+*/
+struct Mapping44 {
+ static const uptr kMetaShadowBeg = 0x0b0000000000ull;
+ static const uptr kMetaShadowEnd = 0x0d0000000000ull;
+ static const uptr kTraceMemBeg = 0x0d0000000000ull;
+ static const uptr kTraceMemEnd = 0x0f0000000000ull;
+ static const uptr kShadowBeg = 0x000100000000ull;
+ static const uptr kShadowEnd = 0x0b0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000000100ull;
+ static const uptr kLoAppMemEnd = 0x000100000000ull;
+ static const uptr kHeapMemBeg = 0x0f0000000000ull;
+ static const uptr kHeapMemEnd = 0x0f5000000000ull;
+ static const uptr kHiAppMemBeg = 0x0f6000000000ull;
+ static const uptr kHiAppMemEnd = 0x100000000000ull; // 44 bits
+ static const uptr kAppMemMsk = 0x0f0000000000ull;
+ static const uptr kAppMemXor = 0x002100000000ull;
+ static const uptr kVdsoBeg = 0x3c0000000000000ull;
+};
-static USED uptr UserRegions[] = {
- kLoAppMemBeg, kLoAppMemEnd,
- kHiAppMemBeg, kHiAppMemEnd,
- kHeapMemBeg, kHeapMemEnd,
+/*
+C/C++ on linux/powerpc64 (46-bit VMA)
+0000 0000 1000 - 0100 0000 0000: main binary
+0100 0000 0000 - 0200 0000 0000: -
+0100 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 1000 0000 0000: -
+1000 0000 0000 - 2000 0000 0000: metainfo (memory blocks and sync objects)
+2000 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2200 0000 0000: traces
+2200 0000 0000 - 3d00 0000 0000: -
+3d00 0000 0000 - 3e00 0000 0000: heap
+3e00 0000 0000 - 3e80 0000 0000: -
+3e80 0000 0000 - 4000 0000 0000: modules and main thread stack
+*/
+struct Mapping46 {
+ static const uptr kMetaShadowBeg = 0x100000000000ull;
+ static const uptr kMetaShadowEnd = 0x200000000000ull;
+ static const uptr kTraceMemBeg = 0x200000000000ull;
+ static const uptr kTraceMemEnd = 0x220000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x100000000000ull;
+ static const uptr kHeapMemBeg = 0x3d0000000000ull;
+ static const uptr kHeapMemEnd = 0x3e0000000000ull;
+ static const uptr kLoAppMemBeg = 0x000000001000ull;
+ static const uptr kLoAppMemEnd = 0x010000000000ull;
+ static const uptr kHiAppMemBeg = 0x3e8000000000ull;
+ static const uptr kHiAppMemEnd = 0x400000000000ull; // 46 bits
+ static const uptr kAppMemMsk = 0x3c0000000000ull;
+ static const uptr kAppMemXor = 0x020000000000ull;
+ static const uptr kVdsoBeg = 0x7800000000000000ull;
};
-#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
+// Indicates the runtime will define the memory regions at runtime.
+#define TSAN_RUNTIME_VMA 1
+#endif
+
+#elif SANITIZER_GO && !SANITIZER_WINDOWS
/* Go on linux, darwin and freebsd
0000 0000 1000 - 0000 1000 0000: executable
@@ -206,146 +289,529 @@ static USED uptr UserRegions[] = {
6200 0000 0000 - 8000 0000 0000: -
*/
-const uptr kMetaShadowBeg = 0x300000000000ull;
-const uptr kMetaShadowEnd = 0x400000000000ull;
-const uptr kTraceMemBeg = 0x600000000000ull;
-const uptr kTraceMemEnd = 0x620000000000ull;
-const uptr kShadowBeg = 0x200000000000ull;
-const uptr kShadowEnd = 0x238000000000ull;
-const uptr kAppMemBeg = 0x000000001000ull;
-const uptr kAppMemEnd = 0x00e000000000ull;
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x300000000000ull;
+ static const uptr kMetaShadowEnd = 0x400000000000ull;
+ static const uptr kTraceMemBeg = 0x600000000000ull;
+ static const uptr kTraceMemEnd = 0x620000000000ull;
+ static const uptr kShadowBeg = 0x200000000000ull;
+ static const uptr kShadowEnd = 0x238000000000ull;
+ static const uptr kAppMemBeg = 0x000000001000ull;
+ static const uptr kAppMemEnd = 0x00e000000000ull;
+};
+
+#elif SANITIZER_GO && SANITIZER_WINDOWS
+
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00f8 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 0500 0000 0000: shadow
+0500 0000 0000 - 0560 0000 0000: -
+0560 0000 0000 - 0760 0000 0000: traces
+0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
+07d0 0000 0000 - 8000 0000 0000: -
+*/
+
+struct Mapping {
+ static const uptr kMetaShadowBeg = 0x076000000000ull;
+ static const uptr kMetaShadowEnd = 0x07d000000000ull;
+ static const uptr kTraceMemBeg = 0x056000000000ull;
+ static const uptr kTraceMemEnd = 0x076000000000ull;
+ static const uptr kShadowBeg = 0x010000000000ull;
+ static const uptr kShadowEnd = 0x050000000000ull;
+ static const uptr kAppMemBeg = 0x000000001000ull;
+ static const uptr kAppMemEnd = 0x00e000000000ull;
+};
+
+#else
+# error "Unknown platform"
+#endif
+
+
+#ifdef TSAN_RUNTIME_VMA
+extern uptr vmaSize;
+#endif
+
+
+enum MappingType {
+ MAPPING_LO_APP_BEG,
+ MAPPING_LO_APP_END,
+ MAPPING_HI_APP_BEG,
+ MAPPING_HI_APP_END,
+#ifdef TSAN_MID_APP_RANGE
+ MAPPING_MID_APP_BEG,
+ MAPPING_MID_APP_END,
+#endif
+ MAPPING_HEAP_BEG,
+ MAPPING_HEAP_END,
+ MAPPING_APP_BEG,
+ MAPPING_APP_END,
+ MAPPING_SHADOW_BEG,
+ MAPPING_SHADOW_END,
+ MAPPING_META_SHADOW_BEG,
+ MAPPING_META_SHADOW_END,
+ MAPPING_TRACE_BEG,
+ MAPPING_TRACE_END,
+ MAPPING_VDSO_BEG,
+};
+
+template<typename Mapping, int Type>
+uptr MappingImpl(void) {
+ switch (Type) {
+#if !SANITIZER_GO
+ case MAPPING_LO_APP_BEG: return Mapping::kLoAppMemBeg;
+ case MAPPING_LO_APP_END: return Mapping::kLoAppMemEnd;
+# ifdef TSAN_MID_APP_RANGE
+ case MAPPING_MID_APP_BEG: return Mapping::kMidAppMemBeg;
+ case MAPPING_MID_APP_END: return Mapping::kMidAppMemEnd;
+# endif
+ case MAPPING_HI_APP_BEG: return Mapping::kHiAppMemBeg;
+ case MAPPING_HI_APP_END: return Mapping::kHiAppMemEnd;
+ case MAPPING_HEAP_BEG: return Mapping::kHeapMemBeg;
+ case MAPPING_HEAP_END: return Mapping::kHeapMemEnd;
+ case MAPPING_VDSO_BEG: return Mapping::kVdsoBeg;
+#else
+ case MAPPING_APP_BEG: return Mapping::kAppMemBeg;
+ case MAPPING_APP_END: return Mapping::kAppMemEnd;
+#endif
+ case MAPPING_SHADOW_BEG: return Mapping::kShadowBeg;
+ case MAPPING_SHADOW_END: return Mapping::kShadowEnd;
+ case MAPPING_META_SHADOW_BEG: return Mapping::kMetaShadowBeg;
+ case MAPPING_META_SHADOW_END: return Mapping::kMetaShadowEnd;
+ case MAPPING_TRACE_BEG: return Mapping::kTraceMemBeg;
+ case MAPPING_TRACE_END: return Mapping::kTraceMemEnd;
+ }
+}
+template<int Type>
+uptr MappingArchImpl(void) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return MappingImpl<Mapping39, Type>();
+ case 42: return MappingImpl<Mapping42, Type>();
+ case 48: return MappingImpl<Mapping48, Type>();
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MappingImpl<Mapping44, Type>();
+ else
+ return MappingImpl<Mapping46, Type>();
+ DCHECK(0);
+#else
+ return MappingImpl<Mapping, Type>();
+#endif
+}
+
+#if !SANITIZER_GO
ALWAYS_INLINE
-bool IsAppMem(uptr mem) {
- return mem >= kAppMemBeg && mem < kAppMemEnd;
+uptr LoAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_LO_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr LoAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_LO_APP_END>();
}
+#ifdef TSAN_MID_APP_RANGE
ALWAYS_INLINE
-bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
+uptr MidAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_MID_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr MidAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_MID_APP_END>();
}
+#endif
ALWAYS_INLINE
-bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+uptr HeapMemBeg(void) {
+ return MappingArchImpl<MAPPING_HEAP_BEG>();
+}
+ALWAYS_INLINE
+uptr HeapMemEnd(void) {
+ return MappingArchImpl<MAPPING_HEAP_END>();
}
ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
- DCHECK(IsAppMem(x));
- return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+uptr HiAppMemBeg(void) {
+ return MappingArchImpl<MAPPING_HI_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr HiAppMemEnd(void) {
+ return MappingArchImpl<MAPPING_HI_APP_END>();
}
ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
- DCHECK(IsAppMem(x));
- return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
- kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+uptr VdsoBeg(void) {
+ return MappingArchImpl<MAPPING_VDSO_BEG>();
}
+#else
+
ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- return (s & ~kShadowBeg) / kShadowCnt;
+uptr AppMemBeg(void) {
+ return MappingArchImpl<MAPPING_APP_BEG>();
+}
+ALWAYS_INLINE
+uptr AppMemEnd(void) {
+ return MappingArchImpl<MAPPING_APP_END>();
}
-static USED uptr UserRegions[] = {
- kAppMemBeg, kAppMemEnd,
-};
+#endif
-#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
+static inline
+bool GetUserRegion(int i, uptr *start, uptr *end) {
+ switch (i) {
+ default:
+ return false;
+#if !SANITIZER_GO
+ case 0:
+ *start = LoAppMemBeg();
+ *end = LoAppMemEnd();
+ return true;
+ case 1:
+ *start = HiAppMemBeg();
+ *end = HiAppMemEnd();
+ return true;
+ case 2:
+ *start = HeapMemBeg();
+ *end = HeapMemEnd();
+ return true;
+# ifdef TSAN_MID_APP_RANGE
+ case 3:
+ *start = MidAppMemBeg();
+ *end = MidAppMemEnd();
+ return true;
+# endif
+#else
+ case 0:
+ *start = AppMemBeg();
+ *end = AppMemEnd();
+ return true;
+#endif
+ }
+}
-/* Go on windows
-0000 0000 1000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
-00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 0100 0000 0000: -
-0100 0000 0000 - 0500 0000 0000: shadow
-0500 0000 0000 - 0560 0000 0000: -
-0560 0000 0000 - 0760 0000 0000: traces
-0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
-07d0 0000 0000 - 8000 0000 0000: -
-*/
+ALWAYS_INLINE
+uptr ShadowBeg(void) {
+ return MappingArchImpl<MAPPING_SHADOW_BEG>();
+}
+ALWAYS_INLINE
+uptr ShadowEnd(void) {
+ return MappingArchImpl<MAPPING_SHADOW_END>();
+}
-const uptr kMetaShadowBeg = 0x076000000000ull;
-const uptr kMetaShadowEnd = 0x07d000000000ull;
-const uptr kTraceMemBeg = 0x056000000000ull;
-const uptr kTraceMemEnd = 0x076000000000ull;
-const uptr kShadowBeg = 0x010000000000ull;
-const uptr kShadowEnd = 0x050000000000ull;
-const uptr kAppMemBeg = 0x000000001000ull;
-const uptr kAppMemEnd = 0x00e000000000ull;
+ALWAYS_INLINE
+uptr MetaShadowBeg(void) {
+ return MappingArchImpl<MAPPING_META_SHADOW_BEG>();
+}
+ALWAYS_INLINE
+uptr MetaShadowEnd(void) {
+ return MappingArchImpl<MAPPING_META_SHADOW_END>();
+}
+
+ALWAYS_INLINE
+uptr TraceMemBeg(void) {
+ return MappingArchImpl<MAPPING_TRACE_BEG>();
+}
+ALWAYS_INLINE
+uptr TraceMemEnd(void) {
+ return MappingArchImpl<MAPPING_TRACE_END>();
+}
+
+
+template<typename Mapping>
+bool IsAppMemImpl(uptr mem) {
+#if !SANITIZER_GO
+ return (mem >= Mapping::kHeapMemBeg && mem < Mapping::kHeapMemEnd) ||
+# ifdef TSAN_MID_APP_RANGE
+ (mem >= Mapping::kMidAppMemBeg && mem < Mapping::kMidAppMemEnd) ||
+# endif
+ (mem >= Mapping::kLoAppMemBeg && mem < Mapping::kLoAppMemEnd) ||
+ (mem >= Mapping::kHiAppMemBeg && mem < Mapping::kHiAppMemEnd);
+#else
+ return mem >= Mapping::kAppMemBeg && mem < Mapping::kAppMemEnd;
+#endif
+}
ALWAYS_INLINE
bool IsAppMem(uptr mem) {
- return mem >= kAppMemBeg && mem < kAppMemEnd;
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return IsAppMemImpl<Mapping39>(mem);
+ case 42: return IsAppMemImpl<Mapping42>(mem);
+ case 48: return IsAppMemImpl<Mapping48>(mem);
+ }
+ DCHECK(0);
+ return false;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsAppMemImpl<Mapping44>(mem);
+ else
+ return IsAppMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsAppMemImpl<Mapping>(mem);
+#endif
+}
+
+
+template<typename Mapping>
+bool IsShadowMemImpl(uptr mem) {
+ return mem >= Mapping::kShadowBeg && mem <= Mapping::kShadowEnd;
}
ALWAYS_INLINE
bool IsShadowMem(uptr mem) {
- return mem >= kShadowBeg && mem <= kShadowEnd;
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return IsShadowMemImpl<Mapping39>(mem);
+ case 42: return IsShadowMemImpl<Mapping42>(mem);
+ case 48: return IsShadowMemImpl<Mapping48>(mem);
+ }
+ DCHECK(0);
+ return false;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsShadowMemImpl<Mapping44>(mem);
+ else
+ return IsShadowMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsShadowMemImpl<Mapping>(mem);
+#endif
+}
+
+
+template<typename Mapping>
+bool IsMetaMemImpl(uptr mem) {
+ return mem >= Mapping::kMetaShadowBeg && mem <= Mapping::kMetaShadowEnd;
}
ALWAYS_INLINE
bool IsMetaMem(uptr mem) {
- return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return IsMetaMemImpl<Mapping39>(mem);
+ case 42: return IsMetaMemImpl<Mapping42>(mem);
+ case 48: return IsMetaMemImpl<Mapping48>(mem);
+ }
+ DCHECK(0);
+ return false;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return IsMetaMemImpl<Mapping44>(mem);
+ else
+ return IsMetaMemImpl<Mapping46>(mem);
+ DCHECK(0);
+#else
+ return IsMetaMemImpl<Mapping>(mem);
+#endif
}
-ALWAYS_INLINE
-uptr MemToShadow(uptr x) {
+
+template<typename Mapping>
+uptr MemToShadowImpl(uptr x) {
DCHECK(IsAppMem(x));
- return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg;
+#if !SANITIZER_GO
+ return (((x) & ~(Mapping::kAppMemMsk | (kShadowCell - 1)))
+ ^ Mapping::kAppMemXor) * kShadowCnt;
+#else
+# ifndef SANITIZER_WINDOWS
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) | Mapping::kShadowBeg;
+# else
+ return ((x & ~(kShadowCell - 1)) * kShadowCnt) + Mapping::kShadowBeg;
+# endif
+#endif
}
ALWAYS_INLINE
-u32 *MemToMeta(uptr x) {
+uptr MemToShadow(uptr x) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return MemToShadowImpl<Mapping39>(x);
+ case 42: return MemToShadowImpl<Mapping42>(x);
+ case 48: return MemToShadowImpl<Mapping48>(x);
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToShadowImpl<Mapping44>(x);
+ else
+ return MemToShadowImpl<Mapping46>(x);
+ DCHECK(0);
+#else
+ return MemToShadowImpl<Mapping>(x);
+#endif
+}
+
+
+template<typename Mapping>
+u32 *MemToMetaImpl(uptr x) {
DCHECK(IsAppMem(x));
+#if !SANITIZER_GO
+ return (u32*)(((((x) & ~(Mapping::kAppMemMsk | (kMetaShadowCell - 1)))) /
+ kMetaShadowCell * kMetaShadowSize) | Mapping::kMetaShadowBeg);
+#else
+# ifndef SANITIZER_WINDOWS
return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
- kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+ kMetaShadowCell * kMetaShadowSize) | Mapping::kMetaShadowBeg);
+# else
+ return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+ kMetaShadowCell * kMetaShadowSize) + Mapping::kMetaShadowBeg);
+# endif
+#endif
}
ALWAYS_INLINE
-uptr ShadowToMem(uptr s) {
- CHECK(IsShadowMem(s));
- // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
- return (s - kShadowBeg) / kShadowCnt;
+u32 *MemToMeta(uptr x) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return MemToMetaImpl<Mapping39>(x);
+ case 42: return MemToMetaImpl<Mapping42>(x);
+ case 48: return MemToMetaImpl<Mapping48>(x);
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return MemToMetaImpl<Mapping44>(x);
+ else
+ return MemToMetaImpl<Mapping46>(x);
+ DCHECK(0);
+#else
+ return MemToMetaImpl<Mapping>(x);
+#endif
}
-static USED uptr UserRegions[] = {
- kAppMemBeg, kAppMemEnd,
-};
+template<typename Mapping>
+uptr ShadowToMemImpl(uptr s) {
+ DCHECK(IsShadowMem(s));
+#if !SANITIZER_GO
+ // The shadow mapping is non-linear and we've lost some bits, so we don't have
+ // an easy way to restore the original app address. But the mapping is a
+ // bijection, so we try to restore the address as belonging to low/mid/high
+ // range consecutively and see if shadow->app->shadow mapping gives us the
+ // same address.
+ uptr p = (s / kShadowCnt) ^ Mapping::kAppMemXor;
+ if (p >= Mapping::kLoAppMemBeg && p < Mapping::kLoAppMemEnd &&
+ MemToShadow(p) == s)
+ return p;
+# ifdef TSAN_MID_APP_RANGE
+ p = ((s / kShadowCnt) ^ Mapping::kAppMemXor) +
+ (Mapping::kMidAppMemBeg & Mapping::kAppMemMsk);
+ if (p >= Mapping::kMidAppMemBeg && p < Mapping::kMidAppMemEnd &&
+ MemToShadow(p) == s)
+ return p;
+# endif
+ return ((s / kShadowCnt) ^ Mapping::kAppMemXor) | Mapping::kAppMemMsk;
+#else // #if !SANITIZER_GO
+# ifndef SANITIZER_WINDOWS
+ return (s & ~Mapping::kShadowBeg) / kShadowCnt;
+# else
+ return (s - Mapping::kShadowBeg) / kShadowCnt;
+# endif // SANITIZER_WINDOWS
+#endif
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return ShadowToMemImpl<Mapping39>(s);
+ case 42: return ShadowToMemImpl<Mapping42>(s);
+ case 48: return ShadowToMemImpl<Mapping48>(s);
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return ShadowToMemImpl<Mapping44>(s);
+ else
+ return ShadowToMemImpl<Mapping46>(s);
+ DCHECK(0);
#else
-# error "Unknown platform"
+ return ShadowToMemImpl<Mapping>(s);
#endif
+}
+
+
// The additional page is to catch shadow stack overflow as paging fault.
// Windows wants 64K alignment for mmaps.
const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
+ (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
-uptr ALWAYS_INLINE GetThreadTrace(int tid) {
- uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
- DCHECK_LT(p, kTraceMemEnd);
+template<typename Mapping>
+uptr GetThreadTraceImpl(int tid) {
+ uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+ DCHECK_LT(p, Mapping::kTraceMemEnd);
return p;
}
-uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
- uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ALWAYS_INLINE
+uptr GetThreadTrace(int tid) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return GetThreadTraceImpl<Mapping39>(tid);
+ case 42: return GetThreadTraceImpl<Mapping42>(tid);
+ case 48: return GetThreadTraceImpl<Mapping48>(tid);
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceImpl<Mapping46>(tid);
+ DCHECK(0);
+#else
+ return GetThreadTraceImpl<Mapping>(tid);
+#endif
+}
+
+
+template<typename Mapping>
+uptr GetThreadTraceHeaderImpl(int tid) {
+ uptr p = Mapping::kTraceMemBeg + (uptr)tid * kTotalTraceSize
+ kTraceSize * sizeof(Event);
- DCHECK_LT(p, kTraceMemEnd);
+ DCHECK_LT(p, Mapping::kTraceMemEnd);
return p;
}
+ALWAYS_INLINE
+uptr GetThreadTraceHeader(int tid) {
+#ifdef __aarch64__
+ switch (vmaSize) {
+ case 39: return GetThreadTraceHeaderImpl<Mapping39>(tid);
+ case 42: return GetThreadTraceHeaderImpl<Mapping42>(tid);
+ case 48: return GetThreadTraceHeaderImpl<Mapping48>(tid);
+ }
+ DCHECK(0);
+ return 0;
+#elif defined(__powerpc64__)
+ if (vmaSize == 44)
+ return GetThreadTraceHeaderImpl<Mapping44>(tid);
+ else
+ return GetThreadTraceHeaderImpl<Mapping46>(tid);
+ DCHECK(0);
+#else
+ return GetThreadTraceHeaderImpl<Mapping>(tid);
+#endif
+}
+
void InitializePlatform();
+void InitializePlatformEarly();
void CheckAndProtect();
void InitializeShadowMemoryPlatform();
void FlushShadowMemory();
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
-
-// Says whether the addr relates to a global var.
-// Guesses with high probability, may yield both false positives and negatives.
-bool IsGlobalVar(uptr addr);
int ExtractResolvFDs(void *state, int *fds, int nfd);
int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc
index 09cec5fdffd..2ed5718a12e 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cc
+++ b/libsanitizer/tsan/tsan_platform_linux.cc
@@ -16,6 +16,8 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
@@ -32,6 +34,10 @@
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
+#if SANITIZER_LINUX
+#include <sys/personality.h>
+#include <setjmp.h>
+#endif
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -66,8 +72,10 @@ void InitializeGuardPtr() __attribute__((visibility("hidden")));
namespace __tsan {
-static uptr g_data_start;
-static uptr g_data_end;
+#ifdef TSAN_RUNTIME_VMA
+// Runtime detected VMA size.
+uptr vmaSize;
+#endif
enum {
MemTotal = 0,
@@ -84,29 +92,30 @@ enum {
void FillProfileCallback(uptr p, uptr rss, bool file,
uptr *mem, uptr stats_size) {
mem[MemTotal] += rss;
- if (p >= kShadowBeg && p < kShadowEnd)
+ if (p >= ShadowBeg() && p < ShadowEnd())
mem[MemShadow] += rss;
- else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
+ else if (p >= MetaShadowBeg() && p < MetaShadowEnd())
mem[MemMeta] += rss;
-#ifndef SANITIZER_GO
- else if (p >= kHeapMemBeg && p < kHeapMemEnd)
+#if !SANITIZER_GO
+ else if (p >= HeapMemBeg() && p < HeapMemEnd())
mem[MemHeap] += rss;
- else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
+ else if (p >= LoAppMemBeg() && p < LoAppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
- else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+ else if (p >= HiAppMemBeg() && p < HiAppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
#else
- else if (p >= kAppMemBeg && p < kAppMemEnd)
+ else if (p >= AppMemBeg() && p < AppMemEnd())
mem[file ? MemFile : MemMmap] += rss;
#endif
- else if (p >= kTraceMemBeg && p < kTraceMemEnd)
+ else if (p >= TraceMemBeg() && p < TraceMemEnd())
mem[MemTrace] += rss;
else
mem[MemOther] += rss;
}
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
- uptr mem[MemCount] = {};
+ uptr mem[MemCount];
+ internal_memset(mem, 0, sizeof(mem[0]) * MemCount);
__sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
StackDepotStats *stacks = StackDepotGetStats();
internal_snprintf(buf, buf_size,
@@ -123,7 +132,7 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
void FlushShadowMemoryCallback(
const SuspendedThreadsList &suspended_threads_list,
void *argument) {
- FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+ ReleaseMemoryToOS(ShadowBeg(), ShadowEnd() - ShadowBeg());
}
#endif
@@ -133,7 +142,7 @@ void FlushShadowMemory() {
#endif
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Mark shadow for .rodata sections with the special kShadowRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static void MapRodata() {
@@ -195,55 +204,35 @@ void InitializeShadowMemoryPlatform() {
MapRodata();
}
-static void InitDataSeg() {
- MemoryMappingLayout proc_maps(true);
- uptr start, end, offset;
- char name[128];
-#if SANITIZER_FREEBSD
- // On FreeBSD BSS is usually the last block allocated within the
- // low range and heap is the last block allocated within the range
- // 0x800000000-0x8ffffffff.
- while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
- /*protection*/ 0)) {
- DPrintf("%p-%p %p %s\n", start, end, offset, name);
- if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
- name[0] == '\0') {
- g_data_start = start;
- g_data_end = end;
- }
+#endif // #if !SANITIZER_GO
+
+void InitializePlatformEarly() {
+#ifdef TSAN_RUNTIME_VMA
+ vmaSize =
+ (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
+#if defined(__aarch64__)
+ if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize);
+ Die();
}
-#else
- bool prev_is_data = false;
- while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
- /*protection*/ 0)) {
- DPrintf("%p-%p %p %s\n", start, end, offset, name);
- bool is_data = offset != 0 && name[0] != 0;
- // BSS may get merged with [heap] in /proc/self/maps. This is not very
- // reliable.
- bool is_bss = offset == 0 &&
- (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
- if (g_data_start == 0 && is_data)
- g_data_start = start;
- if (is_bss)
- g_data_end = end;
- prev_is_data = is_data;
+#elif defined(__powerpc64__)
+ if (vmaSize != 44 && vmaSize != 46) {
+ Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+ Printf("FATAL: Found %d - Supported 44 and 46\n", vmaSize);
+ Die();
}
#endif
- DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
- CHECK_LT(g_data_start, g_data_end);
- CHECK_GE((uptr)&g_data_start, g_data_start);
- CHECK_LT((uptr)&g_data_start, g_data_end);
+#endif
}
-#endif // #ifndef SANITIZER_GO
-
void InitializePlatform() {
DisableCoreDumperIfNecessary();
// Go maps shadow memory lazily and works fine with limited address space.
// Unlimited stack is not a problem as well, because the executable
// is not compiled with -pie.
- if (kCppMode) {
+ if (!SANITIZER_GO) {
bool reexec = false;
// TSan doesn't play well with unlimited stack size (as stack
// overlaps with shadow memory). If we detect unlimited stack size,
@@ -266,6 +255,18 @@ void InitializePlatform() {
reexec = true;
}
#if SANITIZER_LINUX && defined(__aarch64__)
+ // After patch "arm64: mm: support ARCH_MMAP_RND_BITS." is introduced in
+ // linux kernel, the random gap between stack and mapped area is increased
+ // from 128M to 36G on 39-bit aarch64. As it is almost impossible to cover
+ // this big range, we should disable randomized virtual space on aarch64.
+ int old_personality = personality(0xffffffff);
+ if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
+ VReport(1, "WARNING: Program is run with randomized virtual address "
+ "space, which wouldn't work with ThreadSanitizer.\n"
+ "Re-execing with fixed virtual address space.\n");
+ CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
+ reexec = true;
+ }
// Initialize the guard pointer used in {sig}{set,long}jump.
InitializeGuardPtr();
#endif
@@ -273,23 +274,18 @@ void InitializePlatform() {
ReExec();
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
CheckAndProtect();
InitTlsSize();
- InitDataSeg();
#endif
}
-bool IsGlobalVar(uptr addr) {
- return g_data_start && addr >= g_data_start && addr < g_data_end;
-}
-
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Extract file descriptors passed to glibc internal __res_iclose function.
// This is required to properly "close" the fds, because we do not see internal
// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
int cnt = 0;
__res_state *statp = (__res_state*)state;
for (int i = 0; i < MAXNS && cnt < nfd; i++) {
@@ -337,10 +333,73 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
}
#endif
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void ReplaceSystemMalloc() { }
#endif
+#if !SANITIZER_GO
+#if SANITIZER_ANDROID
+
+#if defined(__aarch64__)
+# define __get_tls() \
+ ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
+#elif defined(__x86_64__)
+# define __get_tls() \
+ ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
+#else
+#error unsupported architecture
+#endif
+
+// On Android, __thread is not supported. So we store the pointer to ThreadState
+// in TLS_SLOT_TSAN, which is the tls slot allocated by Android bionic for tsan.
+static const int TLS_SLOT_TSAN = 8;
+// On Android, one thread can call intercepted functions after
+// DestroyThreadState(), so add a fake thread state for "dead" threads.
+static ThreadState *dead_thread_state = nullptr;
+
+ThreadState *cur_thread() {
+ ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ if (thr == nullptr) {
+ __sanitizer_sigset_t emptyset;
+ internal_sigfillset(&emptyset);
+ __sanitizer_sigset_t oldset;
+ CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
+ thr = reinterpret_cast<ThreadState*>(__get_tls()[TLS_SLOT_TSAN]);
+ if (thr == nullptr) {
+ thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
+ "ThreadState"));
+ __get_tls()[TLS_SLOT_TSAN] = thr;
+ if (dead_thread_state == nullptr) {
+ dead_thread_state = reinterpret_cast<ThreadState*>(
+ MmapOrDie(sizeof(ThreadState), "ThreadState"));
+ dead_thread_state->fast_state.SetIgnoreBit();
+ dead_thread_state->ignore_interceptors = 1;
+ dead_thread_state->is_dead = true;
+ *const_cast<int*>(&dead_thread_state->tid) = -1;
+ CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
+ PROT_READ));
+ }
+ }
+ CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
+ }
+ return thr;
+}
+
+void cur_thread_finalize() {
+ __sanitizer_sigset_t emptyset;
+ internal_sigfillset(&emptyset);
+ __sanitizer_sigset_t oldset;
+ CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
+ ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ if (thr != dead_thread_state) {
+ __get_tls()[TLS_SLOT_TSAN] = dead_thread_state;
+ UnmapOrDie(thr, sizeof(ThreadState));
+ }
+ CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
+}
+#endif // SANITIZER_ANDROID
+#endif // if !SANITIZER_GO
+
} // namespace __tsan
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
diff --git a/libsanitizer/tsan/tsan_platform_mac.cc b/libsanitizer/tsan/tsan_platform_mac.cc
index e1405ffeabf..ff5131e75bb 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cc
+++ b/libsanitizer/tsan/tsan_platform_mac.cc
@@ -40,7 +40,7 @@
namespace __tsan {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
atomic_uintptr_t *a = (atomic_uintptr_t *)dst;
void *val = (void *)atomic_load_relaxed(a);
@@ -65,20 +65,18 @@ static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
// when TLVs are not accessible (early process startup, thread cleanup, ...).
// The following provides a "poor man's TLV" implementation, where we use the
// shadow memory of the pointer returned by pthread_self() to store a pointer to
-// the ThreadState object. The main thread's ThreadState pointer is stored
-// separately in a static variable, because we need to access it even before the
+// the ThreadState object. The main thread's ThreadState is stored separately
+// in a static variable, because we need to access it even before the
// shadow memory is set up.
static uptr main_thread_identity = 0;
-static ThreadState *main_thread_state = nullptr;
+ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
ThreadState *cur_thread() {
- ThreadState **fake_tls;
uptr thread_identity = (uptr)pthread_self();
if (thread_identity == main_thread_identity || main_thread_identity == 0) {
- fake_tls = &main_thread_state;
- } else {
- fake_tls = (ThreadState **)MemToShadow(thread_identity);
+ return (ThreadState *)&main_thread_state;
}
+ ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
(uptr *)fake_tls, sizeof(ThreadState));
return thr;
@@ -89,7 +87,11 @@ ThreadState *cur_thread() {
// handler will try to access the unmapped ThreadState.
void cur_thread_finalize() {
uptr thread_identity = (uptr)pthread_self();
- CHECK_NE(thread_identity, main_thread_identity);
+ if (thread_identity == main_thread_identity) {
+ // Calling dispatch_main() or xpc_main() actually invokes pthread_exit to
+ // exit the main thread. Let's keep the main thread's ThreadState.
+ return;
+ }
ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
internal_munmap(*fake_tls, sizeof(ThreadState));
*fake_tls = nullptr;
@@ -106,7 +108,7 @@ void FlushShadowMemory() {
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void InitializeShadowMemoryPlatform() { }
// On OS X, GCD worker threads are created without a call to pthread_create. We
@@ -122,23 +124,27 @@ typedef void (*pthread_introspection_hook_t)(unsigned int event,
extern "C" pthread_introspection_hook_t pthread_introspection_hook_install(
pthread_introspection_hook_t hook);
static const uptr PTHREAD_INTROSPECTION_THREAD_CREATE = 1;
-static const uptr PTHREAD_INTROSPECTION_THREAD_DESTROY = 4;
+static const uptr PTHREAD_INTROSPECTION_THREAD_TERMINATE = 3;
static pthread_introspection_hook_t prev_pthread_introspection_hook;
static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
void *addr, size_t size) {
if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
if (thread == pthread_self()) {
// The current thread is a newly created GCD worker thread.
+ ThreadState *thr = cur_thread();
+ Processor *proc = ProcCreate();
+ ProcWire(proc, thr);
ThreadState *parent_thread_state = nullptr; // No parent.
int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
CHECK_NE(tid, 0);
- ThreadState *thr = cur_thread();
ThreadStart(thr, tid, GetTid());
}
- } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
- ThreadState *thr = cur_thread();
- if (thr->tctx && thr->tctx->parent_tid == kInvalidTid) {
- DestroyThreadState();
+ } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
+ if (thread == pthread_self()) {
+ ThreadState *thr = cur_thread();
+ if (thr->tctx) {
+ DestroyThreadState();
+ }
}
}
@@ -147,9 +153,12 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
}
#endif
+void InitializePlatformEarly() {
+}
+
void InitializePlatform() {
DisableCoreDumperIfNecessary();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
CheckAndProtect();
CHECK_EQ(main_thread_identity, 0);
@@ -160,7 +169,7 @@ void InitializePlatform() {
#endif
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
@@ -176,10 +185,6 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
}
#endif
-bool IsGlobalVar(uptr addr) {
- return false;
-}
-
} // namespace __tsan
#endif // SANITIZER_MAC
diff --git a/libsanitizer/tsan/tsan_platform_posix.cc b/libsanitizer/tsan/tsan_platform_posix.cc
index 5e3d12e9496..0a3b61a08dc 100644
--- a/libsanitizer/tsan/tsan_platform_posix.cc
+++ b/libsanitizer/tsan/tsan_platform_posix.cc
@@ -21,15 +21,16 @@
namespace __tsan {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void InitializeShadowMemory() {
// Map memory shadow.
uptr shadow =
- (uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg, "shadow");
- if (shadow != kShadowBeg) {
+ (uptr)MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(),
+ "shadow");
+ if (shadow != ShadowBeg()) {
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
+ "to link with -pie (%p, %p).\n", shadow, ShadowBeg());
Die();
}
// This memory range is used for thread stacks and large user mmaps.
@@ -44,29 +45,50 @@ void InitializeShadowMemory() {
const uptr kMadviseRangeBeg = 0xff00000000ull;
const uptr kMadviseRangeSize = 0x0100000000ull;
#elif defined(__aarch64__)
- const uptr kMadviseRangeBeg = 0x7e00000000ull;
- const uptr kMadviseRangeSize = 0x0100000000ull;
+ uptr kMadviseRangeBeg = 0;
+ uptr kMadviseRangeSize = 0;
+ if (vmaSize == 39) {
+ kMadviseRangeBeg = 0x7d00000000ull;
+ kMadviseRangeSize = 0x0300000000ull;
+ } else if (vmaSize == 42) {
+ kMadviseRangeBeg = 0x3f000000000ull;
+ kMadviseRangeSize = 0x01000000000ull;
+ } else {
+ DCHECK(0);
+ }
+#elif defined(__powerpc64__)
+ uptr kMadviseRangeBeg = 0;
+ uptr kMadviseRangeSize = 0;
+ if (vmaSize == 44) {
+ kMadviseRangeBeg = 0x0f60000000ull;
+ kMadviseRangeSize = 0x0010000000ull;
+ } else if (vmaSize == 46) {
+ kMadviseRangeBeg = 0x3f0000000000ull;
+ kMadviseRangeSize = 0x010000000000ull;
+ } else {
+ DCHECK(0);
+ }
#endif
NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg),
kMadviseRangeSize * kShadowMultiplier);
// Meta shadow is compressing and we don't flush it,
// so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory.
// On one program it reduces memory consumption from 5GB to 2.5GB.
- NoHugePagesInRegion(kMetaShadowBeg, kMetaShadowEnd - kMetaShadowBeg);
+ NoHugePagesInRegion(MetaShadowBeg(), MetaShadowEnd() - MetaShadowBeg());
if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
+ DontDumpShadowMemory(ShadowBeg(), ShadowEnd() - ShadowBeg());
DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
- kShadowBeg, kShadowEnd,
- (kShadowEnd - kShadowBeg) >> 30);
+ ShadowBeg(), ShadowEnd(),
+ (ShadowEnd() - ShadowBeg()) >> 30);
// Map meta shadow.
- uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
+ uptr meta_size = MetaShadowEnd() - MetaShadowBeg();
uptr meta =
- (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size, "meta shadow");
- if (meta != kMetaShadowBeg) {
+ (uptr)MmapFixedNoReserve(MetaShadowBeg(), meta_size, "meta shadow");
+ if (meta != MetaShadowBeg()) {
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
Printf("FATAL: Make sure to compile with -fPIE and "
- "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
+ "to link with -pie (%p, %p).\n", meta, MetaShadowBeg());
Die();
}
if (common_flags()->use_madv_dontdump)
@@ -81,7 +103,7 @@ static void ProtectRange(uptr beg, uptr end) {
CHECK_LE(beg, end);
if (beg == end)
return;
- if (beg != (uptr)MmapNoAccess(beg, end - beg)) {
+ if (beg != (uptr)MmapFixedNoAccess(beg, end - beg)) {
Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
Printf("FATAL: Make sure you are not using unlimited stack\n");
Die();
@@ -95,25 +117,30 @@ void CheckAndProtect() {
while (proc_maps.Next(&p, &end, 0, 0, 0, &prot)) {
if (IsAppMem(p))
continue;
- if (p >= kHeapMemEnd &&
+ if (p >= HeapMemEnd() &&
p < HeapEnd())
continue;
if (prot == 0) // Zero page or mprotected.
continue;
- if (p >= kVdsoBeg) // vdso
+ if (p >= VdsoBeg()) // vdso
break;
Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
Die();
}
- ProtectRange(kLoAppMemEnd, kShadowBeg);
- ProtectRange(kShadowEnd, kMetaShadowBeg);
- ProtectRange(kMetaShadowEnd, kTraceMemBeg);
+ ProtectRange(LoAppMemEnd(), ShadowBeg());
+ ProtectRange(ShadowEnd(), MetaShadowBeg());
+#ifdef TSAN_MID_APP_RANGE
+ ProtectRange(MetaShadowEnd(), MidAppMemBeg());
+ ProtectRange(MidAppMemEnd(), TraceMemBeg());
+#else
+ ProtectRange(MetaShadowEnd(), TraceMemBeg());
+#endif
// Memory for traces is mapped lazily in MapThreadTrace.
// Protect the whole range for now, so that user does not map something here.
- ProtectRange(kTraceMemBeg, kTraceMemEnd);
- ProtectRange(kTraceMemEnd, kHeapMemBeg);
- ProtectRange(HeapEnd(), kHiAppMemBeg);
+ ProtectRange(TraceMemBeg(), TraceMemEnd());
+ ProtectRange(TraceMemEnd(), HeapMemBeg());
+ ProtectRange(HeapEnd(), HiAppMemBeg());
}
#endif
diff --git a/libsanitizer/tsan/tsan_platform_windows.cc b/libsanitizer/tsan/tsan_platform_windows.cc
index ccea22ed66e..54ec6a655df 100644
--- a/libsanitizer/tsan/tsan_platform_windows.cc
+++ b/libsanitizer/tsan/tsan_platform_windows.cc
@@ -29,6 +29,9 @@ void FlushShadowMemory() {
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
}
+void InitializePlatformEarly() {
+}
+
void InitializePlatform() {
}
diff --git a/libsanitizer/tsan/tsan_ppc_regs.h b/libsanitizer/tsan/tsan_ppc_regs.h
new file mode 100644
index 00000000000..15bd10ad96b
--- /dev/null
+++ b/libsanitizer/tsan/tsan_ppc_regs.h
@@ -0,0 +1,94 @@
+#define r0 0
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+#define f0 0
+#define f1 1
+#define f2 2
+#define f3 3
+#define f4 4
+#define f5 5
+#define f6 6
+#define f7 7
+#define f8 8
+#define f9 9
+#define f10 10
+#define f11 11
+#define f12 12
+#define f13 13
+#define f14 14
+#define f15 15
+#define f16 16
+#define f17 17
+#define f18 18
+#define f19 19
+#define f20 20
+#define f21 21
+#define f22 22
+#define f23 23
+#define f24 24
+#define f25 25
+#define f26 26
+#define f27 27
+#define f28 28
+#define f29 29
+#define f30 30
+#define f31 31
+#define v0 0
+#define v1 1
+#define v2 2
+#define v3 3
+#define v4 4
+#define v5 5
+#define v6 6
+#define v7 7
+#define v8 8
+#define v9 9
+#define v10 10
+#define v11 11
+#define v12 12
+#define v13 13
+#define v14 14
+#define v15 15
+#define v16 16
+#define v17 17
+#define v18 18
+#define v19 19
+#define v20 20
+#define v21 21
+#define v22 22
+#define v23 23
+#define v24 24
+#define v25 25
+#define v26 26
+#define v27 27
+#define v28 28
+#define v29 29
+#define v30 30
+#define v31 31
diff --git a/libsanitizer/tsan/tsan_preinit.cc b/libsanitizer/tsan/tsan_preinit.cc
new file mode 100644
index 00000000000..d5d1659c09b
--- /dev/null
+++ b/libsanitizer/tsan/tsan_preinit.cc
@@ -0,0 +1,25 @@
+//===-- tsan_preinit.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.
+//
+// Call __tsan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "tsan_interface.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+
+// The symbol is called __local_tsan_preinit, because it's not intended to be
+// exported.
+// This code linked into the main executable when -fsanitize=thread is in
+// the link flags. It can only use exported interface functions.
+__attribute__((section(".preinit_array"), used))
+void (*__local_tsan_preinit)(void) = __tsan_init;
+
+#endif
diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc
index 119b1ec1da9..ba3e34fbfa5 100644
--- a/libsanitizer/tsan/tsan_report.cc
+++ b/libsanitizer/tsan/tsan_report.cc
@@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
// FIXME(dvyukov): it must be leaking a lot of memory.
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
const int kThreadBufSize = 32;
const char *thread_name(char *buf, int tid) {
@@ -94,6 +94,8 @@ static const char *ReportTypeString(ReportType typ) {
return "destroy of a locked mutex";
if (typ == ReportTypeMutexDoubleLock)
return "double lock of a mutex";
+ if (typ == ReportTypeMutexInvalidAccess)
+ return "use of an invalid mutex (e.g. uninitialized or destroyed)";
if (typ == ReportTypeMutexBadUnlock)
return "unlock of an unlocked mutex (or by a wrong thread)";
if (typ == ReportTypeMutexBadReadLock)
@@ -232,7 +234,7 @@ static void PrintThread(const ReportThread *rt) {
Printf(" '%s'", rt->name);
char thrbuf[kThreadBufSize];
Printf(" (tid=%zu, %s) created by %s",
- rt->pid, rt->running ? "running" : "finished",
+ rt->os_id, rt->running ? "running" : "finished",
thread_name(thrbuf, rt->parent_tid));
if (rt->stack)
Printf(" at:");
@@ -265,10 +267,15 @@ static bool FrameIsInternal(const SymbolizedStack *frame) {
if (frame == 0)
return false;
const char *file = frame->info.file;
- return file != 0 &&
- (internal_strstr(file, "tsan_interceptors.cc") ||
- internal_strstr(file, "sanitizer_common_interceptors.inc") ||
- internal_strstr(file, "tsan_interface_"));
+ const char *module = frame->info.module;
+ if (file != 0 &&
+ (internal_strstr(file, "tsan_interceptors.cc") ||
+ internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+ internal_strstr(file, "tsan_interface_")))
+ return true;
+ if (module != 0 && (internal_strstr(module, "libclang_rt.tsan_")))
+ return true;
+ return false;
}
static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
@@ -352,7 +359,7 @@ void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
}
-#else // #ifndef SANITIZER_GO
+#else // #if !SANITIZER_GO
const int kMainThreadId = 1;
@@ -372,9 +379,9 @@ void PrintStack(const ReportStack *ent) {
static void PrintMop(const ReportMop *mop, bool first) {
Printf("\n");
- Printf("%s by ",
+ Printf("%s at %p by ",
(first ? (mop->write ? "Write" : "Read")
- : (mop->write ? "Previous write" : "Previous read")));
+ : (mop->write ? "Previous write" : "Previous read")), mop->addr);
if (mop->tid == kMainThreadId)
Printf("main goroutine:\n");
else
@@ -382,6 +389,31 @@ static void PrintMop(const ReportMop *mop, bool first) {
PrintStack(mop->stack);
}
+static void PrintLocation(const ReportLocation *loc) {
+ switch (loc->type) {
+ case ReportLocationHeap: {
+ Printf("\n");
+ Printf("Heap block of size %zu at %p allocated by ",
+ loc->heap_chunk_size, loc->heap_chunk_start);
+ if (loc->tid == kMainThreadId)
+ Printf("main goroutine:\n");
+ else
+ Printf("goroutine %d:\n", loc->tid);
+ PrintStack(loc->stack);
+ break;
+ }
+ case ReportLocationGlobal: {
+ Printf("\n");
+ Printf("Global var %s of size %zu at %p declared at %s:%zu\n",
+ loc->global.name, loc->global.size, loc->global.start,
+ loc->global.file, loc->global.line);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
static void PrintThread(const ReportThread *rt) {
if (rt->id == kMainThreadId)
return;
@@ -397,6 +429,8 @@ void PrintReport(const ReportDesc *rep) {
Printf("WARNING: DATA RACE");
for (uptr i = 0; i < rep->mops.Size(); i++)
PrintMop(rep->mops[i], i == 0);
+ for (uptr i = 0; i < rep->locs.Size(); i++)
+ PrintLocation(rep->locs[i]);
for (uptr i = 0; i < rep->threads.Size(); i++)
PrintThread(rep->threads[i]);
} else if (rep->typ == ReportTypeDeadlock) {
diff --git a/libsanitizer/tsan/tsan_report.h b/libsanitizer/tsan/tsan_report.h
index 68924edb547..e51ed4f50f8 100644
--- a/libsanitizer/tsan/tsan_report.h
+++ b/libsanitizer/tsan/tsan_report.h
@@ -25,6 +25,7 @@ enum ReportType {
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,
ReportTypeMutexDoubleLock,
+ ReportTypeMutexInvalidAccess,
ReportTypeMutexBadUnlock,
ReportTypeMutexBadReadLock,
ReportTypeMutexBadReadUnlock,
@@ -84,7 +85,7 @@ struct ReportLocation {
struct ReportThread {
int id;
- uptr pid;
+ uptr os_id;
bool running;
char *name;
int parent_tid;
diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc
index 4fceca6f41f..07fa165e939 100644
--- a/libsanitizer/tsan/tsan_rtl.cc
+++ b/libsanitizer/tsan/tsan_rtl.cc
@@ -42,7 +42,7 @@ extern "C" void __tsan_resume() {
namespace __tsan {
-#if !defined(SANITIZER_GO) && !SANITIZER_MAC
+#if !SANITIZER_GO && !SANITIZER_MAC
THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
#endif
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
@@ -53,12 +53,12 @@ Context *ctx;
bool OnFinalize(bool failed);
void OnInitialize();
#else
-SANITIZER_INTERFACE_ATTRIBUTE
-bool WEAK OnFinalize(bool failed) {
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+bool OnFinalize(bool failed) {
return failed;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void WEAK OnInitialize() {}
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+void OnInitialize() {}
#endif
static char thread_registry_placeholder[sizeof(ThreadRegistry)];
@@ -84,7 +84,7 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
return new(mem) ThreadContext(tid);
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static const u32 kThreadQuarantineSize = 16;
#else
static const u32 kThreadQuarantineSize = 64;
@@ -115,7 +115,7 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
// , ignore_reads_and_writes()
// , ignore_interceptors()
, clock(tid, reuse_count)
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
, jmp_bufs(MBlockJmpBuf)
#endif
, tid(tid)
@@ -124,13 +124,13 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
, stk_size(stk_size)
, tls_addr(tls_addr)
, tls_size(tls_size)
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
, last_sleep_clock(tid)
#endif
{
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
uptr n_threads;
uptr n_running_threads;
@@ -233,14 +233,17 @@ static void StopBackgroundThread() {
void DontNeedShadowFor(uptr addr, uptr size) {
uptr shadow_beg = MemToShadow(addr);
uptr shadow_end = MemToShadow(addr + size);
- FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
+ ReleaseMemoryToOS(shadow_beg, shadow_end - shadow_beg);
}
void MapShadow(uptr addr, uptr size) {
// Global data is not 64K aligned, but there are no adjacent mappings,
// so we can get away with unaligned mapping.
// CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
- MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier, "shadow");
+ const uptr kPageSize = GetPageSizeCached();
+ uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), kPageSize);
+ uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), kPageSize);
+ MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow");
// Meta shadow is 2:1, so tread carefully.
static bool data_mapped = false;
@@ -271,8 +274,8 @@ void MapShadow(uptr addr, uptr size) {
void MapThreadTrace(uptr addr, uptr size, const char *name) {
DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
- CHECK_GE(addr, kTraceMemBeg);
- CHECK_LE(addr + size, kTraceMemEnd);
+ CHECK_GE(addr, TraceMemBeg());
+ CHECK_LE(addr + size, TraceMemEnd());
CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment
uptr addr1 = (uptr)MmapFixedNoReserve(addr, size, name);
if (addr1 != addr) {
@@ -283,13 +286,17 @@ void MapThreadTrace(uptr addr, uptr size, const char *name) {
}
static void CheckShadowMapping() {
- for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
- const uptr beg = UserRegions[i];
- const uptr end = UserRegions[i + 1];
+ uptr beg, end;
+ for (int i = 0; GetUserRegion(i, &beg, &end); i++) {
+ // Skip cases for empty regions (heap definition for architectures that
+ // do not use 64-bit allocator).
+ if (beg == end)
+ continue;
VPrintf(3, "checking shadow region %p-%p\n", beg, end);
+ uptr prev = 0;
for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
- for (int x = -1; x <= 1; x++) {
- const uptr p = p0 + x;
+ for (int x = -(int)kShadowCell; x <= (int)kShadowCell; x += kShadowCell) {
+ const uptr p = RoundDown(p0 + x, kShadowCell);
if (p < beg || p >= end)
continue;
const uptr s = MemToShadow(p);
@@ -297,8 +304,18 @@ static void CheckShadowMapping() {
VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m);
CHECK(IsAppMem(p));
CHECK(IsShadowMem(s));
- CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s));
+ CHECK_EQ(p, ShadowToMem(s));
CHECK(IsMetaMem(m));
+ if (prev) {
+ // Ensure that shadow and meta mappings are linear within a single
+ // user range. Lots of code that processes memory ranges assumes it.
+ const uptr prev_s = MemToShadow(prev);
+ const uptr prev_m = (uptr)MemToMeta(prev);
+ CHECK_EQ(s - prev_s, (p - prev) * kShadowMultiplier);
+ CHECK_EQ((m - prev_m) / kMetaShadowSize,
+ (p - prev) / kMetaShadowCell);
+ }
+ prev = p;
}
}
}
@@ -317,26 +334,35 @@ void Initialize(ThreadState *thr) {
SetCheckFailedCallback(TsanCheckFailed);
ctx = new(ctx_placeholder) Context;
- const char *options = GetEnv(kTsanOptionsEnv);
+ const char *options = GetEnv(SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS");
CacheBinaryName();
InitializeFlags(&ctx->flags, options);
- CheckVMASize();
-#ifndef SANITIZER_GO
+ AvoidCVE_2016_2143();
+ InitializePlatformEarly();
+#if !SANITIZER_GO
+ // Re-exec ourselves if we need to set additional env or command line args.
+ MaybeReexec();
+
InitializeAllocator();
ReplaceSystemMalloc();
#endif
+ if (common_flags()->detect_deadlocks)
+ ctx->dd = DDetector::Create(flags());
+ Processor *proc = ProcCreate();
+ ProcWire(proc, thr);
InitializeInterceptors();
CheckShadowMapping();
InitializePlatform();
InitializeMutex();
InitializeDynamicAnnotations();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
InitializeShadowMemory();
+ InitializeAllocatorLate();
#endif
// Setup correct file descriptor for error reports.
__sanitizer_set_report_path(common_flags()->log_path);
InitializeSuppressions();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
InitializeLibIgnore();
Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
// On MIPS, TSan initialization is run before
@@ -347,8 +373,6 @@ void Initialize(ThreadState *thr) {
SetSandboxingCallback(StopBackgroundThread);
#endif
#endif
- if (common_flags()->detect_deadlocks)
- ctx->dd = DDetector::Create(flags());
VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n",
(int)internal_getpid());
@@ -362,6 +386,10 @@ void Initialize(ThreadState *thr) {
#endif
ctx->initialized = true;
+#if !SANITIZER_GO
+ Symbolizer::LateInitialize();
+#endif
+
if (flags()->stop_on_start) {
Printf("ThreadSanitizer is suspended at startup (pid %d)."
" Call __tsan_resume().\n",
@@ -384,7 +412,7 @@ int Finalize(ThreadState *thr) {
CommonSanitizerReportMutex.Unlock();
ctx->report_mtx.Unlock();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (Verbosity()) AllocatorPrintStats();
#endif
@@ -392,7 +420,7 @@ int Finalize(ThreadState *thr) {
if (ctx->nreported) {
failed = true;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
#else
Printf("Found %d data race(s)\n", ctx->nreported);
@@ -407,7 +435,7 @@ int Finalize(ThreadState *thr) {
if (common_flags()->print_suppressions)
PrintMatchedSuppressions();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (flags()->print_benign)
PrintMatchedBenignRaces();
#endif
@@ -422,7 +450,7 @@ int Finalize(ThreadState *thr) {
return failed ? common_flags()->exitcode : 0;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void ForkBefore(ThreadState *thr, uptr pc) {
ctx->thread_registry->Lock();
ctx->report_mtx.Lock();
@@ -455,7 +483,7 @@ void ForkChildAfter(ThreadState *thr, uptr pc) {
}
#endif
-#ifdef SANITIZER_GO
+#if SANITIZER_GO
NOINLINE
void GrowShadowStack(ThreadState *thr) {
const int sz = thr->shadow_stack_end - thr->shadow_stack;
@@ -474,7 +502,7 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {
if (!thr->is_inited) // May happen during bootstrap.
return 0;
if (pc != 0) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#else
if (thr->shadow_stack_pos == thr->shadow_stack_end)
@@ -520,7 +548,7 @@ uptr TraceParts() {
return TraceSize() / kTracePartSize;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
extern "C" void __tsan_trace_switch() {
TraceSwitch(cur_thread());
}
@@ -553,7 +581,7 @@ void HandleRace(ThreadState *thr, u64 *shadow_mem,
thr->racy_state[0] = cur.raw();
thr->racy_state[1] = old.raw();
thr->racy_shadow_addr = shadow_mem;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
HACKY_CALL(__tsan_report_race);
#else
ReportRace(thr);
@@ -750,7 +778,7 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
}
#endif
- if (kCppMode && *shadow_mem == kShadowRodata) {
+ if (!SANITIZER_GO && *shadow_mem == kShadowRodata) {
// Access to .rodata section, no races here.
// Measurements show that it can be 10-20% of all memory accesses.
StatInc(thr, StatMop);
@@ -837,7 +865,7 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
// UnmapOrDie/MmapFixedNoReserve does not work on Windows,
// so we do it only for C/C++.
- if (kGoMode || size < common_flags()->clear_shadow_mmap_threshold) {
+ if (SANITIZER_GO || size < common_flags()->clear_shadow_mmap_threshold) {
u64 *p = (u64*)MemToShadow(addr);
CHECK(IsShadowMem((uptr)p));
CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
@@ -923,7 +951,7 @@ void FuncEntry(ThreadState *thr, uptr pc) {
// Shadow stack maintenance can be replaced with
// stack unwinding during trace switch (which presumably must be faster).
DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#else
if (thr->shadow_stack_pos == thr->shadow_stack_end)
@@ -943,7 +971,7 @@ void FuncExit(ThreadState *thr) {
}
DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#endif
thr->shadow_stack_pos--;
@@ -954,7 +982,7 @@ void ThreadIgnoreBegin(ThreadState *thr, uptr pc) {
thr->ignore_reads_and_writes++;
CHECK_GT(thr->ignore_reads_and_writes, 0);
thr->fast_state.SetIgnoreBit();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (!ctx->after_multithreaded_fork)
thr->mop_ignore_set.Add(CurrentStackId(thr, pc));
#endif
@@ -966,7 +994,7 @@ void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
CHECK_GE(thr->ignore_reads_and_writes, 0);
if (thr->ignore_reads_and_writes == 0) {
thr->fast_state.ClearIgnoreBit();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
thr->mop_ignore_set.Reset();
#endif
}
@@ -976,7 +1004,7 @@ void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
thr->ignore_sync++;
CHECK_GT(thr->ignore_sync, 0);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (!ctx->after_multithreaded_fork)
thr->sync_ignore_set.Add(CurrentStackId(thr, pc));
#endif
@@ -986,7 +1014,7 @@ void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
thr->ignore_sync--;
CHECK_GE(thr->ignore_sync, 0);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (thr->ignore_sync == 0)
thr->sync_ignore_set.Reset();
#endif
@@ -1010,7 +1038,7 @@ void build_consistency_nostats() {}
} // namespace __tsan
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Must be included in this file to make sure everything is inlined.
#include "tsan_interface_inl.h"
#endif
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index 12587dd203e..522c76002a1 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -50,9 +50,9 @@
namespace __tsan {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
struct MapUnmapCallback;
-#if defined(__mips64) || defined(__aarch64__)
+#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
static const uptr kAllocatorSpace = 0;
static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kAllocatorRegionSizeLog = 20;
@@ -64,8 +64,15 @@ typedef SizeClassAllocator32<kAllocatorSpace, kAllocatorSize, 0,
CompactSizeClassMap, kAllocatorRegionSizeLog, ByteMap,
MapUnmapCallback> PrimaryAllocator;
#else
-typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
- DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
+struct AP64 { // Allocator64 parameters. Deliberately using a short name.
+ static const uptr kSpaceBeg = Mapping::kHeapMemBeg;
+ static const uptr kSpaceSize = Mapping::kHeapMemEnd - Mapping::kHeapMemBeg;
+ static const uptr kMetadataSize = 0;
+ typedef DefaultSizeClassMap SizeClassMap;
+ typedef __tsan::MapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator64<AP64> PrimaryAllocator;
#endif
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
@@ -322,6 +329,36 @@ struct JmpBuf {
uptr *shadow_stack_pos;
};
+// A Processor represents a physical thread, or a P for Go.
+// It is used to store internal resources like allocate cache, and does not
+// participate in race-detection logic (invisible to end user).
+// In C++ it is tied to an OS thread just like ThreadState, however ideally
+// it should be tied to a CPU (this way we will have fewer allocator caches).
+// In Go it is tied to a P, so there are significantly fewer Processor's than
+// ThreadState's (which are tied to Gs).
+// A ThreadState must be wired with a Processor to handle events.
+struct Processor {
+ ThreadState *thr; // currently wired thread, or nullptr
+#if !SANITIZER_GO
+ AllocatorCache alloc_cache;
+ InternalAllocatorCache internal_alloc_cache;
+#endif
+ DenseSlabAllocCache block_cache;
+ DenseSlabAllocCache sync_cache;
+ DenseSlabAllocCache clock_cache;
+ DDPhysicalThread *dd_pt;
+};
+
+#if !SANITIZER_GO
+// ScopedGlobalProcessor temporary setups a global processor for the current
+// thread, if it does not have one. Intended for interceptors that can run
+// at the very thread end, when we already destroyed the thread processor.
+struct ScopedGlobalProcessor {
+ ScopedGlobalProcessor();
+ ~ScopedGlobalProcessor();
+};
+#endif
+
// This struct is stored in TLS.
struct ThreadState {
FastState fast_state;
@@ -343,7 +380,7 @@ struct ThreadState {
int ignore_reads_and_writes;
int ignore_sync;
// Go does not support ignores.
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
IgnoreSet mop_ignore_set;
IgnoreSet sync_ignore_set;
#endif
@@ -356,9 +393,7 @@ struct ThreadState {
u64 racy_state[2];
MutexSet mset;
ThreadClock clock;
-#ifndef SANITIZER_GO
- AllocatorCache alloc_cache;
- InternalAllocatorCache internal_alloc_cache;
+#if !SANITIZER_GO
Vector<JmpBuf> jmp_bufs;
int ignore_interceptors;
#endif
@@ -382,17 +417,20 @@ struct ThreadState {
#if SANITIZER_DEBUG && !SANITIZER_GO
InternalDeadlockDetector internal_deadlock_detector;
#endif
- DDPhysicalThread *dd_pt;
DDLogicalThread *dd_lt;
+ // Current wired Processor, or nullptr. Required to handle any events.
+ Processor *proc1;
+#if !SANITIZER_GO
+ Processor *proc() { return proc1; }
+#else
+ Processor *proc();
+#endif
+
atomic_uintptr_t in_signal_handler;
ThreadSignalContext *signal_ctx;
- DenseSlabAllocCache block_cache;
- DenseSlabAllocCache sync_cache;
- DenseSlabAllocCache clock_cache;
-
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
u32 last_sleep_stack_id;
ThreadClock last_sleep_clock;
#endif
@@ -401,14 +439,16 @@ struct ThreadState {
// If set, malloc must not be called.
int nomalloc;
+ const ReportDesc *current_report;
+
explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
unsigned reuse_count,
uptr stk_addr, uptr stk_size,
uptr tls_addr, uptr tls_size);
};
-#ifndef SANITIZER_GO
-#if SANITIZER_MAC
+#if !SANITIZER_GO
+#if SANITIZER_MAC || SANITIZER_ANDROID
ThreadState *cur_thread();
void cur_thread_finalize();
#else
@@ -418,7 +458,7 @@ INLINE ThreadState *cur_thread() {
return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
}
INLINE void cur_thread_finalize() { }
-#endif // SANITIZER_MAC
+#endif // SANITIZER_MAC || SANITIZER_ANDROID
#endif // SANITIZER_GO
class ThreadContext : public ThreadContextBase {
@@ -505,13 +545,13 @@ extern Context *ctx; // The one and the only global runtime context.
struct ScopedIgnoreInterceptors {
ScopedIgnoreInterceptors() {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
cur_thread()->ignore_interceptors++;
#endif
}
~ScopedIgnoreInterceptors() {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
cur_thread()->ignore_interceptors--;
#endif
}
@@ -680,6 +720,11 @@ void ThreadSetName(ThreadState *thr, const char *name);
int ThreadCount(ThreadState *thr);
void ProcessPendingSignals(ThreadState *thr);
+Processor *ProcCreate();
+void ProcDestroy(Processor *proc);
+void ProcWire(Processor *proc, ThreadState *thr);
+void ProcUnwire(Processor *proc, ThreadState *thr);
+
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
bool rw, bool recursive, bool linker_init);
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
@@ -690,6 +735,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false);
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
+void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr);
void Acquire(ThreadState *thr, uptr pc, uptr addr);
// AcquireGlobal synchronizes the current thread with all other threads.
@@ -745,7 +791,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
StatInc(thr, StatEvents);
u64 pos = fs.GetTracePos();
if (UNLIKELY((pos % kTracePartSize) == 0)) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
HACKY_CALL(__tsan_trace_switch);
#else
TraceSwitch(thr);
@@ -757,9 +803,9 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
*evp = ev;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
uptr ALWAYS_INLINE HeapEnd() {
- return kHeapMemEnd + PrimaryAllocator::AdditionalSize();
+ return HeapMemEnd() + PrimaryAllocator::AdditionalSize();
}
#endif
diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S
index ef06f0444ae..ab5a830d60c 100644
--- a/libsanitizer/tsan/tsan_rtl_aarch64.S
+++ b/libsanitizer/tsan/tsan_rtl_aarch64.S
@@ -1,6 +1,4 @@
#include "sanitizer_common/sanitizer_asm.h"
-
-.section .bss
.type __tsan_pointer_chk_guard, %object
.size __tsan_pointer_chk_guard, 8
__tsan_pointer_chk_guard:
diff --git a/libsanitizer/tsan/tsan_rtl_amd64.S b/libsanitizer/tsan/tsan_rtl_amd64.S
index 6df36a500a7..caa832375e5 100644
--- a/libsanitizer/tsan/tsan_rtl_amd64.S
+++ b/libsanitizer/tsan/tsan_rtl_amd64.S
@@ -1,7 +1,13 @@
#include "sanitizer_common/sanitizer_asm.h"
-.hidden __tsan_trace_switch
-.globl __tsan_trace_switch_thunk
-__tsan_trace_switch_thunk:
+#if !defined(__APPLE__)
+.section .text
+#else
+.section __TEXT,__text
+#endif
+
+ASM_HIDDEN(__tsan_trace_switch)
+.globl ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk)
+ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk):
CFI_STARTPROC
# Save scratch registers.
push %rax
@@ -40,7 +46,7 @@ __tsan_trace_switch_thunk:
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
- call __tsan_trace_switch
+ call ASM_TSAN_SYMBOL(__tsan_trace_switch)
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
@@ -79,9 +85,9 @@ __tsan_trace_switch_thunk:
ret
CFI_ENDPROC
-.hidden __tsan_report_race
-.globl __tsan_report_race_thunk
-__tsan_report_race_thunk:
+ASM_HIDDEN(__tsan_report_race)
+.globl ASM_TSAN_SYMBOL(__tsan_report_race_thunk)
+ASM_TSAN_SYMBOL(__tsan_report_race_thunk):
CFI_STARTPROC
# Save scratch registers.
push %rax
@@ -120,7 +126,7 @@ __tsan_report_race_thunk:
shr $4, %rsp # clear 4 lsb, align to 16
shl $4, %rsp
- call __tsan_report_race
+ call ASM_TSAN_SYMBOL(__tsan_report_race)
# Unalign stack frame back.
mov %rbx, %rsp # restore the original rsp
@@ -159,11 +165,13 @@ __tsan_report_race_thunk:
ret
CFI_ENDPROC
-.hidden __tsan_setjmp
+ASM_HIDDEN(__tsan_setjmp)
+#if !defined(__APPLE__)
.comm _ZN14__interception11real_setjmpE,8,8
-.globl setjmp
-.type setjmp, @function
-setjmp:
+#endif
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -173,29 +181,38 @@ setjmp:
#if defined(__FreeBSD__)
lea 8(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
pop %rdi
CFI_ADJUST_CFA_OFFSET(-8)
CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(setjmp)
+#endif
CFI_ENDPROC
-.size setjmp, .-setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
.comm _ZN14__interception12real__setjmpE,8,8
-.globl _setjmp
-.type _setjmp, @function
-_setjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -205,29 +222,38 @@ _setjmp:
#if defined(__FreeBSD__)
lea 8(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 16(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 16(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
pop %rdi
CFI_ADJUST_CFA_OFFSET(-8)
CFI_RESTORE(%rdi)
// tail jump to libc setjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(_setjmp)
+#endif
CFI_ENDPROC
-.size _setjmp, .-_setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
.comm _ZN14__interception14real_sigsetjmpE,8,8
-.globl sigsetjmp
-.type sigsetjmp, @function
-sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -244,14 +270,19 @@ sigsetjmp:
#if defined(__FreeBSD__)
lea 24(%rsp), %rdi
mov %rdi, %rsi
-#else
+#elif defined(__APPLE__)
+ lea 32(%rsp), %rdi
+ mov %rdi, %rsi
+#elif defined(__linux__)
lea 32(%rsp), %rdi
mov %rdi, %rsi
xor %fs:0x30, %rsi // magic mangling of rsp (see libc setjmp)
rol $0x11, %rsi
+#else
+# error "Unknown platform"
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// unalign stack frame
add $8, %rsp
CFI_ADJUST_CFA_OFFSET(-8)
@@ -265,15 +296,20 @@ sigsetjmp:
CFI_RESTORE(%rdi)
// tail jump to libc sigsetjmp
movl $0, %eax
+#if !defined(__APPLE__)
movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
+#else
+ jmp ASM_TSAN_SYMBOL(sigsetjmp)
+#endif
CFI_ENDPROC
-.size sigsetjmp, .-sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+#if !defined(__APPLE__)
.comm _ZN14__interception16real___sigsetjmpE,8,8
-.globl __sigsetjmp
-.type __sigsetjmp, @function
-__sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp):
CFI_STARTPROC
// save env parameter
push %rdi
@@ -297,7 +333,7 @@ __sigsetjmp:
rol $0x11, %rsi
#endif
// call tsan interceptor
- call __tsan_setjmp
+ call ASM_TSAN_SYMBOL(__tsan_setjmp)
// unalign stack frame
add $8, %rsp
CFI_ADJUST_CFA_OFFSET(-8)
@@ -314,7 +350,8 @@ __sigsetjmp:
movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx
jmp *(%rdx)
CFI_ENDPROC
-.size __sigsetjmp, .-__sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+#endif // !defined(__APPLE__)
#if defined(__FreeBSD__) || defined(__linux__)
/* We do not need executable stack. */
diff --git a/libsanitizer/tsan/tsan_rtl_mips64.S b/libsanitizer/tsan/tsan_rtl_mips64.S
new file mode 100644
index 00000000000..b1c9d8bb12d
--- /dev/null
+++ b/libsanitizer/tsan/tsan_rtl_mips64.S
@@ -0,0 +1,212 @@
+.section .text
+.hidden __tsan_setjmp
+.comm _ZN14__interception11real_setjmpE,8,8
+.globl setjmp
+.type setjmp, @function
+setjmp:
+
+ // save env parameters
+ daddiu $sp,$sp,-40
+ sd $s0,32($sp)
+ sd $ra,24($sp)
+ sd $fp,16($sp)
+ sd $gp,8($sp)
+
+ // calculate and save pointer to GOT
+ lui $gp,%hi(%neg(%gp_rel(setjmp)))
+ daddu $gp,$gp,$t9
+ daddiu $gp,$gp,%lo(%neg(%gp_rel(setjmp)))
+ move $s0,$gp
+
+ // save jmp_buf
+ sd $a0,0($sp)
+
+ // obtain $sp
+ dadd $a0,$zero,$sp
+
+ // call tsan interceptor
+ jal __tsan_setjmp
+ daddiu $a1,$a0,40
+
+ // restore jmp_buf
+ ld $a0,0($sp)
+
+ // restore gp
+ move $gp,$s0
+
+ // load pointer of libc setjmp to t9
+ dla $t9,(_ZN14__interception11real_setjmpE)
+
+ // restore env parameters
+ ld $gp,8($sp)
+ ld $fp,16($sp)
+ ld $ra,24($sp)
+ ld $s0,32($sp)
+ daddiu $sp,$sp,40
+
+ // tail jump to libc setjmp
+ ld $t9,0($t9)
+ jr $t9
+ nop
+
+.size setjmp, .-setjmp
+
+.hidden __tsan_setjmp
+.globl _setjmp
+.comm _ZN14__interception12real__setjmpE,8,8
+.type _setjmp, @function
+_setjmp:
+
+ // Save env parameters
+ daddiu $sp,$sp,-40
+ sd $s0,32($sp)
+ sd $ra,24($sp)
+ sd $fp,16($sp)
+ sd $gp,8($sp)
+
+ // calculate and save pointer to GOT
+ lui $gp,%hi(%neg(%gp_rel(_setjmp)))
+ daddu $gp,$gp,$t9
+ daddiu $gp,$gp,%lo(%neg(%gp_rel(_setjmp)))
+ move $s0,$gp
+
+ // save jmp_buf
+ sd $a0,0($sp)
+
+ // obtain $sp
+ dadd $a0,$zero,$sp
+
+ // call tsan interceptor
+ jal __tsan_setjmp
+ daddiu $a1,$a0,40
+
+ // restore jmp_buf
+ ld $a0,0($sp)
+
+ // restore gp
+ move $gp,$s0
+
+ // load pointer of libc _setjmp to t9
+ dla $t9,(_ZN14__interception12real__setjmpE)
+
+ // restore env parameters
+ ld $gp,8($sp)
+ ld $fp,16($sp)
+ ld $ra,24($sp)
+ ld $s0,32($sp)
+ daddiu $sp,$sp,40
+
+ // tail jump to libc _setjmp
+ ld $t9,0($t9)
+ jr $t9
+ nop
+
+.size _setjmp, .-_setjmp
+
+.hidden __tsan_setjmp
+.globl sigsetjmp
+.comm _ZN14__interception14real_sigsetjmpE,8,8
+.type sigsetjmp, @function
+sigsetjmp:
+
+ // Save env parameters
+ daddiu $sp,$sp,-48
+ sd $s0,40($sp)
+ sd $ra,32($sp)
+ sd $fp,24($sp)
+ sd $gp,16($sp)
+
+ // calculate and save pointer to GOT
+ lui $gp,%hi(%neg(%gp_rel(sigsetjmp)))
+ daddu $gp,$gp,$t9
+ daddiu $gp,$gp,%lo(%neg(%gp_rel(sigsetjmp)))
+ move $s0,$gp
+
+ // save jmp_buf and savesig
+ sd $a0,0($sp)
+ sd $a1,8($sp)
+
+ // obtain $sp
+ dadd $a0,$zero,$sp
+
+ // call tsan interceptor
+ jal __tsan_setjmp
+ daddiu $a1,$a0,48
+
+ // restore jmp_buf and savesig
+ ld $a0,0($sp)
+ ld $a1,8($sp)
+
+ // restore gp
+ move $gp,$s0
+
+ // load pointer of libc sigsetjmp to t9
+ dla $t9,(_ZN14__interception14real_sigsetjmpE)
+
+ // restore env parameters
+ ld $gp,16($sp)
+ ld $fp,24($sp)
+ ld $ra,32($sp)
+ ld $s0,40($sp)
+ daddiu $sp,$sp,48
+
+ // tail jump to libc sigsetjmp
+ ld $t9,0($t9)
+ jr $t9
+ nop
+
+.size sigsetjmp, .-sigsetjmp
+
+.hidden __tsan_setjmp
+.comm _ZN14__interception16real___sigsetjmpE,8,8
+.globl __sigsetjmp
+.type __sigsetjmp, @function
+__sigsetjmp:
+
+ // Save env parameters
+ daddiu $sp,$sp,-48
+ sd $s0,40($sp)
+ sd $ra,32($sp)
+ sd $fp,24($sp)
+ sd $gp,16($sp)
+
+ // calculate and save pointer to GOT
+ lui $gp,%hi(%neg(%gp_rel(__sigsetjmp)))
+ daddu $gp,$gp,$t9
+ daddiu $gp,$gp,%lo(%neg(%gp_rel(__sigsetjmp)))
+ move $s0,$gp
+
+ // save jmp_buf and savesig
+ sd $a0,0($sp)
+ sd $a1,8($sp)
+
+ // obtain $sp
+ dadd $a0,$zero,$sp
+
+ // call tsan interceptor
+ jal __tsan_setjmp
+ daddiu $a1,$a0,48
+
+ // restore jmp_buf and savesig
+ ld $a0,0($sp)
+ ld $a1,8($sp)
+
+ // restore gp
+ move $gp,$s0
+
+ // load pointer to libc __sigsetjmp in t9
+ dla $t9,(_ZN14__interception16real___sigsetjmpE)
+
+ // restore env parameters
+ ld $gp,16($sp)
+ ld $fp,24($sp)
+ ld $ra,32($sp)
+ ld $s0,40($sp)
+ daddiu $sp,$sp,48
+
+ // tail jump to libc __sigsetjmp
+ ld $t9,0($t9)
+ jr $t9
+ nop
+
+.size __sigsetjmp, .-__sigsetjmp
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc
index deb7722f521..e575bbfb7e9 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cc
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cc
@@ -30,7 +30,7 @@ struct Callback : DDCallback {
Callback(ThreadState *thr, uptr pc)
: thr(thr)
, pc(pc) {
- DDCallback::pt = thr->dd_pt;
+ DDCallback::pt = thr->proc()->dd_pt;
DDCallback::lt = thr->dd_lt;
}
@@ -48,7 +48,7 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
uptr addr, u64 mid) {
// In Go, these misuses are either impossible, or detected by std lib,
// or false positives (e.g. unlock in a different thread).
- if (kGoMode)
+ if (SANITIZER_GO)
return;
ThreadRegistryLock l(ctx->thread_registry);
ScopedReport rep(typ);
@@ -74,7 +74,7 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
s->is_rw = rw;
s->is_recursive = recursive;
s->is_linker_init = linker_init;
- if (kCppMode && s->creation_stack_id == 0)
+ if (!SANITIZER_GO && s->creation_stack_id == 0)
s->creation_stack_id = CurrentStackId(thr, pc);
s->mtx.Unlock();
}
@@ -82,21 +82,14 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
StatInc(thr, StatMutexDestroy);
-#ifndef SANITIZER_GO
- // Global mutexes not marked as LINKER_INITIALIZED
- // cause tons of not interesting reports, so just ignore it.
- if (IsGlobalVar(addr))
- return;
-#endif
- if (IsAppMem(addr)) {
- CHECK(!thr->is_freeing);
- thr->is_freeing = true;
- MemoryWrite(thr, pc, addr, kSizeLog1);
- thr->is_freeing = false;
- }
- SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
if (s == 0)
return;
+ if (s->is_linker_init) {
+ // Destroy is no-op for linker-initialized mutexes.
+ s->mtx.Unlock();
+ return;
+ }
if (common_flags()->detect_deadlocks) {
Callback cb(thr, pc);
ctx->dd->MutexDestroy(&cb, &s->dd);
@@ -112,7 +105,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
u64 mid = s->GetId();
u32 last_lock = s->last_lock;
if (!unlock_locked)
- s->Reset(thr); // must not reset it before the report is printed
+ s->Reset(thr->proc()); // must not reset it before the report is printed
s->mtx.Unlock();
if (unlock_locked) {
ThreadRegistryLock l(ctx->thread_registry);
@@ -126,15 +119,23 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
rep.AddStack(trace, true);
rep.AddLocation(addr, 1);
OutputReport(thr, rep);
- }
- if (unlock_locked) {
- SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
if (s != 0) {
- s->Reset(thr);
+ s->Reset(thr->proc());
s->mtx.Unlock();
}
}
thr->mset.Remove(mid);
+ // Imitate a memory write to catch unlock-destroy races.
+ // Do this outside of sync mutex, because it can report a race which locks
+ // sync mutexes.
+ if (IsAppMem(addr)) {
+ CHECK(!thr->is_freeing);
+ thr->is_freeing = true;
+ MemoryWrite(thr, pc, addr, kSizeLog1);
+ thr->is_freeing = false;
+ }
// s will be destroyed and freed in MetaMap::FreeBlock.
}
@@ -192,7 +193,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
int rec = 0;
bool report_bad_unlock = false;
- if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
+ if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) {
if (flags()->report_mutex_bugs && !s->is_broken) {
s->is_broken = true;
report_bad_unlock = true;
@@ -348,11 +349,21 @@ void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
}
+void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) {
+ DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr);
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ u64 mid = s->GetId();
+ s->mtx.Unlock();
+ ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, mid);
+}
+
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
if (thr->ignore_sync)
return;
- SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, false);
+ if (!s)
+ return;
AcquireImpl(thr, pc, &s->clock);
s->mtx.ReadUnlock();
}
@@ -399,7 +410,7 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
@@ -424,7 +435,7 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
if (thr->ignore_sync)
return;
thr->clock.set(thr->fast_state.epoch());
- thr->clock.acquire(&thr->clock_cache, c);
+ thr->clock.acquire(&thr->proc()->clock_cache, c);
StatInc(thr, StatSyncAcquire);
}
@@ -433,7 +444,7 @@ void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
return;
thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&thr->clock_cache, c);
+ thr->clock.release(&thr->proc()->clock_cache, c);
StatInc(thr, StatSyncRelease);
}
@@ -442,7 +453,7 @@ void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
return;
thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(&thr->clock_cache, c);
+ thr->clock.ReleaseStore(&thr->proc()->clock_cache, c);
StatInc(thr, StatSyncRelease);
}
@@ -451,7 +462,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
return;
thr->clock.set(thr->fast_state.epoch());
thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.acq_rel(&thr->clock_cache, c);
+ thr->clock.acq_rel(&thr->proc()->clock_cache, c);
StatInc(thr, StatSyncAcquire);
StatInc(thr, StatSyncRelease);
}
diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
new file mode 100644
index 00000000000..81d309fbd2f
--- /dev/null
+++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
@@ -0,0 +1,286 @@
+#include "tsan_ppc_regs.h"
+ .hidden __tsan_setjmp
+ .globl _setjmp
+ .type _setjmp, @function
+ .align 4
+#if _CALL_ELF == 2
+_setjmp:
+#else
+ .section ".opd","aw"
+ .align 3
+_setjmp:
+ .quad .L._setjmp,.TOC.@tocbase,0
+ .previous
+#endif
+.L._setjmp:
+ mflr r0
+ stdu r1,-48(r1)
+ std r2,24(r1)
+ std r3,32(r1)
+ std r0,40(r1)
+ // r3 is the original stack pointer.
+ addi r3,r1,48
+ // r4 is the mangled stack pointer (see glibc)
+ ld r4,-28696(r13)
+ xor r4,r3,r4
+ // Materialize a TOC in case we were called from libc.
+ // For big-endian, we load the TOC from the OPD. For little-
+ // endian, we use the .TOC. symbol to find it.
+ nop
+ bcl 20,31,0f
+0:
+ mflr r2
+#if _CALL_ELF == 2
+ addis r2,r2,.TOC.-0b@ha
+ addi r2,r2,.TOC.-0b@l
+#else
+ addis r2,r2,_setjmp-0b@ha
+ addi r2,r2,_setjmp-0b@l
+ ld r2,8(r2)
+#endif
+ // Call the interceptor.
+ bl __tsan_setjmp
+ nop
+ // Restore regs needed for setjmp.
+ ld r3,32(r1)
+ ld r0,40(r1)
+ // Emulate the real setjmp function. We do this because we can't
+ // perform a sibcall: The real setjmp function trashes the TOC
+ // pointer, and with a sibcall we have no way to restore it.
+ // This way we can make sure our caller's stack pointer and
+ // link register are saved correctly in the jmpbuf.
+ ld r6,-28696(r13)
+ addi r5,r1,48 // original stack ptr of caller
+ xor r5,r6,r5
+ std r5,0(r3) // mangled stack ptr of caller
+ ld r5,24(r1)
+ std r5,8(r3) // caller's saved TOC pointer
+ xor r0,r6,r0
+ std r0,16(r3) // caller's mangled return address
+ mfcr r0
+ // Nonvolatiles.
+ std r14,24(r3)
+ stfd f14,176(r3)
+ stw r0,172(r3) // CR
+ std r15,32(r3)
+ stfd f15,184(r3)
+ std r16,40(r3)
+ stfd f16,192(r3)
+ std r17,48(r3)
+ stfd f17,200(r3)
+ std r18,56(r3)
+ stfd f18,208(r3)
+ std r19,64(r3)
+ stfd f19,216(r3)
+ std r20,72(r3)
+ stfd f20,224(r3)
+ std r21,80(r3)
+ stfd f21,232(r3)
+ std r22,88(r3)
+ stfd f22,240(r3)
+ std r23,96(r3)
+ stfd f23,248(r3)
+ std r24,104(r3)
+ stfd f24,256(r3)
+ std r25,112(r3)
+ stfd f25,264(r3)
+ std r26,120(r3)
+ stfd f26,272(r3)
+ std r27,128(r3)
+ stfd f27,280(r3)
+ std r28,136(r3)
+ stfd f28,288(r3)
+ std r29,144(r3)
+ stfd f29,296(r3)
+ std r30,152(r3)
+ stfd f30,304(r3)
+ std r31,160(r3)
+ stfd f31,312(r3)
+ addi r5,r3,320
+ mfspr r0,256
+ stw r0,168(r3) // VRSAVE
+ addi r6,r5,16
+ stvx v20,0,r5
+ addi r5,r5,32
+ stvx v21,0,r6
+ addi r6,r6,32
+ stvx v22,0,r5
+ addi r5,r5,32
+ stvx v23,0,r6
+ addi r6,r6,32
+ stvx v24,0,r5
+ addi r5,r5,32
+ stvx v25,0,r6
+ addi r6,r6,32
+ stvx v26,0,r5
+ addi r5,r5,32
+ stvx v27,0,r6
+ addi r6,r6,32
+ stvx v28,0,r5
+ addi r5,r5,32
+ stvx v29,0,r6
+ addi r6,r6,32
+ stvx v30,0,r5
+ stvx v31,0,r6
+ // Clear the "mask-saved" slot.
+ li r4,0
+ stw r4,512(r3)
+ // Restore TOC, LR, and stack and return to caller.
+ ld r2,24(r1)
+ ld r0,40(r1)
+ addi r1,r1,48
+ li r3,0 // This is the setjmp return path
+ mtlr r0
+ blr
+ .size _setjmp, .-.L._setjmp
+
+ .globl setjmp
+ .type setjmp, @function
+ .align 4
+setjmp:
+ b _setjmp
+ .size setjmp, .-setjmp
+
+ // sigsetjmp is like setjmp, except that the mask in r4 needs
+ // to be saved at offset 512 of the jump buffer.
+ .globl __sigsetjmp
+ .type __sigsetjmp, @function
+ .align 4
+#if _CALL_ELF == 2
+__sigsetjmp:
+#else
+ .section ".opd","aw"
+ .align 3
+__sigsetjmp:
+ .quad .L.__sigsetjmp,.TOC.@tocbase,0
+ .previous
+#endif
+.L.__sigsetjmp:
+ mflr r0
+ stdu r1,-64(r1)
+ std r2,24(r1)
+ std r3,32(r1)
+ std r4,40(r1)
+ std r0,48(r1)
+ // r3 is the original stack pointer.
+ addi r3,r1,64
+ // r4 is the mangled stack pointer (see glibc)
+ ld r4,-28696(r13)
+ xor r4,r3,r4
+ // Materialize a TOC in case we were called from libc.
+ // For big-endian, we load the TOC from the OPD. For little-
+ // endian, we use the .TOC. symbol to find it.
+ nop
+ bcl 20,31,1f
+1:
+ mflr r2
+#if _CALL_ELF == 2
+ addis r2,r2,.TOC.-1b@ha
+ addi r2,r2,.TOC.-1b@l
+#else
+ addis r2,r2,_setjmp-1b@ha
+ addi r2,r2,_setjmp-1b@l
+ ld r2,8(r2)
+#endif
+ // Call the interceptor.
+ bl __tsan_setjmp
+ nop
+ // Restore regs needed for __sigsetjmp.
+ ld r3,32(r1)
+ ld r4,40(r1)
+ ld r0,48(r1)
+ // Emulate the real sigsetjmp function. We do this because we can't
+ // perform a sibcall: The real sigsetjmp function trashes the TOC
+ // pointer, and with a sibcall we have no way to restore it.
+ // This way we can make sure our caller's stack pointer and
+ // link register are saved correctly in the jmpbuf.
+ ld r6,-28696(r13)
+ addi r5,r1,64 // original stack ptr of caller
+ xor r5,r6,r5
+ std r5,0(r3) // mangled stack ptr of caller
+ ld r5,24(r1)
+ std r5,8(r3) // caller's saved TOC pointer
+ xor r0,r6,r0
+ std r0,16(r3) // caller's mangled return address
+ mfcr r0
+ // Nonvolatiles.
+ std r14,24(r3)
+ stfd f14,176(r3)
+ stw r0,172(r3) // CR
+ std r15,32(r3)
+ stfd f15,184(r3)
+ std r16,40(r3)
+ stfd f16,192(r3)
+ std r17,48(r3)
+ stfd f17,200(r3)
+ std r18,56(r3)
+ stfd f18,208(r3)
+ std r19,64(r3)
+ stfd f19,216(r3)
+ std r20,72(r3)
+ stfd f20,224(r3)
+ std r21,80(r3)
+ stfd f21,232(r3)
+ std r22,88(r3)
+ stfd f22,240(r3)
+ std r23,96(r3)
+ stfd f23,248(r3)
+ std r24,104(r3)
+ stfd f24,256(r3)
+ std r25,112(r3)
+ stfd f25,264(r3)
+ std r26,120(r3)
+ stfd f26,272(r3)
+ std r27,128(r3)
+ stfd f27,280(r3)
+ std r28,136(r3)
+ stfd f28,288(r3)
+ std r29,144(r3)
+ stfd f29,296(r3)
+ std r30,152(r3)
+ stfd f30,304(r3)
+ std r31,160(r3)
+ stfd f31,312(r3)
+ addi r5,r3,320
+ mfspr r0,256
+ stw r0,168(r3) // VRSAVE
+ addi r6,r5,16
+ stvx v20,0,r5
+ addi r5,r5,32
+ stvx v21,0,r6
+ addi r6,r6,32
+ stvx v22,0,r5
+ addi r5,r5,32
+ stvx v23,0,r6
+ addi r6,r6,32
+ stvx v24,0,r5
+ addi r5,r5,32
+ stvx v25,0,r6
+ addi r6,r6,32
+ stvx v26,0,r5
+ addi r5,r5,32
+ stvx v27,0,r6
+ addi r6,r6,32
+ stvx v28,0,r5
+ addi r5,r5,32
+ stvx v29,0,r6
+ addi r6,r6,32
+ stvx v30,0,r5
+ stvx v31,0,r6
+ // Save into the "mask-saved" slot.
+ stw r4,512(r3)
+ // Restore TOC, LR, and stack and return to caller.
+ ld r2,24(r1)
+ ld r0,48(r1)
+ addi r1,r1,64
+ li r3,0 // This is the sigsetjmp return path
+ mtlr r0
+ blr
+ .size __sigsetjmp, .-.L.__sigsetjmp
+
+ .globl sigsetjmp
+ .type sigsetjmp, @function
+ .align 4
+sigsetjmp:
+ b __sigsetjmp
+ .size sigsetjmp, .-sigsetjmp
diff --git a/libsanitizer/tsan/tsan_rtl_proc.cc b/libsanitizer/tsan/tsan_rtl_proc.cc
new file mode 100644
index 00000000000..1b0a9b38938
--- /dev/null
+++ b/libsanitizer/tsan/tsan_rtl_proc.cc
@@ -0,0 +1,59 @@
+//===-- tsan_rtl_proc.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 (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "tsan_flags.h"
+
+namespace __tsan {
+
+Processor *ProcCreate() {
+ void *mem = InternalAlloc(sizeof(Processor));
+ internal_memset(mem, 0, sizeof(Processor));
+ Processor *proc = new(mem) Processor;
+ proc->thr = nullptr;
+#if !SANITIZER_GO
+ AllocatorProcStart(proc);
+#endif
+ if (common_flags()->detect_deadlocks)
+ proc->dd_pt = ctx->dd->CreatePhysicalThread();
+ return proc;
+}
+
+void ProcDestroy(Processor *proc) {
+ CHECK_EQ(proc->thr, nullptr);
+#if !SANITIZER_GO
+ AllocatorProcFinish(proc);
+#endif
+ ctx->clock_alloc.FlushCache(&proc->clock_cache);
+ ctx->metamap.OnProcIdle(proc);
+ if (common_flags()->detect_deadlocks)
+ ctx->dd->DestroyPhysicalThread(proc->dd_pt);
+ proc->~Processor();
+ InternalFree(proc);
+}
+
+void ProcWire(Processor *proc, ThreadState *thr) {
+ CHECK_EQ(thr->proc1, nullptr);
+ CHECK_EQ(proc->thr, nullptr);
+ thr->proc1 = proc;
+ proc->thr = thr;
+}
+
+void ProcUnwire(Processor *proc, ThreadState *thr) {
+ CHECK_EQ(thr->proc1, proc);
+ CHECK_EQ(proc->thr, thr);
+ thr->proc1 = nullptr;
+ proc->thr = nullptr;
+}
+
+} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc
index d0d1fbaf45a..8f2882485e6 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cc
+++ b/libsanitizer/tsan/tsan_rtl_report.cc
@@ -36,6 +36,10 @@ void TsanCheckFailed(const char *file, int line, const char *cond,
// on the other hand there is no sense in processing interceptors
// since we are going to die soon.
ScopedIgnoreInterceptors ignore;
+#if !SANITIZER_GO
+ cur_thread()->ignore_sync++;
+ cur_thread()->ignore_reads_and_writes++;
+#endif
Printf("FATAL: ThreadSanitizer CHECK failed: "
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
file, line, cond, (uptr)v1, (uptr)v2);
@@ -47,13 +51,18 @@ void TsanCheckFailed(const char *file, int line, const char *cond,
#ifdef TSAN_EXTERNAL_HOOKS
bool OnReport(const ReportDesc *rep, bool suppressed);
#else
-SANITIZER_INTERFACE_ATTRIBUTE
-bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
+SANITIZER_WEAK_CXX_DEFAULT_IMPL
+bool OnReport(const ReportDesc *rep, bool suppressed) {
(void)rep;
return suppressed;
}
#endif
+SANITIZER_WEAK_DEFAULT_IMPL
+void __tsan_on_report(const ReportDesc *rep) {
+ (void)rep;
+}
+
static void StackStripMain(SymbolizedStack *frames) {
SymbolizedStack *last_frame = nullptr;
SymbolizedStack *last_frame2 = nullptr;
@@ -64,7 +73,7 @@ static void StackStripMain(SymbolizedStack *frames) {
if (last_frame2 == 0)
return;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
const char *last = last_frame->info.function;
const char *last2 = last_frame2->info.function;
// Strip frame above 'main'
@@ -184,10 +193,10 @@ void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
return;
}
void *mem = internal_alloc(MBlockReportThread, sizeof(ReportThread));
- ReportThread *rt = new(mem) ReportThread();
+ ReportThread *rt = new(mem) ReportThread;
rep_->threads.PushBack(rt);
rt->id = tctx->tid;
- rt->pid = tctx->os_id;
+ rt->os_id = tctx->os_id;
rt->running = (tctx->status == ThreadStatusRunning);
rt->name = internal_strdup(tctx->name);
rt->parent_tid = tctx->parent_tid;
@@ -197,17 +206,17 @@ void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
rt->stack->suppressable = suppressable;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
+static bool FindThreadByUidLockedCallback(ThreadContextBase *tctx, void *arg) {
+ int unique_id = *(int *)arg;
+ return tctx->unique_id == (u32)unique_id;
+}
+
static ThreadContext *FindThreadByUidLocked(int unique_id) {
ctx->thread_registry->CheckLocked();
- for (unsigned i = 0; i < kMaxTid; i++) {
- ThreadContext *tctx = static_cast<ThreadContext*>(
- ctx->thread_registry->GetThreadLocked(i));
- if (tctx && tctx->unique_id == (u32)unique_id) {
- return tctx;
- }
- }
- return 0;
+ return static_cast<ThreadContext *>(
+ ctx->thread_registry->FindThreadContextLocked(
+ FindThreadByUidLockedCallback, &unique_id));
}
static ThreadContext *FindThreadByTidLocked(int tid) {
@@ -242,7 +251,7 @@ ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) {
#endif
void ScopedReport::AddThread(int unique_tid, bool suppressable) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid))
AddThread(tctx, suppressable);
#endif
@@ -254,7 +263,7 @@ void ScopedReport::AddMutex(const SyncVar *s) {
return;
}
void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
- ReportMutex *rm = new(mem) ReportMutex();
+ ReportMutex *rm = new(mem) ReportMutex;
rep_->mutexes.PushBack(rm);
rm->id = s->uid;
rm->addr = s->addr;
@@ -266,7 +275,7 @@ u64 ScopedReport::AddMutex(u64 id) {
u64 uid = 0;
u64 mid = id;
uptr addr = SyncVar::SplitId(id, &uid);
- SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
// Check that the mutex is still alive.
// Another mutex can be created at the same address,
// so check uid as well.
@@ -287,7 +296,7 @@ void ScopedReport::AddDeadMutex(u64 id) {
return;
}
void *mem = internal_alloc(MBlockReportMutex, sizeof(ReportMutex));
- ReportMutex *rm = new(mem) ReportMutex();
+ ReportMutex *rm = new(mem) ReportMutex;
rep_->mutexes.PushBack(rm);
rm->id = id;
rm->addr = 0;
@@ -298,7 +307,7 @@ void ScopedReport::AddDeadMutex(u64 id) {
void ScopedReport::AddLocation(uptr addr, uptr size) {
if (addr == 0)
return;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
int fd = -1;
int creat_tid = -1;
u32 creat_stack = 0;
@@ -340,15 +349,15 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
rep_->locs.PushBack(loc);
AddThread(tctx);
}
+#endif
if (ReportLocation *loc = SymbolizeData(addr)) {
loc->suppressable = true;
rep_->locs.PushBack(loc);
return;
}
-#endif
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
void ScopedReport::AddSleep(u32 stack_id) {
rep_->sleep = SymbolizeStackId(stack_id);
}
@@ -490,6 +499,8 @@ bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
return false;
atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
+ CHECK_EQ(thr->current_report, nullptr);
+ thr->current_report = rep;
Suppression *supp = 0;
uptr pc_or_addr = 0;
for (uptr i = 0; pc_or_addr == 0 && i < rep->mops.Size(); i++)
@@ -510,13 +521,17 @@ bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
thr->is_freeing = false;
bool suppressed = OnReport(rep, pc_or_addr != 0);
thr->is_freeing = old_is_freeing;
- if (suppressed)
+ if (suppressed) {
+ thr->current_report = nullptr;
return false;
+ }
}
PrintReport(rep);
+ __tsan_on_report(rep);
ctx->nreported++;
if (flags()->halt_on_error)
Die();
+ thr->current_report = nullptr;
return true;
}
@@ -647,7 +662,7 @@ void ReportRace(ThreadState *thr) {
rep.AddLocation(addr_min, addr_max - addr_min);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
{ // NOLINT
Shadow s(thr->racy_state[1]);
if (s.epoch() <= thr->last_sleep_clock.get(s.tid()))
@@ -667,8 +682,16 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
PrintStack(SymbolizeStack(trace));
}
+// Always inlining PrintCurrentStackSlow, because LocatePcInTrace assumes
+// __sanitizer_print_stack_trace exists in the actual unwinded stack, but
+// tail-call to PrintCurrentStackSlow breaks this assumption because
+// __sanitizer_print_stack_trace disappears after tail-call.
+// However, this solution is not reliable enough, please see dvyukov's comment
+// http://reviews.llvm.org/D19148#406208
+// Also see PR27280 comment 2 and 3 for breaking examples and analysis.
+ALWAYS_INLINE
void PrintCurrentStackSlow(uptr pc) {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
BufferedStackTrace *ptrace =
new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
BufferedStackTrace();
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc
index 3939c77d41c..6c4b74e2a76 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cc
+++ b/libsanitizer/tsan/tsan_rtl_thread.cc
@@ -28,7 +28,7 @@ ThreadContext::ThreadContext(int tid)
, epoch1() {
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
ThreadContext::~ThreadContext() {
}
#endif
@@ -40,7 +40,7 @@ void ThreadContext::OnDead() {
void ThreadContext::OnJoined(void *arg) {
ThreadState *caller_thr = static_cast<ThreadState *>(arg);
AcquireImpl(caller_thr, 0, &sync);
- sync.Reset(&caller_thr->clock_cache);
+ sync.Reset(&caller_thr->proc()->clock_cache);
}
struct OnCreatedArgs {
@@ -66,13 +66,13 @@ void ThreadContext::OnCreated(void *arg) {
void ThreadContext::OnReset() {
CHECK_EQ(sync.size(), 0);
- FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
- //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
+ ReleaseMemoryToOS(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+ //!!! ReleaseMemoryToOS(GetThreadTraceHeader(tid), sizeof(Trace));
}
void ThreadContext::OnDetached(void *arg) {
ThreadState *thr1 = static_cast<ThreadState*>(arg);
- sync.Reset(&thr1->clock_cache);
+ sync.Reset(&thr1->proc()->clock_cache);
}
struct OnStartedArgs {
@@ -92,7 +92,7 @@ void ThreadContext::OnStarted(void *arg) {
epoch1 = (u64)-1;
new(thr) ThreadState(ctx, tid, unique_id, epoch0, reuse_count,
args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
@@ -104,13 +104,8 @@ void ThreadContext::OnStarted(void *arg) {
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
-#ifndef SANITIZER_GO
- AllocatorThreadStart(thr);
-#endif
- if (common_flags()->detect_deadlocks) {
- thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ if (common_flags()->detect_deadlocks)
thr->dd_lt = ctx->dd->CreateLogicalThread(unique_id);
- }
thr->fast_state.SetHistorySize(flags()->history_size);
// Commit switch to the new part of the trace.
// TraceAddEvent will reset stack0/mset0 in the new part for us.
@@ -119,7 +114,7 @@ void ThreadContext::OnStarted(void *arg) {
thr->fast_synch_epoch = epoch0;
AcquireImpl(thr, 0, &sync);
StatInc(thr, StatSyncAcquire);
- sync.Reset(&thr->clock_cache);
+ sync.Reset(&thr->proc()->clock_cache);
thr->is_inited = true;
DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
"tls_addr=%zx tls_size=%zx\n",
@@ -128,6 +123,12 @@ void ThreadContext::OnStarted(void *arg) {
}
void ThreadContext::OnFinished() {
+#if SANITIZER_GO
+ internal_free(thr->shadow_stack);
+ thr->shadow_stack = nullptr;
+ thr->shadow_stack_pos = nullptr;
+ thr->shadow_stack_end = nullptr;
+#endif
if (!detached) {
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
@@ -136,15 +137,8 @@ void ThreadContext::OnFinished() {
}
epoch1 = thr->fast_state.epoch();
- if (common_flags()->detect_deadlocks) {
- ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ if (common_flags()->detect_deadlocks)
ctx->dd->DestroyLogicalThread(thr->dd_lt);
- }
- ctx->clock_alloc.FlushCache(&thr->clock_cache);
- ctx->metamap.OnThreadIdle(thr);
-#ifndef SANITIZER_GO
- AllocatorThreadFinish(thr);
-#endif
thr->~ThreadState();
#if TSAN_COLLECT_STATS
StatAggregate(ctx->stat, thr->stat);
@@ -152,7 +146,7 @@ void ThreadContext::OnFinished() {
thr = 0;
}
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
struct ThreadLeak {
ThreadContext *tctx;
int count;
@@ -174,7 +168,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
}
#endif
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
if (tctx->tid == 0) {
Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
@@ -206,7 +200,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
void ThreadFinalize(ThreadState *thr) {
ThreadCheckIgnore(thr);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (!flags()->report_thread_leaks)
return;
ThreadRegistryLock l(ctx->thread_registry);
@@ -244,7 +238,7 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
uptr stk_size = 0;
uptr tls_addr = 0;
uptr tls_size = 0;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
if (tid) {
@@ -275,7 +269,7 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
tr->Unlock();
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
if (ctx->after_multithreaded_fork) {
thr->ignore_interceptors++;
ThreadIgnoreBegin(thr, 0);
diff --git a/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc
index 5eccca69312..740cb86c69e 100644
--- a/libsanitizer/tsan/tsan_stat.cc
+++ b/libsanitizer/tsan/tsan_stat.cc
@@ -166,6 +166,7 @@ void StatOutput(u64 *stat) {
name[StatMtxFired] = " FiredSuppressions ";
name[StatMtxRacy] = " RacyStacks ";
name[StatMtxFD] = " FD ";
+ name[StatMtxGlobalProc] = " GlobalProc ";
Printf("Statistics:\n");
for (int i = 0; i < StatCnt; i++)
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index 002570f42f1..788adeb56ea 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -171,6 +171,7 @@ enum StatType {
StatMtxFired,
StatMtxRacy,
StatMtxFD,
+ StatMtxGlobalProc,
// This must be the last.
StatCnt
diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc
index 5c8d03dddd2..dc862b1b9ad 100644
--- a/libsanitizer/tsan/tsan_suppressions.cc
+++ b/libsanitizer/tsan/tsan_suppressions.cc
@@ -19,7 +19,7 @@
#include "tsan_mman.h"
#include "tsan_platform.h"
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Suppressions for true/false positives in standard libraries.
static const char *const std_suppressions =
// Libstdc++ 4.4 has data races in std::string.
@@ -32,7 +32,8 @@ static const char *const std_suppressions =
"race:std::_Sp_counted_ptr_inplace<std::thread::_Impl\n";
// Can be overriden in frontend.
-extern "C" const char *WEAK __tsan_default_suppressions() {
+SANITIZER_WEAK_DEFAULT_IMPL
+const char *__tsan_default_suppressions() {
return 0;
}
#endif
@@ -51,7 +52,7 @@ void InitializeSuppressions() {
suppression_ctx = new (suppression_placeholder) // NOLINT
SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
suppression_ctx->ParseFromFile(flags()->suppressions);
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
suppression_ctx->Parse(__tsan_default_suppressions());
suppression_ctx->Parse(std_suppressions);
#endif
@@ -77,6 +78,8 @@ static const char *conv(ReportType typ) {
return kSuppressionMutex;
else if (typ == ReportTypeMutexDoubleLock)
return kSuppressionMutex;
+ else if (typ == ReportTypeMutexInvalidAccess)
+ return kSuppressionMutex;
else if (typ == ReportTypeMutexBadUnlock)
return kSuppressionMutex;
else if (typ == ReportTypeMutexBadReadLock)
@@ -89,7 +92,7 @@ static const char *conv(ReportType typ) {
return kSuppressionNone;
else if (typ == ReportTypeDeadlock)
return kSuppressionDeadlock;
- Printf("ThreadSanitizer: unknown report type %d\n", typ),
+ Printf("ThreadSanitizer: unknown report type %d\n", typ);
Die();
}
@@ -156,8 +159,8 @@ void PrintMatchedSuppressions() {
Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count,
(int)internal_getpid());
for (uptr i = 0; i < matched.size(); i++) {
- Printf("%d %s:%s\n", matched[i]->hit_count, matched[i]->type,
- matched[i]->templ);
+ Printf("%d %s:%s\n", atomic_load_relaxed(&matched[i]->hit_count),
+ matched[i]->type, matched[i]->templ);
}
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_symbolize.cc b/libsanitizer/tsan/tsan_symbolize.cc
index 0e54562e385..7b04782d1ad 100644
--- a/libsanitizer/tsan/tsan_symbolize.cc
+++ b/libsanitizer/tsan/tsan_symbolize.cc
@@ -36,10 +36,10 @@ void ExitSymbolizer() {
// May be overriden by JIT/JAVA/etc,
// whatever produces PCs marked with kExternalPCBit.
-extern "C" bool WEAK __tsan_symbolize_external(uptr pc,
- char *func_buf, uptr func_siz,
- char *file_buf, uptr file_siz,
- int *line, int *col) {
+SANITIZER_WEAK_DEFAULT_IMPL
+bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz,
+ char *file_buf, uptr file_siz, int *line,
+ int *col) {
return false;
}
@@ -69,7 +69,7 @@ ReportLocation *SymbolizeData(uptr addr) {
if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
return 0;
ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
- ent->global = info;
+ internal_memcpy(&ent->global, &info, sizeof(info));
return ent;
}
diff --git a/libsanitizer/tsan/tsan_sync.cc b/libsanitizer/tsan/tsan_sync.cc
index 91ad8c8b228..0ee2295e69e 100644
--- a/libsanitizer/tsan/tsan_sync.cc
+++ b/libsanitizer/tsan/tsan_sync.cc
@@ -28,13 +28,13 @@ void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
this->next = 0;
creation_stack_id = 0;
- if (kCppMode) // Go does not use them
+ if (!SANITIZER_GO) // Go does not use them
creation_stack_id = CurrentStackId(thr, pc);
if (common_flags()->detect_deadlocks)
DDMutexInit(thr, pc, this);
}
-void SyncVar::Reset(ThreadState *thr) {
+void SyncVar::Reset(Processor *proc) {
uid = 0;
creation_stack_id = 0;
owner_tid = kInvalidTid;
@@ -45,12 +45,12 @@ void SyncVar::Reset(ThreadState *thr) {
is_broken = 0;
is_linker_init = 0;
- if (thr == 0) {
+ if (proc == 0) {
CHECK_EQ(clock.size(), 0);
CHECK_EQ(read_clock.size(), 0);
} else {
- clock.Reset(&thr->clock_cache);
- read_clock.Reset(&thr->clock_cache);
+ clock.Reset(&proc->clock_cache);
+ read_clock.Reset(&proc->clock_cache);
}
}
@@ -59,7 +59,7 @@ MetaMap::MetaMap() {
}
void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
- u32 idx = block_alloc_.Alloc(&thr->block_cache);
+ u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache);
MBlock *b = block_alloc_.Map(idx);
b->siz = sz;
b->tid = thr->tid;
@@ -69,16 +69,16 @@ void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
*meta = idx | kFlagBlock;
}
-uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) {
+uptr MetaMap::FreeBlock(Processor *proc, uptr p) {
MBlock* b = GetBlock(p);
if (b == 0)
return 0;
uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
- FreeRange(thr, pc, p, sz);
+ FreeRange(proc, p, sz);
return sz;
}
-bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+bool MetaMap::FreeRange(Processor *proc, uptr p, uptr sz) {
bool has_something = false;
u32 *meta = MemToMeta(p);
u32 *end = MemToMeta(p + sz);
@@ -94,14 +94,14 @@ bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
has_something = true;
while (idx != 0) {
if (idx & kFlagBlock) {
- block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
+ block_alloc_.Free(&proc->block_cache, idx & ~kFlagMask);
break;
} else if (idx & kFlagSync) {
DCHECK(idx & kFlagSync);
SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
u32 next = s->next;
- s->Reset(thr);
- sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
+ s->Reset(proc);
+ sync_alloc_.Free(&proc->sync_cache, idx & ~kFlagMask);
idx = next;
} else {
CHECK(0);
@@ -117,24 +117,30 @@ bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
// which can be huge. The function probes pages one-by-one until it finds a page
// without meta objects, at this point it stops freeing meta objects. Because
// thread stacks grow top-down, we do the same starting from end as well.
-void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
+void MetaMap::ResetRange(Processor *proc, uptr p, uptr sz) {
+ if (SANITIZER_GO) {
+ // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
+ // so we do the optimization only for C/C++.
+ FreeRange(proc, p, sz);
+ return;
+ }
const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
if (sz <= 4 * kPageSize) {
// If the range is small, just do the normal free procedure.
- FreeRange(thr, pc, p, sz);
+ FreeRange(proc, p, sz);
return;
}
// First, round both ends of the range to page size.
uptr diff = RoundUp(p, kPageSize) - p;
if (diff != 0) {
- FreeRange(thr, pc, p, diff);
+ FreeRange(proc, p, diff);
p += diff;
sz -= diff;
}
diff = p + sz - RoundDown(p + sz, kPageSize);
if (diff != 0) {
- FreeRange(thr, pc, p + sz - diff, diff);
+ FreeRange(proc, p + sz - diff, diff);
sz -= diff;
}
// Now we must have a non-empty page-aligned range.
@@ -144,18 +150,21 @@ void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
const uptr p0 = p;
const uptr sz0 = sz;
// Probe start of the range.
- while (sz > 0) {
- bool has_something = FreeRange(thr, pc, p, kPageSize);
+ for (uptr checked = 0; sz > 0; checked += kPageSize) {
+ bool has_something = FreeRange(proc, p, kPageSize);
p += kPageSize;
sz -= kPageSize;
- if (!has_something)
+ if (!has_something && checked > (128 << 10))
break;
}
// Probe end of the range.
- while (sz > 0) {
- bool has_something = FreeRange(thr, pc, p - kPageSize, kPageSize);
+ for (uptr checked = 0; sz > 0; checked += kPageSize) {
+ bool has_something = FreeRange(proc, p + sz - kPageSize, kPageSize);
sz -= kPageSize;
- if (!has_something)
+ // Stacks grow down, so sync object are most likely at the end of the region
+ // (if it is a stack). The very end of the stack is TLS and tsan increases
+ // TLS by at least 256K, so check at least 512K.
+ if (!has_something && checked > (512 << 10))
break;
}
// Finally, page out the whole range (including the parts that we've just
@@ -187,8 +196,8 @@ SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc,
return GetAndLock(thr, pc, addr, write_lock, true);
}
-SyncVar* MetaMap::GetIfExistsAndLock(uptr addr) {
- return GetAndLock(0, 0, addr, true, false);
+SyncVar* MetaMap::GetIfExistsAndLock(uptr addr, bool write_lock) {
+ return GetAndLock(0, 0, addr, write_lock, false);
}
SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
@@ -208,8 +217,8 @@ SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
if (s->addr == addr) {
if (myidx != 0) {
- mys->Reset(thr);
- sync_alloc_.Free(&thr->sync_cache, myidx);
+ mys->Reset(thr->proc());
+ sync_alloc_.Free(&thr->proc()->sync_cache, myidx);
}
if (write_lock)
s->mtx.Lock();
@@ -228,7 +237,7 @@ SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
if (myidx == 0) {
const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
- myidx = sync_alloc_.Alloc(&thr->sync_cache);
+ myidx = sync_alloc_.Alloc(&thr->proc()->sync_cache);
mys = sync_alloc_.Map(myidx);
mys->Init(thr, pc, addr, uid);
}
@@ -277,9 +286,9 @@ void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
}
}
-void MetaMap::OnThreadIdle(ThreadState *thr) {
- block_alloc_.FlushCache(&thr->block_cache);
- sync_alloc_.FlushCache(&thr->sync_cache);
+void MetaMap::OnProcIdle(Processor *proc) {
+ block_alloc_.FlushCache(&proc->block_cache);
+ sync_alloc_.FlushCache(&proc->sync_cache);
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
index 50bc872275d..48d7027b428 100644
--- a/libsanitizer/tsan/tsan_sync.h
+++ b/libsanitizer/tsan/tsan_sync.h
@@ -45,19 +45,19 @@ struct SyncVar {
SyncClock clock;
void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid);
- void Reset(ThreadState *thr);
+ void Reset(Processor *proc);
u64 GetId() const {
- // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits.
- return GetLsb((u64)addr | (uid << 47), 61);
+ // 48 lsb is addr, then 14 bits is low part of uid, then 2 zero bits.
+ return GetLsb((u64)addr | (uid << 48), 60);
}
bool CheckId(u64 uid) const {
CHECK_EQ(uid, GetLsb(uid, 14));
return GetLsb(this->uid, 14) == uid;
}
static uptr SplitId(u64 id, u64 *uid) {
- *uid = id >> 47;
- return (uptr)GetLsb(id, 47);
+ *uid = id >> 48;
+ return (uptr)GetLsb(id, 48);
}
};
@@ -70,18 +70,18 @@ class MetaMap {
MetaMap();
void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz);
- uptr FreeBlock(ThreadState *thr, uptr pc, uptr p);
- bool FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
- void ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz);
+ uptr FreeBlock(Processor *proc, uptr p);
+ bool FreeRange(Processor *proc, uptr p, uptr sz);
+ void ResetRange(Processor *proc, uptr p, uptr sz);
MBlock* GetBlock(uptr p);
SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc,
uptr addr, bool write_lock);
- SyncVar* GetIfExistsAndLock(uptr addr);
+ SyncVar* GetIfExistsAndLock(uptr addr, bool write_lock);
void MoveMemory(uptr src, uptr dst, uptr sz);
- void OnThreadIdle(ThreadState *thr);
+ void OnProcIdle(Processor *proc);
private:
static const u32 kFlagMask = 3u << 30;
diff --git a/libsanitizer/tsan/tsan_trace.h b/libsanitizer/tsan/tsan_trace.h
index a27efa9fd7a..1ea733bfd07 100644
--- a/libsanitizer/tsan/tsan_trace.h
+++ b/libsanitizer/tsan/tsan_trace.h
@@ -40,7 +40,7 @@ enum EventType {
typedef u64 Event;
struct TraceHeader {
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
BufferedStackTrace stack0; // Start stack for the trace.
#else
VarSizeStackTrace stack0;
@@ -53,7 +53,7 @@ struct TraceHeader {
struct Trace {
Mutex mtx;
-#ifndef SANITIZER_GO
+#if !SANITIZER_GO
// Must be last to catch overflow as paging fault.
// Go shadow stack is dynamically allocated.
uptr shadow_stack[kShadowStackSize];
diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in
index 51d4da58516..a816d095f6a 100644
--- a/libsanitizer/ubsan/Makefile.in
+++ b/libsanitizer/ubsan/Makefile.in
@@ -208,6 +208,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc
index 935d82c5079..ea85877198a 100644
--- a/libsanitizer/ubsan/ubsan_checks.inc
+++ b/libsanitizer/ubsan/ubsan_checks.inc
@@ -12,40 +12,32 @@
# error "Define UBSAN_CHECK prior to including this file!"
#endif
-// UBSAN_CHECK(Name, SummaryKind, FlagName)
-// SummaryKind and FlagName should be string literals.
+// UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName)
+// SummaryKind and FSanitizeFlagName should be string literals.
-UBSAN_CHECK(GenericUB, "undefined-behavior", "-fsanitize=undefined")
-UBSAN_CHECK(NullPointerUse, "null-pointer-use", "-fsanitize=null")
-UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use",
- "-fsanitize=alignment")
-UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size",
- "-fsanitize=object-size")
+UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
+UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
+UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
+UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",
- "-fsanitize=signed-integer-overflow")
+ "signed-integer-overflow")
UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow",
- "-fsanitize=unsigned-integer-overflow")
+ "unsigned-integer-overflow")
UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
- "-fsanitize=integer-divide-by-zero")
-UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero",
- "-fsanitize=float-divide-by-zero")
-UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "-fsanitize=shift-base")
-UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent",
- "-fsanitize=shift-exponent")
-UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "-fsanitize=bounds")
-UBSAN_CHECK(UnreachableCall, "unreachable-call", "-fsanitize=unreachable")
-UBSAN_CHECK(MissingReturn, "missing-return", "-fsanitize=return")
-UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index",
- "-fsanitize=vla-bound")
-UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow",
- "-fsanitize=float-cast-overflow")
-UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "-fsanitize=bool")
-UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "-fsanitize=enum")
-UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch",
- "-fsanitize=function")
+ "integer-divide-by-zero")
+UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
+UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
+UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
+UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
+UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable")
+UBSAN_CHECK(MissingReturn, "missing-return", "return")
+UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound")
+UBSAN_CHECK(FloatCastOverflow, "float-cast-overflow", "float-cast-overflow")
+UBSAN_CHECK(InvalidBoolLoad, "invalid-bool-load", "bool")
+UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum")
+UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function")
UBSAN_CHECK(InvalidNullReturn, "invalid-null-return",
- "-fsanitize=returns-nonnull-attribute")
-UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument",
- "-fsanitize=nonnull-attribute")
-UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "-fsanitize=vptr")
-UBSAN_CHECK(CFIBadType, "cfi-bad-type", "-fsanitize=cfi")
+ "returns-nonnull-attribute")
+UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute")
+UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr")
+UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi")
diff --git a/libsanitizer/ubsan/ubsan_diag.cc b/libsanitizer/ubsan/ubsan_diag.cc
index 1197f837f75..b6e982a170e 100644
--- a/libsanitizer/ubsan/ubsan_diag.cc
+++ b/libsanitizer/ubsan/ubsan_diag.cc
@@ -43,7 +43,7 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) {
static const char *ConvertTypeToString(ErrorType Type) {
switch (Type) {
-#define UBSAN_CHECK(Name, SummaryKind, FlagName) \
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
case ErrorType::Name: \
return SummaryKind;
#include "ubsan_checks.inc"
@@ -52,6 +52,17 @@ static const char *ConvertTypeToString(ErrorType Type) {
UNREACHABLE("unknown ErrorType!");
}
+static const char *ConvertTypeToFlagName(ErrorType Type) {
+ switch (Type) {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) \
+ case ErrorType::Name: \
+ return FSanitizeFlagName;
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ }
+ UNREACHABLE("unknown ErrorType!");
+}
+
static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
if (!common_flags()->print_summary)
return;
@@ -111,108 +122,98 @@ Diag &Diag::operator<<(const Value &V) {
}
/// Hexadecimal printing for numbers too large for Printf to handle directly.
-static void PrintHex(UIntMax Val) {
+static void RenderHex(InternalScopedString *Buffer, UIntMax Val) {
#if HAVE_INT128_T
- Printf("0x%08x%08x%08x%08x",
- (unsigned int)(Val >> 96),
- (unsigned int)(Val >> 64),
- (unsigned int)(Val >> 32),
- (unsigned int)(Val));
+ Buffer->append("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96),
+ (unsigned int)(Val >> 64), (unsigned int)(Val >> 32),
+ (unsigned int)(Val));
#else
UNREACHABLE("long long smaller than 64 bits?");
#endif
}
-static void renderLocation(Location Loc) {
- InternalScopedString LocBuffer(1024);
+static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
switch (Loc.getKind()) {
case Location::LK_Source: {
SourceLocation SLoc = Loc.getSourceLocation();
if (SLoc.isInvalid())
- LocBuffer.append("<unknown>");
+ Buffer->append("<unknown>");
else
- RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+ RenderSourceLocation(Buffer, SLoc.getFilename(), SLoc.getLine(),
SLoc.getColumn(), common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
- break;
+ return;
}
case Location::LK_Memory:
- LocBuffer.append("%p", Loc.getMemoryLocation());
- break;
+ Buffer->append("%p", Loc.getMemoryLocation());
+ return;
case Location::LK_Symbolized: {
const AddressInfo &Info = Loc.getSymbolizedStack()->info;
- if (Info.file) {
- RenderSourceLocation(&LocBuffer, Info.file, Info.line, Info.column,
+ if (Info.file)
+ RenderSourceLocation(Buffer, Info.file, Info.line, Info.column,
common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
- } else if (Info.module) {
- RenderModuleLocation(&LocBuffer, Info.module, Info.module_offset,
+ else if (Info.module)
+ RenderModuleLocation(Buffer, Info.module, Info.module_offset,
common_flags()->strip_path_prefix);
- } else {
- LocBuffer.append("%p", Info.address);
- }
- break;
+ else
+ Buffer->append("%p", Info.address);
+ return;
}
case Location::LK_Null:
- LocBuffer.append("<unknown>");
- break;
+ Buffer->append("<unknown>");
+ return;
}
- Printf("%s:", LocBuffer.data());
}
-static void renderText(const char *Message, const Diag::Arg *Args) {
+static void RenderText(InternalScopedString *Buffer, const char *Message,
+ const Diag::Arg *Args) {
for (const char *Msg = Message; *Msg; ++Msg) {
if (*Msg != '%') {
- char Buffer[64];
- unsigned I;
- for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
- Buffer[I] = Msg[I];
- Buffer[I] = '\0';
- Printf(Buffer);
- Msg += I - 1;
- } else {
- const Diag::Arg &A = Args[*++Msg - '0'];
- switch (A.Kind) {
- case Diag::AK_String:
- Printf("%s", A.String);
- break;
- case Diag::AK_TypeName: {
- if (SANITIZER_WINDOWS)
- // The Windows implementation demangles names early.
- Printf("'%s'", A.String);
- else
- Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
- break;
- }
- case Diag::AK_SInt:
- // 'long long' is guaranteed to be at least 64 bits wide.
- if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
- Printf("%lld", (long long)A.SInt);
- else
- PrintHex(A.SInt);
- break;
- case Diag::AK_UInt:
- if (A.UInt <= UINT64_MAX)
- Printf("%llu", (unsigned long long)A.UInt);
- else
- PrintHex(A.UInt);
- break;
- case Diag::AK_Float: {
- // FIXME: Support floating-point formatting in sanitizer_common's
- // printf, and stop using snprintf here.
- char Buffer[32];
+ Buffer->append("%c", *Msg);
+ continue;
+ }
+ const Diag::Arg &A = Args[*++Msg - '0'];
+ switch (A.Kind) {
+ case Diag::AK_String:
+ Buffer->append("%s", A.String);
+ break;
+ case Diag::AK_TypeName: {
+ if (SANITIZER_WINDOWS)
+ // The Windows implementation demangles names early.
+ Buffer->append("'%s'", A.String);
+ else
+ Buffer->append("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
+ break;
+ }
+ case Diag::AK_SInt:
+ // 'long long' is guaranteed to be at least 64 bits wide.
+ if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
+ Buffer->append("%lld", (long long)A.SInt);
+ else
+ RenderHex(Buffer, A.SInt);
+ break;
+ case Diag::AK_UInt:
+ if (A.UInt <= UINT64_MAX)
+ Buffer->append("%llu", (unsigned long long)A.UInt);
+ else
+ RenderHex(Buffer, A.UInt);
+ break;
+ case Diag::AK_Float: {
+ // FIXME: Support floating-point formatting in sanitizer_common's
+ // printf, and stop using snprintf here.
+ char FloatBuffer[32];
#if SANITIZER_WINDOWS
- sprintf_s(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
+ sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
#else
- snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
+ snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
#endif
- Printf("%s", Buffer);
- break;
- }
- case Diag::AK_Pointer:
- Printf("%p", A.Pointer);
- break;
- }
+ Buffer->append("%s", FloatBuffer);
+ break;
+ }
+ case Diag::AK_Pointer:
+ Buffer->append("%p", A.Pointer);
+ break;
}
}
}
@@ -240,9 +241,9 @@ static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
}
/// Render a snippet of the address space near a location.
-static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
- Range *Ranges, unsigned NumRanges,
- const Diag::Arg *Args) {
+static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
+ Range *Ranges, unsigned NumRanges,
+ const Diag::Arg *Args) {
// Show at least the 8 bytes surrounding Loc.
const unsigned MinBytesNearLoc = 4;
MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
@@ -265,14 +266,15 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
}
// Emit data.
+ InternalScopedString Buffer(1024);
for (uptr P = Min; P != Max; ++P) {
unsigned char C = *reinterpret_cast<const unsigned char*>(P);
- Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
+ Buffer.append("%s%02x", (P % 8 == 0) ? " " : " ", C);
}
- Printf("\n");
+ Buffer.append("\n");
// Emit highlights.
- Printf(Decor.Highlight());
+ Buffer.append(Decor.Highlight());
Range *InRange = upperBound(Min, Ranges, NumRanges);
for (uptr P = Min; P != Max; ++P) {
char Pad = ' ', Byte = ' ';
@@ -284,10 +286,13 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Pad = '~';
if (InRange && InRange->getStart().getMemoryLocation() <= P)
Byte = '~';
- char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
- Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
+ if (P % 8 == 0)
+ Buffer.append("%c", Pad);
+ Buffer.append("%c", Pad);
+ Buffer.append("%c", P == Loc ? '^' : Byte);
+ Buffer.append("%c", Byte);
}
- Printf("%s\n", Decor.EndHighlight());
+ Buffer.append("%s\n", Decor.EndHighlight());
// Go over the line again, and print names for the ranges.
InRange = 0;
@@ -302,9 +307,9 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
if (InRange && InRange->getStart().getMemoryLocation() == P) {
while (Spaces--)
- Printf(" ");
- renderText(InRange->getText(), Args);
- Printf("\n");
+ Buffer.append(" ");
+ RenderText(&Buffer, InRange->getText(), Args);
+ Buffer.append("\n");
// FIXME: We only support naming one range for now!
break;
}
@@ -312,6 +317,7 @@ static void renderMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Spaces += 2;
}
+ Printf("%s", Buffer.data());
// FIXME: Print names for anything we can identify within the line:
//
// * If we can identify the memory itself as belonging to a particular
@@ -328,28 +334,30 @@ Diag::~Diag() {
// All diagnostics should be printed under report mutex.
CommonSanitizerReportMutex.CheckLocked();
Decorator Decor;
- Printf(Decor.Bold());
+ InternalScopedString Buffer(1024);
- renderLocation(Loc);
+ Buffer.append(Decor.Bold());
+ RenderLocation(&Buffer, Loc);
+ Buffer.append(":");
switch (Level) {
case DL_Error:
- Printf("%s runtime error: %s%s",
- Decor.Warning(), Decor.EndWarning(), Decor.Bold());
+ Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.EndWarning(),
+ Decor.Bold());
break;
case DL_Note:
- Printf("%s note: %s", Decor.Note(), Decor.EndNote());
+ Buffer.append("%s note: %s", Decor.Note(), Decor.EndNote());
break;
}
- renderText(Message, Args);
+ RenderText(&Buffer, Message, Args);
- Printf("%s\n", Decor.Default());
+ Buffer.append("%s\n", Decor.Default());
+ Printf("%s", Buffer.data());
if (Loc.isMemoryLocation())
- renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
- NumRanges, Args);
+ PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args);
}
ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
@@ -363,14 +371,19 @@ ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
MaybeReportErrorSummary(SummaryLoc, Type);
CommonSanitizerReportMutex.Unlock();
- if (Opts.DieAfterReport || flags()->halt_on_error)
+ if (flags()->halt_on_error)
Die();
}
ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kVptrCheck[] = "vptr_check";
-static const char *kSuppressionTypes[] = { kVptrCheck };
+static const char *kSuppressionTypes[] = {
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName,
+#include "ubsan_checks.inc"
+#undef UBSAN_CHECK
+ kVptrCheck,
+};
void __ubsan::InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
@@ -386,4 +399,28 @@ bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
return suppression_ctx->Match(TypeName, kVptrCheck, &s);
}
+bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) {
+ InitAsStandaloneIfNecessary();
+ CHECK(suppression_ctx);
+ const char *SuppType = ConvertTypeToFlagName(ET);
+ // Fast path: don't symbolize PC if there is no suppressions for given UB
+ // type.
+ if (!suppression_ctx->HasSuppressionType(SuppType))
+ return false;
+ Suppression *s = nullptr;
+ // Suppress by file name known to runtime.
+ if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s))
+ return true;
+ // Suppress by module name.
+ if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) {
+ if (suppression_ctx->Match(Module, SuppType, &s))
+ return true;
+ }
+ // Suppress by function or source file name from debug info.
+ SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC));
+ const AddressInfo &AI = Stack.get()->info;
+ return suppression_ctx->Match(AI.function, SuppType, &s) ||
+ suppression_ctx->Match(AI.file, SuppType, &s);
+}
+
#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_diag.h b/libsanitizer/ubsan/ubsan_diag.h
index 7103d522953..3456aaa72c5 100644
--- a/libsanitizer/ubsan/ubsan_diag.h
+++ b/libsanitizer/ubsan/ubsan_diag.h
@@ -209,23 +209,25 @@ public:
};
struct ReportOptions {
- /// If DieAfterReport is specified, UBSan will terminate the program after the
- /// report is printed.
- bool DieAfterReport;
+ // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
+ // expected to return.
+ bool FromUnrecoverableHandler;
/// pc/bp are used to unwind the stack trace.
uptr pc;
uptr bp;
};
enum class ErrorType {
-#define UBSAN_CHECK(Name, SummaryKind, FlagName) Name,
+#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
#include "ubsan_checks.inc"
#undef UBSAN_CHECK
};
-#define GET_REPORT_OPTIONS(die_after_report) \
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
+
+#define GET_REPORT_OPTIONS(unrecoverable_handler) \
GET_CALLER_PC_BP; \
- ReportOptions Opts = {die_after_report, pc, bp}
+ ReportOptions Opts = {unrecoverable_handler, pc, bp}
/// \brief Instantiate this class before printing diagnostics in the error
/// report. This class ensures that reports from different threads and from
@@ -236,14 +238,15 @@ class ScopedReport {
ErrorType Type;
public:
- ScopedReport(ReportOptions Opts, Location SummaryLoc,
- ErrorType Type = ErrorType::GenericUB);
- void setErrorType(ErrorType T) { Type = T; }
+ ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
~ScopedReport();
};
void InitializeSuppressions();
bool IsVptrCheckSuppressed(const char *TypeName);
+// Sometimes UBSan runtime can know filename from handlers arguments, even if
+// debug info is missing.
+bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
} // namespace __ubsan
diff --git a/libsanitizer/ubsan/ubsan_flags.cc b/libsanitizer/ubsan/ubsan_flags.cc
index 4e7db7a6a57..19f5de1727e 100644
--- a/libsanitizer/ubsan/ubsan_flags.cc
+++ b/libsanitizer/ubsan/ubsan_flags.cc
@@ -57,7 +57,7 @@ void InitializeFlags() {
parser.ParseString(MaybeCallUbsanDefaultOptions());
// Override from environment variable.
parser.ParseString(GetEnv("UBSAN_OPTIONS"));
- SetVerbosity(common_flags()->verbosity);
+ InitializeCommonFlags();
if (Verbosity()) ReportUnrecognizedFlags();
if (common_flags()->help) parser.PrintFlagDescriptions();
diff --git a/libsanitizer/ubsan/ubsan_handlers.cc b/libsanitizer/ubsan/ubsan_handlers.cc
index 8530fcffc88..0e343d32307 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cc
+++ b/libsanitizer/ubsan/ubsan_handlers.cc
@@ -19,17 +19,20 @@
using namespace __sanitizer;
using namespace __ubsan;
-static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
- // If source location is already acquired, we don't need to print an error
- // report for the second time. However, if we're in an unrecoverable handler,
- // it's possible that location was required by concurrently running thread.
- // In this case, we should continue the execution to ensure that any of
- // threads will grab the report mutex and print the report before
- // crashing the program.
- return SLoc.isDisabled() && !Opts.DieAfterReport;
+namespace __ubsan {
+bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
+ // We are not allowed to skip error report: if we are in unrecoverable
+ // handler, we have to terminate the program right now, and therefore
+ // have to print some diagnostic.
+ //
+ // Even if source location is disabled, it doesn't mean that we have
+ // already report an error to the user: some concurrently running
+ // thread could have acquired it, but not yet printed the report.
+ if (Opts.FromUnrecoverableHandler)
+ return false;
+ return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename());
}
-namespace __ubsan {
const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
@@ -39,8 +42,18 @@ const char *TypeCheckKinds[] = {
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
ReportOptions Opts) {
Location Loc = Data->Loc.acquire();
- // Use the SourceLocation from Data to track deduplication, even if 'invalid'
- if (ignoreReport(Loc.getSourceLocation(), Opts))
+
+ ErrorType ET;
+ if (!Pointer)
+ ET = ErrorType::NullPointerUse;
+ else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ ET = ErrorType::MisalignedPointerUse;
+ else
+ ET = ErrorType::InsufficientObjectSize;
+
+ // Use the SourceLocation from Data to track deduplication, even if it's
+ // invalid.
+ if (ignoreReport(Loc.getSourceLocation(), Opts, ET))
return;
SymbolizedStackHolder FallbackLoc;
@@ -49,24 +62,28 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
Loc = FallbackLoc;
}
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
- if (!Pointer) {
- R.setErrorType(ErrorType::NullPointerUse);
+ switch (ET) {
+ case ErrorType::NullPointerUse:
Diag(Loc, DL_Error, "%0 null pointer of type %1")
- << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
- } else if (Data->Alignment && (Pointer & (Data->Alignment - 1))) {
- R.setErrorType(ErrorType::MisalignedPointerUse);
+ << TypeCheckKinds[Data->TypeCheckKind] << Data->Type;
+ break;
+ case ErrorType::MisalignedPointerUse:
Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
"which requires %2 byte alignment")
- << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer
- << Data->Alignment << Data->Type;
- } else {
- R.setErrorType(ErrorType::InsufficientObjectSize);
+ << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer
+ << Data->Alignment << Data->Type;
+ break;
+ case ErrorType::InsufficientObjectSize:
Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
"for an object of type %2")
- << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
+ << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Data->Type;
+ break;
+ default:
+ UNREACHABLE("unexpected error type!");
}
+
if (Pointer)
Diag(Pointer, DL_Note, "pointer points here");
}
@@ -89,12 +106,14 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
const char *Operator, T RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- bool IsSigned = Data->Type.isSignedIntegerTy();
- ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
- : ErrorType::UnsignedIntegerOverflow);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "%0 integer overflow: "
"%1 %2 %3 cannot be represented in type %4")
@@ -102,12 +121,13 @@ static void handleIntegerOverflowImpl(OverflowData *Data, ValueHandle LHS,
<< Value(Data->Type, LHS) << Operator << RHS << Data->Type;
}
-#define UBSAN_OVERFLOW_HANDLER(handler_name, op, abort) \
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op, unrecoverable) \
void __ubsan::handler_name(OverflowData *Data, ValueHandle LHS, \
ValueHandle RHS) { \
- GET_REPORT_OPTIONS(abort); \
+ GET_REPORT_OPTIONS(unrecoverable); \
handleIntegerOverflowImpl(Data, LHS, op, Value(Data->Type, RHS), Opts); \
- if (abort) Die(); \
+ if (unrecoverable) \
+ Die(); \
}
UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "+", false)
@@ -120,12 +140,14 @@ UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow_abort, "*", true)
static void handleNegateOverflowImpl(OverflowData *Data, ValueHandle OldVal,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ bool IsSigned = Data->Type.isSignedIntegerTy();
+ ErrorType ET = IsSigned ? ErrorType::SignedIntegerOverflow
+ : ErrorType::UnsignedIntegerOverflow;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- bool IsSigned = Data->Type.isSignedIntegerTy();
- ScopedReport R(Opts, Loc, IsSigned ? ErrorType::SignedIntegerOverflow
- : ErrorType::UnsignedIntegerOverflow);
+ ScopedReport R(Opts, Loc, ET);
if (IsSigned)
Diag(Loc, DL_Error,
@@ -152,22 +174,30 @@ void __ubsan::__ubsan_handle_negate_overflow_abort(OverflowData *Data,
static void handleDivremOverflowImpl(OverflowData *Data, ValueHandle LHS,
ValueHandle RHS, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ Value LHSVal(Data->Type, LHS);
+ Value RHSVal(Data->Type, RHS);
+
+ ErrorType ET;
+ if (RHSVal.isMinusOne())
+ ET = ErrorType::SignedIntegerOverflow;
+ else if (Data->Type.isIntegerTy())
+ ET = ErrorType::IntegerDivideByZero;
+ else
+ ET = ErrorType::FloatDivideByZero;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
- Value LHSVal(Data->Type, LHS);
- Value RHSVal(Data->Type, RHS);
- if (RHSVal.isMinusOne()) {
- R.setErrorType(ErrorType::SignedIntegerOverflow);
- Diag(Loc, DL_Error,
- "division of %0 by -1 cannot be represented in type %1")
- << LHSVal << Data->Type;
- } else {
- R.setErrorType(Data->Type.isIntegerTy() ? ErrorType::IntegerDivideByZero
- : ErrorType::FloatDivideByZero);
+ switch (ET) {
+ case ErrorType::SignedIntegerOverflow:
+ Diag(Loc, DL_Error, "division of %0 by -1 cannot be represented in type %1")
+ << LHSVal << Data->Type;
+ break;
+ default:
Diag(Loc, DL_Error, "division by zero");
+ break;
}
}
@@ -188,29 +218,34 @@ static void handleShiftOutOfBoundsImpl(ShiftOutOfBoundsData *Data,
ValueHandle LHS, ValueHandle RHS,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ Value LHSVal(Data->LHSType, LHS);
+ Value RHSVal(Data->RHSType, RHS);
+
+ ErrorType ET;
+ if (RHSVal.isNegative() ||
+ RHSVal.getPositiveIntValue() >= Data->LHSType.getIntegerBitWidth())
+ ET = ErrorType::InvalidShiftExponent;
+ else
+ ET = ErrorType::InvalidShiftBase;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
- Value LHSVal(Data->LHSType, LHS);
- Value RHSVal(Data->RHSType, RHS);
- if (RHSVal.isNegative()) {
- R.setErrorType(ErrorType::InvalidShiftExponent);
- Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
- } else if (RHSVal.getPositiveIntValue() >=
- Data->LHSType.getIntegerBitWidth()) {
- R.setErrorType(ErrorType::InvalidShiftExponent);
- Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2")
- << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
- } else if (LHSVal.isNegative()) {
- R.setErrorType(ErrorType::InvalidShiftBase);
- Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+ if (ET == ErrorType::InvalidShiftExponent) {
+ if (RHSVal.isNegative())
+ Diag(Loc, DL_Error, "shift exponent %0 is negative") << RHSVal;
+ else
+ Diag(Loc, DL_Error, "shift exponent %0 is too large for %1-bit type %2")
+ << RHSVal << Data->LHSType.getIntegerBitWidth() << Data->LHSType;
} else {
- R.setErrorType(ErrorType::InvalidShiftBase);
- Diag(Loc, DL_Error,
- "left shift of %0 by %1 places cannot be represented in type %2")
- << LHSVal << RHSVal << Data->LHSType;
+ if (LHSVal.isNegative())
+ Diag(Loc, DL_Error, "left shift of negative value %0") << LHSVal;
+ else
+ Diag(Loc, DL_Error,
+ "left shift of %0 by %1 places cannot be represented in type %2")
+ << LHSVal << RHSVal << Data->LHSType;
}
}
@@ -232,10 +267,12 @@ void __ubsan::__ubsan_handle_shift_out_of_bounds_abort(
static void handleOutOfBoundsImpl(OutOfBoundsData *Data, ValueHandle Index,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::OutOfBoundsIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::OutOfBoundsIndex);
+ ScopedReport R(Opts, Loc, ET);
Value IndexVal(Data->IndexType, Index);
Diag(Loc, DL_Error, "index %0 out of bounds for type %1")
@@ -282,10 +319,12 @@ void __ubsan::__ubsan_handle_missing_return(UnreachableData *Data) {
static void handleVLABoundNotPositive(VLABoundData *Data, ValueHandle Bound,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::NonPositiveVLAIndex;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::NonPositiveVLAIndex);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "variable length array bound evaluates to "
"non-positive value %0")
@@ -327,6 +366,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
SymbolizedStackHolder CallerLoc;
Location Loc;
const TypeDescriptor *FromType, *ToType;
+ ErrorType ET = ErrorType::FloatCastOverflow;
if (looksLikeFloatCastOverflowDataV1(DataPtr)) {
auto Data = reinterpret_cast<FloatCastOverflowData *>(DataPtr);
@@ -337,14 +377,14 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
} else {
auto Data = reinterpret_cast<FloatCastOverflowDataV2 *>(DataPtr);
SourceLocation SLoc = Data->Loc.acquire();
- if (ignoreReport(SLoc, Opts))
+ if (ignoreReport(SLoc, Opts, ET))
return;
Loc = SLoc;
FromType = &Data->FromType;
ToType = &Data->ToType;
}
- ScopedReport R(Opts, Loc, ErrorType::FloatCastOverflow);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"value %0 is outside the range of representable values of type %2")
@@ -365,14 +405,16 @@ void __ubsan::__ubsan_handle_float_cast_overflow_abort(void *Data,
static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
- return;
-
// This check could be more precise if we used different handlers for
// -fsanitize=bool and -fsanitize=enum.
bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'"));
- ScopedReport R(Opts, Loc, IsBool ? ErrorType::InvalidBoolLoad
- : ErrorType::InvalidEnumLoad);
+ ErrorType ET =
+ IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
@@ -395,10 +437,12 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
ValueHandle Function,
ReportOptions Opts) {
SourceLocation CallLoc = Data->Loc.acquire();
- if (ignoreReport(CallLoc, Opts))
+ ErrorType ET = ErrorType::FunctionTypeMismatch;
+
+ if (ignoreReport(CallLoc, Opts, ET))
return;
- ScopedReport R(Opts, CallLoc, ErrorType::FunctionTypeMismatch);
+ ScopedReport R(Opts, CallLoc, ET);
SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
const char *FName = FLoc.get()->info.function;
@@ -427,10 +471,12 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort(
static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullReturn;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::InvalidNullReturn);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
@@ -451,10 +497,12 @@ void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::InvalidNullArgument;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc, ErrorType::InvalidNullArgument);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
"never be null") << Data->ArgIndex;
@@ -473,13 +521,18 @@ void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
Die();
}
-static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function,
+static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,
ReportOptions Opts) {
+ if (Data->CheckKind != CFITCK_ICall)
+ Die();
+
SourceLocation Loc = Data->Loc.acquire();
- if (ignoreReport(Loc, Opts))
+ ErrorType ET = ErrorType::CFIBadType;
+
+ if (ignoreReport(Loc, Opts, ET))
return;
- ScopedReport R(Opts, Loc);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
"indirect function call")
@@ -492,16 +545,37 @@ static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function,
Diag(FLoc, DL_Note, "%0 defined here") << FName;
}
-void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *Data,
- ValueHandle Function) {
+namespace __ubsan {
+#ifdef UBSAN_CAN_USE_CXXABI
+SANITIZER_WEAK_ATTRIBUTE
+void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts);
+#else
+static void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts) {
+ Die();
+}
+#endif
+} // namespace __ubsan
+
+void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
+ ValueHandle Value,
+ uptr ValidVtable) {
GET_REPORT_OPTIONS(false);
- handleCFIBadIcall(Data, Function, Opts);
+ if (Data->CheckKind == CFITCK_ICall)
+ handleCFIBadIcall(Data, Value, Opts);
+ else
+ HandleCFIBadType(Data, Value, ValidVtable, Opts);
}
-void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *Data,
- ValueHandle Function) {
+void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
+ ValueHandle Value,
+ uptr ValidVtable) {
GET_REPORT_OPTIONS(true);
- handleCFIBadIcall(Data, Function, Opts);
+ if (Data->CheckKind == CFITCK_ICall)
+ handleCFIBadIcall(Data, Value, Opts);
+ else
+ HandleCFIBadType(Data, Value, ValidVtable, Opts);
Die();
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index 668535868e9..ef741ca58ef 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -146,14 +146,25 @@ struct NonNullArgData {
/// \brief Handle passing null pointer to function with nonnull attribute.
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
-struct CFIBadIcallData {
+/// \brief Known CFI check kinds.
+/// Keep in sync with the enum of the same name in CodeGenFunction.h
+enum CFITypeCheckKind : unsigned char {
+ CFITCK_VCall,
+ CFITCK_NVCall,
+ CFITCK_DerivedCast,
+ CFITCK_UnrelatedCast,
+ CFITCK_ICall,
+};
+
+struct CFICheckFailData {
+ CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
-/// \brief Handle control flow integrity failure for indirect function calls.
-RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
-
+/// \brief Handle control flow integrity failures.
+RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
+ uptr VtableIsValid)
}
#endif // UBSAN_HANDLERS_H
diff --git a/libsanitizer/ubsan/ubsan_handlers_cxx.cc b/libsanitizer/ubsan/ubsan_handlers_cxx.cc
index b50b4d4636d..015a9ffee02 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.cc
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.cc
@@ -13,6 +13,7 @@
#include "ubsan_platform.h"
#if CAN_SANITIZE_UB
+#include "ubsan_handlers.h"
#include "ubsan_handlers_cxx.h"
#include "ubsan_diag.h"
#include "ubsan_type_hash.h"
@@ -27,34 +28,42 @@ namespace __ubsan {
extern const char *TypeCheckKinds[];
}
-static void HandleDynamicTypeCacheMiss(
+// Returns true if UBSan has printed an error report.
+static bool HandleDynamicTypeCacheMiss(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
ReportOptions Opts) {
if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
// Just a cache miss. The type matches after all.
- return;
+ return false;
// Check if error report should be suppressed.
DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
- return;
+ return false;
SourceLocation Loc = Data->Loc.acquire();
- if (Loc.isDisabled())
- return;
+ ErrorType ET = ErrorType::DynamicTypeMismatch;
+ if (ignoreReport(Loc, Opts, ET))
+ return false;
- ScopedReport R(Opts, Loc, ErrorType::DynamicTypeMismatch);
+ ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
"%0 address %1 which does not point to an object of type %2")
<< TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
// If possible, say what type it actually points to.
- if (!DTI.isValid())
- Diag(Pointer, DL_Note, "object has invalid vptr")
- << TypeName(DTI.getMostDerivedTypeName())
- << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
- else if (!DTI.getOffset())
+ if (!DTI.isValid()) {
+ if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
+ Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big")
+ << TypeName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
+ } else {
+ Diag(Pointer, DL_Note, "object has invalid vptr")
+ << TypeName(DTI.getMostDerivedTypeName())
+ << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
+ }
+ } else if (!DTI.getOffset())
Diag(Pointer, DL_Note, "object is of type %0")
<< TypeName(DTI.getMostDerivedTypeName())
<< Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
@@ -67,6 +76,7 @@ static void HandleDynamicTypeCacheMiss(
<< TypeName(DTI.getSubobjectTypeName())
<< Range(Pointer, Pointer + sizeof(uptr),
"vptr for %2 base class of %1");
+ return true;
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
@@ -76,45 +86,60 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
}
void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
- GET_REPORT_OPTIONS(true);
- HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
+ // Note: -fsanitize=vptr is always recoverable.
+ GET_REPORT_OPTIONS(false);
+ if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
+ Die();
}
-static void HandleCFIBadType(CFIBadTypeData *Data, ValueHandle Vtable,
- ReportOptions Opts) {
+namespace __ubsan {
+void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
- ScopedReport R(Opts, Loc, ErrorType::CFIBadType);
- DynamicTypeInfo DTI = getDynamicTypeInfoFromVtable((void*)Vtable);
+ ErrorType ET = ErrorType::CFIBadType;
- static const char *TypeCheckKinds[] = {
- "virtual call",
- "non-virtual call",
- "base-to-derived cast",
- "cast to unrelated type",
- };
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+ DynamicTypeInfo DTI = ValidVtable
+ ? getDynamicTypeInfoFromVtable((void *)Vtable)
+ : DynamicTypeInfo(0, 0, 0);
+
+ const char *CheckKindStr;
+ switch (Data->CheckKind) {
+ case CFITCK_VCall:
+ CheckKindStr = "virtual call";
+ break;
+ case CFITCK_NVCall:
+ CheckKindStr = "non-virtual call";
+ break;
+ case CFITCK_DerivedCast:
+ CheckKindStr = "base-to-derived cast";
+ break;
+ case CFITCK_UnrelatedCast:
+ CheckKindStr = "cast to unrelated type";
+ break;
+ case CFITCK_ICall:
+ Die();
+ }
Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
"%1 (vtable address %2)")
- << Data->Type << TypeCheckKinds[Data->TypeCheckKind] << (void *)Vtable;
+ << Data->Type << CheckKindStr << (void *)Vtable;
// If possible, say what type it actually points to.
- if (!DTI.isValid())
- Diag(Vtable, DL_Note, "invalid vtable");
- else
+ if (!DTI.isValid()) {
+ const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
+ if (module)
+ Diag(Vtable, DL_Note, "invalid vtable in module %0") << module;
+ else
+ Diag(Vtable, DL_Note, "invalid vtable");
+ } else {
Diag(Vtable, DL_Note, "vtable is of type %0")
<< TypeName(DTI.getMostDerivedTypeName());
+ }
}
+} // namespace __ubsan
-void __ubsan::__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data,
- ValueHandle Vtable) {
- GET_REPORT_OPTIONS(false);
- HandleCFIBadType(Data, Vtable, Opts);
-}
-
-void __ubsan::__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data,
- ValueHandle Vtable) {
- GET_REPORT_OPTIONS(true);
- HandleCFIBadType(Data, Vtable, Opts);
-}
-
-#endif // CAN_SANITIZE_UB
+#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_handlers_cxx.h b/libsanitizer/ubsan/ubsan_handlers_cxx.h
index b1486864298..37382359b1e 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.h
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.h
@@ -23,12 +23,6 @@ struct DynamicTypeCacheMissData {
unsigned char TypeCheckKind;
};
-struct CFIBadTypeData {
- SourceLocation Loc;
- const TypeDescriptor &Type;
- unsigned char TypeCheckKind;
-};
-
/// \brief Handle a runtime type check failure, caused by an incorrect vptr.
/// When this handler is called, all we know is that the type was not in the
/// cache; this does not necessarily imply the existence of a bug.
@@ -38,14 +32,6 @@ void __ubsan_handle_dynamic_type_cache_miss(
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
-
-/// \brief Handle a control flow integrity check failure by printing a
-/// diagnostic.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data, ValueHandle Vtable);
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data, ValueHandle Vtable);
-
}
#endif // UBSAN_HANDLERS_H
diff --git a/libsanitizer/ubsan/ubsan_init.cc b/libsanitizer/ubsan/ubsan_init.cc
index 5da4122c07a..07f748109e7 100644
--- a/libsanitizer/ubsan/ubsan_init.cc
+++ b/libsanitizer/ubsan/ubsan_init.cc
@@ -37,6 +37,7 @@ static void CommonStandaloneInit() {
InitializeFlags();
CacheBinaryName();
__sanitizer_set_report_path(common_flags()->log_path);
+ AndroidLogInit();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
CommonInit();
ubsan_mode = UBSAN_MODE_STANDALONE;
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index 999bf815493..fa4e1a191aa 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -15,7 +15,8 @@
// Other platforms should be easy to add, and probably work as-is.
#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \
(defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
- defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__))
+ defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \
+ defined(__s390__))
# define CAN_SANITIZE_UB 1
#elif defined(_WIN32)
# define CAN_SANITIZE_UB 1
diff --git a/libsanitizer/ubsan/ubsan_type_hash.h b/libsanitizer/ubsan/ubsan_type_hash.h
index 2da070edffa..610fcb44ea7 100644
--- a/libsanitizer/ubsan/ubsan_type_hash.h
+++ b/libsanitizer/ubsan/ubsan_type_hash.h
@@ -51,6 +51,10 @@ bool checkDynamicType(void *Object, void *Type, HashValue Hash);
const unsigned VptrTypeCacheSize = 128;
+/// A sanity check for Vtable. Offsets to top must be reasonably small
+/// numbers (by absolute value). It's a weak check for Vtable corruption.
+const int VptrMaxOffsetToTop = 1<<20;
+
/// \brief A cache of the results of checkDynamicType. \c checkDynamicType would
/// return \c true (modulo hash collisions) if
/// \code
diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cc b/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
index e4f133434d6..790b126815d 100644
--- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
+++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
@@ -71,6 +71,8 @@ public:
namespace abi = __cxxabiv1;
+using namespace __sanitizer;
+
// We implement a simple two-level cache for type-checking results. For each
// (vptr,type) pair, a hash is computed. This hash is assumed to be globally
// unique; if it collides, we will get false negatives, but:
@@ -113,7 +115,9 @@ static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
const abi::__class_type_info *Base,
sptr Offset) {
- if (Derived->__type_name == Base->__type_name)
+ if (Derived->__type_name == Base->__type_name ||
+ (SANITIZER_NON_UNIQUE_TYPEINFO &&
+ !internal_strcmp(Derived->__type_name, Base->__type_name)))
return Offset == 0;
if (const abi::__si_class_type_info *SI =
@@ -161,7 +165,7 @@ static const abi::__class_type_info *findBaseAtOffset(
dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
if (!VTI)
// No base class subobjects.
- return 0;
+ return nullptr;
for (unsigned int base = 0; base != VTI->base_count; ++base) {
sptr OffsetHere = VTI->base_info[base].__offset_flags >>
@@ -176,7 +180,7 @@ static const abi::__class_type_info *findBaseAtOffset(
return Base;
}
- return 0;
+ return nullptr;
}
namespace {
@@ -192,11 +196,11 @@ struct VtablePrefix {
VtablePrefix *getVtablePrefix(void *Vtable) {
VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
if (!Vptr)
- return 0;
+ return nullptr;
VtablePrefix *Prefix = Vptr - 1;
if (!Prefix->TypeInfo)
// This can't possibly be a valid vtable.
- return 0;
+ return nullptr;
return Prefix;
}
@@ -217,6 +221,10 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) {
VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
if (!Vtable)
return false;
+ if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop) {
+ // Too large or too small offset are signs of Vtable corruption.
+ return false;
+ }
// Check that this is actually a type_info object for a class type.
abi::__class_type_info *Derived =
@@ -238,7 +246,9 @@ __ubsan::DynamicTypeInfo
__ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) {
VtablePrefix *Vtable = getVtablePrefix(VtablePtr);
if (!Vtable)
- return DynamicTypeInfo(0, 0, 0);
+ return DynamicTypeInfo(nullptr, 0, nullptr);
+ if (Vtable->Offset < -VptrMaxOffsetToTop || Vtable->Offset > VptrMaxOffsetToTop)
+ return DynamicTypeInfo(nullptr, Vtable->Offset, nullptr);
const abi::__class_type_info *ObjectType = findBaseAtOffset(
static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
-Vtable->Offset);
diff --git a/libsanitizer/ubsan/ubsan_value.cc b/libsanitizer/ubsan/ubsan_value.cc
index e327f6ffc2e..3e158f92e07 100644
--- a/libsanitizer/ubsan/ubsan_value.cc
+++ b/libsanitizer/ubsan/ubsan_value.cc
@@ -81,12 +81,12 @@ FloatMax Value::getFloatValue() const {
#endif
case 32: {
float Value;
-#if defined(__BIG_ENDIAN__)
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
// For big endian the float value is in the last 4 bytes.
// On some targets we may only have 4 bytes so we count backwards from
// the end of Val to account for both the 32-bit and 64-bit cases.
internal_memcpy(&Value, ((const char*)(&Val + 1)) - 4, 4);
-#else
+#else
internal_memcpy(&Value, &Val, 4);
#endif
return Value;
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 61afd6b78d7..61dafba43e9 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,5 +1,40 @@
+2016-11-07 Jason Merrill <jason@redhat.com>
+
+ * include/bits/c++config (_GLIBCXX_NOEXCEPT_PARM)
+ (_GLIBCXX_NOEXCEPT_QUAL): New.
+ * include/std/type_traits (is_function): Use them.
+ * libsubc++/new (launder): Likewise.
+ * libsupc++/cxxabi.h (__pbase_type_info::__masks): Add
+ __noexcept_mask.
+ * libsupc++/pbase_type_info.cc (__do_catch): Handle function
+ pointer conversion.
+
+2016-11-07 François Dumont <fdumont@gcc.gnu.org>
+
+ * config/abi/pre/gnu-versioned-namespace.ver: Export C++17 new of
+ over-aligned types symbols.
+
2016-10-28 Jonathan Wakely <jwakely@redhat.com>
+ * include/experimental/bits/fs_path.h (__is_path_src)
+ (_S_range_begin, _S_range_end): Overload to treat string_view as a
+ Source object.
+ (path::operator+=, path::compare): Overload for basic_string_view.
+ * testsuite/experimental/filesystem/path/construct/string_view.cc:
+ New test.
+ * testsuite/experimental/filesystem/path/construct/
+ string_view_cxx17.cc: New test.
+
+ * include/experimental/bits/fs_path.h
+ (path::_S_convert<_Iter>(_Iter, _Iter)): Remove cv-qualifiers from
+ iterator's value_type.
+ (path::_S_convert<_Iter>(_Iter __first, __null_terminated)): Likewise.
+ Do not use operation not supported by input iterators.
+ (path::__is_path_iter_src): Add partial specialization for const
+ encoded character types.
+ * testsuite/experimental/filesystem/path/construct/range.cc: Test
+ construction from input iterators with const value types.
+
* doc/xml/manual/status_cxx2017.xml: Update status.
* doc/html/*: Regenerate.
* include/std/type_traits (has_unique_object_representations): Guard
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index 34d58aea206..bffb35cf26f 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -348,6 +348,18 @@ CXXABI_2.0 {
# __gnu_cxx::__freeres()
_ZN9__gnu_cxx9__freeresEv;
+
+ # C++17 aligned new/delete
+ _Znw[jmy]St11align_val_t;
+ _Znw[jmy]St11align_val_tRKSt9nothrow_t;
+ _Zna[jmy]St11align_val_t;
+ _Zna[jmy]St11align_val_tRKSt9nothrow_t;
+ _ZdlPvSt11align_val_t;
+ _ZdlPvSt11align_val_tRKSt9nothrow_t;
+ _ZdlPv[jmy]St11align_val_t;
+ _ZdaPvSt11align_val_t;
+ _ZdaPvSt11align_val_tRKSt9nothrow_t;
+ _ZdaPv[jmy]St11align_val_t;
};
# Symbols in the support library (libsupc++) supporting trans-mem.
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index 6d3226fcd57..8a27d14f951 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -146,6 +146,14 @@
# endif
#endif
+#if __cpp_noexcept_function_type
+#define _GLIBCXX_NOEXCEPT_PARM , bool _N
+#define _GLIBCXX_NOEXCEPT_QUAL noexcept (_N)
+#else
+#define _GLIBCXX_NOEXCEPT_PARM
+#define _GLIBCXX_NOEXCEPT_QUAL
+#endif
+
// Macro for extern template, ie controlling template linkage via use
// of extern keyword on template declaration. As documented in the g++
// manual, it inhibits all implicit instantiations and is used
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 4d7291f9f07..70a5445dfa8 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -44,6 +44,9 @@
#include <bits/stl_algobase.h>
#include <bits/quoted_string.h>
#include <bits/locale_conv.h>
+#if __cplusplus == 201402L
+# include <experimental/string_view>
+#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
@@ -61,6 +64,12 @@ inline namespace v1
_GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_BEGIN_NAMESPACE_CXX11
+#if __cplusplus == 201402L
+ using std::experimental::basic_string_view;
+#elif __cplusplus > 201402L
+ using std::basic_string_view;
+#endif
+
/**
* @ingroup filesystem
* @{
@@ -87,6 +96,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
static __is_encoded_char<_CharT>
__is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
+#if __cplusplus >= 201402L
+ template<typename _CharT, typename _Traits>
+ static __is_encoded_char<_CharT>
+ __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
+#endif
+
template<typename _Unknown>
static std::false_type
__is_path_src(const _Unknown&, ...);
@@ -130,6 +145,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data() + __str.size(); }
+#if __cplusplus >= 201402L
+ template<typename _CharT, typename _Traits>
+ static const _CharT*
+ _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
+ { return __str.data(); }
+
+ template<typename _CharT, typename _Traits>
+ static const _CharT*
+ _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
+ { return __str.data() + __str.size(); }
+#endif
+
template<typename _Tp,
typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
typename _Val = typename std::iterator_traits<_Iter>::value_type>
@@ -243,6 +270,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
path& operator+=(const string_type& __x);
path& operator+=(const value_type* __x);
path& operator+=(value_type __x);
+#if __cplusplus >= 201402L
+ path& operator+=(basic_string_view<value_type> __x);
+#endif
template<typename _Source>
_Path<_Source>&
@@ -311,6 +341,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
int compare(const path& __p) const noexcept;
int compare(const string_type& __s) const;
int compare(const value_type* __s) const;
+#if __cplusplus >= 201402L
+ int compare(const basic_string_view<value_type> __s) const;
+#endif
// decomposition
@@ -385,7 +418,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_S_convert(_Iter __first, _Iter __last)
{
using __value_type = typename std::iterator_traits<_Iter>::value_type;
- return _Cvt<__value_type>::_S_convert(__first, __last);
+ return _Cvt<remove_cv_t<__value_type>>::_S_convert(__first, __last);
}
template<typename _InputIterator>
@@ -393,10 +426,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_S_convert(_InputIterator __src, __null_terminated)
{
using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
- std::basic_string<_Tp> __tmp;
- while (*__src != _Tp{})
- __tmp.push_back(*__src++);
- return _S_convert(__tmp.data(), __tmp.data() + __tmp.size());
+ std::basic_string<remove_cv_t<_Tp>> __tmp;
+ for (; *__src != _Tp{}; ++__src)
+ __tmp.push_back(*__src);
+ return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
}
static string_type
@@ -571,6 +604,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
struct path::__is_encoded_char<char32_t> : std::true_type
{ using value_type = char32_t; };
+ template<typename _Tp>
+ struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+
struct path::_Cmpt : path
{
_Cmpt(string_type __s, _Type __t, size_t __pos)
@@ -765,6 +801,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return *this;
}
+#if __cplusplus >= 201402L
+ inline path&
+ path::operator+=(basic_string_view<value_type> __x)
+ {
+ _M_pathname.append(__x.data(), __x.size());
+ _M_split_cmpts();
+ return *this;
+ }
+#endif
+
template<typename _CharT>
inline path::_Path<_CharT*, _CharT*>&
path::operator+=(_CharT __x)
@@ -906,6 +952,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
inline int
path::compare(const value_type* __s) const { return compare(path(__s)); }
+#if __cplusplus >= 201402L
+ inline int
+ path::compare(basic_string_view<value_type> __s) const
+ { return compare(path(__s)); }
+#endif
+
inline path
path::filename() const { return empty() ? path() : *--end(); }
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 6824c9eb27e..e5f2bbaf745 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -458,100 +458,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct is_function
: public false_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...)>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......)>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) volatile>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) volatile _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) volatile &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) volatile & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) volatile &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) volatile && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) volatile>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) volatile _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) volatile &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) volatile & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) volatile &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) volatile && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const volatile>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const volatile _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const volatile &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes...) const volatile &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes...) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const volatile>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const volatile _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const volatile &>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const volatile & _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
- template<typename _Res, typename... _ArgTypes>
- struct is_function<_Res(_ArgTypes......) const volatile &&>
+ template<typename _Res, typename... _ArgTypes _GLIBCXX_NOEXCEPT_PARM>
+ struct is_function<_Res(_ArgTypes......) const volatile && _GLIBCXX_NOEXCEPT_QUAL>
: public true_type { };
#define __cpp_lib_is_null_pointer 201309
diff --git a/libstdc++-v3/libsupc++/cxxabi.h b/libstdc++-v3/libsupc++/cxxabi.h
index f4b8f75fd18..7f1bd996a35 100644
--- a/libstdc++-v3/libsupc++/cxxabi.h
+++ b/libstdc++-v3/libsupc++/cxxabi.h
@@ -279,7 +279,8 @@ namespace __cxxabiv1
__restrict_mask = 0x4,
__incomplete_mask = 0x8,
__incomplete_class_mask = 0x10,
- __transaction_safe_mask = 0x20
+ __transaction_safe_mask = 0x20,
+ __noexcept_mask = 0x40
};
protected:
diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new
index 6bc6c008c18..1e596493815 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -197,10 +197,10 @@ namespace std
// The program is ill-formed if T is a function type or
// (possibly cv-qualified) void.
- template<typename _Ret, typename... _Args>
- void launder(_Ret (*)(_Args...)) = delete;
- template<typename _Ret, typename... _Args>
- void launder(_Ret (*)(_Args......)) = delete;
+ template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
+ void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete;
+ template<typename _Ret, typename... _Args _GLIBCXX_NOEXCEPT_PARM>
+ void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete;
void launder(void*) = delete;
void launder(const void*) = delete;
diff --git a/libstdc++-v3/libsupc++/pbase_type_info.cc b/libstdc++-v3/libsupc++/pbase_type_info.cc
index ff6b756519b..b2b9c090097 100644
--- a/libstdc++-v3/libsupc++/pbase_type_info.cc
+++ b/libstdc++-v3/libsupc++/pbase_type_info.cc
@@ -80,12 +80,13 @@ __do_catch (const type_info *thr_type,
unsigned tflags = thrown_type->__flags;
- bool throw_tx = (tflags & __transaction_safe_mask);
- bool catch_tx = (__flags & __transaction_safe_mask);
- if (throw_tx && !catch_tx)
- /* Catch can perform a transaction-safety conversion. */
- tflags &= ~__transaction_safe_mask;
- if (catch_tx && !throw_tx)
+ const unsigned fqual_mask = __transaction_safe_mask|__noexcept_mask;
+ unsigned throw_fqual = (tflags & fqual_mask);
+ unsigned catch_fqual = (__flags & fqual_mask);
+ if (throw_fqual & ~catch_fqual)
+ /* Catch can perform a function pointer conversion. */
+ tflags &= catch_fqual;
+ if (catch_fqual & ~throw_fqual)
/* But not the reverse. */
return false;
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
index b68e65d84ef..3dfec2fac5c 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/range.cc
@@ -24,6 +24,7 @@
#include <experimental/filesystem>
#include <string>
#include <testsuite_fs.h>
+#include <testsuite_iterators.h>
using std::experimental::filesystem::path;
using __gnu_test::compare_paths;
@@ -54,6 +55,52 @@ test01()
compare_paths(p1, p7);
compare_paths(p1, p8);
#endif
+
+ using __gnu_test::test_container;
+ using __gnu_test::input_iterator_wrapper;
+ // Test with input iterators and const value_types
+ test_container<char, input_iterator_wrapper>
+ r1(&s.front(), &s.front() + s.size());
+ path p9(r1.begin(), r1.end());
+ compare_paths(p1, p9);
+
+ test_container<char, input_iterator_wrapper>
+ r2(&s.front(), &s.front() + s.size() + 1); // includes null-terminator
+ path p10(r2.begin());
+ compare_paths(p1, p10);
+
+ test_container<const char, input_iterator_wrapper>
+ r3(s.c_str(), s.c_str() + s.size());
+ path p11(r3.begin(), r3.end());
+ compare_paths(p1, p11);
+
+ test_container<const char, input_iterator_wrapper>
+ r4(s.c_str(), s.c_str() + s.size() + 1); // includes null-terminator
+ path p12(r4.begin());
+ compare_paths(p1, p12);
+
+#if _GLIBCXX_USE_WCHAR_T
+ // Test with input iterators and const value_types
+ test_container<wchar_t, input_iterator_wrapper>
+ r5(&ws.front(), &ws.front() + ws.size());
+ path p13(r5.begin(), r5.end());
+ compare_paths(p1, p13);
+
+ test_container<wchar_t, input_iterator_wrapper>
+ r6(&ws.front(), &ws.front() + ws.size() + 1); // includes null-terminator
+ path p14(r6.begin());
+ compare_paths(p1, p14);
+
+ test_container<const wchar_t, input_iterator_wrapper>
+ r7(ws.c_str(), ws.c_str() + ws.size());
+ path p15(r7.begin(), r7.end());
+ compare_paths(p1, p15);
+
+ test_container<const wchar_t, input_iterator_wrapper>
+ r8(ws.c_str(), ws.c_str() + ws.size() + 1); // includes null-terminator
+ path p16(r8.begin());
+ compare_paths(p1, p16);
+#endif
}
}
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
new file mode 100644
index 00000000000..13ebaaa905a
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
@@ -0,0 +1,56 @@
+// { dg-options "-lstdc++fs -std=gnu++1z" }
+// { dg-do run { target c++1z } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library 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 3, or (at your option)
+// any later version.
+
+// This library 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 library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <experimental/filesystem>
+#include <string_view>
+#include <string>
+#include <testsuite_fs.h>
+
+using std::experimental::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+ for (std::string s : __gnu_test::test_paths)
+ {
+ path p1 = s;
+ std::string_view sv(s);
+ path p2 = sv;
+ compare_paths(p1, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring ws(s.begin(), s.end());
+ path p3 = ws;
+ std::wstring_view wsv(ws);
+ path p4 = wsv;
+ compare_paths(p1, p4);
+#endif
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc b/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc
index 20bc198d5f1..15cebed38f8 100644
--- a/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc
+++ b/libstdc++-v3/testsuite/ext/profile/mutex_extensions_neg.cc
@@ -25,7 +25,7 @@
#include <vector>
-// { dg-error "multiple inlined namespaces" "" { target *-*-* } 342 }
+// { dg-error "multiple inlined namespaces" "" { target *-*-* } 350 }
// "template argument 1 is invalid"
// { dg-prune-output "tuple:993" }