[GDB] 使用 gdb 的巨集指令,印出 STL container (如 map) 的儲存內容

[GDB] 使用 gdb 的巨集指令,印出 STL container (如 map) 的儲存內容

今天在用 gdb 查一個 crash 的問題,看到 backtrace 像下面這樣:

(gdb) bt
#1  0x00002b9872b3ec88 in GetFileType (
szSrcFilePath=0x163243c "/Normal.dotm",
pFileType=0x1b2dc70) at ./FileTypeLib.cpp:488
#2  0x00002b986e671ca8 in ffi_call_unix64 () from /opt/python/lib/python2.6/lib-dynload/_ctypes.so
#3  0x00002b986e671af4 in ffi_call () from /opt/python/lib/python2.6/lib-dynload/_ctypes.so
#4  0x00002b986e66c2f4 in _CallProc () from /opt/python/lib/python2.6/lib-dynload/_ctypes.so
#5  0x00002b986e664118 in ?? () from /opt/python/lib/python2.6/lib-dynload/_ctypes.so
#6  0x0000000000417d2d in PyObject_Call ()
#7  0x000000000048fc7a in PyEval_EvalFrameEx ()
......
#30 0x00000036d120683d in start_thread () from /lib64/libpthread.so.0
#31 0x00000036d06d4fcd in clone () from /lib64/libc.so.6

 

嗯… 因為有程式的原始碼,所以可以去查一下 FileTypeLib.cpp 在寫什麼,

懷疑是一個 STL map 的變數 (本例中是 m_mapType) 儲存的值有問題…

用 print 來印看看,基本上看不出什麼,

只能從 _M_node_count 來猜這個 map 裡面有 3 組資料,但內容完全沒提示:

(gdb) print FileTypeManager::s_pInstance->m_mapType
$3 = {_M_t = {
_M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<const EnumType, PairData> > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<const EnumType, PairData> > >> = {<No data fields>}, <No data fields>},
_M_key_compare = {<std::binary_function<EnumType,EnumType,bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_color = std::_S_red,
_M_parent = 0x2b988032f730, _M_left = 0x24c3990, _M_right = 0x2b988037fa80}, _M_node_count = 3}}}

 

要怎麼查 STL map 儲存的值呢?

找了一下,有人說新版的 gdb 的 print 是可以直接印出 STL map 的儲存內容的,

不過我們專案程式跑的平台的 gdb 沒有那麼新…

幸好網路上也有好心人士提供了給 gdb 使用的巨集,

讓我們可以很方便地檢視 STL container 儲存的資料 (如 map, list, vector 等等)~

 

參考資料:stackoverflow: Inspecting standard container (std::map) contents with gdb

 

1. 下載 stl-views.gdb 巨集檔

下載這個巨集檔案 stl-views.gdb 到 gdb 所在的機器,

可以先瞄一下內容,開頭的部分有列出可以用的巨集指令,

像是 pvector 可以印出 vector 的內容,而 map 的內容可以用 pmap 來印出來:

#   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

 

2. 使用 stl-views.gdb 巨集指令

首先用 gdb 開啟 crash dump,接著執行 source 指令,將巨集檔案載入:

 (gdb) source stl-views.gdb

 

用 pmap 指令來印出 m_mapType 的內容看看… 在 pmap 後面要給的是 map 的位址:

(gdb) pmap &(FileTypeManager::s_pInstance->m_mapType)
Map type = MAP_TYPE_TO_PAIR_DATA *
Use pmap <variable_name> <left_element_type> <right_element_type> to see the elements in the map.
Map size = 3

 

gdb 說這個 map 的資料型態是 MAP_TYPE_TO_PAIR_DATA,

這個 MAP_TYPE_TO_PAIR_DATA 事實上是一個 std::map<EnumType, PairData> 的 typedef,

因此 gdb 提示我們要把 map 的 key/value 的資料型態明確指定上去,

修正過後的指令如下:

(gdb) pmap &(FileTypeManager::s_pInstance->m_mapType) EnumType PairData
elem[0]->left: $5 = CONTEXT_FILE
elem[0]->right: $6 = {
nBase = 167460362554190744,
nDiff = 1
}
elem[1]->left: $7 = CONTEXT_URL
elem[1]->right: $8 = {
nBase = -9207449046900266088,
nDiff = 2
}
elem[2]->left: $9 = CONTEXT_MEMORY
elem[2]->right: $10 = {
nBase = -9208743309524860926,
nDiff = 3
}
Map size = 3

 

可以看到 pmap 指令成功地將 map 的內容印出來了,

像是第一個元素 elem[0] 的 key 是 CONTEXT_FILE,

對應的值是一個 struct,裡面有 nBase 和 nDiff 兩個成員~

用這個方法就能很快檢視 STL map 的儲存資料,進而找出造成 crash 的錯誤的值囉~

 

(本頁面已被瀏覽過 1,686 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料