Using Valgrind on files made with make - c++

I'm trying to use valgrind on a program which is the output of the make command using this makefile:
# Intlist makefile
P = intlist
C = g++
F = -m32 -g -O0 -Wall
O = IntListTest.o IntList.o
$(P): $(O)
$(C) $(F) -o $(P) $(O)
IntListTest.o: IntListTest.cpp IntList.h
$(C) $(F) -c IntListTest.cpp
IntList.o: IntList.cpp IntList.h
$(C) $(F) -c IntList.cpp
clean:
rm $(P) $(O)
When I run valgrind on intlist, it generates this:
==130929== Memcheck, a memory error detector
==130929== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==130929== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==130929== Command: intlist
==130929==
valgrind: Fatal error at startup: a function redirection
valgrind: which is mandatory for this platform-tool combination
valgrind: cannot be set up. Details of the redirection are:
valgrind:
valgrind: A must-be-redirected function
valgrind: whose name matches the pattern: strlen
valgrind: in an object with soname matching: ld-linux.so.2
valgrind: was not found whilst processing
valgrind: symbols from the object with soname: ld-linux.so.2
valgrind:
valgrind: Possible fixes: (1, short term): install glibc's debuginfo
valgrind: package on this machine. (2, longer term): ask the packagers
valgrind: for your Linux distribution to please in future ship a non-
valgrind: stripped ld.so (or whatever the dynamic linker .so is called)
valgrind: that exports the above-named function using the standard
valgrind: calling conventions for this platform. The package you need
valgrind: to install for fix (1) is called
valgrind:
valgrind: On Debian, Ubuntu: libc6-dbg
valgrind: On SuSE, openSuSE, Fedora, RHEL: glibc-debuginfo
valgrind:
valgrind: Note that if you are debugging a 32 bit process on a
valgrind: 64 bit system, you will need a corresponding 32 bit debuginfo
valgrind: package (e.g. libc6-dbg:i386).
valgrind:
valgrind: Cannot continue -- exiting now. Sorry.
I feel like there's something wrong with my makefile, but I'm not sure what it is. Any ideas are greatly appreciated. However, This takes place on a college-owned server where I don't have permission to install anything, so that isn't a solution in my case.

You are building a 32bit executable (the -m32 option in your compile/link lines) but from the output valgrind provides, you don't have all the support libraries available to run valgrind on a 32bit executable.
Do you really need your program to be 32bit? If not the simplest thing to do is remove the -m32 option and clean and rebuild everything.
If you really have to have a 32bit binary then read the output valgrind provides above carefully to determine what extra 32bit libraries you're missing and need to install.

Related

Can't cross-compile gdb with MinGW

I'm trying to cross-compile gdb so I could debug my Windows version of program.
My host system is Arch Linux(5.13.4-arch1-1 to be exact).
I'm using MinGW from the official repositories.
$ i686-w64-mingw32-gcc --version
i686-w64-mingw32-gcc (GCC) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
I downloaded the source for gdb from https://ftp.gnu.org/gnu/gdb/ (gdb-10.2.tar.gz).
I unpacked it, cd into dir and ran:
$ ./configure --host=i686-w64-mingw32
$ make
For long it compiled without any errors and then:
CXX source-cache.o
source-cache.c:37:10: fatal error: srchilite/sourcehighlight.h: No such file or directory
37 | #include <srchilite/sourcehighlight.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
And also although compiler already compiled gdbserver and other different programs, I can't run them.
Launching gdbserver.exe with wine gives:
$ wine gdbserver.exe
0024:err:module:import_dll Library libgcc_s_dw2-1.dll (which is needed by L"Z:\\home\\udalny\\.local\\build\\gdb\\gdb-10.2\\gdbserver\\gdbserver.exe") not found
0024:err:module:import_dll Library libstdc++-6.dll (which is needed by L"Z:\\home\\udalny\\.local\\build\\gdb\\gdb-10.2\\gdbserver\\gdbserver.exe") not found
0024:err:module:LdrInitializeThunk Importing dlls for L"Z:\\home\\udalny\\.local\\build\\gdb\\gdb-10.2\\gdbserver\\gdbserver.exe" failed, status c0000135
Is it not statically linked?
Does anybody know how to fix it?
You can avoid the problem with the configure flag --disable-source-highlight if you can do without sourxe highlighting.

gcc / C++ Disable generation of vex instructions

We are debugging memory issues with our large legacy app and would like to use Valgrind to track it down. The app uses the ACE/TAO CORBA library however, Valgrind complains of illegal "vex" instructions in the library.
==29992== Memcheck, a memory error detector
==29992== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==29992== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==29992== Command: DvMain
==29992==
DvMain. Version 6.0 Build 38B16
vex x86->IR: unhandled instruction bytes: 0xC4 0xE2 0x7B 0xF7
==29992== valgrind: Unrecognised instruction at address 0x5f37a4b.
==29992== at 0x5F37A4B: ACE_Select_Reactor_Impl::bit_ops(int, unsigned long, ACE_Select_Reactor_Handle_Set&, int) (in /usr/local/dvstation/lib3p/ACE/libACE.so.6.2.7)
In another SO question, VTT suggested disabling AVX instructions with -mno-avx, which worked on some things. However, still have problems.
I've tried -mno-sse2avx -mno-avx -mno-sse4.1 -mno-sse4.2 -mno-sse4 -mno-sse4a but Valgrind still complains of vex instructions in ::bit_ops() (If you are interested, bit_ops is defined on line 956 of this file)
How do I disable completely the generation of VEX instructions so I can use Valgrind to debug?
Platform is 32-bit Centos 6, g++ 4.9.4
(please don't suggest moving to 64-bit. That's not an option with this product)
Reference:
Compile line for offending file:
/usr/local/gcc-4.9.4/bin/c++4.9 -mno-sse2avx -fvisibility=hidden
-fvisibility-inlines-hidden -fdiagnostics-color=auto
-mno-avx -mno-sse4.1 -mno-sse4.2 -mno-sse4 -mno-sse4a
-O3 -march=native -pthread -fno-strict-aliasing
-Wall -W -Wpointer-arith -pipe -D_GNU_SOURCE
-c -fPIC -o .shobj/Select_Reactor_Base.o Select_Reactor_Base.cpp
VEX is pretty new. Using an old architecture, e.g. -march=pentium4 will disallow VEX instruction coding, but you keep SSE2.
Perhaps you can use valgrind 3.12 from DTS instead, in the form of the devtoolset-6-valgrind package?
devtoolset-6
Support for AVX2 instructions was added in valgrind 3.9, so you might avoid recompiling your software.
VEX is the Valgrind abstract machine representation. It is a fundamental part of Valgrind and you cannot turn it off. You either need to tell the compiler to emit machine code that your version of Valgrind understands or else upgrade to a more recent version of Valgrind that understands AVX.
AVX dates from about 2011 whilst the version of Valgrind that you are using was released in September 2012 and it probably hadn't added AVX support. Confusingly, these extensions also use a "VEX" prefix. In this case the "vex x86->IR" message from Valgrind refers to Valgrind's VEX not the AVX VEX prefix.

How can I get meaningful function names in callgrind output on OSX from the command line?

Goal: I would like to be able to analyze the output of callgrind (and later cachegrind too) and would like to see meaningful variable names when using the callgrind_annotate CLI.
Prior Research: I am aware of the dsym flag in Valgrind (http://valgrind.org/docs/manual/manual-core.html) and believe I have an understanding of how debug symbols work on osx (LLDB not showing source code). The handful of mentions of this issue I've seen on this site either went unanswered or were cases where the -g flag wasn't included.
Theory(May be wrong...): Based on the "dym=" line in valgrind output I'm wondering if valgrind is struggling to find the path for the dsym directory."
What data can I give you?
Given the following source code:
#include <iostream>
#include <cmath>
bool isPrime(int x)
{
int limit = std::sqrt(x);
for (int i = 2; i <= limit; ++i)
{
if (x % i == 0)
{
return false;
}
}
return true;
}
int main()
{
int primeCount = 0;
for (int i = 0; i < 1000000; ++i)
{
if (isPrime(i))
{
++primeCount;
}
}
}
The following command line instructions were used:
g++ -g -c badprime.cpp
g++ badprime.o -o badprime
nm -pa badprime
dsymutil badprime
valgrind --tool=callgrind --dsymutil=yes ./badprime
callgrind_annotate --auto=yes callgrind.out.45056 badprime.cpp
The nm -pa bit was to ensure that the debugging map information was present. I also ran dwarfdump on the dSYM folder to ensure that debugging info was present. I am greeted with the line " No information has been collected for badprime.cpp" as the output of the annotate command.
Compiler information:
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin15.6.0
Valgrind information:
valgrind-3.11.0
Initial verbose output from valgrind:
$ valgrind --tool=callgrind --dsymutil=yes -v ./badprime
==45056== Callgrind, a call-graph generating cache profiler
==45056== Copyright (C) 2002-2015, and GNU GPL'd, by Josef Weidendorfer et al.
==45056== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==45056== Command: ./badprime
==45056==
--45056-- Valgrind options:
--45056-- --tool=callgrind
--45056-- --dsymutil=yes
--45056-- -v
--45056-- Output from sysctl({CTL_KERN,KERN_VERSION}):
--45056-- Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34 PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64
--45056-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-avx-avx2-bmi
--45056-- Page sizes: currently 4096, max supported 4096
--45056-- Valgrind library directory: /usr/local/Cellar/valgrind/3.11.0/lib/valgrind
==45056== For interactive control, run 'callgrind_control -h'.
--45056-- /usr/lib/dyld (rx at 0x7fff5fc00000, rw at 0x7fff5fc38000)
--45056-- reading syms from primary file (6 1229)
--45056-- Scheduler: using generic scheduler lock implementation.
==45056== embedded gdbserver: reading from /var/folders/7h/d91hqksj7bdfxp0km10b2qn40000gp/T//vgdb-pipe-from-vgdb-to-45056-by-dudett-on-???
==45056== embedded gdbserver: writing to /var/folders/7h/d91hqksj7bdfxp0km10b2qn40000gp/T//vgdb-pipe-to-vgdb-from-45056-by-dudett-on-???
==45056== embedded gdbserver: shared mem /var/folders/7h/d91hqksj7bdfxp0km10b2qn40000gp/T//vgdb-pipe-shared-mem-vgdb-45056-by-dudett-on-???
==45056==
==45056== TO CONTROL THIS PROCESS USING vgdb (which you probably
==45056== don't want to do, unless you know exactly what you're doing,
==45056== or are doing some strange experiment):
==45056== /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/../../bin/vgdb --pid=45056 ...command...
==45056==
==45056== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==45056== /path/to/gdb ./badprime
==45056== and then give GDB the following command
==45056== target remote | /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/../../bin/vgdb --pid=45056
==45056== --pid is optional if only one valgrind process is running
==45056==
--45056-- /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_core-amd64-darwin.so (rx at 0x100002000, rw at 0x100004000)
--45056-- reading syms from primary file (3 21)
--45056-- dSYM= /usr/local/Cellar/valgrind/3.11.0/lib/valgrind/vgpreload_core-amd64-darwin.so.dSYM/Contents/Resources/DWARF/vgpreload_core-amd64-darwin.so
callgrind_annotate output:
--------------------------------------------------------------------------------
Profile data file 'callgrind.out.45056' (creator: callgrind-3.11.0)
--------------------------------------------------------------------------------
I1 cache:
D1 cache:
LL cache:
Timerange: Basic block 0 - 278668477
Trigger: Program termination
Profiled target: ./badprime (PID 45056, part 1)
Events recorded: Ir
Events shown: Ir
Event sort order: Ir
Thresholds: 99
Include dirs:
User annotated: badprime.cpp
Auto-annotation: on
--------------------------------------------------------------------------------
Ir
--------------------------------------------------------------------------------
913,332,521 PROGRAM TOTALS
--------------------------------------------------------------------------------
Ir file:function
--------------------------------------------------------------------------------
893,174,739 ???:0x0000000100000ee0 [???]
12,157,012 ???:0x0000000100000f50 [???]
--------------------------------------------------------------------------------
-- User-annotated source: badprime.cpp
--------------------------------------------------------------------------------
No information has been collected for badprime.cpp
I'd be super grateful to whatever help could be provided.
Check your linker (ld) command line options. -s strips all symbol information and it takes precedence over -g in the compiler.
From ld manual:
-s
--strip-all
Omit all symbol information from the output file.
ftp link
I noticed that you don't use ld for linking. So this is not applicable to your problem. However, I will leave my answer here for people who use ld and experience this issue.

How to run valgrind with basic c example?

Installation:
bzip2 -d valgrind-3.10.1.tar.bz2
tar -xf valgrind-3.10.1.tar
then:
./configure
make
make install
or simplier
sudo apt-get install valgrind
How to run valgrind on that simple program example1.c
#include <stdlib.h>
int main()
{
char *x = malloc(100); /* or, in C++, "char *x = new char[100] */
return 0;
}
Run:
valgrind --tool=memcheck --leak-check=yes example1
valgrind: example1: command not found
Output from console:
valgrind: example1: command not found
It looks good. You only need to add a ./ before your executable. Without it, valgrind fails to find it and reports 'command not found'.
valgrind --tool=memcheck --leak-check=yes ./example1
^
First, compile your C program (-g is extremely important; without debug info in the executable valgrind cannot tell you line numbers from the source code where the violations occur nor the original line of the allocations of the memory being violated.):
gcc -g example1.c -o example1
Then run valgrind on the executable:
valgrind --tool=memcheck --leak-check=yes ./example1

how to port c/c++ applications to legacy linux kernel versions

Ok, this is just a bit of a fun exercise, but it can't be too hard compiling programmes for some older linux systems, or can it?
I have access to a couple of ancient systems all running linux and maybe it'd be interesting to see how they perform under load. Say as an example we want to do some linear algebra using Eigen which is a nice header-only library. Any chance to compile it on the target system?
user#ancient:~ $ uname -a
Linux local 2.2.16 #5 Sat Jul 8 20:36:25 MEST 2000 i586 unknown
user#ancient:~ $ gcc --version
egcs-2.91.66
Maybe not... So let's compile it on a current system. Below are my attempts, mainly failed ones. Any more ideas very welcome.
Compile with -m32 -march=i386
user#ancient:~ $ ./a.out
BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 53: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed!
Compile with -m32 -march=i386 -static: Runs on all fairly recent kernel versions but fails if they are slightly older with the well known error message
user#ancient:~ $ ./a.out
FATAL: kernel too old
Segmentation fault
This is a glibc error which has a minimum kernel version it supports, e.g. kernel 2.6.4 on my system:
$ file a.out
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.6.4, not stripped
Compile glibc myself with support for the oldest kernel possible. This post describes it in more detail but essentially it goes like this
wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2
tar -xjf glibc-2.14.tar.bz2
cd glibc-2.14
mkdir build; cd build
../configure --prefix=/usr/local/glibc_32 \
--enable-kernel=2.0.0 \
--with-cpu=i486 --host=i486-linux-gnu \
CC="gcc -m32 -march=i486" CXX="g++ -m32 -march=i486"
make -j 4
make intall
Not sure if the --with-cpu and --host options do anything, most important is to force the use of compiler flags -m32 -march=i486 for 32-bit builds (unfortunately -march=i386 bails out with errors after a while) and --enable-kernel=2.0.0 to make the library compatible with older kernels. Incidentially, during configure I got the warning
WARNING: minimum kernel version reset to 2.0.10
which is still acceptable, I suppose. For a list of things which change with different kernels see ./sysdeps/unix/sysv/linux/kernel-features.h.
Ok, so let's link against the newly compiled glibc library, slightly messy but here it goes:
$ export LIBC_PATH=/usr/local/glibc_32
$ export LIBC_FLAGS=-nostdlib -L${LIBC_PATH} \
${LIBC_PATH}/crt1.o ${LIBC_PATH}/crti.o \
-lm -lc -lgcc -lgcc_eh -lstdc++ -lc \
${LIBC_PATH}/crtn.o
$ g++ -m32 -static prog.o ${LIBC_FLAGS} -o prog
Since we're doing a static compile the link order is important and may well require some trial and error, but basically we learn from what options gcc gives to the linker:
$ g++ -m32 -static -Wl,-v file.o
Note, crtbeginT.o and crtend.o are also linked against which I didn't need for my programmes so I left them out. The output also includes a line like --start-group -lgcc -lgcc_eh -lc --end-group which indicates inter-dependence between the libraries, see this post. I just mentioned -lc twice in the gcc command line which also solves inter-dependence.
Right, the hard work has paid off and now I get
$ file ./prog
./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
statically linked, for GNU/Linux 2.0.10, not stripped
Brilliant I thought, now try it on the old system:
user#ancient:~ $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
This, again, is a glibc error message from ./nptl/sysdeps/i386/tls.h. I fail to understand the details and give up.
Compile on the new system g++ -c -m32 -march=i386 and link on the old. Wow, that actually works for C and simple C++ programmes (not using C++ objects), at least for the few I've tested. This is not too surprising as all I need from libc is printf (and maybe some maths) of which the interface hasn't changed but the interface to libstdc++ is very different now.
Setup a virtual box with an old linux system and gcc version 2.95. Then compile gcc version 4.x.x ... sorry, but too lazy for that right now ...
???
Have found the reason for the error message:
user#ancient $ ./prog
set_thread_area failed when setting up thread-local storage
Segmentation fault
It's because glibc makes a system call to a function which is only available since kernel 2.4.20. In a way it can be seen as a bug of glibc as it wrongly claims to be compatible with kernel 2.0.10 when it requires at least kernel 2.4.20.
The details:
./glibc-2.14/nptl/sysdeps/i386/tls.h
[...]
/* Install the TLS. */ \
asm volatile (TLS_LOAD_EBX \
"int $0x80\n\t" \
TLS_LOAD_EBX \
: "=a" (_result), "=m" (_segdescr.desc.entry_number) \
: "0" (__NR_set_thread_area), \
TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \
[...]
_result == 0 ? NULL \
: "set_thread_area failed when setting up thread-local storage\n"; })
[...]
The main thing here is, it calls the assembly function int 0x80 which is a system call to the linux kernel which decides what to do based on the value of eax, which is set to
__NR_set_thread_area in this case and is defined in
$ grep __NR_set_thread_area /usr/src/linux-2.4.20/include/asm-i386/unistd.h
#define __NR_set_thread_area 243
but not in any earlier kernel versions.
So the good news is that point "3. Compiling glibc with --enable-kernel=2.0.0" will probably produce executables which run on all linux kernels >= 2.4.20.
The only chance to make this work with older kernels would be to disable tls (thread-local storage) but which is not possible with glibc 2.14, despite the fact it is offered as a configure option.
The reason you can't compile it on the original system likely has nothing to do with kernel version (it could, but 2.2 isn't generally old enough for that to be a stumbling block for most code). The problem is that the toolchain is ancient (at the very least, the compiler). However, nothing stops you from building a newer version of G++ with the egcs that is installed. You may also encounter problems with glibc once you've done that, but you should at least get that far.
What you should do will look something like this:
Build latest GCC with egcs
Rebuild latest GCC with the gcc you just built
Build latest binutils and ld with your new compiler
Now you have a well-built modern compiler and (most of a) toolchain with which to build your sample application. If luck is not on your side you may also need to build a newer version of glibc, but this is your problem - the toolchain - not the kernel.