DebianDebugSymbols - hpaluch/hpaluch.github.io GitHub Wiki

Debian Debug symbols

How to install Debian Debug symbols and other information. Tested on Debian 12.

Model example: issue with GNU tar:

Installing package source

To install package source I do this:

sudo apt-get install dpkg-dev
mkdir -p ~/src
cd ~/src
apt-get source tar
# package source is now in: 
ls ~/src/tar-1.34+dfsg

Installing Debug symbols

We need to enable repository with *-dbgsym packages that contains "externalized" debug symbols. More or less we will follow: https://wiki.debian.org/AutomaticDebugPackages

In my case I had this /etc/apt/sources.list for Debian 12:

deb http://ftp.cz.debian.org/debian bookworm main contrib
deb-src http://ftp.cz.debian.org/debian bookworm main contrib

deb http://ftp.cz.debian.org/debian bookworm-updates main contrib
deb-src http://ftp.cz.debian.org/debian bookworm-updates main contrib

# security updates
deb http://security.debian.org bookworm-security main contrib
deb-src http://security.debian.org bookworm-security main contrib

To add debug symbols I examined available directories on: http://deb.debian.org/debian-debug/dists/

In my case I decided to add this line to /etc/apt/sources.list:

deb http://deb.debian.org/debian-debug bookworm-debug main contrib

Now we have to install utility package that will find *-dgbsym for our package + its dependencies:

apt-get install debian-goodies

To install symbols for tar package and its dependencies we have to issue:

find-dbgsym-packages /bin/tar

If there is other output than:

I: All needed dbgsym packages are already installed.

Run as root:

find-dbgsym-packages /bin/tar | xargs apt-get install

# will install: apt-get install libacl1-dbgsym libc6-dbg libpcre2-8-0-dbgsym libselinux1-dbgsym

Analyzing spinning process with perf

Linux perf is easy to use set of package to evaluate performance. To install Linux perf, run:

apt-get install linux-perf

To get real-time overview of system, just run:

sudo perf top

# press 'q' to quit

To analyze specific process (in my case tar process spinning cpu):

# run as root

perf record -p `pidof tar` -g

After some time (say 30 seconds) press Ctrl-C to stop recording. Performance data will be recorded in file perf.data

To browse data try:

# run as root
perf report -g

You can expand stacktrace with e key, example screenshot:

Samples: 334K of event 'cycles', Event count (approx.): 167377283731                                                    
  Children      Self  Command  Shared Object      Symbol                                                                
-   48.18%     0.00%  tar      [unknown]          [.] 0x742f646c6975622f                                               ◆
   - 0x742f646c6975622f                                                                                                ▒
        43.37% find_delayed_link_source                                                                                ▒
-   48.00%    47.68%  tar      tar                [.] extract_link                                                     ▒
     extract_link                                                                                                      ▒
-   43.37%    43.07%  tar      tar                [.] find_delayed_link_source                                         ▒
     43.07% 0x742f646c6975622f                                                                                         ▒
        find_delayed_link_source                                                                                       ▒
+    4.10%     4.09%  tar      libc.so.6          [.] __strcmp_sse2                                                    ▒
+    3.52%     0.01%  tar      [kernel.kallsyms]  [k] entry_SYSCALL_64_after_hwframe

Stacktrace in GDB

Here are basic command how to get stacktrace in GDB. First install GDB:

sudo apt-get install gdb

Example session:

# I will extract .tar.zst there:
mkdir ~/tmp

# ensure that you are in tar source directory:

cd ~/src/tar-1.34+dfsg
gdb /bin/tar

# ensure that there is no error "No symbols", in my example these messages look fine:
Reading symbols from /bin/tar...
Reading symbols from /usr/lib/debug/.build-id/7e/68e3094abf707c55b0a7baaac5c3a956347b0c.debug...

# it is recommended to break at "main" function and setup other breakpoint after "main"
# is reached - otherwise somtimes not all symbols are resolved:

(gdb) break main

Breakpoint 1 at 0xae80: file ./src/tar.c, line 2773.

(gdb) run xpf /home/ansible/deb12-yocto-az/dev-user-1723647938.tar.zst -C /home/ansible/tmp

Starting program: /usr/bin/tar xpf /home/ansible/deb12-yocto-az/dev-user-1723647938.tar.zst -C /home/ansible/tmp
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=5, argv=0x7fffffffe3c8) at ./src/tar.c:2773
warning: Source file is more recent than executable.
2773    {

# Huh, hopefully it is just warning...

# tar will fork - follow child
(gdb) set follow-fork-mode child

# try breakpoint at function of interest:

(gdb) break find_delayed_link_source

Breakpoint 2 at 0x55555556bdd0: file ./src/extract.c, line 1339.

(gdb) break extract_link

Breakpoint 3 at 0x55555556d670: file ./src/extract.c, line 1465.

# continue execution
(gdb) c
Continuing.
[Detaching after fork from child process 1297]

Here is how to get stacktrace when breakpoint is reached:


reakpoint 2, find_delayed_link_source (name=name@entry=0x5555555d83a0 "dev/poky/scripts/cross-intercept/ar")
    at ./src/extract.c:1339
1339    {

(gdb) bt
#0  find_delayed_link_source (name=name@entry=0x5555555d83a0 "dev/poky/scripts/cross-intercept/ar")
    at ./src/extract.c:1339
#1  0x000055555556d360 in create_placeholder_file (
    file_name=file_name@entry=0x5555555d83a0 "dev/poky/scripts/cross-intercept/ar", is_symlink=is_symlink@entry=true, 
    interdir_made=interdir_made@entry=0x7fffffffe037, prev=prev@entry=0x0) at ./src/extract.c:1380
#2  0x000055555556d5f4 in extract_symlink (file_name=0x5555555d83a0 "dev/poky/scripts/cross-intercept/ar", 
    typeflag=<optimized out>) at ./src/extract.c:1540
#3  0x000055555556e9f6 in extract_archive () at ./src/extract.c:1820
#4  0x00005555555784b6 in read_and (do_something=0x55555556e720 <extract_archive>) at ./src/list.c:229
#5  0x000055555555fed8 in main (argc=<optimized out>, argv=<optimized out>) at ./src/tar.c:2845

(gdb) print name

$1 = 0x5555555d83a0 "dev/poky/scripts/cross-intercept/ar"

(gdb) info locals

dl = <optimized out>
st = {st_dev = 93824992763672, st_ino = 93824992382737, st_nlink = 93824992798977, st_mode = 1, st_uid = 0, 
  st_gid = 4294958896, __pad0 = 32767, st_rdev = 93824992372844, st_size = 4299262263789, st_blksize = 0, 
  st_blocks = 93824992782336, st_atim = {tv_sec = 93824992764008, tv_nsec = 0}, st_mtim = {tv_sec = 140737488346896, 
    tv_nsec = 24}, st_ctim = {tv_sec = 140737488346976, tv_nsec = 140737488346912}, __glibc_reserved = {
    -5727356510224353024, 4096, 4096}}

Now we will disable that early breakpoint and continue execution:

# list breakpoints

(gdb) info b

Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000055555555ee80 in main at ./src/tar.c:2773
        breakpoint already hit 1 time
2       breakpoint     keep y   0x000055555556bdd0 in find_delayed_link_source at ./src/extract.c:1339
        breakpoint already hit 1 time
3       breakpoint     keep y   0x000055555556d670 in extract_link at ./src/extract.c:1465

# you can delete breakpoint with number using for example "del 3"

Now other breakpoint reached:

(gdb) c

Continuing.

Breakpoint 2, find_delayed_link_source (
    name=name@entry=0x5555555d8860 "dev/poky/scripts/esdk-tools/runqemu-extract-sdk") at ./src/extract.c:1339
1339    {

(gdb) bt

#0  find_delayed_link_source (name=name@entry=0x5555555df120 "dev/poky/scripts/esdk-tools/runqemu-ifup")
    at ./src/extract.c:1339
#1  0x000055555556d360 in create_placeholder_file (
    file_name=file_name@entry=0x5555555df120 "dev/poky/scripts/esdk-tools/runqemu-ifup", 
    is_symlink=is_symlink@entry=true, interdir_made=interdir_made@entry=0x7fffffffe037, prev=prev@entry=0x0)
    at ./src/extract.c:1380
#2  0x000055555556d5f4 in extract_symlink (file_name=0x5555555df120 "dev/poky/scripts/esdk-tools/runqemu-ifup", 
    typeflag=<optimized out>) at ./src/extract.c:1540
#3  0x000055555556e9f6 in extract_archive () at ./src/extract.c:1820
#4  0x00005555555784b6 in read_and (do_something=0x55555556e720 <extract_archive>) at ./src/list.c:229
#5  0x000055555555fed8 in main (argc=<optimized out>, argv=<optimized out>) at ./src/tar.c:2845

(gdb) info locals
dl = <optimized out>
st = {st_dev = 93824992763672, st_ino = 93824992382737, st_nlink = 93824992772988, st_mode = 1, st_uid = 0, 
  st_gid = 4294958896, __pad0 = 32767, st_rdev = 93824992372844, st_size = 10, st_blksize = 140737352282077, 
  st_blocks = 0, st_atim = {tv_sec = 93824992801056, tv_nsec = 2}, st_mtim = {tv_sec = 140737488346896, tv_nsec = 24}, 
  st_ctim = {tv_sec = 140737488346976, tv_nsec = 140737488346912}, __glibc_reserved = {-5727356510224353024, 
    93824992369424, 93824992772960}}

# list source

(gdb) list

1334       and does not rely on comparing file names, which may differ for
1335       various reasons (e.g. relative vs. absolute file names).
1336     */
1337    static struct delayed_link *
1338    find_delayed_link_source (char const *name)
1339    {
1340      struct delayed_link *dl;
1341      struct stat st;
1342
1343      if (!delayed_link_head)

Examine my problem with tar - I disabled all breakpoints:

(gdb) dis break
(gdb) c