Is there any way to get more debug info from gdb? - c++

I can get more debug info if built my program on Windows compared to Linux.
Here is my code:
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
Base() = default;
virtual ~Base() = default;
};
class Derived : public Base
{
public:
Derived() = default;
~Derived() = default;
private:
int i = 1;
};
int main()
{
vector<Base*> a;
a.push_back(new Derived());
return 0;
}
Build On Linux:
Build On Windows:
It's obvious I can get more information with Windows build version. Such as vector info, vector element real type, derived object info... But Linux version, I only get the pointer address. By the way, they are all debugging by visual studio. Is there some way to add more debug info to the program built by GNU compiler? Such as compiler flags?

I don't use visual studio, so not sure how you will make use of this answer from within that environment, however, I think you can get what you want using the GDB setting: set print object on.
To show this in action, here's my GDB (12.1) session, using the same test program that you posted:
$ gdb -q vec.x
Reading symbols from vec.x...
(gdb) b 26
Breakpoint 1 at 0x401245: file vec.cc, line 26.
(gdb) r
Starting program: /tmp/vec.x
Breakpoint 1, main () at vec.cc:26
26 return 0;
(gdb) p a
$1 = std::vector of length 1, capacity 1 = {0x418eb0}
(gdb) p a[0]
$2 = (Base *) 0x418eb0
(gdb) p *a[0]
$3 = {
_vptr.Base = 0x403040 <vtable for Derived+16>
}
(gdb) set print object on
(gdb) p a[0]
$4 = (Derived *) 0x418eb0
(gdb) p *a[0]
$5 = (Derived) {
<Base> = {
_vptr.Base = 0x403040 <vtable for Derived+16>
},
members of Derived:
i = 1
}
(gdb) q

I fixed this problem by add a init command to the ~/.gdbinit.
Add the following command to the first line of file ~/.gdbinit.
set print object on

Related

GCC: static data member optimized out in the debug build

Consider the following simple code:
template<typename T>
struct Base {
static constexpr int v = 0;
};
struct Derived : Base<int> {};
int main() {
Derived d;
}
I compile it with GCC (8.3.0, 9.1.0, g++ -g -O0 test.cpp), then run GDB to examine the value of d:
(gdb) p d
$1 = {<Base<int>> = {static v = <optimized out>}, <No data fields>}
d.v is gone... I tried to use -ggdb, -ggdb3, -fvar-tracking with no success.
If I compile with clang (clang++ -g -O0 test.cpp), I see the expected result:
(gdb) p d
$1 = {<Base<int>> = {static v = 0}, <No data fields>}
This output is also seen with GCC if Base is not a template class:
(gdb) p d
$1 = {<Base> = {static v = 0}, <No data fields>}
Where did d.v go? Why was it optimized out? Is it possible to prevent this optimization without modifying the source code?
Even though it doesn't have to respect it, by using constexpr and providing an initialized value, you're strongly hinting to the compiler that it should constant-fold Base::v.
Gcc has a -fkeep-static-consts flag that might do what you want.

How to call template member function in gdb?

I'm trying to print the return value of a templated member function in gdb (version 7.6.1 I think) of an rvalue reference, so what I write in gdb amounts to something like this:
gdb> print (*(TypeOne*)var).get<TypeTwo>()
I've tried parenthesizing various parts of the expression with no success, and I wasnt able to find any other question on this. Anyone know?
Starting from this related post: How to `print`/evaluate c++ template functions in gdb
I was able to figure out how to do this within my own program.
I'm not using an rvalue nor a variant so it may not work for that, but I think it's still relevant to this question.
My use case was a method with a single enum as a template parameter, similar to this:
#include <stdio.h>
enum class MyEnum {
VALUE_0 = 0,
VALUE_1 = 1
};
struct TestStruct {
template <MyEnum VALUE>
int getValue() {
if constexpr (VALUE == MyEnum::VALUE_0) {
return value_0;
} else /* VALUE == MyEnum::VALUE_1 */ {
return value_1;
}
}
const int value_0 = 7;
const int value_1 = 9;
};
int main()
{
TestStruct test;
test.template getValue<MyEnum::VALUE_0>();
test.template getValue<MyEnum::VALUE_1>();
return 0;
}
If we use ptype on the object we get a list of methods on the object:
(gdb) b 36
Breakpoint 1 at 0x4004f7: file main.cpp, line 36.
(gdb) r
Starting program: /home/a.out
Breakpoint 1, main () at main.cpp:36
36 return 0;
(gdb) ptype test
type = struct TestStruct {
const int value_0;
const int value_1;
public:
int getValue<(MyEnum)1>(void);
int getValue<(MyEnum)0>(void);
}
If we want to call this method:
int getValue<(MyEnum)1>(void);
We can call it by using the name exactly as shown, in single quotes.
(gdb) p test.'getValue<(MyEnum)1>'()
$1 = 9
You can try it here: https://onlinegdb.com/7OtaUvK3g
Note from the other thread:
Without an explicit instance in the source code, the compiler will treat the template code as it would "static inline" code and optimize it out if it is unused.
So you must call the method somewhere in your code to be able to call it in gdb at all, this will not work otherwise.

How can I cast void pointer to unique_ptr<T> in gdb?

I like to cast a void pointer back to unique_ptr<T> with arbitrary type T so that I can dereference it to the contents of it. But with the following simple example:
#include <memory>
class Foo {
public: Foo(){};
};
int main() {
std::unique_ptr<Foo> p1 (new Foo);
void *p2 = (void*)&p1;
return 0;
}
I get the following error and not be able to cast:
$ gdb ./unique-ptr
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
...
(gdb) b 10
Breakpoint 1 at 0x400682: file unique-ptr.cc, line 10.
(gdb) run
Starting program: /home/vagrant/c-test/unique-ptr/unique-ptr
Breakpoint 1, main () at unique-ptr.cc:10
10 return 0;
(gdb) p p1
$1 = std::unique_ptr<Foo> containing 0x603010
(gdb) p p2
$2 = (void *) 0x7fffffffea40
(gdb) p *(std::unique_ptr<Foo>*)p2
A syntax error in expression, near `)p2'.
(gdb)
Actual use case is that I like to print out contents of unique_ptr contained in container class, but this is the issue currently preventing me to go further.
The actual type name created with the template is not std::unique_ptr<Foo>. Obtain the real type name with:
(gdb) ptype p1
type = class std::unique_ptr<Foo, std::default_delete<Foo> > [with _Tp = Foo, _Dp = std::default_delete<Foo>] {
private:
__tuple_type _M_t;
...
From this, I figured out that gdb recognizes std::unique_ptr<Foo, std::default_delete<Foo> >, and I was able to do:
(gdb) p *(std::unique_ptr<Foo, std::default_delete<Foo> > *)p2
$3 = std::unique_ptr<Foo> containing 0x603010
which matches with
(gdb) p p1
$1 = std::unique_ptr<Foo> containing 0x603010

C++ - gdb gives unexpected output when passing in a struct with std::string member

Consider the following program, which I compile with g++ -g myprog.cc.
#include<iostream>
struct Context {
//char *s; // version 1
std::string s; // version 2
};
void f(Context);
void f(Context c) {}
int main(void) {
Context c = Context();
f(c);
}
Version 1 has a char * member, while version 2 replaces it with std::string.
Using gdb, I step through the code and get this:
Temporary breakpoint 1, main () at myprog.cc:12
12 Context c = Context();
&ebsp;Missing separate debuginfos, use: debuginfo-install libgcc-4.4.7-11.el6.x86_64 libstdc++-4.4.7-11.el6.x86_64
(gdb) s
13 f(c);
(gdb) s
f (c=...) at myprog.cc:9
9 void f(Context c) {}
(gdb) s
main () at myprog.cc:14
14 }
Nothing wrong here.
If I step through version 2, I get:
Temporary breakpoint 1, main () at myprog.cc:12
12 Context c = Context();
Missing separate debuginfos, use: debuginfo-install libgcc-4.4.7-11.el6.x86_64 libstdc++-4.4.7-11.el6.x86_64
(gdb) s
Context::Context (this=0x7fffffffe400) at myprog.cc:3
3 struct Context {
(gdb) s
main () at myprog.cc:13
13 f(c);
(gdb) s
Context::Context (this=0x7fffffffe410) at myprog.cc:3
3 struct Context {
(gdb) s
f (c=...) at myprog.cc:9
9 void f(Context c) {}
(gdb) s
Context::~Context (this=0x7fffffffe410, __in_chrg=) at myprog.cc:3
3 struct Context {
(gdb) s
Context::~Context (this=0x7fffffffe400, __in_chrg=) at myprog.cc:3
3 struct Context {
(gdb) s
main () at myprog.cc:14
14 }
Why is it that when I pass in a struct Context with the std::string member, I get the output Context::Context (this=0x7fffffffe400)?
Also, when I instantiate the struct, this=0x7fffffffe400. When I pass it in, this=0x7fffffffe410. Why is that?
You pass c by value to a function that doesn't do anything. So the compiler has to produce any visible effects of pass by value semantics. The compiler can't be sure that copying and then destroying the string has no consequences, so it does it. It can be sure that copying a char * and destroying the copy has no consequences, so it doesn't bother.
What's happening is you're seeing the compiler generated constructor, which is not generated for the struct with just a pointer, because there would be nothing to do in that constructor. For the struct with the std::string member, it likely calls std::strings constructor.
Since the constructor is a non-static member function, the this=0x7fffffffe400 is the implicit 'this' pointer argument being passed in.

How to print a c++ object members using GDB from an address if the object's class type is like A::B [duplicate]

This question already has answers here:
Why gdb casting is not working?
(4 answers)
Closed 6 years ago.
From this link
gdb interpret memory address as an object
we know that, if an object of class type A is at a specific address such as 0x6cf010, then we can use:
(gdb) p *(A *) 0x6cf010
to print the member elements of this object.
However, this seems doesn't work when c++ namespace is involved. That is, if the object of class type A::B, then all the following trying doesn't work:
(gdb) p *(A::B *) 0x6cf010
(gdb) p *((A::B *) 0x6cf010)
So, who knows how to print the object elements under this conditions?
We can use the following deliberate core code to try to print the members of p from the address (we can use "info locals" to show the address).
#include <stdio.h>
namespace A
{
class B
{
public:
B(int a) : m_a(a) {}
void print()
{
printf("m_a is %d\n", m_a);
}
private:
int m_a;
};
}
int main()
{
A::B *p = new A::B(100);
p->print();
int *q = 0;
// Generating a core here
*q = 0;
return 0;
}
I know that this is labeled as answered, but I was able to reproduce this problem using gdb on OS X (GNU gdb 6.3.50-20050815 (Apple version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)) and the works-for-me solution didn't answer it for me.
Turns out there was another question on SO that did have an answer which worked, so I think it's worth pulling into this quesiton:
Why gdb casting is not working?
The short answer is that you may have to single-quote your namespaced variables:
(gdb) p ('MyScope::MyClass'*) ptr;
Works for me:
g++ -g test.cpp -o test
gdb test
(gdb) break main
(gdb) r
Breakpoint 1, main () at test.cpp:22
22 A::B *p = new A::B(100);
(gdb) n
24 p->print();
(gdb) n
m_a is 100
26 int *q = 0;
(gdb) p p
$1 = (A::B *) 0x602010
(gdb) p (A::B *) 0x602010
$2 = (A::B *) 0x602010
(gdb) p *((A::B *) 0x602010)
$3 = {m_a = 100}
It works for me. What are you using (gcc version, OS, compilation flags?)