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