• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一直比較好奇,調試器是如何生成堆棧的調用過程的,比如如下代碼:
            int add(int a, int b)
            {
                return a + b;
            }

            int main()
            {
                int c = add(1, 2);
                system("pause");

                return 0;
            }

            調用Add時的堆棧截圖如下:


            調試器究竟是如何生成這個堆棧過程的呢?

            我最初的理解調試器是根據EBP來生成該堆棧的,原理如下:

            可以看到按照上面的原理, 每次EBP里存放的都是當前函數的堆棧楨基址,所以我們只要一直遞推,就可以得到完整的Call Stack.

            但是我們很快會發現, 并不是每個函數都是以
            push ebp   
            mov ebp, esp
            開頭的,我們可以寫一些裸(naked)函數,
            比如int __declspec(naked) add(int x,int y) 來手動控制函數頭,
            而且很多編譯器優化過的函數代碼也是沒有該標準函數頭的。

            那么調試器在這種情況下又是如何生成完整的call stack的呢?

            和群里的朋友討論的結果是調試器很可能是在調用call指令時保存了調用現場,
            這樣只要在調試器下運行,它就一直可以知道正確而完整的call stack.

            這也解釋了為什么我們在分析Crash的Dump文件時很多時候得不到正確的堆棧過程?
            有可能是堆棧本身被我們的異常代碼破壞了;
            更有可能是因為我們的代碼在直接運行時沒有調試器的參與, 所以堆棧過程沒有被保存,所以windbg分析dump時只能根據堆棧里內容自己分析和推理堆棧調用過程,所以很多時候得不到正確的堆棧過程。

            那么Windbg分析dump時,會如何倒推堆棧過程呢?

            如果每個函數都是有標準的push ebp, 那么按照ebp遞推就可以了;
            否這就只能用其他方法分析,比如看看堆棧里某個地址是不是函數返回地址(該地址屬于某個模塊的代碼段),這樣就可以確定該地址是某個函數堆棧楨的起始地址。

            上面關于生成call stack的原理只是一些非專業人士的個人看法,如果有不正確的地方,歡迎指正。

            注: 和開發過調試器的朋友討論,上面 關于callstack產生原理的推論,實際上是不正確的, 調試器實際上是通過查詢PDB文件的方式獲取的callstack.
            posted on 2012-07-20 14:00 Richard Wei 閱讀(5347) 評論(3)  編輯 收藏 引用 所屬分類: 匯編

            FeedBack:
            # re: 堆棧楨的生成原理
            2012-07-20 15:31 | Richard Wei
            據寫過調試器的朋友指點,調試器會盡量減少代碼運行時的干預,所以上面關于函數調用時調試器保存調用現場的猜測,應該是不正確的。
            調試器更多的可能是根據PDB文件信息來計算推理的,如果沒有PDB文件,它就只能猜測,很多堆棧信息就會出錯了。

            據說<<軟件調試>>里有相關介紹,回頭看下, 希望這篇博文不要誤導他人。  回復  更多評論
              
            # re: 堆棧楨的生成原理[未登錄]
            2012-07-20 21:19 | Korall
            “和群里的朋友討論的結果是調試器很可能是在調用call指令時保存了調用現場,
            這樣只要在調試器下運行,它就一直可以知道正確而完整的call stack.”

            猜測確實不太符合實際;我還沒有見過哪一款調試器是這樣實現的,虛擬機除外。
            就算是在調試器下運行,不設置“堆棧幀”的函數調試器也是無法知道正確而完整的 call stack 的。  回復  更多評論
              
            # re: 堆棧楨的生成原理
            2012-07-21 00:14 | fzy
            call 會push下一條指令的地址到堆棧。
            可能是根據這個來進行堆棧幀的檢測。
              回復  更多評論
              
            99久久夜色精品国产网站| 久久久久久久人妻无码中文字幕爆 | 国产精品欧美久久久久天天影视| 999久久久无码国产精品| 国产精品亚洲美女久久久| 久久亚洲2019中文字幕| 囯产精品久久久久久久久蜜桃| 久久综合狠狠综合久久综合88| 国产精品一区二区久久精品| 午夜福利91久久福利| 亚洲国产欧美国产综合久久| 国产精品久久99| 久久精品国产AV一区二区三区| 精品九九久久国内精品| 久久久久99这里有精品10 | 草草久久久无码国产专区| 久久亚洲精品国产精品婷婷| 久久er国产精品免费观看2| 欧美久久综合九色综合| 精品久久久久久亚洲| 亚洲国产精品无码久久一区二区| 国产成人综合久久精品尤物| 亚洲午夜久久久久妓女影院 | 久久精品黄AA片一区二区三区| 国产福利电影一区二区三区,免费久久久久久久精| 久久精品国产亚洲精品| 久久精品免费观看| 久久亚洲春色中文字幕久久久| 亚洲国产成人久久综合碰| 品成人欧美大片久久国产欧美... 品成人欧美大片久久国产欧美 | 久久亚洲中文字幕精品有坂深雪| 伊人久久精品影院| 伊色综合久久之综合久久| 久久99精品久久久久久野外| 久久精品国产一区| 国产精品gz久久久| 国产福利电影一区二区三区,免费久久久久久久精| 久久精品国产99久久无毒不卡| 久久国产免费观看精品3| 久久人人爽人人爽人人AV东京热| 69国产成人综合久久精品|