从堆里找回“丢失”的代码
前言
前一陣子,使用小烏龜(TortoiseGit)提交代碼的時候,錯誤的 Revert 了部分代碼,本文記錄了找回這部分代碼的過程。文章標題致敬張銀奎老師《格蠹匯編》的第一章 —— 從堆里搶救丟失的博客。
說明: 本文的截圖都是我用新建的示例工程截取的。
緣起
最近,程序運行的時候,執行某個功能會崩潰,根據經驗猜測,應該是序列化,反序列化的問題。由于手里沒有關鍵的 pdb,調試起來比較費勁,而且項目比較急,暫時先不使用這個功能。準備先提交其它功能的代碼。
大意失荊州
按照慣例,提交之前先檢查一下提交內容。(p.s. 這是個好習慣)
后截的圖發現有一部分代碼會導致序列化有問題。一激動(當時被那個崩潰問題搞得很煩躁),點擊了Revert...。
revert-source點完了就后悔了 —— 這段代碼是為其它功能寫的,應該保留。由于在提交代碼前,關閉了vs ,沒辦法通過 vs 找回了。
說明: 如果文件在 vs 外部被修改,vs 會給出類似下圖的提示,這時候我們選 No 不重新加載就可以了。
這可是我辛辛苦苦,一行一行敲出來的啊。就這么 “丟了” 嗎?丟是不可能丟的,這輩子都不可能丟的。
峰回路轉
幸虧沒有煩躁到直接干掉小烏龜。想起張老師的《格蠹匯編》第一章就是 “從堆里搶救丟失的博客”,講的是使用 windbg 從瀏覽器中找回未能成功發表的博文的故事。趕緊使用 windbg 附加到小烏龜上。先用 .dump /ma e:\dumps\tortoisegit.dmp 保存一份完整轉儲。
保存完整轉儲有了轉儲文件,即使關閉小烏龜也不怕了!稍微平復下我跌宕起伏的內心,應該用哪個命令搜索內存呢?很早之前從張老師的文章里了解到 ?s 命令可以搜索內存。加之,前一段日志剛好嘗試解決過類似的問題,做了筆記。很快就把上次整理好的命令粘貼到 windbg 中進行查找。
搜尋關鍵字
有印象的關鍵字是 args.Contains("--all")。在 windbg 中輸入 !address -f:heap,PAGE_READWRITE -c:"s -u %1 %2 args.Contains(\"--all\")"
搜尋關鍵字搜到兩處,分別使用 du 命令查看這兩處的內容。
查看第一個地址查看第二個地址明顯第一處的內容比較全,選用第一處的地址進行進一步的搜索。如果能找到文件的開始和結束就最好了。經過簡單的嘗試,找到了開始和結束的地址。截圖的話會比較長,這里就不截圖了。開始地址是 0000022f``dae8e5f8-0x3538,結束地址是 0000022f``dae8f030。
說明: 也可以直接使用命令 s -u 0x0 L?0xffffffff`ffffffff "args.Contains("--all")",更簡單明了。
保存到文件
知道開始地址和結束地址了,剩下的就是如何把對應的內容保存到文件中了。windbg 已經為我們準備好了一條命令 —— .writemem。輸入:.writemem e:\dumps\tortoisegit.cs 0000022f``dae8e5f8-0x3538 0000022f``dae8f030 即可把指定范圍的數據保存到文件中。
保存到文件查看保存的文件,果然是對應的文件內容!比較長,這里就不放截圖了。
反思
一定要養成一個良好的版本管理習慣。開發新功能的時候,最好建立一個新分支,并且隨時把變更提交。等開發完了,再合并回主分支,并刪掉功能分支。如果我遵循了這個原則的話,就不會出現這種問題了。當然,也不會有本篇總結了。
遇到問題,一定不要魯莽,保持冷靜。如果我關了小烏龜,那么丟失的代碼就真的沒辦法找回來了。
一定要養成總結問題,記錄問題的好習慣!之前,有同事也遇到了類似的問題,代碼不小心弄丟了。不幸的是,沒能通過這種辦法找回來。幸運的是,當時調查的結果都有記錄,所以這次查這個問題的時候,翻出筆記。復制粘貼,回車,搞定!一氣呵成,相當舒爽!
總結
使用 !address -f:heap, PAGE_READWRITE -c:"s -u %1 %2 \"unicode_string_to_search\"" 可以在堆上搜索 unicode_string_to_search。
可以使用更簡單的 s -u start_address end_address 或者 s -u start_address L?length 搜索。
使用 .writemem 可以把指定范圍的數據保存到文件中。
參考資料
《格蠹匯編》
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-address
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-writemem--write-memory-to-file-
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/address-and-address-range-syntax
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/s--search-memory-
猜你喜歡:
VS 系列:
排錯實戰——解決c++編譯錯誤:error C2059: illegal token on right side of '::'
善用 vs 中的錯誤列表和輸出窗口,高效查找 C++ 多工程編譯錯誤
轉儲文件系列:
轉儲系列文章總結
轉儲文件知多少
你需要知道的 N 種抓取 dump 的工具
你生成的轉儲文件有問題嗎?
向大廠看齊!為自己的程序增加自動轉儲的功能!
內核轉儲,開抓啦!
藍屏(BSOD)轉儲設置,看本文就夠了!
系統藍屏的幾種姿勢,確定不了解下么?
本地內核調試環境搭建,就這么簡單!
雙機內核調試 101
使用 VMware + win10 + VirtualKD + windbg 從零搭建雙機內核調試環境
使用 VMware + win10 + vs2019 從零搭建雙機內核調試環境
本地內核調試神器 —— livekd 使用總結
調試系列:
調試實戰——你知道怎么使用DebugView查看調試信息嗎?
調試實戰——程序CPU占用率飆升,你知道如何快速定位嗎?
調試實戰——崩潰在ComFriendlyWaitMtaThreadProc
調試實戰——使用windbg調試崩潰在ole32!CStdMarshal::DisconnectSrvIPIDs
調試實戰——調試PInvoke導致的內存破壞
調試實戰——調試excel啟動時死鎖
調試實戰——調試DLL卸載時的死鎖
調試實戰——調試TerminateThread導致的死鎖
排錯系列:
排錯實戰——1分鐘解救 run 不出來的 Autoruns
排錯實戰——VS清空最近打開的工程記錄
排錯實戰——拯救加載調試符號失敗的IDA
排錯實戰——你知道拖動窗口時只顯示虛框怎么設置嗎?
排錯實戰——解決Tekla通過.tsep安裝插件失敗的問題
排錯實戰——使用process explorer替換任務管理器
排錯實戰——通過對比分析sysinternals事件修復程序功能異常
總結
以上是生活随笔為你收集整理的从堆里找回“丢失”的代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DevOps vs. Agile:它们有
- 下一篇: 简述使用REST API 的最佳实践