Terminal use gdb to debug .cpp files, (gdb)p command - c++

When I use gdb to debug, I just want to use '(gdb)p x' to print the value of x, but the result is very complicated. Terminal command like this:
(gdb) p word
Output:
$2 = {<std::__1::__basic_string_common<true>> = {<No data fields>}, static __short_mask = 1,
static __long_mask = 1,
__r_ = {<std::__1::__compressed_pair_elem<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__rep, 0, false>> = {__value_ = {{__l = {__cap_ = 1970239750,
__size_ = 0, __data_ = 0x0}, __s = {{__size_ = 6 '\006', __lx = 6 '\006'},
__data_ = "you", '\000' <repeats 19 times>}, __r = {__words = {1970239750, 0,
0}}}}}, <std::__1::__compressed_pair_elem<std::__1::allocator<char>, 1, true>> = {<std::__1::allocator<char>> = {<No data fields>}, <No data fields>}, <No data fields>},
static npos = 18446744073709551615}
What I really want is __data_ = "you" this segment only.
How can I get a simple result like this:
$2 = "you"
Can someone help me? Very appreciate that.

How can I get a simple result like this:
That's what GDB pretty-printers are for.
It looks like you are using libc++ (and probably Clang).
From libc++ documentation:
GDB does not support pretty-printing of libc++ symbols by default. However, libc++ does provide pretty-printers itself. Those can be used as:
$ gdb -ex "source <libcxx>/utils/gdb/libcxx/printers.py" \
-ex "python register_libcxx_printer_loader()" \
<args>
You can put the source <libcxx>/utils/gdb/libcxx/printers.py and the python register_libcxx_printer_loader() commands into your ~/.gdbinit, and then things will just work™.

Related

Unexpected sscanf Result

I have a sscanf statement that is behaving unexpectedly. This is somewhere around loop #8000 that it suddenly does this. This is the code, where str is a string parsed from a file:
char a1[6], a2[6], op[6], a3[6];
int success = sscanf(str.c_str(),"%*s %s %*s %s %s %s",a1, a2, op, a3);
And this is the gdb output on the problem line (str is "assign po012 = po011;"):
(gdb) print str
$9 = {<std::__1::__basic_string_common<true>> = {<No data fields>}, static __short_mask = 1, static __long_mask = 1,
__r_ = {<std::__1::__compressed_pair_elem<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__rep, 0, false>> = {__value_ = {{__l = {__cap_ = 97, __size_ = 23, __data_ = 0x1003001d0 " assign po012 = po011;"}, __s = {{
__size_ = 97 'a', __lx = 97 'a'},
__data_ = "\000\000\000\000\000\000\000\027\000\000\000\000\000\000\000\320\001\060\000\001\000\000"}, __r = {__words = {
97, 23,
4298113488}}}}}, <std::__1::__compressed_pair_elem<std::__1::allocator<char>, 1, true>> = {<std::__1::allocator<char>> = {<No data fields>}, <No data fields>}, <No data fields>}, static npos = 18446744073709551615}
(gdb) n
81 string A1(a1);
(gdb) print a1
$10 = "\000o012"
(gdb) print a2
$13 = "po011;"
a2 has the expected value, but what is happening to a1 in just this one case?
Your arrays have length six:
char a1[6], a2[6], op[6], a3[6];
Yet, sscanf causes "po011;" to be written in a2, and this requires seven characters, since sscanf will add the null terminator. Hence, sscanf causes undefined behavior.
Pragmatically, in your implementation the null terminator was added to the beginning of a1, which changed from the intended "po012" to "\000o012" (the initial p was overwritten). It looks like your implementation chose to store a1 right after a2, so overflowing a2 overwrote a1. This is one of the things that can happen when undefined behavior is triggered.

Using libipt, how does one add a matching rule such as 'dport' for TCP packets?

I've been trying to add netfilter rules programmatically without making calls to the iptables binary. Aside from the header files for libipt, the closest thing to documentation I've found is here. There's nothing in the documentation describing what I want to do, oddly enough.
In ip_tables.h at the bottom of the ipt_entry struct is the following bit of code:
/* The matches (if any), then the target. */
unsigned char elems[0];
However, I haven't found any way to properly read or modify elems.
I also tried adding a rule via iptables iptables -A INPUT -p tcp --dest 192.168.1.10 --dport 8080 -j ACCEPT and then running a program that calls into libipt like so: ipt_entry *rule = iptc_first_rule(chain, iptHandle);. I ran it in GDB and broke on the line following
iptc_first_rule. Dumping the ipt_entry structure gives me this:
(gdb) p *rule
$4 = {
ip = {
src = {
s_addr = 0
},
dst = {
s_addr = 167880896
},
smsk = {
s_addr = 0
},
dmsk = {
s_addr = 4294967295
},
iniface = '\000' <repeats 15 times>,
outiface = '\000' <repeats 15 times>,
iniface_mask = '\000' <repeats 15 times>,
outiface_mask = '\000' <repeats 15 times>,
proto = 6,
flags = 0 '\000',
invflags = 0 '\000'
},
nfcache = 0,
target_offset = 160,
next_offset = 200,
comefrom = 2,
counters = {
pcnt = 0,
bcnt = 0
},
elems = 0x77e85b58 "0"
}
I saw that there was something in the elems member, so I tried dumping it too:
(gdb) x /10s rule->elems
0x77e85b58: "0"
0x77e85b5a: "tcp"
0x77e85b5e: "%s"
0x77e85b61: ""
0x77e85b62: ""
0x77e85b63: ""
0x77e85b64: "%s(): set IP_HDRINC"
0x77e85b78: ""
0x77e85b79: ""
0x77e85b7a: "\377\377P"
Lastly, I tried looking at the source code of iptables. However, I had to stop looking at that spaghetti soup before throwing myself out of the nearest window.
How in the heck do you specify a destination port for a rule?
Edit: I forgot to mention, the target platform is openWRT, which doesn't provide any of the newer netfilter libraries. I'm stuck with libipt/xtables.

In GDB, how to print an object so its data members would be listed in alphabetical order?

For instance, by default it would be something like
(gdb) print obj
$1 = {
elephant = 0xb7d28960 <_IO_2_1_stderr_>,
durian = 0x0,
eggplant = 0x809ed58 "",
peanut = 1080,
onion = 0x0,
ice = 0xb7d28c20 <_IO_2_1_stdin_>,
wheat = 0x0,
raspberry = 0x0
}
How to make it become
(gdb) print obj
$1 = {
durian = 0x0,
eggplant = 0x809ed58 "",
elephant = 0xb7d28960 <_IO_2_1_stderr_>,
ice = 0xb7d28c20 <_IO_2_1_stdin_>,
onion = 0x0,
peanut = 1080,
raspberry = 0x0,
wheat = 0x0
}
That is, the data members are listed in alphabetical order.
Thanks.
There's no way to do this that is built in to gdb.
If you really need to do this you could write some Python code that prints objects however you like. You can either write a new command that works like print, or you could write a pretty-printer that recognizes structures and sorts the members.
That said, there are two reasons to keep things the way they are. First, the current order mirrors what is actually written in your source. Second, the current order also shows the layout in memory of the object. Both of these things help reduce confusion.

gdb: Cast memory address to an STL object

I have a memory address that i know is an STL object. Say the address is 0x603340, and I know there is a map there
How do I display the contents of this memory as said object from gdb?
I tried this:
p ('std::map<std::string, std::string*, std::less<std::string>, std::allocator<std::pair<std::string const, std::string*> > >'*) 0x603340
which gets me:
No symbol "std::map<std::string, std::string*, std::less<std::string>, std::allocator<std::pair<std::string const, std::string*> > >" in current context.
Any idea what am I doing wrong? Thanks.
I have taken this as a first step: simple stl containers inspectors for gdb. I did not manage to use pmap directly but I made use of it and create my own scrupt my_pmap:
>cat my.txt
define my_pmap
set $my_obj = *((std::map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::string*, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::string*> > >*) $arg0)
print $my_obj
set $i = 0
set $node = $my_obj._M_t._M_impl._M_header._M_left
set $end = $my_obj._M_t._M_impl._M_header
set $tree_size = $my_obj._M_t._M_impl._M_node_count
while $i < $tree_size
set $value = (void *)($node + 1)
printf "elem[%u].left: ", $i
p *( std::basic_string<char, std::char_traits<char>, std::allocator<char> >*)$value
set $value = $value + sizeof(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)
printf "elem[%u].right: ", $i
p **((std::basic_string<char, std::char_traits<char>, std::allocator<char> >**)$value)
if $node._M_right != 0
set $node = $node._M_right
while $node._M_left != 0
set $node = $node._M_left
end
else
set $tmp_node = $node._M_parent
while $node == $tmp_node._M_right
set $node = $tmp_node
set $tmp_node = $tmp_node._M_parent
end
if $node._M_right != $tmp_node
set $node = $tmp_node
end
end
set $i=$i+1
end
printf "Map size = %u\n", $tree_size
end
Then I wrote a short C++ test program:
#include <map>
#include <string>
#include <iostream>
int main()
{
std::string local_s1 = "Local1";
std::string local_s2= "Local2";
typedef std::map<std::string, std::string*> my_type_t;
my_type_t my_map;
my_map.insert(std::make_pair("Key-string-1", &local_s1));
my_map.insert(std::make_pair("Key-string-2", &local_s2));
my_map.insert(std::make_pair("Key-string-3", &local_s2));
return 0;
}
And then I tested my script:
>gdb -q ./a.out
Reading symbols from /import/home/sergey.kurenkov/src/linux.x64.6.0/tests/test.gdb_map/a.out...done.
(gdb) start
Temporary breakpoint 1 at 0x400c7c: file main.cpp, line 7.
Starting program: /import/home/sergey.kurenkov/src/linux.x64.6.0/tests/test.gdb_map/a.out
Temporary breakpoint 1, main () at main.cpp:7
7 std::string local_s1 = "Local1";
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6.x86_64
(gdb) source my.txt
(gdb) n
8 std::string local_s2= "Local2";
(gdb)
11 my_type_t my_map;
(gdb)
12 my_map.insert(std::make_pair("Key-string-1", &local_s1));
(gdb)
13 my_map.insert(std::make_pair("Key-string-2", &local_s2));
(gdb)
14 my_map.insert(std::make_pair("Key-string-3", &local_s2));
(gdb)
16 return 0;
(gdb) p &my_map
$1 = (my_type_t *) 0x7fffffffe040
(gdb) my_pmap 0x7fffffffe040
elem[0].left: $2 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603088 "Key-string-1"}}
elem[0].right: $3 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603028 "Local1"}}
elem[1].left: $4 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x6030f8 "Key-string-2"}}
elem[1].right: $5 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603058 "Local2"}}
elem[2].left: $6 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603168 "Key-string-3"}}
elem[2].right: $7 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603058 "Local2"}}
Map size = 3
(gdb)

What happens to the string data when std::string objects are passed to functions?

I've noticed something I don't understand happening to the string arguments to functions.
I've written this little test program:
#include <string>
#include <iostream>
using namespace std;
void foo(string str) {
cout << str << endl;
}
int main(int argc, char** argv) {
string hello = "hello";
foo(hello);
}
I compile it like this:
$ g++ -o string_test -g -O0 string_test.cpp
Under g++ 4.2.1 on Mac OSX 10.6, str inside foo() looks the same as it does as hello outside foo():
12 foo(hello);
(gdb) p hello
$1 = {
static npos = 18446744073709551615,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Alloc_hider:
_M_p = 0x100100098 "hello"
}
}
(gdb) s
foo (str=#0x7fff5fbfd350) at string_test.cpp:7
7 cout << str << endl;
(gdb) p str
$2 = (string &) #0x7fff5fbfd350: {
static npos = 18446744073709551615,
_M_dataplus = {
<std::allocator<char>> = {
<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
members of std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Alloc_hider:
_M_p = 0x100100098 "hello"
}
}
Under g++ 4.3.3 on Ubuntu, however, it doesn't:
12 foo(hello);
(gdb) p hello
$1 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x603028 "hello"}}
(gdb) s
foo (str={static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff5999e530 "(0`"}}) at string_test.cpp:7
7 cout << str << endl;
(gdb) p str
$2 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff5999e530 "(0`"}}
(gdb) p str->_M_dataplus->_M_p
$3 = 0x7fff5999e530 "(0`"
So, what's happening to the value of the string when it is passed to this function? And why the difference between the two compilers?
On my compiler foo() is inlined, so there is only one hello. Perhaps that is what is happening for you too.
What a program looks like in a debugger is not part of the language standard. Only the visible result, like actually printing "Hello", is.