How to find the coverage of a library opened using dlopen()? - c++

I have a C++ library (.so) which is opened using dlopen() by another application. But I need to find the code coverage of this library while run within the application using gcov. Is it possible? If yes, how can it be done?
If not, how can the issue be resolved?

Firstly have your compiled your C++ library with the --coverage flag? I've never actually used a '.so' library with gcov before, so I'm not sure it would work anyway.
Secondly could you arrange a test version of your application to not use dlopen(), but instead be linked to a static library(.a) version of your library and still make the usual calls?

Yes. Coverage of shared library loaded by dlopen can be generated.
1) compile shared library with flags -fprofile-arcs -ftest-coverage
2) compile program that using dlopen with flags -fprofile-arc -ftest-coverage
3) lcov to generate .info file
lcov --capture --rc lcov_branch_coverage=1 --directory path/to/.gcda --output-file coverage.info
4) generate html
genhtml coverage.info --branch-coverage --output-directory out

Related

cant create coverage informations with lcov WARNING: no .gcda files found in ./coverage

I have been trying to get code coverage working for Qt but im struggling with generating any coverage information
Project
example.pro (contains include for googletest.pri)
gtest_dependency (contains googletest.pri
headerfiles for gtest
testsuite.h
sourcefiles for gtest
test.cpp
testsuite.cpp
main.cpp
All files above are pretty much empty just the code to run the test and one test case.
I included the linker flags in the example.pro
QMAKE_CXXFLAGS += -O0 -g --coverage
QMAKE_LFLAGS += -O0 -g --coverage
The problem is when I build the project it creates all the .gcna .gcno files, but when i execute lcov it says
WARNING: no .gcda files found in ./coverage -skipping!
Finished .info-file creation
Reading tracefile ./coverage/coverage.info
lcov: ERROR: no valid records found in tracefile ./coverage/coverage.info
Reading data file ./coverage/coverage-filtered.info
genhtml: ERROR: cannot read file ./coverage/coverage-filtered.info
Qt Version 5.14.2
Compiler mingw730_64
lcov version 1.14
gcov version 7.5.0
Ok i managed to fix it
If you run into the same problem as me check if you have googletest installed on /usr/include, since I use lcov and so on over the linux bash it couldnt find anything since everything was installed over /mnt/ and it couldnt find gtest since it searches in /usr.
Same goes for qt it couldnt find the files even if included with -L and -I.
I had to install both on /usr/

CMake produces object files with .obj extension instead of .o [duplicate]

I'm struggling to get coverage information for gcov. No errors during compilation and linking, but when I run the executable, no coverage data is produced.
I'm using CMake with a separate build directory, passing flags to the compiler and linker in this way:
add_definitions(--coverage)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
Does the executable expect the source code to be in a specific location?
What do I have to add to my CMakeLists.txt to get things going?
Kind regards,
Bjoern
CMake seems to put the code coverage (*.gcda, *.gcdo) files with the object files of your project. If your executable was named "tester" then they would appear in the following path
${CMAKE_BINARY_DIR}/CMakeFiles/tester.dir/
CMake seems to name the source files in a way that isn't very compatible with gcov though. For example if I had a source file called "mytestprog.cpp" it would be build
mytestprog.cpp.o
mytestprog.cpp.gcda
mytestprog.cpp.gcdno
where as gcov seems to expect
mytestprog.gcda
mytestprog.gcdno
I'm not really sure how to fix it. I've tried using LCov instead and that "appeared" to work but I'm not really sure if it did.
Delcypher pointed out the problem.
Solution 1: you can ask cmake to name object files as main.o instead of main.cpp.o etc. using the undocumented CMAKE_CXX_OUTPUT_EXTENSION_REPLACE switch:
cmake -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON ...
Solution 2: if you do not need the .gcov files you can call lcov from the build directory:
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory out
You will find the coverage information in the out directory in html form.
Not sure where you got --coverage from, but these are the arguments I use on Linux to get coverage information using gcc and gcov:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
Here's what gcc --help --verbose has to say about those options:
-ftest-coverage Create
data files needed by "gcov"
-fprofile-arcs Insert
arc-based program profiling code
You don't need to pass --coverage to the linker. --coverage will pass -fprofile-arcs -ftest-coverage to the compiler and -lgcov to the linker.
Are you sure that it isn't creating any gcdo or gcda files? Where are you looking for these files? It should put the gcov file for each object file into the same directory as the object file. Do a find for .gcda files at the top of your build directory. If nothing shows up, gcov might not be getting linked in. Run the following command to see if it is:
nm name_of_binary | grep "gcov"
If it is getting linked in, then gcov might not have permission to write files to where you are running the executable. If it has permission, then I am stumped.

Executing cross-compiled C++ program using Boost on Raspberry Pi

I have built a GCC cross toolchain for the RPi and can cross-compile C++ source and successfully run it after copying the executable to the RPi.
Next I built the Boost libraries targeting ARM, using the cross toolchain. I can successfully build and link C++ source to those Boost libraries using the cross toolchain on my PC.
I then copied the program, dynamically linked to Boost, to the RPi and copied all built libraries into /usr/local/lib on the Pi. However, executing fails:
$ ./my_program
./my_program: error while loading shared libraries: libboost_system.so.1.60.0: cannot open shared object file: No such file or directory
Again, this library, libboost_system.so.1.60.0, exists in /usr/local/lib.
I also tried
export LD_LIBRARY_PATH='/usr/local/lib'
but that doesn't change anything. What am I doing wrong?
EDIT:
I build all source files like this (rpi-g++ is a symlink to my cross-compiler):
rpi-g++ -c -std=c++1y -Wall -Wextra -pedantic -O2 -I /path/to/cross/boost/include *.cpp
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -lboost_system -pthread
EDIT 2:
When linked with
rpi-g++ -o myprog *.o -L /path/to/cross/boost/lib/ -rdynamic -lboost_system -pthread
the problem remains the same. I have checked and verified everything suggested by Technaton as well. Strangely, ldd insists that the created executable is "not a dynamic executable" (checked that on my PC and on the RPi), which doesn't make sense to me.
There are several things you can check. I've posted a complete check list here, but judging from your linker command line, number 5 is probably the culprit.
Check that your library and your program are correctly build for the target architecture. You can verify that by using file ./myprog and file libboost_system.so.1.60.0.
Make sure that you have copied the actual shared object, and not a link to it.
Ensure that the shared object file's permissions are sane (0755).
Run ldconfig -v and check that your shared object file is picked up. Normally, /usr/local/lib is in the standard library search path, and LD_LIBRARY_PATH is not required.
Make sure that your program is actually dynamically linked by running ldd ./myprog. Judging from your linker command line, that is the problem: You're missing -rdynamic.
Check the paths returned from ldd: If you have linked with rpath, the library search path might be screwed up. Try again without -rpath.

gcov with CMake using a separate build directory

I'm struggling to get coverage information for gcov. No errors during compilation and linking, but when I run the executable, no coverage data is produced.
I'm using CMake with a separate build directory, passing flags to the compiler and linker in this way:
add_definitions(--coverage)
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
Does the executable expect the source code to be in a specific location?
What do I have to add to my CMakeLists.txt to get things going?
Kind regards,
Bjoern
CMake seems to put the code coverage (*.gcda, *.gcdo) files with the object files of your project. If your executable was named "tester" then they would appear in the following path
${CMAKE_BINARY_DIR}/CMakeFiles/tester.dir/
CMake seems to name the source files in a way that isn't very compatible with gcov though. For example if I had a source file called "mytestprog.cpp" it would be build
mytestprog.cpp.o
mytestprog.cpp.gcda
mytestprog.cpp.gcdno
where as gcov seems to expect
mytestprog.gcda
mytestprog.gcdno
I'm not really sure how to fix it. I've tried using LCov instead and that "appeared" to work but I'm not really sure if it did.
Delcypher pointed out the problem.
Solution 1: you can ask cmake to name object files as main.o instead of main.cpp.o etc. using the undocumented CMAKE_CXX_OUTPUT_EXTENSION_REPLACE switch:
cmake -DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON ...
Solution 2: if you do not need the .gcov files you can call lcov from the build directory:
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory out
You will find the coverage information in the out directory in html form.
Not sure where you got --coverage from, but these are the arguments I use on Linux to get coverage information using gcc and gcov:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
Here's what gcc --help --verbose has to say about those options:
-ftest-coverage Create
data files needed by "gcov"
-fprofile-arcs Insert
arc-based program profiling code
You don't need to pass --coverage to the linker. --coverage will pass -fprofile-arcs -ftest-coverage to the compiler and -lgcov to the linker.
Are you sure that it isn't creating any gcdo or gcda files? Where are you looking for these files? It should put the gcov file for each object file into the same directory as the object file. Do a find for .gcda files at the top of your build directory. If nothing shows up, gcov might not be getting linked in. Run the following command to see if it is:
nm name_of_binary | grep "gcov"
If it is getting linked in, then gcov might not have permission to write files to where you are running the executable. If it has permission, then I am stumped.

gcov on larger projects (static libraries, ...)

I'm working on larger project which has the following directory layout:
Source
MyA
aa.cpp
ab.cpp
ac.cpp
MyB
ba.cpp
bb.cpp
bc.cpp
MyTest
testaa.cpp
testab.cpp
testac.cpp
testba.cpp
testbb.cpp
testbc.cpp
main.cpp
Build
MyA
aa.o
ab.o
ac.o
libMyA.a (static library)
MyB
ba.o
bb.o
bc.o
libMyB.a (static library)
MyTest
testaa.o
testab.o
testac.o
testba.o
testbb.o
testbc.o
MyTest (executable)
After compiling with -fprofile-arcs -ftest-coverage I execute the MyTest application inside the Build/MyTest directory. As expected there are *.gcno and *.gcda files inside the Build directory. After running gcov inside the MyTest directory different *.gcov files are produced but unfortunately not for everything inside MyA and MyB, although every function is called inside this two libraries. Tried different options but somehow I'm unable to create useful (means correct) *.gcov files with this layout.
If I copy every cpp inside one directory and repeat the steps everything works as expected and the coverage analysis is perfect.
You must specify source files as absolute paths to g++/gcc. Don't use relative paths with ".." or like "foo/bar.cpp", else you'll get errors like "geninfo: WARNING: no data found for XXXX".
Don't include any header files on the command line to g++/gcc. Else you'll get "stamp mismatch with graph file" errors.
So, following should work when having multiple directories:
g++ --coverage -DDEBUG -g3 heyo.cpp /app/helper/blah.cpp /app/libfoo/foo.cpp -o program
./program
lcov --directory . --capture --output-file app.info
genhtml --output-directory cov_htmp app.info
Or, if you're in a Makefile that uses relative paths already, it's convenient to use:
g++ --coverage -DDEBUG -g3 $(abspath heyo.cpp helper/blah.cpp ../foo/bar/baz.cpp) -o program
To be able to keep your directory structure, you need to run gcov once inside each source file folder, but use the -o option to tell gcov where the data files are.
I think it should be like this:
gcov -o ../../Build/MyA *.cpp
I have a project with a similar source file structure, but I let the compiler dump object files etc into the source folders. I then run gcov multiple times from the root folder, once for each source file, but I specify the relative path of the source file and use the -o option to specify the relative folder like this:
gcov -o Source/MyA Source/MyA/aa.cpp
If you performed your product or application testing thoroughly and manually and spent lot of effort on it. If your objective is to get code coverage report using lcov and gcov but by mistake deleted gcno files. You can regenerate gcno files by recompiling the code but it will be generated with new timestamp and gcov reports error saying "stamp mismatch with graph file" and no code coverage report will be generated. This will result in all your testing effort getting wasted.
There is a shortcut to still generate the code coverage report. This is just a workaround and should not be relied upon all the time. Its recommended to preserve *.gcno files till your testing completes.
Note down your gcc version(gcc -v) and download its source code from one of the mirror sites
Eg - ftp://gd.tuwien.ac.at/gnu/sourceware/gcc/releases/gcc-4.4.6/gcc-4.4.6.tar.bz2
After extracting downloaded file, gcc the folder structure will be as follows
gcc-4.4.6
gcc-4.4.6/gcc
If you directly go inside gcc-4.4.6/gcc and try to do ./configure and compile(make) from there then you will encounter below problem
build/genmodes -h > tmp-modes.h
/bin/sh: build/genmodes: No such file or directory
Solution is do ./configure and make from gcc-4.4.6 and no errors will be shown related to genmodes. This will compile all modules including gcc. You may have to install mpfr and gmp modules which are needed by gcc if any error shown by ./configure
goto gcc-4.4.6/gcc/gcov.c and comment below lines and then recompile with above command
/* if (tag != bbg_stamp)
{
fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
goto cleanup;
}*/
Example path of new gcov binary after compilation is gcc-4.4.6/host-x86_64-unknown-linux-gnu/gcc/gcov
Place this binary in /usr/bin and regenerate code coverage report with command as shown in below example
lcov --capture --directory ./ --output-file coverage.info ; genhtml coverage.info --output-directory /var/www/html/coverage
Now you should not get "stamp mismatch with graph file" error and you will get code coverage report properly