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 EnableContinuousCoverage(ctx android.BaseModuleContext) bool { 81 return ctx.DeviceConfig().ClangCoverageContinuousMode() 82} 83 84func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { 85 clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled() 86 gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled() 87 88 if !gcovCoverage && !clangCoverage { 89 return flags, deps 90 } 91 92 if cov.Properties.CoverageEnabled { 93 cov.linkCoverage = true 94 95 if gcovCoverage { 96 flags.GcovCoverage = true 97 flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0") 98 99 // Override -Wframe-larger-than and non-default optimization 100 // flags that the module may use. 101 flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0") 102 } else if clangCoverage { 103 flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, 104 "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__") 105 // Override -Wframe-larger-than. We can expect frame size increase after 106 // coverage instrumentation. 107 flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=") 108 if EnableContinuousCoverage(ctx) { 109 flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation") 110 } 111 112 // http://b/248022906, http://b/247941801 enabling coverage and hwasan-globals 113 // instrumentation together causes duplicate-symbol errors for __llvm_profile_filename. 114 if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) { 115 flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-hwasan-globals=0") 116 } 117 } 118 } 119 120 // Even if we don't have coverage enabled, if any of our object files were compiled 121 // with coverage, then we need to add --coverage to our ldflags. 122 if !cov.linkCoverage { 123 if ctx.static() && !ctx.staticBinary() { 124 // For static libraries, the only thing that changes our object files 125 // are included whole static libraries, so check to see if any of 126 // those have coverage enabled. 127 ctx.VisitDirectDeps(func(m android.Module) { 128 if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { 129 if depTag.static() && depTag.wholeStatic { 130 if cc, ok := m.(*Module); ok && cc.coverage != nil { 131 if cc.coverage.linkCoverage { 132 cov.linkCoverage = true 133 } 134 } 135 } 136 } 137 }) 138 } else { 139 // For executables and shared libraries, we need to check all of 140 // our static dependencies. 141 ctx.VisitDirectDeps(func(m android.Module) { 142 cc, ok := m.(*Module) 143 if !ok || cc.coverage == nil { 144 return 145 } 146 147 if static, ok := cc.linker.(libraryInterface); !ok || !static.static() { 148 return 149 } 150 151 if cc.coverage.linkCoverage { 152 cov.linkCoverage = true 153 } 154 }) 155 } 156 } 157 158 if cov.linkCoverage { 159 if gcovCoverage { 160 flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage") 161 162 coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module) 163 deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) 164 165 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") 166 } else if clangCoverage { 167 flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag) 168 if EnableContinuousCoverage(ctx) { 169 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation") 170 } 171 172 coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) 173 deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) 174 flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open") 175 } 176 } 177 178 return flags, deps 179} 180 181func (cov *coverage) begin(ctx BaseModuleContext) { 182 if ctx.Host() { 183 // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a 184 // Just turn off for now. 185 } else { 186 cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion()) 187 } 188} 189 190func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool, 191 useSdk bool, sdkVersion string) CoverageProperties { 192 // Coverage is disabled globally 193 if !ctx.DeviceConfig().NativeCoverageEnabled() { 194 return properties 195 } 196 197 var needCoverageVariant bool 198 var needCoverageBuild bool 199 200 if moduleTypeHasCoverage { 201 // Check if Native_coverage is set to false. This property defaults to true. 202 needCoverageVariant = BoolDefault(properties.Native_coverage, true) 203 if useSdk && sdkVersion != "current" { 204 // Native coverage is not supported for SDK versions < 23 205 if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 { 206 needCoverageVariant = false 207 } 208 } 209 210 if needCoverageVariant { 211 // Coverage variant is actually built with coverage if enabled for its module path 212 needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir()) 213 } 214 } 215 216 properties.NeedCoverageBuild = needCoverageBuild 217 properties.NeedCoverageVariant = needCoverageVariant 218 219 return properties 220} 221 222type UseCoverage interface { 223 android.Module 224 IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool 225} 226 227// Coverage is an interface for non-CC modules to implement to be mutated for coverage 228type Coverage interface { 229 UseCoverage 230 SetPreventInstall() 231 HideFromMake() 232 MarkAsCoverageVariant(bool) 233 EnableCoverageIfNeeded() 234} 235 236func coverageMutator(mctx android.BottomUpMutatorContext) { 237 if c, ok := mctx.Module().(*Module); ok && c.coverage != nil { 238 needCoverageVariant := c.coverage.Properties.NeedCoverageVariant 239 needCoverageBuild := c.coverage.Properties.NeedCoverageBuild 240 if needCoverageVariant { 241 m := mctx.CreateVariations("", "cov") 242 243 // Setup the non-coverage version and set HideFromMake and 244 // PreventInstall to true. 245 m[0].(*Module).coverage.Properties.CoverageEnabled = false 246 m[0].(*Module).coverage.Properties.IsCoverageVariant = false 247 m[0].(*Module).Properties.HideFromMake = true 248 m[0].(*Module).Properties.PreventInstall = true 249 250 // The coverage-enabled version inherits HideFromMake, 251 // PreventInstall from the original module. 252 m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild 253 m[1].(*Module).coverage.Properties.IsCoverageVariant = true 254 } 255 } else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) { 256 // APEX and Rust modules fall here 257 258 // Note: variant "" is also created because an APEX can be depended on by another 259 // module which are split into "" and "cov" variants. e.g. when cc_test refers 260 // to an APEX via 'data' property. 261 m := mctx.CreateVariations("", "cov") 262 m[0].(Coverage).MarkAsCoverageVariant(false) 263 m[0].(Coverage).SetPreventInstall() 264 m[0].(Coverage).HideFromMake() 265 266 m[1].(Coverage).MarkAsCoverageVariant(true) 267 m[1].(Coverage).EnableCoverageIfNeeded() 268 } else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) { 269 // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of 270 // deps. 271 mctx.CreateVariations("cov") 272 mctx.AliasVariation("cov") 273 } 274} 275 276func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath { 277 apiLevelsJson := android.GetApiLevelsJson(ctx) 278 symbolFilePath := android.PathForModuleSrc(ctx, symbolFile) 279 outputFile := ctx.baseModuleName() + ".xml" 280 parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile) 281 rule := android.NewRuleBuilder(pctx, ctx) 282 rule.Command(). 283 BuiltTool("ndk_api_coverage_parser"). 284 Input(symbolFilePath). 285 Output(parsedApiCoveragePath). 286 Implicit(apiLevelsJson). 287 FlagWithArg("--api-map ", apiLevelsJson.String()) 288 rule.Build("native_library_api_list", "Generate native API list based on symbol files for coverage measurement") 289 return parsedApiCoveragePath 290} 291