Last active
March 17, 2019 15:47
-
-
Save Clcanny/111ef1f3dfd927e277ee87223bac84e5 to your computer and use it in GitHub Desktop.
gdb stl pretty printer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################## | |
# # | |
# STL GDB evaluators/views/utilities # | |
# # | |
########################################## | |
# | |
# The new GDB commands: | |
# are entirely non instrumental | |
# do not depend on any "inline"(s) - e.g. size(), [], etc | |
# are extremely tolerant to debugger settings | |
# | |
# This file should be "included" in .gdbinit as following: | |
# source stl-views.gdb or just paste it into your .gdbinit file | |
# | |
# The following STL containers are currently supported: | |
# | |
# std::vector<T> -- via pvector command | |
# std::list<T> -- via plist command | |
# std::map<T,T> -- via pmap command | |
# std::multimap<T,T> -- via pmap command | |
# std::set<T> -- via pset command | |
# std::multiset<T> -- via pset command | |
# std::deque<T> -- via pdequeue command | |
# std::stack<T> -- via pstack command | |
# std::queue<T> -- via pqueue command | |
# std::priority_queue<T> -- via ppqueue command | |
# std::bitset<n> -- via pbitset command | |
# std::string -- via pstring command | |
# std::widestring -- via pwstring command | |
# | |
# The end of this file contains (optional) C++ beautifiers | |
# | |
########################################################################## | |
# # | |
# CopyLefty @ 2008 - Dan C Marinescu - No Rights Reserved / GPL V3. # | |
# Inspired by intial work of Tom Malnar and many others # | |
# (do whatever you want with this code, hope it helps) # | |
# Email: dan_c_marinescu@yahoo.com # | |
# # | |
########################################################################## | |
# | |
# std::vector<> | |
# | |
define pvector | |
if $argc == 0 | |
help pvector | |
else | |
set $size = $arg0._M_impl._M_finish - $arg0._M_impl._M_start | |
set $capacity = $arg0._M_impl._M_end_of_storage - $arg0._M_impl._M_start | |
set $size_max = $size - 1 | |
end | |
if $argc == 1 | |
set $i = 0 | |
while $i < $size | |
printf "elem[%u]: ", $i | |
p *($arg0._M_impl._M_start + $i) | |
set $i++ | |
end | |
end | |
if $argc == 2 | |
set $idx = $arg1 | |
if $idx < 0 || $idx > $size_max | |
printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max | |
else | |
printf "elem[%u]: ", $idx | |
p *($arg0._M_impl._M_start + $idx) | |
end | |
end | |
if $argc == 3 | |
set $start_idx = $arg1 | |
set $stop_idx = $arg2 | |
if $start_idx > $stop_idx | |
set $tmp_idx = $start_idx | |
set $start_idx = $stop_idx | |
set $stop_idx = $tmp_idx | |
end | |
if $start_idx < 0 || $stop_idx < 0 || $start_idx > $size_max || $stop_idx > $size_max | |
printf "idx1, idx2 are not in acceptable range: [0..%u].\n", $size_max | |
else | |
set $i = $start_idx | |
while $i <= $stop_idx | |
printf "elem[%u]: ", $i | |
p *($arg0._M_impl._M_start + $i) | |
set $i++ | |
end | |
end | |
end | |
if $argc > 0 | |
printf "Vector size = %u\n", $size | |
printf "Vector capacity = %u\n", $capacity | |
printf "Element " | |
whatis $arg0._M_impl._M_start | |
end | |
end | |
document pvector | |
Prints std::vector<T> information. | |
Syntax: pvector <vector> <idx1> <idx2> | |
Note: idx, idx1 and idx2 must be in acceptable range [0..<vector>.size()-1]. | |
Examples: | |
pvector v - Prints vector content, size, capacity and T typedef | |
pvector v 0 - Prints element[idx] from vector | |
pvector v 1 2 - Prints elements in range [idx1..idx2] from vector | |
end | |
# | |
# std::list<> | |
# | |
define plist | |
if $argc == 0 | |
help plist | |
else | |
set $head = &$arg0._M_impl._M_node | |
set $current = $arg0->_M_impl->_M_node->_M_next | |
set $size = 0 | |
while $current != $head | |
if $argc == 2 | |
printf "elem[%u]: ", $size | |
p *($arg1*)($current + 1) | |
end | |
if $argc == 3 | |
if $size == $arg2 | |
printf "elem[%u]: ", $size | |
p *($arg1*)($current + 1) | |
end | |
end | |
set $current = $current->_M_next | |
set $size++ | |
end | |
printf "List size = %u \n", $size | |
if $argc == 1 | |
printf "List " | |
whatis $arg0 | |
printf "Use plist <variable_name> <element_type> to see the elements in the list.\n" | |
end | |
end | |
end | |
document plist | |
Prints std::list<T> information. | |
Syntax: plist <list> <T> <idx>: Prints list size, if T defined all elements or just element at idx | |
Examples: | |
plist l - prints list size and definition | |
plist l int - prints all elements and list size | |
plist l int 2 - prints the third element in the list (if exists) and list size | |
end | |
# | |
# std::map and std::multimap | |
# | |
define pmap | |
if $argc == 0 | |
help pmap | |
else | |
set $tree = $arg0 | |
set $i = 0 | |
set $node = $tree->_M_t->_M_impl->_M_header->_M_left | |
set $end = $tree->_M_t->_M_impl->_M_header | |
set $tree_size = $tree->_M_t->_M_impl->_M_node_count | |
if $argc == 1 | |
printf "Map " | |
whatis $tree | |
printf "Use pmap <variable_name> <left_element_type> <right_element_type> to see the elements in the map.\n" | |
end | |
if $argc == 3 | |
while $i < $tree_size | |
set $value = (void *)($node + 1) | |
printf "elem[%u]->left: ", $i | |
p *($arg1*)$value | |
set $value = $value + 4 | |
printf "elem[%u]->right: ", $i | |
p *($arg2*)$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++ | |
end | |
end | |
if $argc == 4 | |
set $idx = $arg3 | |
set $ElementsFound = 0 | |
while $i < $tree_size | |
set $value = (void *)($node + 1) | |
if *($arg1*)$value == $idx | |
printf "elem[%u]->left: ", $i | |
p *($arg1*)$value | |
set $value = $value + 4 | |
printf "elem[%u]->right: ", $i | |
p *($arg2*)$value | |
set $ElementsFound++ | |
end | |
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++ | |
end | |
printf "Number of elements found = %u\n", $ElementsFound | |
end | |
if $argc == 5 | |
set $idx1 = $arg3 | |
set $idx2 = $arg4 | |
set $ElementsFound = 0 | |
while $i < $tree_size | |
set $value = (void *)($node + 1) | |
set $valueLeft = *($arg1*)$value | |
set $valueRight = *($arg2*)($value + 4) | |
if $valueLeft == $idx1 && $valueRight == $idx2 | |
printf "elem[%u]->left: ", $i | |
p $valueLeft | |
printf "elem[%u]->right: ", $i | |
p $valueRight | |
set $ElementsFound++ | |
end | |
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++ | |
end | |
printf "Number of elements found = %u\n", $ElementsFound | |
end | |
printf "Map size = %u\n", $tree_size | |
end | |
end | |
document pmap | |
Prints std::map<TLeft and TRight> or std::multimap<TLeft and TRight> information. Works for std::multimap as well. | |
Syntax: pmap <map> <TtypeLeft> <TypeRight> <valLeft> <valRight>: Prints map size, if T defined all elements or just element(s) with val(s) | |
Examples: | |
pmap m - prints map size and definition | |
pmap m int int - prints all elements and map size | |
pmap m int int 20 - prints the element(s) with left-value = 20 (if any) and map size | |
pmap m int int 20 200 - prints the element(s) with left-value = 20 and right-value = 200 (if any) and map size | |
end | |
# | |
# std::set and std::multiset | |
# | |
define pset | |
if $argc == 0 | |
help pset | |
else | |
set $tree = $arg0 | |
set $i = 0 | |
set $node = $tree->_M_t->_M_impl->_M_header->_M_left | |
set $end = $tree->_M_t->_M_impl->_M_header | |
set $tree_size = $tree->_M_t->_M_impl->_M_node_count | |
if $argc == 1 | |
printf "Set " | |
whatis $tree | |
printf "Use pset <variable_name> <element_type> to see the elements in the set.\n" | |
end | |
if $argc == 2 | |
while $i < $tree_size | |
set $value = (void *)($node + 1) | |
printf "elem[%u]: ", $i | |
p *($arg1*)$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++ | |
end | |
end | |
if $argc == 3 | |
set $idx = $arg2 | |
set $ElementsFound = 0 | |
while $i < $tree_size | |
set $value = (void *)($node + 1) | |
if *($arg1*)$value == $idx | |
printf "elem[%u]: ", $i | |
p *($arg1*)$value | |
set $ElementsFound++ | |
end | |
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++ | |
end | |
printf "Number of elements found = %u\n", $ElementsFound | |
end | |
printf "Set size = %u\n", $tree_size | |
end | |
end | |
document pset | |
Prints std::set<T> or std::multiset<T> information. Works for std::multiset as well. | |
Syntax: pset <set> <T> <val>: Prints set size, if T defined all elements or just element(s) having val | |
Examples: | |
pset s - prints set size and definition | |
pset s int - prints all elements and the size of s | |
pset s int 20 - prints the element(s) with value = 20 (if any) and the size of s | |
end | |
# | |
# std::dequeue | |
# | |
define pdequeue | |
if $argc == 0 | |
help pdequeue | |
else | |
set $size = 0 | |
set $start_cur = $arg0._M_impl._M_start._M_cur | |
set $start_last = $arg0._M_impl._M_start._M_last | |
set $start_stop = $start_last | |
while $start_cur != $start_stop | |
p *$start_cur | |
set $start_cur++ | |
set $size++ | |
end | |
set $finish_first = $arg0._M_impl._M_finish._M_first | |
set $finish_cur = $arg0._M_impl._M_finish._M_cur | |
set $finish_last = $arg0._M_impl._M_finish._M_last | |
if $finish_cur < $finish_last | |
set $finish_stop = $finish_cur | |
else | |
set $finish_stop = $finish_last | |
end | |
while $finish_first != $finish_stop | |
p *$finish_first | |
set $finish_first++ | |
set $size++ | |
end | |
printf "Dequeue size = %u\n", $size | |
end | |
end | |
document pdequeue | |
Prints std::dequeue<T> information. | |
Syntax: pdequeue <dequeue>: Prints dequeue size, if T defined all elements | |
Deque elements are listed "left to right" (left-most stands for front and right-most stands for back) | |
Example: | |
pdequeue d - prints all elements and size of d | |
end | |
# | |
# std::stack | |
# | |
define pstack | |
if $argc == 0 | |
help pstack | |
else | |
set $start_cur = $arg0.c._M_impl._M_start._M_cur | |
set $finish_cur = $arg0.c._M_impl._M_finish._M_cur | |
set $size = $finish_cur - $start_cur | |
set $i = $size - 1 | |
while $i >= 0 | |
p *($start_cur + $i) | |
set $i-- | |
end | |
printf "Stack size = %u\n", $size | |
end | |
end | |
document pstack | |
Prints std::stack<T> information. | |
Syntax: pstack <stack>: Prints all elements and size of the stack | |
Stack elements are listed "top to buttom" (top-most element is the first to come on pop) | |
Example: | |
pstack s - prints all elements and the size of s | |
end | |
# | |
# std::queue | |
# | |
define pqueue | |
if $argc == 0 | |
help pqueue | |
else | |
set $start_cur = $arg0.c._M_impl._M_start._M_cur | |
set $finish_cur = $arg0.c._M_impl._M_finish._M_cur | |
set $size = $finish_cur - $start_cur | |
set $i = 0 | |
while $i < $size | |
p *($start_cur + $i) | |
set $i++ | |
end | |
printf "Queue size = %u\n", $size | |
end | |
end | |
document pqueue | |
Prints std::queue<T> information. | |
Syntax: pqueue <queue>: Prints all elements and the size of the queue | |
Queue elements are listed "top to bottom" (top-most element is the first to come on pop) | |
Example: | |
pqueue q - prints all elements and the size of q | |
end | |
# | |
# std::priority_queue | |
# | |
define ppqueue | |
if $argc == 0 | |
help ppqueue | |
else | |
set $size = $arg0.c._M_impl._M_finish - $arg0.c._M_impl._M_start | |
set $capacity = $arg0.c._M_impl._M_end_of_storage - $arg0.c._M_impl._M_start | |
set $i = $size - 1 | |
while $i >= 0 | |
p *($arg0.c._M_impl._M_start + $i) | |
set $i-- | |
end | |
printf "Priority queue size = %u\n", $size | |
printf "Priority queue capacity = %u\n", $capacity | |
end | |
end | |
document ppqueue | |
Prints std::priority_queue<T> information. | |
Syntax: ppqueue <priority_queue>: Prints all elements, size and capacity of the priority_queue | |
Priority_queue elements are listed "top to buttom" (top-most element is the first to come on pop) | |
Example: | |
ppqueue pq - prints all elements, size and capacity of pq | |
end | |
# | |
# std::bitset | |
# | |
define pbitset | |
if $argc == 0 | |
help pbitset | |
else | |
p /t $arg0._M_w | |
end | |
end | |
document pbitset | |
Prints std::bitset<n> information. | |
Syntax: pbitset <bitset>: Prints all bits in bitset | |
Example: | |
pbitset b - prints all bits in b | |
end | |
# | |
# std::string | |
# | |
define pstring | |
if $argc == 0 | |
help pstring | |
else | |
printf "String \t\t\t= \"%s\"\n", $arg0._M_data() | |
printf "String size/length \t= %u\n", $arg0._M_rep()->_M_length | |
printf "String capacity \t= %u\n", $arg0._M_rep()->_M_capacity | |
printf "String ref-count \t= %d\n", $arg0._M_rep()->_M_refcount | |
end | |
end | |
document pstring | |
Prints std::string information. | |
Syntax: pstring <string> | |
Example: | |
pstring s - Prints content, size/length, capacity and ref-count of string s | |
end | |
# | |
# std::wstring | |
# | |
define pwstring | |
if $argc == 0 | |
help pwstring | |
else | |
call printf("WString \t\t= \"%ls\"\n", $arg0._M_data()) | |
printf "WString size/length \t= %u\n", $arg0._M_rep()->_M_length | |
printf "WString capacity \t= %u\n", $arg0._M_rep()->_M_capacity | |
printf "WString ref-count \t= %d\n", $arg0._M_rep()->_M_refcount | |
end | |
end | |
document pwstring | |
Prints std::wstring information. | |
Syntax: pwstring <wstring> | |
Example: | |
pwstring s - Prints content, size/length, capacity and ref-count of wstring s | |
end | |
# | |
# C++ related beautifiers | |
# | |
set print pretty on | |
set print object on | |
set print static-members on | |
set print vtbl on | |
set print demangle on | |
set demangle-style gnu-v3 | |
set print sevenbit-strings off |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import gdb | |
import json | |
def isRawPointer(value): | |
t = "{}".format(value.type) | |
# handle pointer of stl container | |
if t.startswith("std::") and t.endswith("::pointer"): | |
return True | |
return value.type.code == gdb.TYPE_CODE_PTR | |
def handleRawPointer(pointer): | |
rawPointerMap = {} | |
rawPointerMap["_gdb_address"] = "{}".format(pointer) | |
try: | |
value = pointer.dereference() | |
value = value.fetch_lazy() | |
value = handle(value) | |
rawPointerMap["_gdb_dereference"] = value | |
except Exception: | |
rawPointerMap["_gdb_dereference"] = None | |
return rawPointerMap | |
def isStructOrUnion(value): | |
code = value.type.code | |
return (code == gdb.TYPE_CODE_STRUCT or code == gdb.TYPE_CODE_UNION) | |
def handleStructOrUnion(instance): | |
instanceMap = {} | |
for key in instance.type.keys(): | |
value = instance[key] | |
value = handle(value) | |
key = "{}".format(key) | |
instanceMap[key] = value | |
return instanceMap | |
def isStlVector(gdbValue): | |
try: | |
return gdbValue.type.tag.startswith("std::vector") | |
except Exception: | |
return False | |
def handleStlVector(gdbValue): | |
start = gdbValue["_M_impl"]["_M_start"] | |
end = gdbValue["_M_impl"]["_M_finish"] | |
size = end - start | |
vectorMap = {} | |
vectorMap["_gdb_vectorSize"] = int(size) | |
vectorList = [] | |
for i in range(size): | |
vectorList.append(handle((start + i).dereference())) | |
vectorMap["_gdb_vectorList"] = vectorList | |
return vectorMap | |
def isStlList(value): | |
pass | |
def handleStlList(value): | |
pass | |
def handle(gdbValue): | |
m = {} | |
if isRawPointer(gdbValue): | |
m = handleRawPointer(gdbValue) | |
elif isStlVector(gdbValue): | |
m = handleStlVector(gdbValue) | |
elif isStructOrUnion(gdbValue): | |
m = handleStructOrUnion(gdbValue) | |
else: | |
m["_gdb_value"] = "{}".format(gdbValue) | |
m["_gdb_type"] = "{}".format(gdbValue.type) | |
return m | |
def gdbPrettyPrint(gdbValue): | |
print(json.dumps(handle(gdbValue), indent=2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1. https://blog.csdn.net/littlestream9527/article/details/39050599 | |
2. https://sourceware.org/ml/gdb/2008-02/msg00064/stl-views.gdb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1. support shared ptr and other | |
2. support sem_t and conditional variable | |
3. support nested stl container, shared_ptr in stl container and other nested situations | |
4. test |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment