c++ code doesn't catch exception on FreeBSD - c++

I have a program running on many different linux distros. When I compile it on FreeBSD 10.1 for some reason the catch clauses stop working and exceptions that should get caught crash my program. When debugging I modified one of the catch clauses to "catch (...)" and still the exception wasn't caught. I guess the issue is related to the linker, but I don't know how to debug it futher. When I tried compiling a test program that simply throws and catches and exception it worked - so I guess the linker fails to link the different objects properly.
Anyone know how can I solve it?
Thanks
EDIT:
compilation examples (original paths in the commands are longer, deleted them for clarity):
I compiled many classes like this:
/usr/local/bin/g++ -O3 -c -DFreeBSD -D_FreeBSD -I. -I/usr/local/openjdk8/include -I/usr/local/openjdk8/include/freebsd -DBOOL_DEFINED -D_BOOL -DFreeBSD -fPIC -I../../../../common/cpp -DVERSION_MAJOR=8 -DVERSION_MIDDLE=2 -DVERSION_MINOR=8 -DNSC_DEBUG -DUSE_HINT_FILES -o CNBCommand.o CNBCommand.cpp
then create an archive with
ar srv "bin/FreeBSD_10.1-RELEASE/mechanism.a" <many .o files compiled like above>
And the final executable is linked with:
/usr/local/bin/g++ -O3 -B/usr/local/bin -rpath=/usr/local/lib -lstdc++ -lpthread -o "../bin/FreeBSD_10.1-RELEASE/nbstatus" <many *.o files compiled like above> bin/FreeBSD_10.1-RELEASE/mechanism.a
This is the g++ I use:
/usr/local/bin/g++ -v
Using built-in specs.
COLLECT_GCC=/usr/local/bin/g++
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc49/gcc/x86_64-portbld-freebsd10.1/4.9.3/lto-wrapper
Target: x86_64-portbld-freebsd10.1
Configured with: ./../gcc-4.9-20141126/configure --disable-nls --enable-gnu-indirect-function --libdir=/usr/local/lib/gcc49 --libexecdir=/usr/local/libexec/gcc49 --program-suffix=49 --with-as=/usr/local/bin/as --with-gmp=/usr/local --with-gxx-include-dir=/usr/local/lib/gcc49/include/c++/ --with-ld=/usr/local/bin/ld --with-pkgversion='FreeBSD Ports Collection' --with-system-zlib --with-ecj-jar=/usr/local/share/java/ecj-4.5.jar --enable-languages=c,c++,objc,fortran,java --prefix=/usr/local --mandir=/usr/local/man --infodir=/usr/local/info/gcc49 --build=x86_64-portbld-freebsd10.1
Thread model: posix
gcc version 4.9.3 20141126 (prerelease) (FreeBSD Ports Collection)

You have to link with -Wl,-rpath=/usr/local/lib/gcc<VERSION> or you'll link against libc++, which doesn't match the headers gcc uses.
Check pkg info -Dx gcc for the right path.

Related

Debug symbols not included in gcc-compiled C++

I am building a module in C++ to be used in Python. My flow is three steps: I compile the individual C++ sources into objects, create a library, and then run a setup.py script to compile the .pyx->.cpp->.so, while referring to the library I just created.
I know I can just do everything in one step with the Cython setup.py, and that is what I used to do. The reason for splitting it into multiple steps is I'd like the C++ code to evolve on its own, in which case I would just use the compiled library in Cython/python.
So this flow works fine, when there are no bugs. The issue is I am trying to find the source of a segfault, so I'd like to get the debugging symbols so that I can run with gdb (which I installed on OSX 10.14, it was a pain but it worked).
I have a makefile, which does the following.
Step 1: Compile individual C++ source files
All the files are compiled with the bare minimum flags, but -g is there:
gcc -mmacosx-version-min=10.7 -stdlib=libc++ -std=c++14 -c -g -O0 -I ./csrc -o /Users/colinww/system-model/build/data_buffer.o csrc/data_buffer.cpp
I think even here there is a problem: when I do nm -pa data_buffer.o, I see no debug symbols. Furthermore, I get:
(base) cmac-2:system-model colinww$ dsymutil build/data_buffer.o
warning: no debug symbols in executable (-arch x86_64)
Step 2: Compile cython sources
The makefile has the line
cd $(CSRC_DIR) && CC=$(CC) CXX=$(CXX) python3 setup_csrc.py build_ext --build-lib $(BUILD)
The relevant parts of setup.py are
....
....
....
compile_args = ['-stdlib=libc++', '-std=c++14', '-O0', '-g']
link_args = ['-stdlib=libc++', '-g']
....
....
....
Extension("circbuf",
["circbuf.pyx"],
language="c++",
libraries=["cpysim"],
include_dirs = ['../build'],
library_dirs=['../build'],
extra_compile_args=compile_args,
extra_link_args=link_args),
....
....
....
ext = cythonize(extensions,
gdb_debug=True,
compiler_directives={'language_level': '3'})
setup(ext_modules=ext,
cmdclass={'build_ext': build_ext},
include_dirs=[np.get_include()])
When this is run, it generates a bunch of compilation/linking commands like
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/colinww/anaconda3/include -arch x86_64 -I/Users/colinww/anaconda3/include -arch x86_64 -I. -I../build -I/Users/colinww/anaconda3/lib/python3.7/site-packages/numpy/core/include -I/Users/colinww/anaconda3/include/python3.7m -c circbuf.cpp -o build/temp.macosx-10.7-x86_64-3.7/circbuf.o -stdlib=libc++ -std=c++14 -O0 -g
and
g++ -bundle -undefined dynamic_lookup -L/Users/colinww/anaconda3/lib -arch x86_64 -L/Users/colinww/anaconda3/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.7-x86_64-3.7/circbuf.o -L../build -lcpysim -o /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so -stdlib=libc++ -g
In both commands, the -g flag is present.
Step 3: Run debugger
Finally, I run my program with gdb
(base) cmac-2:sim colinww$ gdb python3
(gdb) run system_sim.py
It dumps out a ton of stuff related to system files (seems unrelated) and finally runs my program, and when it segfaults:
Thread 2 received signal SIGSEGV, Segmentation fault.
0x0000000a4585469e in cpysim::DataBuffer<double>::Write(long, long, double) () from /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so
(gdb) info local
No symbol table info available.
(gdb) where
#0 0x0000000a4585469e in cpysim::DataBuffer<double>::Write(long, long, double) () from /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so
#1 0x0000000a458d6276 in cpysim::ChannelFilter::Filter(long, long, long) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#2 0x0000000a458b0d29 in __pyx_pf_6chfilt_6ChFilt_4filter(__pyx_obj_6chfilt_ChFilt*, long, long, long) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#3 0x0000000a458b0144 in __pyx_pw_6chfilt_6ChFilt_5filter(_object*, _object*, _object*) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#4 0x000000010002f1b8 in _PyMethodDef_RawFastCallKeywords ()
#5 0x000000010003be64 in _PyMethodDescr_FastCallKeywords ()
As I mentioned above, I think the problem starts in the initial compilation step. This has nothing to do with cython, I'm just calling gcc from the command line, passing the -g flag.
(base) cmac-2:system-model colinww$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Any help is appreciated, thank you!
UPDATE
I removed the gcc tag and changed it to clang. So I guess now I'm confused, if Apple will alias gcc to clang, doesn't that imply that in "that mode" it should behave like gcc (and, implied, someone made sure it was so).
UPDATE 2
So, I never could get the debug symbols to appear in the debugger, and had to resort to lots of interesting if-printf statements, but the problem was due to an index variable becoming undefined. So thanks for all the suggestions, but the problem is more or less resolved (until next time). Thanks!
The macOS linker doesn't link debug information into the final binary the way linkers usually do on other Unixen. Rather it leaves the debug information in the .o files and writes a "debug map" into the binary that tells the debugger how to find and link up the debug info read from the .o files. The debug map is stripped when you strip your binary.
So you have to make sure that you don't move or delete your .o files after the final link, and that you don't strip the binary you are debugging before debugging it.
You can check for the presence of the debug map by doing:
$ nm -ap <PATH_TO_BINARY> | grep OSO
You should see output like:
000000005d152f51 - 03 0001 OSO /Path/To/Build/Folder/SomeFile.o
If you don't see that the executable probably got stripped. If the .o file is no around then somebody cleaned your build folder earlier than they should have.
I also don't know if gdb knows how to read the debug map on macOS. If the debug map entries and the .o files are present, you might try lldb and see if that can find the debug info. If it can, then this is likely a gdb-on-macOS problem. If the OSO's and the .o files are all present, then something I can't guess went wrong, and it might be worth filing a bug with http://bugreporter.apple.com.

How to change default GCC compiler to be used with MPI on Linux CentOS

I have two GCC compilers installed on a Linux (CentOS) machine. The old version of GCC (4.4.7) is in the default folder (came with CentOS) and the newer one that I intend to use is in /usr/local/gcc/4.9.3/. My code utilizes MPI and LAPACK/LAPACKE/BLAS libraries and with the old GCC I used to compile source (for example “main.cpp”) like this:
mpiCC main.cpp -o main -L/home/USER1/lapack-3.6.1 -llapacke -llapack -lblas -lm –Wall
This still invokes the old GCC 4.4.7. What should I modify so the above MPI compilation (mpiCC) invokes GCC 4.9.3 executable from the new location at /usr/local/gcc/4.9.3/el6/bin/ ?
From MPICH Installer's Guide version 3.2 (page 6):
"The MPICH configure step will attempt to find the C, C++, and Fortran compilers for you, but if you either want to override the default or need to specify a compiler that configure doesn't recognize, you can specify them on the command line [...]. For example, to select the Intel compilers instead of the GNU compilers on a system with both, use"
./configure CC=icc CXX=icpc F77=ifort FC=ifort ...
Is there a way to dicriminate between different version of GCC compilers in ./configure ?
I guess mpiCC uses the first gcc compiler found in the $PATH variable.
You should be able to set the new version of gcc by running:
PATH="/usr/local/gcc/4.9.3/el6/bin:$PATH" mpiCC main.cpp -o main -L/home/USER1/lapack-3.6.1 -llapacke -llapack -lblas -lm –Wall
If you really want two versions of GCC installed at the same time and use both of them here is a good link that explains how to do this:
http://gcc.gnu.org/faq.html#multiple
Finally found how. Here is the recipe:
1) check your if you shell is bash, if not set it to bash: $ echo $SHELL
/bin/tcsh
It was tcsh and needed to be set to bash.
2) Switch to bash: $ bash
bash-4.1$
3) Add new version of GCC to the front of the PATH:
bash-4.1$ export PATH=/usr/local/gcc/4.9.3/el6/bin:$PATH
4) Check the PATH: bash-4.1$ echo $PATH
/usr/local/gcc/4.9.3/el6/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin
5) Check version of GCC used (It picks up the first GCC from the PATH):
bash-4.1$ gcc --version
gcc (GCC) 4.9.3
Note: this is just for the current session.

gfortran is called instead of mpif90

I am trying to compile a big solver using a makefile. When typing make, the following command gets executed:
mpif90 -O2 -fpp -I/somePath/ -c precision.F90
I get the following error:
gfortran: error: unrecognized command line option ‘-fpp’
I typed which mpif90 to see where it is pointing to:
/usr/local/intel14/impi/4.1.3.048/intel64/bin/mpif90
I tried to manually enter the command to make sure it did not have anything to do with the makefile and I got the same error. Why is gfortran being called? It must be some linking error but I can't figure it out.
The comments put me on the right track. I did not know mpif90 was just a wrapper.
$ /usr/local/inter14/impi/4.1.3.048/intel64/bin/mpif90 -v
mpif90 for the Intel(R) MPI Library 4.1 for Linux*
Copyright(C) 2003-2014, Intel Corporation. All rights reserved.
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/local/gcc5.2/libexec/gcc/x86_64-unknown-linux-gnu/5.2.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ./configure --prefix=/usr/local/gcc5.2 --disable-multilib
Thread model: posix
gcc version 5.2.0 (GCC)
I asked the code's author to do the same, the output pointed to an intel compiler. So what remains is to link ifort. This fixed it for me (bash shell):
export I_MPI_F90=ifort
You can just use the alternative
/usr/local/intel14/impi/4.1.3.048/intel64/bin/mpiifort

GCC Fails to Generate Object Files When Compiling

Recently I have noticed that GCC does not generate object (*.o) files when compiling with '-c'. It does not issue any errors or warnings. I have run it with '-verbose' but it shows nothing out of the ordinary.
Running under Windows:
gcc -Wall -c source_file.c
I have also tried compiling with '-verbose' to display detailed information
gcc -Wall -verbose -c source_file.c
It should produce 'source_file.o' but it doesn't. Any idea what's going on?
The issue has been resolved. Reinstalling GCC (mingw) fixed the problem. It is possible the problem came about because I tried to install the 64-bit version of GCC (Mingw-w64) to top of the 32-bit version...

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.