2
votes

I am experiencing an issue where gdb is mapping a line number to the wrong memory address when adding a breakpoint.

The following x86 Linux assembly program prints "hello".

/* hello.s */

  .section .data
str:
  .ascii "hello\n"
  strlen = . - str

  .section .text

print:
  pushl %ebp
  movl  %esp, %ebp
  pushl %ebx
  movl  $4, %eax
  movl  $1, %ebx
  movl  $str, %ecx
  movl  $strlen, %edx
  int   $0x80
  popl  %ebx
  movl  %ebp, %esp
  popl  %ebp
  ret

  .globl _start
_start:
  call  print
  movl  $1, %eax
  movl  $0, %ebx
  int   $0x80

I compile it with debugging information, and then link.

$ as -g --32 -o hello.o hello.s
$ ld -m elf_i386 -o hello hello.o

Next, in gdb, I try to set a breakpoint on line 11, the first line of the print function (pushl %ebp).

$ gdb ./hello
(gdb) break hello.s:11

Breakpoint 3 at 0x8048078: file hello.s, line 11.

As shown in the output, the breakpoint is set at address 0x8048078. However, that is the wrong address. When I run my program in gdb, it breaks at line 14. The address of line 11 is 0x8048074, confirmed using gdb's info command.

(gdb) info line hello.s:11

Line 11 of "hello.s" starts at address 0x8048074 and ends at 0x8048075 .

Setting a breakpoint on the print instruction directly works (the break point is set for the address of line 11, 0x8048074).

How come when I add a breakpoint for line 11, gdb does not use the same address as output by using the info command above? This is the memory address I am trying to break on.

I am experiencing the same behavior on both gdb 7.11.1 and 8.0.1. I have tried adding a .type print,@function annotation, but that did not solve my issue.

1
I won't trust that much DWARF info produced by assembler. It is generally produced by the compilerBasile Starynkevitch
GDB by default is detecting the stack frame prologue code. If it finds such prologue code it will place the breakpoint after it. In this case it automatically moved the breakpoint to line 14 from line 11. If you know the exact address of the instruction you want to break at you can do b *0x8048074 (or whatever address you really wish to stop at). The asterisk it front will prevent the debugger from skipping the prologue code automatically.Michael Petch
A related (but not exact duplicate) question is here: stackoverflow.com/questions/25545994/…Michael Petch

1 Answers

5
votes

How come

By default, GDB tries to skip past function prolog, when you set a breakpoint on a function, or a line on which the function starts.

This tends to be what C developers want, since they usually aren't interested in parameter setup.

If you want something else, use b *address or b &print to prevent GDB from doing its usual thing.