1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cc 16 17import ( 18 "strconv" 19 20 "github.com/google/blueprint" 21 22 "android/soong/android" 23) 24 25const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw" 26 27type CoverageProperties struct { 28 Native_coverage *bool 29 30 NeedCoverageVariant bool `blueprint:"mutated"` 31 NeedCoverageBuild bool `blueprint:"mutated"` 32 33 CoverageEnabled bool `blueprint:"mutated"` 34 IsCoverageVariant bool `blueprint:"mutated"` 35} 36 37type coverage struct { 38 Properties CoverageProperties 39 40 // Whether binaries containing this module need --coverage added to their ldflags 41 linkCoverage bool 42} 43 44func (cov *coverage) props() []interface{} { 45 return []interface{}{&cov.Properties} 46} 47 48func getGcovProfileLibraryName(ctx ModuleContextIntf) string { 49 // This function should only ever be called for a cc.Module, so the 50 // following statement should always succeed. 51 if ctx.useSdk() { 52 return "libprofile-extras_ndk" 53 } else { 54 return "libprofile-extras" 55 } 56} 57 58func getClangProfileLibraryName(ctx ModuleContextIntf) string { 59 if ctx.useSdk() { 60 return "libprofile-clang-extras_ndk" 61 } else if ctx.isCfiAssemblySupportEnabled() { 62 return "libprofile-clang-extras_cfi_support" 63 } else { 64 return "libprofile-clang-extras" 65 } 66} 67 68func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { 69 if cov.Properties.NeedCoverageVariant { 70 ctx.AddVariationDependencies([]blueprint.Variation{ 71 {Mutator: "link", Variation: "static"}, 72 }, CoverageDepTag, getGcovProfileLibraryName(ctx)) 73 ctx.AddVariationDependencies([]blueprint.Variation{ 74 {Mutator: "link", Variation: "static"}, 75 }, CoverageDepTag, getClangProfileLibraryName(ctx)) 76 } 77 return deps 78} 79 80func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { 81 clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled() 82 gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled() 83 84 if !gcovCoverage && !clangCoverage { 85 return flags, deps 86 } 87 88 if cov.Properties.CoverageEnabled { 89 cov.linkCoverage = true 90 91 if gcovCoverage { 92 flags.GcovCoverage = true 93 flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0") 94 95 // Override -Wframe-larger-than and non-default optimization 96 // flags that the module may use. 97 flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0") 98 } else if clangCoverage { 99 flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, 100 "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__") 101 } 102 } 103 104 // Even if we don't have coverage enabled, if any of our object files were compiled 105 // with coverage, then we need to add --coverage to our ldflags. 106 if !cov.linkCoverage { 107 if ctx.static() && !ctx.staticBinary() { 108 // For static libraries, the only thing that changes our object files 109 // are included whole static libraries, so check to see if any of 110 // those have coverage enabled. 111 ctx.VisitDirectDeps(func(m android.Module) { 112 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { 113 if depTag.static() && depTag.wholeStatic { 114 if cc, ok := m.(*Module); ok && cc.coverage != nil { 115 if cc.coverage.linkCoverage { 116 cov.linkCoverage = true 117 } 118 } 119 } 120 } 121 }) 122 } else { 123 // For executables and shared libraries, we need to check all of 124 // our static dependencies. 125 ctx.VisitDirectDeps(func(m android.Module) { 126 cc, ok := m.(*Module) 127 if !ok || cc.coverage == nil { 128 return 129 } 130 131 if static, ok := cc.linker.(libraryInterface); !ok || !static.static() { 132 return 133 } 134 135 if cc.coverage.linkCoverage { 136 cov.linkCoverage = true 137 } 138 }) 139 } 140 } 141 142 if cov.linkCoverage { 143 if gcovCoverage { 144 flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage") 145 146 coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module) 147 deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) 148 149 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") 150 } else if clangCoverage { 151 flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag) 152 153 coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) 154 deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) 155 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open") 156 } 157 } 158 159 return flags, deps 160} 161 162func (cov *coverage) begin(ctx BaseModuleContext) { 163 if ctx.Host() { 164 // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a 165 // Just turn off for now. 166 } else { 167 cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion()) 168 } 169} 170 171func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool, 172 useSdk bool, sdkVersion string) CoverageProperties { 173 // Coverage is disabled globally 174 if !ctx.DeviceConfig().NativeCoverageEnabled() { 175 return properties 176 } 177 178 var needCoverageVariant bool 179 var needCoverageBuild bool 180 181 if moduleTypeHasCoverage { 182 // Check if Native_coverage is set to false. This property defaults to true. 183 needCoverageVariant = BoolDefault(properties.Native_coverage, true) 184 if useSdk && sdkVersion != "current" { 185 // Native coverage is not supported for SDK versions < 23 186 if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 { 187 needCoverageVariant = false 188 } 189 } 190 191 if needCoverageVariant { 192 // Coverage variant is actually built with coverage if enabled for its module path 193 needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir()) 194 } 195 } 196 197 properties.NeedCoverageBuild = needCoverageBuild 198 properties.NeedCoverageVariant = needCoverageVariant 199 200 return properties 201} 202 203// Coverage is an interface for non-CC modules to implement to be mutated for coverage 204type Coverage interface { 205 android.Module 206 IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool 207 SetPreventInstall() 208 HideFromMake() 209 MarkAsCoverageVariant(bool) 210 EnableCoverageIfNeeded() 211} 212 213func coverageMutator(mctx android.BottomUpMutatorContext) { 214 if c, ok := mctx.Module().(*Module); ok && c.coverage != nil { 215 needCoverageVariant := c.coverage.Properties.NeedCoverageVariant 216 needCoverageBuild := c.coverage.Properties.NeedCoverageBuild 217 if needCoverageVariant { 218 m := mctx.CreateVariations("", "cov") 219 220 // Setup the non-coverage version and set HideFromMake and 221 // PreventInstall to true. 222 m[0].(*Module).coverage.Properties.CoverageEnabled = false 223 m[0].(*Module).coverage.Properties.IsCoverageVariant = false 224 m[0].(*Module).Properties.HideFromMake = true 225 m[0].(*Module).Properties.PreventInstall = true 226 227 // The coverage-enabled version inherits HideFromMake, 228 // PreventInstall from the original module. 229 m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild 230 m[1].(*Module).coverage.Properties.IsCoverageVariant = true 231 } 232 } else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) { 233 // APEX and Rust modules fall here 234 235 // Note: variant "" is also created because an APEX can be depended on by another 236 // module which are split into "" and "cov" variants. e.g. when cc_test refers 237 // to an APEX via 'data' property. 238 m := mctx.CreateVariations("", "cov") 239 m[0].(Coverage).MarkAsCoverageVariant(false) 240 m[0].(Coverage).SetPreventInstall() 241 m[0].(Coverage).HideFromMake() 242 243 m[1].(Coverage).MarkAsCoverageVariant(true) 244 m[1].(Coverage).EnableCoverageIfNeeded() 245 } 246} 247