GDB reports wrong address for parameter in c++ obj

2019-04-28 13:54发布

问题:

I'm experiencing a weird behavior with GDB passing a string as the parameter to a constructor. The code works fine, but when I step through in the debugger, GDB seems to think my parameter is at a different address then it is. Does anyone know what's going on here?

Here's the simplest program I can create that demonstrates the problem:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ nl gdb_weird.cpp
     1  #include <iostream>
     2  #include <string>
     3
     4  class C
     5  {
     6  public:
     7     C(std::string str)
     8     {
     9        std::string* str_ptr = &str;
    10        std::cout << "Address of str: " << &str << std::endl;
    11        std::cout << "Address in str_ptr: " << str_ptr << std::endl;
    12        std::cout << "Value of str: " << str << std::endl;
    13     };
    14  };
    15
    16  int main(int, char*[])
    17  {
    18     std::string s("Hello, World!");
    19     C c(s);
    20     return 0;
    21  }

Compile with debugging info, no optimization.
Note, that I see this problem when compiled for x86, x64, and mingw(x86).
I have not tried other architectures.

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ -O0 -g -Wall -Wextra gdb_weird.cpp -m32

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Now, debug:

--(jwcacces@neptune)--------------------------------------------(/home/jwcacces)--
--$ gdb a.out
GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/jwcacces/a.out...done.

(gdb) br main
Breakpoint 1 at 0x80488ce: file gdb_weird.cpp, line 18.

(gdb) run
Starting program: /home/jwcacces/a.out

Breakpoint 1, main () at gdb_weird.cpp:18
18         std::string s("Hello, World!");

(gdb) next
19         C c(s);

(gdb) step
C::C (this=0xffffd74f, str=...) at gdb_weird.cpp:9
9             std::string* str_ptr = &str;

Here's the weirdness, when I try to output str, I get garbage:

(gdb) output str
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>},
                                           <No data fields>},
                 _M_p = 0xffffd748 "\024\260\004\b\364\177\354\367\360\211\004\b\364\177\354", <incomplete sequence \367>
                }
}

So, what does GDB think the address of str is?

(gdb) output &str
(std::string *) 0xffffd734

And what does the program think the address of str is?

(gdb) next
10            std::cout << "Address of str: " << &str << std::endl;

(gdb) next
Address of str: 0xffffd748
11            std::cout << "Address in str_ptr: " << str_ptr << std::endl;

(gdb) next
Address in str_ptr: 0xffffd748
12            std::cout << "Value of str: " << str << std::endl;

This is really strange, the program thinks str is at 0xffffd748, but gdb thinks its at 0xffffd734
And, when you output the string object that would be at 0xffffd748 it works correctly.

(gdb) output *(std::string*)0xffffd748
{
  static npos = <optimized out>,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, 
                                           <No data fields>
                                          },
                 _M_p = 0x804b014 "Hello, World!"
                }
}

And the program itself hs no problem using the parameter:

(gdb) next
Value of str: Hello, World!
13         };

(gdb) continue
Continuing.
[Inferior 1 (process 19463) exited normally]

(gdb) quit

I have tried changing the type of the constructor parameter to an int, a struct, a pointer, but I can not reproduce the weirdness.
Also, I have tried setting the debugging format to -ggdb.

Questions:

  • What's going on here?
  • Why does gdb say that std::string's npos member is optimized out (optimized out of library maybe), and does that have anything to do with it?
  • Is it just a coincidence that in the "object" that would be where GDB thinks str is, the _M_p member points to 0xffffd748, the address that str actually is located at?
  • In what other circumstances with this behavior happen?

---- WOAH, Breakthrough ----
If I set the debugging format to -gstabs+, GDB gets the address of str right.
Does this mean that the gdb debugging format does not work correctly?

回答1:

From any post (https://gcc.gnu.org/ml/gcc/2001-04/msg01037.html) it seems that -gstabs or -gstabs+ are the correct flags when debugging C++. I hope this can help.