Meta+Userland: Add ENABLE_USERSPACE_COVERAGE_COLLECTION CMake option

This option sets -fprofile-instr-generate -fcoverage-mapping for Clang
builds only on almost all of Userland. Loader and LibTimeZone are
exempt. This can be used for generating code coverage reports, or even
PGO in the future.
This commit is contained in:
Andrew Kaster 2022-03-04 18:02:09 -07:00 committed by Andreas Kling
parent a6b2c34746
commit 5120b39d0e
Notes: sideshowbarker 2024-07-17 11:23:43 +09:00
9 changed files with 39 additions and 2 deletions

View file

@ -43,6 +43,7 @@ directory to `Build/i686` and then running `ninja <target>`:
There are some optional features that can be enabled during compilation that are intended to help with specific types of development work or introduce experimental features. Currently, the following build options are available: There are some optional features that can be enabled during compilation that are intended to help with specific types of development work or introduce experimental features. Currently, the following build options are available:
- `ENABLE_ADDRESS_SANITIZER` and `ENABLE_KERNEL_ADDRESS_SANITIZER`: builds in runtime checks for memory corruption bugs (like buffer overflows and memory leaks) in Lagom test cases and the kernel, respectively. - `ENABLE_ADDRESS_SANITIZER` and `ENABLE_KERNEL_ADDRESS_SANITIZER`: builds in runtime checks for memory corruption bugs (like buffer overflows and memory leaks) in Lagom test cases and the kernel, respectively.
- `ENABLE_KERNEL_COVERAGE_COLLECTION`: enables the KCOV API and kernel coverage collection instrumentation. Only useful for coverage guided kernel fuzzing. - `ENABLE_KERNEL_COVERAGE_COLLECTION`: enables the KCOV API and kernel coverage collection instrumentation. Only useful for coverage guided kernel fuzzing.
- `ENABLE_USERSPACE_COVERAGE_COLLECTION`: enables coverage collection instrumentation for userspace. Currently only works with a Clang build.
- `ENABLE_MEMORY_SANITIZER`: enables runtime checks for uninitialized memory accesses in Lagom test cases. - `ENABLE_MEMORY_SANITIZER`: enables runtime checks for uninitialized memory accesses in Lagom test cases.
- `ENABLE_UNDEFINED_SANITIZER`: builds in runtime checks for [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) (like null pointer dereferences and signed integer overflows) in Lagom test cases. - `ENABLE_UNDEFINED_SANITIZER`: builds in runtime checks for [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior) (like null pointer dereferences and signed integer overflows) in Lagom test cases.
- `ENABLE_COMPILER_EXPLORER_BUILD`: Skip building non-library entities in Lagom (this only applies to Lagom). - `ENABLE_COMPILER_EXPLORER_BUILD`: Skip building non-library entities in Lagom (this only applies to Lagom).

View file

@ -12,3 +12,4 @@ serenity_option(ENABLE_KERNEL_COVERAGE_COLLECTION OFF CACHE BOOL "Enable KCOV a
serenity_option(ENABLE_KERNEL_LTO OFF CACHE BOOL "Build the kernel with link-time optimization") serenity_option(ENABLE_KERNEL_LTO OFF CACHE BOOL "Build the kernel with link-time optimization")
serenity_option(ENABLE_EXTRA_KERNEL_DEBUG_SYMBOLS OFF CACHE BOOL "Enable -Og and -ggdb3 options for Kernel code for easier debugging") serenity_option(ENABLE_EXTRA_KERNEL_DEBUG_SYMBOLS OFF CACHE BOOL "Enable -Og and -ggdb3 options for Kernel code for easier debugging")
serenity_option(ENABLE_MOLD_LINKER OFF CACHE BOOL "Link the SerenityOS userland with the mold linker") serenity_option(ENABLE_MOLD_LINKER OFF CACHE BOOL "Link the SerenityOS userland with the mold linker")
serenity_option(ENABLE_USERSPACE_COVERAGE_COLLECTION OFF CACHE BOOL "Enable code coverage instrumentation for userspace binaries in clang")

View file

@ -73,6 +73,9 @@ function(serenity_libc target_name fs_name)
if (NOT ENABLE_MOLD_LINKER) if (NOT ENABLE_MOLD_LINKER)
target_link_options(${target_name} PRIVATE -Wl,--no-dependent-libraries) target_link_options(${target_name} PRIVATE -Wl,--no-dependent-libraries)
endif() endif()
if (ENABLE_USERSPACE_COVERAGE_COLLECTION)
target_link_libraries(${target_name} clang_rt.profile)
endif()
endif() endif()
target_link_directories(LibC PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_link_directories(LibC PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
serenity_generated_sources(${target_name}) serenity_generated_sources(${target_name})

View file

@ -1,5 +1,21 @@
add_compile_options(-O2) add_compile_options(-O2)
# Escape hatch target to prevent runtime startup libraries from having coverage enabled
# at awkward points in program initialization
add_library(NoCoverage INTERFACE)
if (ENABLE_USERSPACE_COVERAGE_COLLECTION)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate -fcoverage-mapping)
target_compile_options(NoCoverage INTERFACE -fno-profile-generate -fno-profile-instr-use -fno-profile-instr-generate -fno-coverage-mapping)
target_link_options(NoCoverage INTERFACE -fno-profile-generate -fno-profile-instr-use -fno-profile-instr-generate -fno-coverage-mapping)
else()
message(FATAL_ERROR "ENABLE_USERSPACE_COVERAGE_COLLECTION not supported yet for ${CMAKE_CXX_COMPILER_ID}")
endif()
endif()
add_subdirectory(Applications) add_subdirectory(Applications)
add_subdirectory(Demos) add_subdirectory(Demos)
add_subdirectory(DevTools) add_subdirectory(DevTools)

View file

@ -44,6 +44,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
target_link_libraries(Loader.so PRIVATE clang_rt.builtins) target_link_libraries(Loader.so PRIVATE clang_rt.builtins)
endif () endif ()
target_link_libraries(Loader.so PRIVATE LibTimeZone) # Note: Don't confuse the coverage results by instrumenting Loader
target_link_libraries(Loader.so PRIVATE LibTimeZone NoCoverage)
target_link_options(Loader.so PRIVATE LINKER:--no-dynamic-linker) target_link_options(Loader.so PRIVATE LINKER:--no-dynamic-linker)
install(TARGETS Loader.so RUNTIME DESTINATION usr/lib/) install(TARGETS Loader.so RUNTIME DESTINATION usr/lib/)

View file

@ -93,24 +93,32 @@ endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option")
# Note: We link all these against NoCoverage so that we don't break ports by requiring coverage symbols
# in runtime/startup objects.
# Since all native serenity applications use dynamic libraries, prevent coverage on libc.a as well
add_library(crt0 STATIC crt0.cpp) add_library(crt0 STATIC crt0.cpp)
target_link_libraries(crt0 PRIVATE NoCoverage)
add_custom_command( add_custom_command(
TARGET crt0 TARGET crt0
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crt0> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0.o COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crt0> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0.o
) )
add_library(crt0_shared STATIC crt0_shared.cpp) add_library(crt0_shared STATIC crt0_shared.cpp)
target_link_libraries(crt0_shared PRIVATE NoCoverage)
add_custom_command( add_custom_command(
TARGET crt0_shared TARGET crt0_shared
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crt0_shared> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0_shared.o COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crt0_shared> ${CMAKE_INSTALL_PREFIX}/usr/lib/crt0_shared.o
) )
add_library(crti STATIC ${CRTI_SOURCE}) add_library(crti STATIC ${CRTI_SOURCE})
target_link_libraries(crti PRIVATE NoCoverage)
add_custom_command( add_custom_command(
TARGET crti TARGET crti
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crti> ${CMAKE_INSTALL_PREFIX}/usr/lib/crti.o COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crti> ${CMAKE_INSTALL_PREFIX}/usr/lib/crti.o
) )
add_library(crtn STATIC ${CRTN_SOURCE}) add_library(crtn STATIC ${CRTN_SOURCE})
target_link_libraries(crtn PRIVATE NoCoverage)
add_custom_command( add_custom_command(
TARGET crtn TARGET crtn
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crtn> ${CMAKE_INSTALL_PREFIX}/usr/lib/crtn.o COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:crtn> ${CMAKE_INSTALL_PREFIX}/usr/lib/crtn.o
@ -119,6 +127,7 @@ add_custom_command(
set_source_files_properties (ssp.cpp PROPERTIES COMPILE_FLAGS set_source_files_properties (ssp.cpp PROPERTIES COMPILE_FLAGS
"-fno-stack-protector") "-fno-stack-protector")
add_library(ssp STATIC ssp.cpp) add_library(ssp STATIC ssp.cpp)
target_link_libraries(ssp PRIVATE NoCoverage)
add_custom_command( add_custom_command(
TARGET ssp TARGET ssp
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:ssp> ${CMAKE_INSTALL_PREFIX}/usr/lib/ssp.o COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_OBJECTS:ssp> ${CMAKE_INSTALL_PREFIX}/usr/lib/ssp.o
@ -131,7 +140,7 @@ set(SOURCES ${LIBC_SOURCES} ${AK_SOURCES} ${ELF_SOURCES} ${ASM_SOURCES})
set_source_files_properties(stdio.cpp PROPERTIES COMPILE_FLAGS "-fno-builtin-fputc -fno-builtin-fputs -fno-builtin-fwrite") set_source_files_properties(stdio.cpp PROPERTIES COMPILE_FLAGS "-fno-builtin-fputc -fno-builtin-fputs -fno-builtin-fwrite")
add_library(LibCStaticWithoutDeps STATIC ${SOURCES}) add_library(LibCStaticWithoutDeps STATIC ${SOURCES})
target_link_libraries(LibCStaticWithoutDeps ssp LibTimeZone) target_link_libraries(LibCStaticWithoutDeps PUBLIC ssp LibTimeZone PRIVATE NoCoverage)
add_dependencies(LibCStaticWithoutDeps LibM LibSystem LibUBSanitizer) add_dependencies(LibCStaticWithoutDeps LibM LibSystem LibUBSanitizer)
add_custom_target(LibCStatic add_custom_target(LibCStatic

View file

@ -10,3 +10,4 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
serenity_libc(LibUBSanitizer ubsan) serenity_libc(LibUBSanitizer ubsan)
add_library(LibUBSanitizerStatic STATIC ${SOURCES}) add_library(LibUBSanitizerStatic STATIC ${SOURCES})
target_link_libraries(LibUBSanitizerStatic PRIVATE NoCoverage)

View file

@ -8,3 +8,4 @@ target_include_directories(LibSystem PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_library(LibSystemStatic STATIC ${SOURCES}) add_library(LibSystemStatic STATIC ${SOURCES})
target_include_directories(LibSystemStatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(LibSystemStatic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(LibSystemStatic PRIVATE NoCoverage)

View file

@ -7,3 +7,7 @@ set(SOURCES
add_library(LibTimeZone OBJECT ${SOURCES}) add_library(LibTimeZone OBJECT ${SOURCES})
target_compile_definitions(LibTimeZone PRIVATE ENABLE_TIME_ZONE_DATA=$<BOOL:${ENABLE_TIME_ZONE_DATABASE_DOWNLOAD}>) target_compile_definitions(LibTimeZone PRIVATE ENABLE_TIME_ZONE_DATA=$<BOOL:${ENABLE_TIME_ZONE_DATABASE_DOWNLOAD}>)
# NOTE: These objects are used by the DynamicLoader, which is always built without coverage instrumentation.
# We could allow them to be instrumented for coverage if DynamicLoader built its own copy
target_link_libraries(LibTimeZone PRIVATE NoCoverage)