Why does a 2-stage command-line build with clang not generate a dSYM directory? - c++

I have a simple project I want to debug want to produce dSYM folder with debugging symbols.
Running:
clang++ -std=c++14 -stdlib=libc++ -g -o Lazy Lazy.cpp
Creates Lazy.dSYM as I expect.
However:
clang++ -std=c++14 -stdlib=libc++ -g -c Lazy.cpp
clang++ -stdlib=libc++ -g -o Lazy Lazy.o
Does not create Lazy.dSYM (It seems that the symbols are embedded in the binary).
Sadly the 2-step build is what my modified makefile does. How can I generate Lazy.dSYM from a 2-stage compile-and-link build?
I don't need a dSYM directory, just debugging symbols, but would like to understand when and why it is created.

The creation of the .dSYM bundle is done by a tool called dsymutil. When Apple added support for DWARF debugging information, they decided to separate "executable linking" from "debug information linking". As such, the debug information linking is not done by the normal linker, it's done by dsymutil.
As a convenience, when you build a program all in one step, the compiler invokes dsymutil on your behalf. That's because it knows it has all of the inputs. If you add the -v (a.k.a. --verbose) option to the compile command, you will see the invocation of dsymutil as the last step it does.
In other cases, though, it doesn't do that. It leaves the debug information linking step for the user to do manually. You can do it by simply issuing the command:
dsymutil <your_program>
Here's an article by an Apple engineer who helped design and implement Apple's support for DWARF explaining their thinking. He also answered a question here on Stack Overflow about this stuff.

Related

Debug symbols stability

I am compiling an application with -g option:
gcc -g -o main1 main.c
then I strip debug object from it:
objcopy --strip-debug main1
Let's assume that my main1 application will crash and I would like to use a core dump coredump1 to debug the problem.
Could I rebuild the source code once more
gcc -g -o main2 main.c
and extract debug symbols
objcopy --only-keep-debug main2 main2.debug
and use main2.debug to debug the coredump1?
Can I trust that debug symbols will be always aligned? Is it guaranteed by language standard or compiler requirement?
Will debug symbols match if my source code will contain strings based on macros like__DATE__ or __TIME__ ?
Will it work if I enable code optimization?
Will debug symbols match ...
Will it work if I enable code optimizaiton?
As others have commented, you should not rely on this, and instead always build with -g and separate debug symbols out before shipping the "final product".
That said, in practice this works for GCC1 with or without optimization, but doesn't work at all for Clang/LLVM (which gives you a practical reason not to depend on this).
1 Or at least it did last time I tried this for several non-trivial binaries a few years ago.
Note that maintaining this property requires active effort from the compiler developers and thus can be broken as violations are introduced, noticed and fixed.

How do you save links with g++/C++?

I am writing some OpenGL code, and my links to libraries in /usr/lib is getting quite unwieldly:
g++ Application.cpp -lglfw -lGL -lGLEW
I don't want to hunt around/can't remember the exact names of the libraries EVERY TIME i want to complile something, so in my project folder I have a file called linkingsNeeded.txt. That file contains that command and nothing else. Is there a way to save the list of linkings so I can just type
g++ Application.cpp
And not have to deal with manually linking? Say, in the #include section of the CPP file?
Learn to use some build automation tool such as GNU make or ninja.
You'll then edit your Makefile (with make); this could be inspirational and just build your program by typing make. Most source code editors (like GNU emacs) or IDEs can be easily configured to run make with a single keypress.
Of course you want to invoke GCC as g++ -Wall -Wextra -g since you want all warnings and debug info (for the GDB debugger).
Read also How to debug small programs and more about C++, perhaps even the n3337 quasi C++11 standard.

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 can I tell GCC to use custom library for -l instead of the system one?

I have a custom build of SQLite3 at /somepath, so /somepath/.libs contains libsqlite3.so.0.8.6 and the symbolic links to it. I wanted to link a program against it and assumed
g++ -O3 -g -fPIC -I /somepath -I /somepath/src -L /somepath/.libs -lsqlite3 -o myfile.so myfile.cpp
would work. It compiles, but I get a segmentation fault due to some problem in my code, and when trying to debug I run into the issues which look like LD_PRELOAD not working with my program and Setting my lib for LD_PRELOAD makes some processes produce loader errors: I can run LD_PRELOAD=myfile.so /somepath/sqlite3 ..., but under GDB I get symbol lookup error and LD_DEBUG=all LD_PRELOAD=myfile.so gdc -c core /somepath/sqlite3 ... reveals symbols are getting looked up in /usr/lib/x86_64-linux-gnu/libsqlite3.so.0 instead of /somepath/libsqlite3.so.0, and unsurprisingly missing the symbols for functions added in the custom build. How can I fix this and debug my code?
The -lsqlite3 argument should be last. Order of arguments to g++ matters a lot. You should read more about runpath and perhaps pass -Wl,-rpath,/somepath/.libs
You may want to pass -v once to g++ to understand what is happening (what programs are actually running). You might also pass -Wl,--verbose to ask a more verbose link.
Then you can use ldd on your executable (and also readelf) to find out more what are its link time dependencies.
With suitable arguments to g++ you should not need additional options to gdb
From http://visualgdb.com/gdbreference/commands/set_solib-search-path
Inside gdb use the commands below.
set solib-search-path [Directories]
show solib-search-path

What does the gcc -R parameter do?

I am trying to run an autotools configure script for the bson-cpp project, and it fails because it cannot determine what flags it needs to compile with boost_filesystem. A quick look at confg.log shows:
g++ -o conftest -g -O2 -pthread -L/usr/local/lib -R/usr/local/lib -L/usr/local/libexec conftest.o -lboost_filesystem-mt -lboost_system-mt >&5
g++: error: unrecognized option '-R'
So, naturally, I tried to find out what the R option does, but I can't seem to find it documented anywhere. I've checked here and here to no avail. What does the option do and how do I tell autotools not to use it?
-R does not seem to be an option for g++ or gcc anywhere. -R may be a linker option on some platforms that is equivalent of -rpath to gnu ld, ... This seems to be a known bug in boost builds ... have a look at Use -Wl to pass arguments to the linker.
It actually has the patch available there
I am re-posting it for convenience, however PLEASE PLEASE look at the original URL linked above for official patch!
--- ../gnote/m4/boost.m4 2011-01-25 14:30:18.000000000 +0200
+++ m4/boost.m4 2011-02-27 20:57:11.686221539 +0200
## -403,7 +403,7 ##
LDFLAGS=$boost_save_LDFLAGS
LIBS=$boost_save_LIBS
if test x"$Boost_lib" = xyes; then
- Boost_lib_LDFLAGS="-L$boost_ldpath -R$boost_ldpath"
+ Boost_lib_LDFLAGS="-L$boost_ldpath -Wl,-R$boost_ldpath"
Boost_lib_LDPATH="$boost_ldpath"
break 6
else
It's an option similar to -rpath, but available only on some platforms. The script is maybe failing detecting your platform ?
It is not a valid option for GCC, so it does not do anything.
It is possibly a valid option for other compilers though, which could be why autoconf gives it a shot.
Not all errors in the config.log files are a problem. autoconf figures out a lot of things by "guessing", i.e. trying something and keeping that if it worked.