c++ , java unwind 展開過程 ,看不太懂

展開代碼數組按降序排列。發生異常時,操作系統將整個上下文存儲在上下文記錄中。然後調用異常調度邏輯,該邏輯重複執行下列步驟以查找異常處理程序。

  1. 使用存儲在上下文記錄中的當前 RIP 來搜索 RUNTIME_FUNCTION 表項,該表項描述當前函數(在鏈式 UNWIND_INFO 項的情況下爲函數部分)。

  2. 如果找不到任何函數表項,則異常處理程序在葉函數中,RSP 將直接對返回指針進行尋址。將 [RSP] 處的返回指針存儲在更新的上下文中,將模擬的 RSP 加 8,然後重複步驟 1。

  3. 如果找到了函數表項,則 RIP 可能位於以下三個區域:a) 在 Epilog 中;b) 在 Prolog 中;c) 在異常處理程序可能包含的代碼中。

    • a) 如果 RIP 在 Epilog 中,則控制離開此函數,對此函數來說,可能沒有與此異常關聯的異常處理程序,並且 Epilog 的效果必須繼續保持,以便計算調用方函數的上下文。爲了確定 RIP 是否在 Epilog 中,將對來自 RIP 的代碼流進行檢查。如果該代碼流可以匹配合法 Epilog 的結尾部分,則該代碼流在 Epilog 中,會對 Epilog 的其餘部分進行模擬,並且在處理每個指令時對上下文記錄進行更新。然後,重複步驟 1。

    • b) 如果 RIP 在 Prolog 中,則控制尚未進入此函數,對此函數來說,可能沒有與此異常關聯的異常處理程序,並且 Prolog 的效果必須撤消,以便計算調用方函數的上下文。如果從函數開始到 RIP 的距離小於或等於在展開信息中編碼的 Prolog 大小,則 RIP 在 Prolog 中。展開 prolog 效果的方法如下:向前掃描整個展開代碼數組,找到滿足以下條件的第一項,該項的偏移量小於或等於 RIP 距函數開始處的偏移量,然後撤消展開代碼數組中其餘各項的效果。然後,重複步驟 1。

    • c) 如果 RIP 不在 Prolog 或 Epilog 中,並且函數有一個異常處理程序(設置了 UNW_FLAG_EHANDLER),則調用語言特定的處理程序。該處理程序掃描其數據並根據相應情況調用篩選函數,並可以返回經過處理的異常或返回繼續進行的搜索。此外,該處理程序還可以直接對某個展開進行初始化。

  4. 如果語言特定的處理程序返回一個已處理狀態,則執行過程將使用原始上下文記錄繼續進行。

  5. 如果沒有語言特定的處理程序,或者該處理程序返回一個“繼續搜索”狀態,則必須將上下文記錄展開爲調用方的狀態。通過處理展開代碼數組的所有元素並撤消每個元素的效果,可以完成此操作。然後,重複步驟 1。

涉及鏈式展開信息時,仍然遵循這些基本步驟。唯一的區別在於,當瀏覽展開代碼數組以展開某個 Prolog 的效果時,一旦到達數組末尾,該 prolog 就被鏈接到父展開信息,從而可以瀏覽該處的整個展開代碼數組。此鏈接將一直保持,直至到達沒有 UNW_CHAINED_INFO 標誌的展開信息爲止,從而完成展開代碼數組的瀏覽。

最小的展開數據集爲 8 字節。這可能表示一個函數,該函數僅分配了小於或等於 128 字節的堆棧,並可能保存了一個非易失寄存器。對於不具有展開代碼的零長度 Prolog,這也可能表示其鏈式展開信息結構的大小

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章