Tuesday Jan 17, 2012

Separation of debug and executable

To reduce the size of shipped binaries it can be useful to separate the debug information into a separate file. This procedure is covered in the dbx manual. We can use objdump to extract the debug information and then to link the executable with the extracted data.

Here's a short example executable:

#include <stdio.h>
#include <math.h>

int main()
{
  double d=1.0;
  d = sin(d);
  printf("sin(1.0) = %f\n",d);
}

Compiled with debug:

$ cc -g hello.c -lm
$ ./a.out
sin(1.0) = 0.841471

We can debug this executable with dbx. Note that, in this case, we compiled without optimisation in order to get the best debug information. Doing this does potentially sacrifice some performance. We can follow the same procedure with optimised code.

$ dbx ./a.out
Reading ld.so.1
Reading libm.so.2
Reading libc.so.1
(dbx) stop in main
(2) stop in main
(dbx) run
Running: a.out
(process id 53296)
stopped in main at line 6 in file "hello.c"
    6     double d=1.0;
(dbx) step
stopped in main at line 7 in file "hello.c"
    7     d = sin(d);
(dbx) print d
d = 1.0
(dbx) cont
Reading libc_psr.so.1
sin(1.0) = 0.841471

First of all we are going to use objcopy to extract the debug information from ./a.out and place it into ./a.out.debug:

$ /usr/sfw/bin/gobjcopy --only-keep-debug ./a.out ./a.out.debug

Now we can strip a.out of debug information:

$ strip ./a.out

To prove that this has removed the debug information we can try running under dbx:

$ dbx  ./a.out
Reading ld.so.1
Reading libm.so.2
Reading libc.so.1
(dbx) stop in main
dbx: warning: 'main' has no debugger info -- will trigger on first instruction
(2) stop in main
(dbx) quit

Now we want to use objcopy to make a link between the executable and its debug information:

$ /usr/sfw/bin/gobjcopy --add-gnu-debuglink=./a.out.debug ./a.out

Now when we debug the executable we are back to full debug:

$ dbx ./a.out
Reading ld.so.1
Reading libm.so.2
Reading libc.so.1
(dbx) stop  in main
(2) stop in main
(dbx) run
Running: a.out
(process id 58837)
stopped in main at line 6 in file "hello.c"
    6     double d=1.0;
(dbx) next
stopped in main at line 7 in file "hello.c"
    7     d = sin(d);
(dbx) print d
d = 1.0
(dbx) cont
Reading libc_psr.so.1
sin(1.0) = 0.841471

execution completed, exit code is 0
(dbx) quit

Tuesday Dec 23, 2008

Debugging inline templates with dbx

Been working on inline templates to improve the performance on a couple of hot routines in a customer code. I've a couple of articles on this kind of work if you want to find out more details. There's an introductory article which covers the rules, and there's an article specifically talking about using VIS instructions.

Anyway, one of the most important things to do is to write a test harness, it's very easy to make a mistake and have the template not work for some particular situation. For these routines, one of my colleagues had already written a test harness. I ended up extending it to try a different corner case, and at that point discovered that my code no longer validated. The problem turned out to be a branch that should have been branch >= 2 and I'd coded branch != 2. The original test cases terminated with the value 2 at this point, but the new test I added ended up with the value 1, which still should have terminated, but the inline template as written didn't handle it correctly.

So I fired up dbx to take a look at what was going on:

$ cc -g test.c test.il
$ dbx a.out
Reading a.out
Reading ld.so.1
Reading libc.so.1
(dbx) stop at 150
(dbx) run
stopped in main at line 150 in file "test.c"
  150           res1=campare(&buff1[j],buff2,i);

The stop at <line> command tells the debugger to stop at the problem line number (more details). However, the problem actually occurred when j was equal to 1. So I really should specify the break point better (more details).

(dbx) status
\*(2) stop at "mcmp-test-all.c":150
(dbx) delete 2
(dbx) stop at 150 -if j==1
(3) stop at "mcmp-test-all.c":150 -if j == 1
(dbx) run
Running: a.out
(process id 14983)

That got me to the point where the problem occurred. My initial thought was to step through the execution of the inline template using the nexti command. However, this is pretty inefficient:

(dbx) nexti
stopped in main at 0x00011cfc
0x00011cfc: main+0x1394:        sll      %l0, 1, %l1
(dbx) nexti
stopped in main at 0x00011d00
0x00011d00: main+0x1398:        add      %l3, %l1, %l0
(dbx) nexti
stopped in main at 0x00011d04
0x00011d04: main+0x139c:        ld       [%fp - 1044], %l1

It could take quite a large number of instructions before I actually encountered the problem code. Plus each step takes three lines on screen. However, there's a tracei command which traces the execution at the assembly code level (more details).

(dbx) tracei next
(dbx) cont
0x00011d08: main+0x13a0:        mov      %l0, %o0
0x00011d0c: main+0x13a4:        mov      %l2, %o1
0x00011d10: main+0x13a8:        mov      %l1, %o2
0x00011d14: main+0x13ac:        nop

The output took me through the code, and knowing the code path I had expected, I could pretty easily see the branch that caused the code to diverge.

Wednesday Mar 26, 2008

Debugging C++ with dbx

Here's the page on how to debug C++ exceptions using dbx. It omits my often repeated mantra about the -g flag. For C++ -g currently turns off 'front-end' inlining. This usually results in a significant loss in performance, but a benefit in the code being easier to read without the inlining. If you are interested in debugging the same code that you get without -g, or the faster code that does having inlining, then use the flag -g0 when building the application.

Friday Oct 05, 2007

dbx commands and disassembly

Here's a list of the command supported by dbx. The listi command shows the disassembled code for the next instructions:

% dbx a.out
(dbx) stop in main
dbx: warning: 'main' has no debugger info -- will trigger on first instruction
(2) stop in main
(dbx) run
Running: a.out
(process id 16158)
Reading libc_psr.so.1
stopped in main at 0x00010cd0
0x00010cd0: main       :        save     %sp, -120, %sp
(dbx) listi
dbx: warning: no source lines at current PC; use "dis" instead
0x00010cd4: main+0x0004:        sethi    %hi(0x21000), %l0
0x00010cd8: main+0x0008:        clr      [%l0 + 0x00000164]
...
About

Darryl Gove is a senior engineer in the Solaris Studio team, working on optimising applications and benchmarks for current and future processors. He is also the author of the books:
Multicore Application Programming
Solaris Application Programming
The Developer's Edge
Free Download

Search

Categories
Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today
Bookmarks
The Developer's Edge
Solaris Application Programming
Publications
Webcasts
Presentations
OpenSPARC Book
Multicore Application Programming
Docs