The native OCaml compiler exposes options that control whether debug information is emitted. For instance -g controls whether to record information needed to reconstruct exception backtraces. Is there an option to emit the debug information that would be needed for gdb to associate breakpoints with source information like file name and line number?
I don't think OCaml is, at present, a fully supported language for gdb and it isn't possible to pretty-print values or evaluate OCaml expressions. That is okay, I'm just wondering how to configure the ocamlopt compiler or gdb in such a way that gdb can find the source file. Ideally I'd like to be able to see both the OCaml sources and the C source files that implement OCaml runtime when they are present (i.e. when building a compiler by hand rather than through OPAM).
For instance,
(* hello.ml *)
let main () =
Printf.printf "hi there\n%!";;
let () = main ()
compiled using corebuild hello.native, produces a symlink to an executable, hello.native.
and then, when starting gdb:
(gdb) file hello.native
Reading symbols from hello.native...done.
(gdb) start
Temporary breakpoint 1 at 0x405580: file main.c, line 32.
Starting program: /home/g/ws/tmp/ocaml/hello/hello.native
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main (argc=0x1, argv=0x7fffffffdaf8) at main.c:32
32 main.c: No such file or directory.
We can see that it was unable to determine where the file is.
When you hit C-x a and switch gdb to tui mode, then the message [ No Source Available ] is visible in the top pane.
Use the dir directive in gdb to point it to the place where is the source code of the OCaml runtime, e.g.,
(gdb) dir ~/warehouse/ocaml/byterun/
Source directories searched: /home/ivg/warehouse/ocaml/byterun:$cdir:$cwd
(gdb) l
27 #endif
28
29 CAMLextern void caml_main (char_os **);
30
31 #ifdef _WIN32
32 CAMLextern void caml_expand_command_line (int *, wchar_t ***);
33
34 int wmain(int argc, wchar_t **argv)
35 #else
36 int main(int argc, char **argv)
Few more tips. You can link your program with the debugging runtime, e.g.,
ocamlopt -runtime-variant x -g hello.ml -o hello
It won't have the source code embedded though.
Also, OCaml has quite a good support for gdb, you can step, backtrace, and even observe the source code. The only problem is that names are usually mangled, so it is hard to set up a breakpoint. However, you can use objdump to reverse engineer your file. It is easy if it is built with the -g option:
$ objdump -S hello | grep hello.ml -A 10
(* hello.ml *)
let main () =
404a70: 48 8d 1d 81 a6 24 00 lea 0x24a681(%rip),%rbx # 64f0f8 <camlHello__5>
404a77: 48 8d 05 da b3 24 00 lea 0x24b3da(%rip),%rax # 64fe58 <camlPervasives>
Printf.printf "hi there\n%!";;
404a7e: 48 8b 80 d0 00 00 00 mov 0xd0(%rax),%rax
404a85: e9 66 ae 01 00 jmpq 41f8f0 <camlPrintf__fprintf_1294>
404a8a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000404a90 <camlHello__entry>:
Related
I'm porting a windows application to Linux, the application fetches version from a exe using Windows APIs GetFileVersionInfoSize() and GetFileVersionInfo(). But I'm unable to find something similar to that in Linux.
I'm aware that I can use readelf to read contents of application or object files in Linux as below
[root#Panch-Linux]# readelf <xyz.so> -h
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - Linux
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4f7ec0
Start of program headers: 64 (bytes into file)
Start of section headers: 17823344 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 38
Section header string table index: 35
Shoud I use readelf to get the version information, if yes then the string "Version" is the one which actually represents the file version. Also please let me know how to use readelf in C++ programming on Linux environment.
If this is not the right way, please suggest me appropriate way of doing this.
System : I'm running 32 bit Ubuntu 12.04 on a i32 chipset.
Build Info : I'm using C++ 11 with Qt 4.8.1 and GCC.
Problem : I am developing a project that depends on in-house developed libraries hereafter mentioned to as slug. These libraries are built into .so files via the traditional "cmake ." then "make all" process. After the .so files are generated from cmake, I copy the .so files into a sub-directory of my project so that I can test that they are working before I install them into /usr/lib. Then I provide Qt (in my .pro file) with a absolute path to each library and build my application. My application finds these local libraries and compiles without errors or warnings. However, when I run my application (via command line) I receive the following error:
error while loading shared libraries: libslugSpec.so: wrong ELF class: ELFCLASS64
However, when I build the slug libraries on a 64 bit environment and link to them in a 64 bit environment my application runs perfectly. So, I figured I built the .so files for a 64 bit environment,and proceeded to edit the CMakeLists.txt file used to build the libraries. I add numerous 32 bit compilation and linking flags, shared object module flags, in addition to cuda (which slug relies on) bitness flags . No matter what combination of flags I tried, the libraries generated kept causing the error when running my application executable. So I decided to run the readelf -h command on each shared object file and check to see if they were really 64 bit. I found out that none of them are in fact, all producing logs similar to the following: (output for one of 3 .so files)
readelf -h libslugSpec.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x10150
Start of program headers: 52 (bytes into file)
Start of section headers: 511960 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 38
Section header string table index: 35
So now I am completely at a loss and can't seem to find an answer anywhere. Any illumination into how this could be happening would be a huge help.
For reference, here are the flags I am providing in the qt .pro file that builds my application:
QMAKE_CXXFLAGS += "-std=gnu++0x"
QT += core gui opengl
TARGET = source
TEMPLATE = app
CONFIG+= wwwidgets
#linux specific settings
unix:!macx{
LIBS += -lGLEW -lGLU /home/alex/Dropbox/brain-viz/source/lib/libslugUtil.so /home/alex/Dropbox/brain-viz/source/lib/libslugSpec.so /home/alex/Dropbox/brain-viz/source/lib/libslugSim.so
}
#windows specific settings
win32{
LIBS += -lglew32 -lwwwidgets4d
}
This error message:
error while loading shared libraries: libslugSpec.so: wrong ELF class: ELFCLASS64
Is not consistent with this output:
readelf -h libslugSpec.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Conclusion: you load a different version of libslugSpec.so from the one you ran readelf -h on.
Find out which libslugSpec.so is loaded at runtime by doing this:
LD_DEBUG=files,libs /path/to/your/executable
Then run readelf -h on that library, and confirm that it is in fact ELF64.
Finally replace it with the version you've built (or set LD_LIBRARY_PATH to pick up your version before "system" one), and the problem will be solved.
I was curious about .obj files: I pretty much don't know what they are (or what they contain), so I opened them with Vim text editor and what I found inside was an Alien like language...
Is there any way to understand what they represent and what is their content
Also, for what are they being used ?
Thanks.
Sure.
But every different platform has a different object format. On Windows, you could use a tool like dumpbin (dumpbin comes with Visual Studio). On Linux, you could use "dumpobj", or disassemble the program.
Here's a good link for Linux:
http://www.linuxjournal.com/article/1060
PS:
objdump also lets you disassemble the object. Like you used to be able to do with "debug" on DOS PCs...
The .obj files used by link.exe has MS COFF format.
You can find "Microsoft PE and COFF Specification" here, and parse .obj file according to it.
Or, you can use existing tool like dumpbin.
The readelf tool is good at showing you some details on the data:
$ readelf -a /usr/bin/readelf
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
...
Some of its abilities to inspect specific sections of the executable can come in handy too:
$ readelf -p .rodata /usr/bin/readelf | more
String dump of section '.rodata':
[ 4] R_IA64_IMM14
[ 11] R_IA64_NONE
...
[ 1f58] Personality routine:
[ 1f70] __gcc_personality_v0
[ 1f85] __gxx_personality_v0
[ 1f9a] __gcj_personality_v0
[ 1faf] __gnu_objc_personality_v0
...
Actually disassembling the code is a bit of a stretch; if you compile your code with -g for debugging symbols, you can use readelf --debug-dump to read the program source, type information, etc.
I try to enable msvc memory leak detection with line number like this snippet I found here:
Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18}
normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
I tried to set the preprocessor define
_CRTDBG_MAP_ALLOC
manually in the project properties but I only get this:
Dumping objects ->
{1466} normal block at 0x00BD4DD0, 40 bytes long.
Data: <(o; ; (o; 1 > 28 6F 3B 00 90 A9 3B 00 28 6F 3B 00 00 D6 31 10
without line numbers. I also tried to manually define main by using BOOST_TEST_NO_MAIN and dump by myself like this:
int main( int argc, char* argv[] )
{
int res = ::boost::unit_test::unit_test_main( &init_function, argc, argv );
_CrtDumpMemoryLeaks();
return res;
}
But also without any success. How can this be done?
Using Boost.Test you can use --detect_memory_leaks="allocation number"
In MSVC you can set a breakpoint to the allocation number 1466, in the code:
_crtBreakAlloc = 1466
or in the Watch window you can add _crtBreakAlloc and value 1466 once the application started (of course you need a breakpoint in the main function). More details on MSDN
Try to use the debugger! For example, with help of deleaker can select the stack to see where memory was allocated
This is an output of Boost.Test when test case failes:
bjam toolset=msvc
...patience...
...found 1287 targets...
...updating 4 targets...
compile-c-c++ ..\bin\test\Function.test\msvc-8.0\debug\link-static\threading-multi\Function.obj
Function.cpp
msvc.link ..\bin\test\Function.test\msvc-8.0\debug\link-static\threading-multi\Function.exe
msvc.manifest ..\bin\test\Function.test\msvc-8.0\debug\link-static\threading-multi\Function.exe
testing.capture-output ..\bin\test\Function.test\msvc-8.0\debug\link-static\threading-multi\Function.run
====== BEGIN OUTPUT ======
Running 1 test case...
Function.cpp(26): fatal error in "FunctionConstruction": critical check pf->Name() == "F13" failed [F1 != F13]
*** 1 failure detected in test suite "foo_test"
Detected memory leaks!
Dumping objects ->
{235} normal block at 0x003A7C88, 32 bytes long.
Data: 00 00 00 00 CD CD CD CD 54 31 00 CD CD CD CD CD
{234} normal block at 0x003A7E00, 96 bytes long.
Data: 00 00 00 00 CD CD CD CD 54 31 00 CD CD CD CD CD
{233} normal block at 0x003A7D88, 76 bytes long.
Data: F4 D9 45 00 00 00 00 00 CD CD CD CD 00 7E 3A 00
Object dump complete.
EXIT STATUS: 201
====== END OUTPUT ======
MSVC parses this errors correctly so i can double click and jump to place in code. But emacs can't parse this output. How to teach it?
The solution will involve customizing the variables: 'compilation-error-regexp-alist, 'compilation-error-regexp-alist-alist, 'compilation-directory-matcher.
The first, 'compilation-error-regexp-alist is just a list of symbols telling the compilation mode what to look up in the second variable `'compilation-error-regexp-alist-alist', so you'll probably just add something for boost:
(add-to-list 'compilation-error-regexp-alist 'boost)
Then, to make that work, you need to add a list to the second variable, 'compilation-error-regexp-alist-alist. This is where it starts to get tricky. You'll need to read the documentation for the first variable to get the regexp right, but it'll be something like:
(add-to-list 'compilation-error-regexp-alist-alist
'(boost
"^\\(.*\\)(\\([0-9]+\\)): fatal error in" 1 2))
The regexp matches the error line, and the 1 and 2 specify the sub expression specifying the filename and line number respectively. There are other things you can specify (see the documentation).
Though, to be honest, the above two settings are probably unnecessary as I'm pretty sure one of the existing regexps will match the format. The problem really exists with the directory tracking.
The last variable, `'compilation-directory-matcher' is the one that lets the next-error track where to find the files. So it needs to be updated appropriately. It doesn't look like the boost test spits out the somewhat standard "Entering directory ..." that Emacs looks for, but the information seems to be there in the compile line...
You might also try asking on the boost user mailing list to see if someone there has solved this problem. The mailing list can be found here.