Why works addr2line only for functions - c

I've got addr2line working for function addresses:
$ nm -S executable | grep main
08048742 000000a0 T main
$ addr2line -e executable 08048742
/home/blablabla/src/main.c:80
Unfortunately it only works if I supply an address of a function, when passing an address of a data symbol (e.g. the address of a crc table) it can never resolve the file/line number:
$ nm -S executable | grep tableCRC
080491bc 00000200 r tableCRC
$ addr2line -e executable 080491bc
??:0
I guess that that kind of debug information just isn't included for data because this feature is probably intended for analyzing backtraces, but maybe there's a compiler/linker option to force this?
I want to use the output of addr2line to generate detailed information about how much memory size a file or module uses (instead of the global number reported by the 'size' tool).

The --print-size and --line-numbers options to nm are probably what you are looking for.
Please note that the ELF object needs to contain debugging information for the --line-numbers option to work.

Related

"No symbol version section for versioned symbol"

I'm attempting to cross-compile my own shared library (libmystuff.so) against another shared library (libtheirstuff.so) that makes use of the libcurl shared library and am getting the following error:
libmystuff.so: No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3'
Which is then followed by:
final link failed: Nonrepresentable section on output.
Going through the code that creates libtheirstuff, I can see that curl_global_init is the first reference to curl.
Doing ldd libtheirstuff.so on the target platform (arm5) shows that it can find all of the references.
What's going on here?
Edit: Here are the calls to gcc
arm-none-linux-gnueabi-gcc -fPIC -c mystuff_impl.c -o mystuff_impl.o -I/home/me/arm/include
arm-none-linux-gnueabi-gcc -shared -Wl,soname=libmystuff.so -o libmystuff.so.0.1 mystuff_impl.o -L/home/me/arm/lib -ltheirstuff
Linker was grabbing the wrong version.
This problem (No symbol version section for versioned symbol
'curl_global_init##CURL_OPENSSL_3') also appears when you are trying to compile a binary that will work on multiple Linux distributions. You can check for the problem like this:
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init##CURL_OPENSSL_3
The solution in this case is to build on a machine where libcurl has been compiled with ./configure --disable-versioned-symbols. Binaries compiled this way will work elsewhere (including on systems which use versioned symbols). A portable binary should produce output like this (without any # signs):
$ objdump -x mybinary | grep curl_global_init
0... F *UND* 0... curl_global_init

How to check if a macro exists in an object file in C?

For example, I define a macro:
#ifdef VERSION
//.... do something
#endif
How can I check if VERSION exist in my object file or not? I tried to disassemble it with objdump, but found no actual value of my macro VERSION. VERSION is defined in Makefile.
Try compiling with -g3 option in gcc. It stores macro information too in the generated ELF file.
After this, if you've defined a macro MACRO_NAME just grep for it in the output executable or your object file. For example,
$ grep MACRO_NAME a.out # any object file will do instead of a.out
Binary file a.out matches
Or you can even try,
$ strings -a -n 1 a.out | grep MACRO_NAME
-a Do not scan only the initialized and loaded sections of object files;
scan the whole files.
-n min-len Print sequences of characters that are at least min-len characters long,
instead of the default 4.
The following command displays contents of .debug_macro DWARF section:
$ readelf --debug-dump=macro path/to/binary
or
$ objdump --dwarf=macro path/to/binary
You can also use dwarfdump path/to/binary, but it's not easy to leave only .debug_macro section in the output.

How to use the addr2line command in Linux?

I am trying to use addr2line command in Unix but everytime it is giving the same output as ??:0. I am giving command as addr2line -e a.out 0x4005BDC . I got this address while running this a.out executable with valgrind tool to find the memory leakage. I also compiled the source code with -g option.
You can also use gdb instead of addr2line to examine memory address. Load executable file in gdb and print the name of a symbol which is stored at the address. 16 Examining the Symbol Table.
(gdb) info symbol 0x4005BDC
You need to specify an offset to addr2line, not a virtual address (VA). Presumably if you had address space randomization turned off, you could use a full VA, but in most modern OSes, address spaces are randomized for a new process.
Given the VA 0x4005BDC by valgrind, find the base address of your process or library in memory. Do this by examining the /proc/<PID>/maps file while your program is running. The line of interest is the text segment of your process, which is identifiable by the permissions r-xp and the name of your program or library.
Let's say that the base VA is 0x0x4005000. Then you would find the difference between the valgrind supplied VA and the base VA: 0xbdc. Then, supply that to add2line:
addr2line -e a.out -j .text 0xbdc
And see if that gets you your line number.
That's exactly how you use it. There is a possibility that the address you have does not correspond to something directly in your source code though.
For example:
$ cat t.c
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
$ gcc -g t.c
$ addr2line -e a.out 0x400534
/tmp/t.c:3
$ addr2line -e a.out 0x400550
??:0
0x400534 is the address of main in my case. 0x400408 is also a valid function address in a.out, but it's a piece of code generated/imported by GCC, that has no debug info. (In this case, __libc_csu_init. You can see the layout of your executable with readelf -a your_exe.)
Other times when addr2line will fail is if you're including a library that has no debug information.
Try adding the -f option to show the function names :
addr2line -f -e a.out 0x4005BDC

Which library the program is linked to that provides a given function?

I have a program invoking function foo that is defined in a library. How can I know where the library is in the file system? (like is it a static library or a dynamically linked lib?)
Update: with using ldd, the program has a lot of dependency library. How to tell which lib contains function foo?
You didn't say which OS you are on, and the answer is system-dependent.
On Linux and most UNIX systems, you can simply ask the linker to tell you. For example, suppose you wanted to know where printf is coming from into this program:
#include <stdio.h>
int main()
{
return printf("Hello\n");
}
$ gcc -c t.c
$ gcc t.o -Wl,-y,printf
t.o: reference to printf
/lib/libc.so.6: definition of printf
This tells you that printf is referenced in t.o and defined in libc.so.6. Above solution will work for both static and shared libraries.
Since you tagged this question with gdb, here is what you can do in gdb:
gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400528
(gdb) run
Breakpoint 1, 0x0000000000400528 in main ()
(gdb) info symbol &printf
printf in section .text of /lib/libc.so.6
If foo comes from a shared library, gdb will tell you which one. If it comes from a static library (in which case gdb will say in section .text of a.out), use the -Wl,-y,foo solution above. You could also do a "brute force" solution like this:
find / -name '*.a' -print0 | xargs -0 nm -A | grep ' foo$'
For shared libs try using ldd command line tool.
For static libs the library is in the program itself - there are no external dependencies, which is the whole point of using static libs.
You cannot list static libraries in the final binary. To list the linked dynamic libraries, use the commands: On Linux, use ldd [file]. On Mac OS X, use otool -L [file]. On Windows, I have no idea ;-)

How can I tell if a library was compiled with -g?

I have some compiled libraries on x86 Linux and I want to quickly determine whether they were compiled with debugging symbols.
If you're running on Linux, use objdump --debugging. There should be an entry for each object file in the library. For object files without debugging symbols, you'll see something like:
objdump --debugging libvoidincr.a
In archive libvoidincr.a:
voidincr.o: file format elf64-x86-64
If there are debugging symbols, the output will be much more verbose.
The suggested command
objdump --debugging libinspected.a
objdump --debugging libinspected.so
gives me always the same result at least on Ubuntu/Linaro 4.5.2:
libinspected.a: file format elf64-x86-64
libinspected.so: file format elf64-x86-64
no matter whether the archive/shared library was built with or without -g option
What really helped me to determine whether -g was used is readelf tool:
readelf --debug-dump=decodedline libinspected.so
or
readelf --debug-dump=line libinspected.so
This will print out set of lines consisting of source filename, line number and address if such debug info is included into library, otherwise it'll print nothing.
You may pass whatever value you'll find necessary for --debug-dump option instead of decodedline.
What helped is:
gdb mylib.so
It prints when debug symbols are not found:
Reading symbols from mylib.so...(no debugging symbols found)...done.
Or when found:
Reading symbols from mylib.so...done.
None of earlier answers were giving meaningful results for me: libs without debug symbols were giving lots of output, etc.
nm -a <lib> will print all symbols from library, including debug ones.
So you can compare the outputs of nm <lib> and nm -a <lib> - if they differ, your lib contains some debug symbols.
On OSX you can use dsymutil -s and dwarfdump.
Using dsymutil -s <lib_file> | more you will see source file paths in files that have debug symbols, but only the function names otherwise.
You can use objdump for this.
EDIT: From the man-page:
-W
--dwarf
Displays the contents of the DWARF debug sections in the file, if
any are present.
Answers suggesting the use of objdump --debugging or readelf --debug-dump=... don't work in the case that debug information is stored in a file separate from the binary, i.e. the binary contains a debug link section. Perhaps one could call that a bug in readelf.
The following code should handle this correctly:
# Test whether debug information is available for a given binary
has_debug_info() {
readelf -S "$1" | grep -q " \(.debug_info\)\|\(.gnu_debuglink\) "
}
See Separate Debug Files in the GDB manual for more information.
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/developer_guide/debugging
The command readelf -wi file is a good verification of debuginfo, compiled within your program.

Resources