0

I have limited experience with gdb and debugging shared objects in general, so I wonder if anyone could shed some light on the behavior I am seeing.

Basically I am trying to understand the internals of a poorly-documented library. To that end, I wrote a program that makes minimal use of the library and I am trying to step through it to see what's going on.

The problem is that after a few uses of the "step" command in gdb, the program executes more than one instruction. One reason I believe this is that eventually gdb indicates that three threads have been launched, but no where in the code do I see why that might have happened.

In the past I have tried rebuilding the library with debug symbols, but that doesn't seem to get me any further. I am not even sure if this is relevant, since I thought gbd could still step through instructions without debug symbols (even if not having them meant it would give me less information).

In case it is relevant: I am debugging a 3-line program I wrote that links dynamically against the library of interest. I have the source for the library but it is complicated, so I hoped gdb would shed some light on things.

Thanks in advance!

Joshua Gevirtz
  • 401
  • 3
  • 14
  • What optimization options are you using? The more optimization, the harder to use with a debugger. – Shawn Jan 15 '19 at 21:09
  • Are you trying to step through optimized C++ code in gdb? That would would super confusing. – SergeyA Jan 15 '19 at 21:09
  • @Shawn Looking at the build script for the library in question reveals that setting their DEBUG parameter to "true" means the -O0 is used. – Joshua Gevirtz Jan 15 '19 at 21:13
  • @Shawn Nevermind! I wasn't using the build script properly. I just rebuilt and set the debug option appropriately, so it seems the optimizations are off now. – Joshua Gevirtz Jan 15 '19 at 21:58
  • If someone wants to post an answer about the optimizations I will mark it as correct. Thanks a ton! – Joshua Gevirtz Jan 15 '19 at 21:58

2 Answers2

0

I thought gbd could still step through instructions

It could, but the command to do so is stepi, not step that you are using.

Step steps over lines, which requires presence of debugging info in the sources.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
0

A little bit about optimizations

For example, this is a C Code:

int main(int argc, char** argv) {
  printf("Hello World\n");
  return 0;
}

When you build with -O0, code optimization is done barely, and the code runs very slowly. This is the unoptimized code (gcc -m32):

; Variables:
        ;    arg_4: 12
        ;    arg_0: 8
        ;    var_4: -4
        ;    var_8: -8
        ;    var_C: -12
        ;    var_10: -16
        ;    var_18: -24
push       ebp
mov        ebp, esp
sub        esp, 0x18
call       _main+11
pop        eax                            ; CODE XREF=_main+6

-- These lines are gone after optimization --
mov        ecx, dword [ebp+arg_4]
mov        edx, dword [ebp+arg_0]
--                                    --
lea        eax, dword [eax-0x1f5b+0x1fa6] ; "Hello World!\\n"

-- There lines are gone after optimization --
mov        dword [ebp+var_4], 0x0
mov        dword [ebp+var_8], edx
mov        dword [ebp+var_C], ecx

mov        dword [esp+0x18+var_18], eax  ; method imp___symbol_stub__printf
call       imp___symbol_stub__printf
xor        ecx, ecx                           
mov        dword [ebp+var_10], eax
mov        eax, ecx                                    
add        esp, 0x18                           
pop        ebp
ret

When you build with -03, you will notice there are fewer lines. The optimized code (gcc -m32 -O3):

push       ebp
mov        ebp, esp
sub        esp, 0x8
call       _main+11
pop        eax                             ; CODE XREF=_main+6
lea        eax, dword [eax-0x1f6b+0x1f9e]  ; "Hello World!"
mov        dword [esp+0x8+var_8], eax      ; "%s" for imp___symbol_stub__puts
call       imp___symbol_stub__puts
xor        eax, eax
add        esp, 0x8
pop        eep
ret

The reason why unoptimized code has unnecesary lines is because the main takes two arguments and saves them into registers whether you are using or not without optimization, but with optimization the compiler deletes these mov instructions, because the arguments are neither used nor needed. Likewise, the values of registers are also saved into stack variables as arguments are copied onto stack variables.

Tyson90
  • 106
  • 8