coverage.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. package cc
  15. import (
  16. "strconv"
  17. "github.com/google/blueprint"
  18. "android/soong/android"
  19. )
  20. const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
  21. type CoverageProperties struct {
  22. Native_coverage *bool
  23. NeedCoverageVariant bool `blueprint:"mutated"`
  24. NeedCoverageBuild bool `blueprint:"mutated"`
  25. CoverageEnabled bool `blueprint:"mutated"`
  26. IsCoverageVariant bool `blueprint:"mutated"`
  27. }
  28. type coverage struct {
  29. Properties CoverageProperties
  30. // Whether binaries containing this module need --coverage added to their ldflags
  31. linkCoverage bool
  32. }
  33. func (cov *coverage) props() []interface{} {
  34. return []interface{}{&cov.Properties}
  35. }
  36. func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
  37. // This function should only ever be called for a cc.Module, so the
  38. // following statement should always succeed.
  39. if ctx.useSdk() {
  40. return "libprofile-extras_ndk"
  41. } else {
  42. return "libprofile-extras"
  43. }
  44. }
  45. func getClangProfileLibraryName(ctx ModuleContextIntf) string {
  46. if ctx.useSdk() {
  47. return "libprofile-clang-extras_ndk"
  48. } else if ctx.isCfiAssemblySupportEnabled() {
  49. return "libprofile-clang-extras_cfi_support"
  50. } else {
  51. return "libprofile-clang-extras"
  52. }
  53. }
  54. func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
  55. if cov.Properties.NeedCoverageVariant {
  56. ctx.AddVariationDependencies([]blueprint.Variation{
  57. {Mutator: "link", Variation: "static"},
  58. }, CoverageDepTag, getGcovProfileLibraryName(ctx))
  59. ctx.AddVariationDependencies([]blueprint.Variation{
  60. {Mutator: "link", Variation: "static"},
  61. }, CoverageDepTag, getClangProfileLibraryName(ctx))
  62. }
  63. return deps
  64. }
  65. func EnableContinuousCoverage(ctx android.BaseModuleContext) bool {
  66. return ctx.DeviceConfig().ClangCoverageContinuousMode()
  67. }
  68. func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
  69. clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
  70. gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()
  71. if !gcovCoverage && !clangCoverage {
  72. return flags, deps
  73. }
  74. if cov.Properties.CoverageEnabled {
  75. cov.linkCoverage = true
  76. if gcovCoverage {
  77. flags.GcovCoverage = true
  78. flags.Local.CommonFlags = append(flags.Local.CommonFlags, "--coverage", "-O0")
  79. // Override -Wframe-larger-than and non-default optimization
  80. // flags that the module may use.
  81. flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
  82. } else if clangCoverage {
  83. flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag,
  84. "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__")
  85. // Override -Wframe-larger-than. We can expect frame size increase after
  86. // coverage instrumentation.
  87. flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=")
  88. if EnableContinuousCoverage(ctx) {
  89. flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation")
  90. }
  91. // http://b/248022906, http://b/247941801 enabling coverage and hwasan-globals
  92. // instrumentation together causes duplicate-symbol errors for __llvm_profile_filename.
  93. if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) {
  94. flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-hwasan-globals=0")
  95. }
  96. }
  97. }
  98. // Even if we don't have coverage enabled, if any of our object files were compiled
  99. // with coverage, then we need to add --coverage to our ldflags.
  100. if !cov.linkCoverage {
  101. if ctx.static() && !ctx.staticBinary() {
  102. // For static libraries, the only thing that changes our object files
  103. // are included whole static libraries, so check to see if any of
  104. // those have coverage enabled.
  105. ctx.VisitDirectDeps(func(m android.Module) {
  106. if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
  107. if depTag.static() && depTag.wholeStatic {
  108. if cc, ok := m.(*Module); ok && cc.coverage != nil {
  109. if cc.coverage.linkCoverage {
  110. cov.linkCoverage = true
  111. }
  112. }
  113. }
  114. }
  115. })
  116. } else {
  117. // For executables and shared libraries, we need to check all of
  118. // our static dependencies.
  119. ctx.VisitDirectDeps(func(m android.Module) {
  120. cc, ok := m.(*Module)
  121. if !ok || cc.coverage == nil {
  122. return
  123. }
  124. if static, ok := cc.linker.(libraryInterface); !ok || !static.static() {
  125. return
  126. }
  127. if cc.coverage.linkCoverage {
  128. cov.linkCoverage = true
  129. }
  130. })
  131. }
  132. }
  133. if cov.linkCoverage {
  134. if gcovCoverage {
  135. flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
  136. coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
  137. deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
  138. flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
  139. } else if clangCoverage {
  140. flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag)
  141. if EnableContinuousCoverage(ctx) {
  142. flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation")
  143. }
  144. coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
  145. deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
  146. flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
  147. }
  148. }
  149. return flags, deps
  150. }
  151. func (cov *coverage) begin(ctx BaseModuleContext) {
  152. if ctx.Host() {
  153. // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
  154. // Just turn off for now.
  155. } else {
  156. cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion())
  157. }
  158. }
  159. func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
  160. useSdk bool, sdkVersion string) CoverageProperties {
  161. // Coverage is disabled globally
  162. if !ctx.DeviceConfig().NativeCoverageEnabled() {
  163. return properties
  164. }
  165. var needCoverageVariant bool
  166. var needCoverageBuild bool
  167. if moduleTypeHasCoverage {
  168. // Check if Native_coverage is set to false. This property defaults to true.
  169. needCoverageVariant = BoolDefault(properties.Native_coverage, true)
  170. if useSdk && sdkVersion != "current" {
  171. // Native coverage is not supported for SDK versions < 23
  172. if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 {
  173. needCoverageVariant = false
  174. }
  175. }
  176. if needCoverageVariant {
  177. // Coverage variant is actually built with coverage if enabled for its module path
  178. needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir())
  179. }
  180. }
  181. properties.NeedCoverageBuild = needCoverageBuild
  182. properties.NeedCoverageVariant = needCoverageVariant
  183. return properties
  184. }
  185. type UseCoverage interface {
  186. android.Module
  187. IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool
  188. }
  189. // Coverage is an interface for non-CC modules to implement to be mutated for coverage
  190. type Coverage interface {
  191. UseCoverage
  192. SetPreventInstall()
  193. HideFromMake()
  194. MarkAsCoverageVariant(bool)
  195. EnableCoverageIfNeeded()
  196. }
  197. func coverageMutator(mctx android.BottomUpMutatorContext) {
  198. if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
  199. needCoverageVariant := c.coverage.Properties.NeedCoverageVariant
  200. needCoverageBuild := c.coverage.Properties.NeedCoverageBuild
  201. if needCoverageVariant {
  202. m := mctx.CreateVariations("", "cov")
  203. // Setup the non-coverage version and set HideFromMake and
  204. // PreventInstall to true.
  205. m[0].(*Module).coverage.Properties.CoverageEnabled = false
  206. m[0].(*Module).coverage.Properties.IsCoverageVariant = false
  207. m[0].(*Module).Properties.HideFromMake = true
  208. m[0].(*Module).Properties.PreventInstall = true
  209. // The coverage-enabled version inherits HideFromMake,
  210. // PreventInstall from the original module.
  211. m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild
  212. m[1].(*Module).coverage.Properties.IsCoverageVariant = true
  213. }
  214. } else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
  215. // APEX and Rust modules fall here
  216. // Note: variant "" is also created because an APEX can be depended on by another
  217. // module which are split into "" and "cov" variants. e.g. when cc_test refers
  218. // to an APEX via 'data' property.
  219. m := mctx.CreateVariations("", "cov")
  220. m[0].(Coverage).MarkAsCoverageVariant(false)
  221. m[0].(Coverage).SetPreventInstall()
  222. m[0].(Coverage).HideFromMake()
  223. m[1].(Coverage).MarkAsCoverageVariant(true)
  224. m[1].(Coverage).EnableCoverageIfNeeded()
  225. } else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) {
  226. // Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
  227. // deps.
  228. mctx.CreateVariations("cov")
  229. mctx.AliasVariation("cov")
  230. }
  231. }
  232. func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
  233. apiLevelsJson := android.GetApiLevelsJson(ctx)
  234. symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
  235. outputFile := ctx.baseModuleName() + ".xml"
  236. parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile)
  237. rule := android.NewRuleBuilder(pctx, ctx)
  238. rule.Command().
  239. BuiltTool("ndk_api_coverage_parser").
  240. Input(symbolFilePath).
  241. Output(parsedApiCoveragePath).
  242. Implicit(apiLevelsJson).
  243. FlagWithArg("--api-map ", apiLevelsJson.String())
  244. rule.Build("native_library_api_list", "Generate native API list based on symbol files for coverage measurement")
  245. return parsedApiCoveragePath
  246. }