異質除錯的 DWARF 擴充功能¶
警告
本文檔描述 DWARF 版本 5 [DWARF] 的臨時擴充功能,以支援異質除錯。目前尚未完全實作,且可能會變更。
1. 簡介¶
AMD [AMD] 一直致力於支援異質運算。異質運算程式可以使用高階語言編寫,例如 C++ 或 Fortran,並搭配 OpenMP 指令、OpenCL 或 HIP(用於異質運算的攜帶式 C++ 程式設計環境 [HIP])。異質編譯器和執行時期允許程式在同一個原生程序中的多個裝置上執行。裝置可能包括 CPU、GPU、DSP、FPGA 或其他特殊用途加速器。目前,HIP 程式在具有 CPU 和 GPU 的系統上執行。
AMD [AMD] ROCm 平台 [AMD-ROCm] 是異質系統架構 (HSA) 基金會 [HSA] 定義的異質運算裝置產業標準的實作。它是開源的,並包含對 LLVM [LLVM] 進行編譯和 GDB 進行除錯 [GDB] 等開源專案的貢獻。
LLVM 編譯器具有對市售 AMD GPU 硬體 (AMDGPU) 的上游支援 [AMDGPU-LLVM]。開源 ROCgdb [AMD-ROCgdb] 基於 GDB 的除錯器也具有對 AMDGPU 的支援,並且正在上游化。第三方也正在將 AMDGPU 的支援添加到 GCC [GCC] 編譯器和 Perforce TotalView HPC 除錯器 [Perforce-TotalView]。
為了支援異質程式的除錯,已經識別出當前 DWARF 版本 5 [DWARF] 未提供的幾個功能。2. 擴充功能 節概述了為解決遺失的功能而設計的擴充功能。這些擴充功能旨在具有通用性,並與 DWARF 版本 5 向後相容。它們的目標是適用於滿足任何異質系統的需求,而不是特定於供應商或架構。接下來是附錄 A. 相對於 DWARF 版本 5 的變更,其中包含相對於 DWARF 版本 5 標準的擴充功能的文字變更。其中包含許多註解,提出了懸而未決的問題,或提供了可能值得考慮的替代方法。然後附錄 C. 更多範例 連結到 AMD GPU 特定擴充功能用法,其中包括一個範例。最後,附錄 D. 參考文獻 提供了更多資訊的參考文獻。
2. 擴充功能¶
這些擴充功能透過與許多個人合作以及在 GDB 除錯器和 LLVM 編譯器中的積極原型設計而不斷發展。來自 Perforce TotalView HPC 除錯器和 GCC 編譯器的開發人員的意見也備受讚賞。
到目前為止提供的輸入和獲得的見解已納入目前的版本中。計畫是參與上游化工作並處理任何回饋。如果大家普遍感興趣,那麼這些擴充功能中的一些或全部可以作為未來的 DWARF 標準提案提交。
設計擴充功能的一般原則是
與 DWARF 版本 5 [DWARF] 標準向後相容。
保持供應商和架構中立。它們旨在適用於其他異質硬體裝置,包括 GPU、DSP、FPGA 和其他專用硬體。這些裝置統統包含與 AMDGPU 裝置類似的特性和需求。
為非 GPU 程式碼提供改進的最佳化支援。例如,某些擴充功能適用於支援大型向量暫存器的傳統 CPU 硬體。編譯器可以將原始碼語言以及描述大規模並行執行的原始碼語言擴充功能,映射到向量暫存器的通道上。這在 ML 和 HPC 中使用的程式語言中很常見。
根據 DWARF 版本 5 規範,以一致的樣式完整定義格式良好的 DWARF。
一些通用化也可能有利於已提出的其他 DWARF 問題。
本節的其餘部分列舉了擴充功能,並針對異質除錯說明了每個擴充功能的動機。
2.1 允許 DWARF 運算式堆疊上的位置描述¶
DWARF 版本 5 不允許位置描述作為 DWARF 運算式堆疊上的條目。它們只能是 DWARF 運算式評估的最終結果。但是,透過允許位置描述成為 DWARF 運算式堆疊上的第一級條目,可以自然地組合包含值和位置描述的運算式。它允許物件位於任何種類的記憶體位址空間、暫存器中、成為隱含值、未定義或它們的組合。
透過仔細擴充 DWARF,所有現有的 DWARF 運算式都可以保留其目前的語意含義。DWARF 具有隱含轉換,可將表示預設位址空間中位址的值轉換為記憶體位置描述。這可以擴充為允許將預設位址空間記憶體位置描述隱含地轉換回其位址值。這允許所有 DWARF 版本 5 運算式保留其相同的含義,同時能夠顯式建立非預設位址空間中的記憶體位置描述,並將複合位置描述的功能通用化為任何種類的位置描述。
對於那些熟悉 DWARF 版本 5 中位置描述定義的人來說,這些擴充功能中的定義呈現方式不同,但實際上確實定義了相同的概念,並具有相同的基本語意。但是,它以一種允許概念擴充的方式來支援位址空間、位元定址、由任何種類的位置描述組成的複合位置描述的能力,以及支援位於多個位置的物件的能力。總體而言,這些變更擴展了可以支援的架構集,並改進了對最佳化程式碼的支援。
考慮了幾種方法,並且提出的方法,連同它啟用的擴充功能,似乎是最簡單和最乾淨的方法,可以最大程度地提高 DWARF 支援除錯最佳化 GPU 和非 GPU 程式碼的能力。檢查 GDB 除錯器和 LLVM 編譯器,似乎只需要適度的變更,因為它們都已經必須支援位置描述的一般使用。預計其他除錯器和編譯器也會是這種情況。
GDB 已被修改為評估 DWARF 版本 5 運算式,其中位置描述作為堆疊條目並具有隱含轉換。所有 GDB 測試都已通過,但有一個測試案例被證明是違反 DWARF 版本 5 規則的無效測試案例。GDB 中的程式碼實際上變得更簡單了,因為所有評估都在單一堆疊上完成,並且不再需要為位置描述結果維護單獨的結構。這讓人對向後相容性充滿信心。
請參閱 A.2.5 DWARF 運算式 和巢狀章節。
此擴充功能在允許 DWARF 運算式堆疊上的位置描述 [AMDGPU-DWARF-LOC] 中單獨描述。
2.2 將 CFI 通用化以允許任何位置描述種類¶
CFI 描述還原被溢出的被呼叫者儲存的暫存器。目前,CFI 僅允許位置描述是暫存器、記憶體位址或隱含位置描述。AMDGPU 最佳化程式碼可能會將純量暫存器溢出到向量暫存器的部分中。這需要擴充 CFI 以允許支援任何位置描述種類。
請參閱 A.6.4 呼叫框架資訊。
2.3 將 DWARF 運算式通用化以支援多個位置¶
在 DWARF 版本 5 中,位置描述定義為單一位置描述或位置列表。位置列表定義為實際上是未定義的位置描述,或定義為一個或多個單一位置描述,以描述具有多個位置的物件。
透過 2.1 允許 DWARF 運算式堆疊上的位置描述,DW_OP_push_object_address
和 DW_OP_call*
運算可以將位置描述放在堆疊上。此外,除錯器資訊條目屬性,例如 DW_AT_data_member_location
、DW_AT_use_location
和 DW_AT_vtable_elem_location
定義為在評估運算式之前將位置描述推送到運算式堆疊上。
DWARF 版本 5 僅允許堆疊包含值,因此堆疊上只能有一個記憶體位址。這使得這些運算和屬性無法處理具有多個位置或位置不是記憶體的位置描述。
由於 2.1 允許 DWARF 運算式堆疊上的位置描述 允許堆疊包含位置描述,因此運算被通用化以支援可以有多個位置的位置描述。這與 DWARF 版本 5 向後相容,並允許支援具有多個位置的物件。例如,描述如何存取物件欄位的運算式可以使用具有多個位置的位置描述進行評估,並將產生具有多個位置的位置描述。
透過此變更,描述 DWARF 運算式和位置列表的單獨 DWARF 版本 5 區段被統一為描述一般 DWARF 運算式的單一區段。這種統一是允許位置描述成為評估堆疊一部分的自然結果和必然結果。
請參閱 A.2.5.3 DWARF 位置描述。
2.4 將位置描述的偏移通用化¶
DW_OP_plus
和 DW_OP_minus
運算可以定義為對預設目標架構特定位址空間中的記憶體位置描述和通用類型值進行運算,以產生更新的記憶體位置描述。這允許它們繼續用於偏移位址。
為了將偏移通用化為任何位置描述,包括描述位元組在暫存器中、是隱含的或它們的組合的位置描述,新增了 DW_OP_LLVM_offset
、DW_OP_LLVM_offset_uconst
和 DW_OP_LLVM_bit_offset
偏移運算。
偏移運算可以對任何大小的位置儲存進行運算。例如,隱含位置儲存的大小可以是任意位元數。將超出位置儲存大小的偏移定義為評估錯誤,比強制實作支援潛在的無限精度偏移以使其能夠正確追蹤可能暫時溢出或下溢但最終在範圍內的系列正負偏移更簡單。這對於算術運算來說很簡單,因為它們是根據固定大小的基礎類型上的二補數算術定義的。因此,偏移運算定義整數溢出是不合適的。這與 DW_OP_plus
、DW_OP_plus_uconst
和 DW_OP_minus
算術運算形成對比,後者定義它會導致環繞。
擁有偏移運算允許 DW_OP_push_object_address
推送可能在暫存器中或為隱含值的位置描述。DW_TAG_ptr_to_member_type
的 DWARF 運算式可以使用偏移運算,而無需考慮推送了哪種類型的位置描述。
由於 2.1 允許 DWARF 運算式堆疊上的位置描述 已將位置儲存通用化為位元可索引,因此 DW_OP_LLVM_bit_offset
將 DWARF 通用化以處理位元欄位。這在 DWARF 版本 5 中通常是不可能的。
DW_OP_*piece
運算僅允許字面值索引。需要一種使用任意位置描述(例如向量暫存器)的計算偏移的方式。偏移運算提供了這種能力,因為它們可以用於計算堆疊上的位置描述。
可以定義 DW_OP_plus
、DW_OP_plus_uconst
和 DW_OP_minus
來對位置描述進行運算,以避免需要 DW_OP_LLVM_offset
和 DW_OP_LLVM_offset_uconst
。但是,不建議這樣做,因為目前算術運算定義為需要相同基礎類型的值,並產生具有相同基礎類型的結果。允許這些運算對位置描述起作用將允許第一個運算元是位置描述,第二個運算元是整數值類型,反之亦然,並傳回位置描述。這使得預設位址空間記憶體位置描述和通用基礎類型值之間的隱含轉換規則變得複雜。目前,規則會將此類位置描述轉換為記憶體位址值,然後執行二補數環繞算術。如果結果用作位置描述,它將被隱含地轉換回預設位址空間記憶體位置描述。這與位置描述的溢出規則不同。為了允許控制,將需要一個將記憶體位置描述轉換為位址整數類型值的運算。保持位置描述運算和算術運算的區分避免了這種語意複雜性。
請參閱 DW_OP_LLVM_offset
、DW_OP_LLVM_offset_uconst
和 DW_OP_LLVM_bit_offset
,位於 A.2.5.4.4.1 一般位置描述運算。
2.5 將未定義位置描述的建立通用化¶
目前的 DWARF 使用空運算式來指示未定義的位置描述。由於 2.1 允許 DWARF 運算式堆疊上的位置描述 允許在堆疊上建立位置描述,因此有必要有一種顯式方式來指定未定義的位置描述。
例如,DW_OP_LLVM_select_bit_piece
(請參閱 2.13 SIMT 硬體發散控制流程的支援)運算在堆疊上採用多個位置描述。如果沒有此功能,則無法指定輸入位置描述中的特定一個是未定義的。
請參閱 DW_OP_LLVM_undefined
運算,位於 A.2.5.4.4.2 未定義位置描述運算。
2.6 將複合位置描述的建立通用化¶
為了允許組合複合位置描述,需要一個顯式運算來指示複合位置描述定義的結束。如果達到 DWARF 運算式的結尾,則可以隱含此運算,從而允許目前的 DWARF 運算式保持合法。
請參閱 DW_OP_LLVM_piece_end
,位於 A.2.5.4.4.6 複合位置描述運算。
2.7 將 DWARF 基礎物件通用化以允許任何位置描述種類¶
對於 AMDGPU 而言,暫存器的數量和記憶體運算的成本遠高於典型的 CPU。編譯器嘗試將整個變數和陣列最佳化到暫存器中。
目前,DWARF 僅允許 DW_OP_push_object_address
和相關運算與全域記憶體位置一起使用。為了支援 AMDGPU 最佳化程式碼,需要將 DWARF 通用化以允許使用任何位置描述。這允許暫存器或複合位置描述,它們可能是記憶體、暫存器甚至隱含值的混合。
請參閱 DW_OP_push_object_address
,位於 A.2.5.4.4.1 一般位置描述運算。
2.8 位址空間的一般支援¶
AMDGPU 需要能夠描述不同種類記憶體中的位址。最佳化程式碼可能需要描述一個變數,該變數駐留在不同種類儲存體的片段中,這些片段可能包括暫存器的部分、混合記憶體種類的記憶體、隱含值或未定義。
DWARF 具有區段位址的概念。但是,無法在 DWARF 運算式中指定區段,DWARF 運算式只能指定區段位址的偏移部分。區段索引僅由指定 DWARF 運算式的實體提供。因此,區段索引只能是完整物件(例如變數)的屬性。這使其僅適用於描述位於單一種類記憶體中的實體(例如變數或子程式碼)。
AMDGPU 使用多個位址空間。例如,變數可以分配在暫存器中,該暫存器部分溢出到私有位址空間中的呼叫堆疊,部分溢出到本機位址空間。DWARF 提到了位址空間,例如作為 DW_OP_xderef*
運算的引數。新增了一個定義位址空間的新區段(請參閱 A.2.13 位址空間)。
將新的屬性 DW_AT_LLVM_address_space
新增到指標和參考類型(請參閱 A.5.3 類型修飾符條目)。這允許編譯器指定用於表示指標或參考類型的位址空間。
DWARF 在許多運算式運算中使用了位址的概念,但未定義它與位址空間的關係。例如,DW_OP_push_object_address
推送物件的位址。其他上下文在評估運算式之前隱含地將位址推送到堆疊上。例如,DW_TAG_ptr_to_member_type
的 DW_AT_use_location
屬性。運算式屬於原始碼語言類型,該類型可能適用於分配在不同種類儲存體中的物件。因此,希望使用位址的運算式可以這樣做,而無需考慮它指定哪種類型的儲存體,包括記憶體位置描述的位址空間。例如,成員值指標可能希望應用於可能駐留在任何位址空間中的物件。
DWARF DW_OP_xderef*
運算允許將值轉換為指定位址空間的位址,然後讀取該位址。但它沒有提供為非預設位址空間中的位址建立記憶體位置描述的方法。例如,AMDGPU 變數可以以固定位址分配在本機位址空間中。
DW_OP_LLVM_form_aspace_address
(請參閱 A.2.5.4.4.3 記憶體位置描述運算)運算定義為從位址和位址空間建立記憶體位置描述。它可以用於指定分配在特定位址空間中的變數的位置。這允許位址空間中位址的大小大於通用類型。它還允許消費者具有很大的實作自由度。它允許將隱含轉換回值僅限於預設位址空間,以保持與 DWARF 版本 5 的相容性。對於其他位址空間,產生者可以使用顯式指定位址空間的新運算。
相反,如果 DW_OP_LLVM_form_aspace_address
運算被定義為產生值,並且定義了到記憶體位置描述的隱含轉換,那麼它將受到通用類型大小(與預設位址空間大小匹配)的限制。實作可能必須使用值的保留範圍來表示不同的位址空間。這樣的值可能與實際硬體中的任何位址值都不匹配。這將要求消費者對此類值進行特殊處理。
DW_OP_breg*
將暫存器視為包含預設位址空間中的位址。DW_OP_LLVM_aspace_bregx
(請參閱 A.2.5.4.4.3 記憶體位置描述運算)運算已新增,以允許指定暫存器中保留的位址的位址空間。
類似地,DW_OP_implicit_pointer
將其隱含指標值視為位於預設位址空間中。DW_OP_LLVM_aspace_implicit_pointer
(A.2.5.4.4.5 隱含位置描述運算)運算已新增,以允許指定位址空間。
DWARF 中幾乎所有位址的使用都僅限於定義位置描述,或取消參考以讀取記憶體。例外情況是 DW_CFA_val_offset
,它使用位址來設定暫存器的值。為了支援位址空間,CFA DWARF 運算式被定義為記憶體位置描述。這允許它指定用於將偏移位址轉換回該位址空間中位址的位址空間。請參閱 A.6.4 呼叫框架資訊。
這種擴展記憶體位置描述以支援位址空間的方法,允許所有現有的 DWARF 第 5 版表達式擁有完全相同的語義。 它允許編譯器明確指定它正在使用的位址空間。 例如,當編譯器將來源語言執行緒映射到 SIMT 方式的波前通道時,可以選擇以交錯(swizzled)方式存取私有記憶體。 或者,如果以波前作為執行緒來映射相同的語言,編譯器可以選擇以非交錯(unswizzled)方式存取它。
這種方法也允許編譯器混合使用它用來存取私有記憶體的位址空間。 例如,對於 SIMT,它仍然可以以非交錯方式溢出(spill)整個向量暫存器,同時對於 SIMT 變數存取使用交錯的私有記憶體。
這種方法也允許使用常規的 DW_OP_*piece
操作來組合不同位址空間的記憶體位置描述。
位置描述是儲存的抽象概念。 它們賦予消費者如何實作它們的自由。 它們允許位址空間編碼通道資訊,以便它們可以用於僅使用記憶體位置描述而無需額外資訊來讀取記憶體。 同一組操作可以獨立於其儲存類型而在位置上操作。 因此,DW_OP_deref*
可以用於任何儲存類型,包括不同位址空間的記憶體位置描述。 因此,DW_OP_xderef*
操作是不必要的,除非作為一種更緊湊的方式來編碼非預設位址空間位址,然後再對其進行解引用。 請參閱 A.2.5.4.3.4 特殊值操作。
2.9 向量基本類型支援¶
AMDGPU 的向量暫存器以其完整的波前大小表示,意即波前大小乘以雙字組大小。 這反映了實際硬體,並允許編譯器為將執行緒映射到完整波前的語言生成 DWARF。 它也允許生成更有效率的 DWARF 來描述 CFI,因為整個向量暫存器只需要單個表達式,而不是向量暫存器中每個通道的雙字組都需要單獨的表達式。 它還允許編譯器在將純量暫存器溢出到向量暫存器的部分時,生成索引向量暫存器的 DWARF。
由於 DWARF 堆疊值條目具有基本類型,而 AMDGPU 暫存器是雙字組的向量,因此需要能夠指定基本類型為向量。
請參閱 A.5.1 基本類型條目 中的 DW_AT_LLVM_vector_size
。
2.10 用於建立向量複合位置描述的 DWARF 操作¶
AMDGPU 優化程式碼可能會將向量暫存器溢出到非全域位址空間記憶體,並且這種溢出可能僅針對子程式入口處處於活動狀態的 SIMT 通道執行。 為了支援這一點,部分溢出暫存器的 CFI 規則需要使用一個表達式,該表達式使用 EXEC 暫存器作為位元遮罩,以在暫存器(對於非活動通道)和堆疊溢出位置(對於溢出的活動通道)之間進行選擇。 這需要評估為位置描述,而不是值,因為偵錯器需要在使用者賦值給變數時更改該值。
另一個用途是建立一個表達式,該表達式評估後提供 SIMT 執行模型中活動和非活動通道的邏輯 PC 向量。 同樣,EXEC 暫存器用於在活動和非活動 PC 值之間進行選擇。 為了表示 PC 值的向量,使用了一種建立複合位置描述的方法,該方法是單個位置的向量。
可以使用現有的 DWARF 來逐步建立複合位置描述,可能使用 DWARF 操作進行控制流程以建立迴圈。 然而,對於 AMDGPU,這將需要 64 次迴圈迭代。 一個擔憂是,生成的 DWARF 將具有顯著的大小,並且會相當常見,因為每個在函數中溢出的向量暫存器都需要它。 AMDGPU 最多可以有 512 個向量暫存器。 另一個擔憂是重複評估如此複雜的表達式所花費的時間。
為了避免這些問題,提出了一種可以作為遮罩選擇建立的複合位置描述。 此外,還需要一種操作,該操作建立一個複合位置描述,該描述是另一個位置描述上的向量。 這些操作使用單個 DWARF 操作生成複合位置描述,該操作將向量的所有通道一步組合在一起。 DWARF 表達式更緊湊,並且可以由消費者更有效率地評估。
在 C. 更多範例 附錄中引用了一個使用這些操作的範例。
請參閱 A.2.5.4.4.6 複合位置描述操作 中的 DW_OP_LLVM_select_bit_piece
和 DW_OP_LLVM_extend
。
2.11 用於存取呼叫框架條目暫存器的 DWARF 操作¶
如 2.10 用於建立向量複合位置描述的 DWARF 操作 中所述,需要一個涉及子程式入口處處於活動狀態的 SIMT 通道集的 DWARF 表達式。 SIMT 活動通道遮罩可能保存在一個暫存器中,該暫存器在子程式執行時會被修改。 但是,它的值可能會在子程式入口處保存。
呼叫框架資訊 (CFI) 已經編碼了這種暫存器保存,因此提供一個操作來傳回保存的暫存器的位置,比必須生成 loclist 來描述相同的資訊更有效率。 由於 2.1 允許 DWARF 表達式堆疊上的位置描述 允許堆疊上的位置描述,因此現在這成為可能。
請參閱 A.2.5.4.4.1 一般位置描述操作 中的 DW_OP_LLVM_call_frame_entry_reg
和 A.6.4 呼叫框架資訊。
2.12 對應到 SIMT 硬體的來源語言的支援¶
如果來源語言以 SIMT 方式映射到 AMDGPU 波前上,則變數 DWARF 位置表達式必須計算波前單個通道的位置。 因此,需要一個 DWARF 操作來表示當前通道,很像 DW_OP_push_object_address
表示當前物件。 請參閱 A.2.5.4.3.1 字面值操作 中的 DW_OP_LLVM_push_lane
。
此外,編譯器需要一種方法來溝通有多少來源語言執行緒被映射到目標架構執行緒的 SIMT 通道。 請參閱 A.3.3.5 低階資訊 中的 DW_AT_LLVM_lanes
。
2.13 對 SIMT 硬體發散控制流程的支援¶
如果來源語言以 SIMT 方式映射到 AMDGPU 波前上,則編譯器可以使用 AMDGPU 執行遮罩暫存器來控制哪些通道處於活動狀態。 為了描述非活動通道的概念位置,需要一個屬性,該屬性具有一個表達式,該表達式計算每個通道的來源位置 PC。
為了提高效率,表達式計算整個波前的來源位置。 這可以使用 DW_OP_LLVM_select_bit_piece
操作(請參閱 2.10 用於建立向量複合位置描述的 DWARF 操作)完成。
AMDGPU 可以更新執行遮罩以執行整個波前操作。 因此,需要一個屬性來計算當前活動通道遮罩。 這可以有一個表達式,該表達式可以評估為 SIMT 活動通道遮罩暫存器,或者在整個波前執行模式下評估為保存的遮罩。
在 C. 更多範例 附錄中引用了一個使用這些屬性的範例。
請參閱 A.2.5.4.4.6 複合位置描述操作 中的 DW_AT_LLVM_lane_pc
和 DW_AT_LLVM_active_lane
。
2.14 定義來源語言記憶體類別¶
AMDGPU 支援諸如 OpenCL [OpenCL] 之類的語言,這些語言定義了來源語言記憶體類別。 添加了對定義語言特定記憶體空間的支援,以便消費者可以一致地使用它們。
還添加了對在定義來源語言類型和資料物件分配中使用記憶體空間的支援。
請參閱 A.2.14 記憶體空間。
2.15 定義擴增字串以支援多個擴展¶
向編譯單元偵錯資訊條目添加了 DW_AT_LLVM_augmentation
屬性,以指示該編譯單元的偵錯資訊條目中存在額外的目標架構特定資訊。 這允許消費者知道偵錯資訊條目中存在哪些擴展,就像其他區段的擴增字串一樣。 請參閱 .
還建議了應該用於擴增字串的格式。 這允許消費者在字串包含來自多個供應商的資訊時解析該字串。 擴增字串出現在 DW_AT_LLVM_augmentation
屬性、按名稱查找表以及 CFI 通用資訊條目 (CIE) 中。
請參閱 A.3.1.1 完整和部分編譯單元條目、A.6.1.1.4.1 區段標頭 和 A.6.4.1 呼叫框架資訊的結構。
2.16 支援嵌入線上編譯的原始碼文字¶
AMDGPU 支援包含線上編譯的程式語言,其中原始碼文字可能會在執行時期建立。 例如,OpenCL 和 HIP 語言執行時期支援線上編譯。 為了支援這一點,提供了一種將原始碼文字嵌入到偵錯資訊中的方法。
請參閱 A.6.2 行號資訊。
2.17 允許 MD5 總和檢查碼為可選存在¶
在 DWARF 第 5 版中,檔案時間戳記和檔案大小可以是可選的,但如果 MD5 總和檢查碼存在,則它對於所有檔案都必須有效。 如果使用連結時間最佳化來組合某些具有 MD5 總和檢查碼而某些沒有的編譯單元,這將會是一個問題。 因此,添加了對允許 MD5 總和檢查碼在行表中可選存在的支援。
請參閱 A.6.2 行號資訊。
2.18 新增 HIP 程式語言¶
添加了 AMDGPU 支援的 HIP 程式語言 [HIP]。
請參閱 語言名稱。
2.19 對於導致並行迭代執行的來源語言最佳化的支援¶
編譯器可以執行迴圈最佳化,從而使生成的程式碼並行執行多個迭代。 例如,軟體管線排程以交錯方式排程多個迭代,以允許一個迭代的指令隱藏另一個迭代的指令的延遲。 另一個範例是向量化,它可以利用 SIMD 硬體來允許單個指令使用向量暫存器執行多個迭代。
請注意,儘管這與 SIMT 執行類似,但用戶端偵錯器使用資訊的方式從根本上不同。 在 SIMT 執行中,偵錯器需要將並行執行呈現為不同的來源語言執行緒,使用者可以列出並在它們之間切換焦點。 對於迭代並行最佳化(例如軟體管線和向量化 SIMD),偵錯器不得將並行性呈現為不同的來源語言執行緒。 相反,它必須告知使用者多個迴圈迭代正在並行執行,並允許使用者在它們之間進行選擇。
一般來說,SIMT 執行固定了每個目標架構執行緒的並行執行次數。 然而,軟體管線和 SIMD 向量化都可能改變單個來源語言執行緒執行的不同迴圈的並行迭代次數。
編譯器可以在單個來源語言執行緒的程式碼中同時使用 SIMT 並行和迭代並行技術。
因此,需要一個 DWARF 操作來表示當前並行迭代實例,很像 DW_OP_push_object_address
表示當前物件。 請參閱 A.2.5.4.3.1 字面值操作 中的 DW_OP_LLVM_push_iteration
。
此外,編譯器需要一種方法來溝通有多少來源語言迴圈迭代正在並行執行。 請參閱 A.3.3.5 低階資訊 中的 DW_AT_LLVM_iterations
。
2.20 用於建立執行時期覆蓋複合位置描述的 DWARF 操作¶
在 SIMD 向量化中,編譯器通常會生成將陣列部分提升到向量暫存器中的程式碼。 例如,如果硬體具有 8 個元素的向量暫存器和 8 個寬度的 SIMD 指令,則編譯器可以向量化迴圈,以便它為每個向量化迴圈迭代並行執行 8 個迭代。
在生成的向量化迴圈的第一次迭代中,來源語言迴圈的迭代 0 到 7 將使用 SIMD 指令執行。 然後,在生成的向量化迴圈的下一次迭代中,將執行迭代 8 到 15,依此類推。
如果來源語言迴圈根據迴圈迭代索引存取陣列元素,則編譯器可能會在該迭代期間將該元素讀取到暫存器中。 下一次迭代它將下一個元素讀取到暫存器中,依此類推。 使用 SIMD,這可以推廣到編譯器在第一個向量化迴圈迭代中將陣列元素 0 到 7 讀取到向量暫存器中,然後在下一次迭代中讀取陣列元素 8 到 15,依此類推。
陣列的 DWARF 位置描述需要表達所有元素都在記憶體中,除了已提升到向量暫存器的切片。 切片的起始位置是一個執行時期值,基於迭代索引模向量化大小。 這不能用 DW_OP_piece
和 DW_OP_bit_piece
來表達,它們僅允許表達常數偏移。
因此,定義了一個新的運算符,它接受兩個位置描述、一個偏移量和一個大小,並創建一個複合位置描述,該複合位置描述有效地將第二個位置描述用作第一個位置描述的覆蓋,並根據偏移量和大小定位。 請參閱 A.2.5.4.4.6 複合位置描述操作 中的 DW_OP_LLVM_overlay
和 DW_OP_LLVM_bit_overlay
。
考慮一個已部分暫存器化的陣列,使得當前處理的元素保存在暫存器中,而陣列的其餘部分保留在記憶體中。 例如,考慮這個 C 函數中的迴圈
1extern void foo(uint32_t dst[], uint32_t src[], int len) {
2 for (int i = 0; i < len; ++i)
3 dst[i] += src[i];
4}
在迴圈體內,機器碼將 src[i]
和 dst[i]
載入到暫存器中,將它們相加,然後將結果儲存回 dst[i]
。
考慮迴圈體中 dst
和 src
的位置,元素 dst[i]
和 src[i]
將位於暫存器中,所有其他元素都位於記憶體中。 假設暫存器 R0
包含 dst
的基底位址,暫存器 R1
包含 i
,暫存器 R2
包含暫存器化的 dst[i]
元素。 我們可以將 dst
的位置描述為記憶體位置,其中暫存器位置覆蓋在涉及 i
的執行時期偏移處
1// 1. Memory location description of dst elements located in memory:
2DW_OP_breg0 0
3
4// 2. Register location description of element dst[i] is located in R2:
5DW_OP_reg2
6
7// 3. Offset of the register within the memory of dst:
8DW_OP_breg1 0
9DW_OP_lit4
10DW_OP_mul
11
12// 4. The size of the register element:
13DW_OP_lit4
14
15// 5. Make a composite location description for dst that is the memory #1 with
16// the register #2 positioned as an overlay at offset #3 of size #4:
17DW_OP_LLVM_overlay
2.21 對來源語言記憶體空間的支援¶
AMDGPU 支援諸如 OpenCL 之類的語言,這些語言定義了來源語言記憶體空間。 添加了對定義語言特定記憶體空間的支援,以便消費者可以一致地使用它們。 請參閱 A.2.14 記憶體空間。
新增了一個新的屬性 DW_AT_LLVM_memory_space
,以支援在定義來源語言指標和參考類型(請參閱 A.5.3 類型修飾符條目)和資料物件分配(請參閱 A.4.1 資料物件條目)中使用記憶體空間。
2.22 表達式操作供應商可擴展性運算碼¶
DWARF 表達式操作的供應商擴展編碼空間僅容納 32 個唯一操作。 實際上,由於缺乏中央註冊表以及對向後相容性的渴望,即使標準版本被 DWARF 正式接受,供應商擴展也永遠不會退役。 這導致了今天可用的新供應商擴展的有效編碼空間微乎其微的情況。
為了擴展這個編碼空間,新增了一個新的 DWARF 操作 DW_OP_LLVM_user
,它充當供應商擴展的「前綴」。 它後面跟著一個 ULEB128 編碼的供應商擴展運算碼,然後是相應供應商擴展操作的運算元。
這種方法允許編碼這些擴展中定義的所有剩餘操作,而不會與現有的供應商擴展衝突。
請參閱 A.2.5.4.0 供應商擴展操作 中的 DW_OP_LLVM_user
。
A. 相對於 DWARF 第 5 版的變更¶
注意
本附錄提供了相對於 DWARF 第 5 版的變更。 它的定義使其向後相容於 DWARF 第 5 版。 非規範性文字以斜體顯示。 除非另有說明,否則章節編號通常與 DWARF 第 5 版標準中的編號對應。 給出了其他操作的定義,以及闡明現有的表達式操作、CFI 操作和屬性如何針對支援位址空間和多個位置的廣義位置描述運作。
新操作、屬性和常數的名稱包含「LLVM
」,並使用供應商特定的程式碼進行編碼,以便這些擴展可以作為 DWARF 第 5 版的 LLVM 供應商擴展來實作。 除了 DW_OP_LLVM_user
之外的新操作都以 DW_OP_LLVM_user
為「前綴」,以便為它們的實作提供足夠的編碼空間。
注意
包含了一些註釋,以描述如何將變更應用於 DWARF 第 5 版標準。 它們還描述了可能需要進一步考慮的基本原理和問題。
A.2 一般描述¶
A.2.2 屬性類型¶
注意
這擴充了 DWARF 第 5 版第 2.2 節和表 2.2。
下表提供了其他屬性。
屬性 |
用法 |
---|---|
|
SIMT 活動通道(請參閱 A.3.3.5 低階資訊) |
|
編譯單元擴增字串(請參閱 A.3.1.1 完整和部分編譯單元條目) |
|
SIMT 通道程式位置(請參閱 A.3.3.5 低階資訊) |
|
SIMT 通道計數(請參閱 A.3.3.5 低階資訊) |
|
並行迭代計數(請參閱 A.3.3.5 低階資訊) |
|
基本類型向量大小(請參閱 A.5.1 基本類型條目) |
|
架構特定位址空間(請參閱 A.2.13 位址空間) |
|
指標或參考類型(請參閱 5.3「類型修飾符條目」)資料物件(請參閱 4.1「資料物件條目」) |
A.2.5 DWARF 表達式¶
注意
本節及其巢狀章節取代了 DWARF 第 5 版第 2.5 節和第 2.6 節。 定義了新的 DWARF 表達式操作擴展,並闡明了對現有 DWARF 第 5 版操作的擴展。 它基於現有 DWARF 第 5 版標準的文字。
DWARF 表達式描述了如何計算值或指定位置。
DWARF 表達式的評估可以提供物件的位置、陣列邊界的值、動態字串的長度、所需的值本身等等。
如果 DWARF 表達式的評估沒有遇到錯誤,那麼它可以產生一個值(請參閱 A.2.5.2 DWARF 表達式值)或一個位置描述(請參閱 A.2.5.3 DWARF 位置描述)。 當評估 DWARF 表達式時,可以指定結果種類是需要值還是位置描述。
如果指定了結果種類,並且評估的結果與指定的結果種類不符,則如果有效,則執行 A.2.5.4.4.3 記憶體位置描述操作 中描述的隱式轉換。 否則,DWARF 表達式格式錯誤。
如果 DWARF 表達式的評估遇到評估錯誤,則結果為評估錯誤。
注意
決定定義評估錯誤的概念。 另一種選擇是以類似於位置描述具有未定義位置描述的方式引入未定義的值基本類型。 然後,遇到評估錯誤的操作可以傳回未定義的位置描述或具有未定義基本類型的值。
如果給定未定義的值,則所有作用於值的操作都將傳回未定義的實體。 然後,表達式將始終評估完成,並且可以進行測試以確定它是否為未定義的實體。
但是,這將增加相當多的額外複雜性,並且與 GDB 在發生這些評估錯誤時拋出異常的情況不符。
如果 DWARF 表達式格式錯誤,則結果未定義。
以下章節詳細說明了 DWARF 表達式何時格式錯誤或導致評估錯誤的規則。
DWARF 表達式可以編碼為操作表達式(請參閱 A.2.5.4 DWARF 操作表達式),或編碼為位置列表表達式(請參閱 A.2.5.5 DWARF 位置列表表達式)。
A.2.5.1 DWARF 表達式評估上下文¶
DWARF 表達式在可以包含多個上下文元素的上下文中評估。 如果指定了多個上下文元素,則它們必須是自洽的,否則評估結果未定義。 可以指定的上下文元素是
當前結果種類
DWARF 表達式評估所需的結果種類。 如果指定,它可以是位置描述或值。
當前執行緒
目標架構執行緒識別符。 對於未使用 SIMT 執行模型實作的來源語言,這對應於使用者呈現的表達式當前正在評估的來源程式執行緒。 對於使用 SIMT 執行模型實作的來源語言,這與當前通道一起對應於使用者呈現的表達式當前正在評估的來源程式執行緒。
對於與目標架構執行緒相關的操作是必需的。
例如,
DW_OP_regval_type
操作,或DW_OP_form_tls_address
和DW_OP_LLVM_form_aspace_address
操作,當給定的位址空間是目標架構執行緒特定的時。
當前通道
在評估使用者呈現的表達式時要使用的基於 0 的 SIMT 通道識別符。 這適用於針對使用 SIMT 執行模型的目標架構實作的來源語言。 這些實作將來源語言執行緒映射到目標架構執行緒的通道。
對於與 SIMT 通道相關的操作是必需的。
例如,
DW_OP_LLVM_push_lane
運算元和DW_OP_LLVM_form_aspace_address
運算元在給定一個 SIMT lane 特定的位址空間時。如果指定,則它必須與對應於上下文框架和程式位置的子程式的
DW_AT_LLVM_lanes
屬性的值一致。如果該值大於或等於 0 且小於DW_AT_LLVM_lanes
屬性的可能預設值,則它是一致的。否則,結果是未定義的。
目前的迭代
要用於評估使用者提供的表達式的從 0 開始的來源語言迭代實例。這適用於支援最佳化功能的目標架構,這些最佳化功能會導致同時執行多個來源語言迴圈迭代。
例如,軟體管線化和 SIMD 向量化。
對於與來源語言迴圈迭代相關的運算元,這是必需的。
例如,
DW_OP_LLVM_push_iteration
運算元。如果指定,則它必須與對應於上下文框架和程式位置的子程式的
DW_AT_LLVM_iterations
屬性的值一致。如果該值大於或等於 0 且小於DW_AT_LLVM_iterations
屬性的可能預設值,則它是一致的。否則,結果是未定義的。
目前的呼叫框架
目標架構呼叫框架識別符。它識別一個呼叫框架,該框架對應於目前執行緒中子程式的活動調用。它由其在呼叫堆疊上的位址識別。該位址稱為標準框架位址 (Canonical Frame Address, CFA)。呼叫框架資訊用於確定目前執行緒呼叫堆疊的呼叫框架的 CFA(請參閱 A.6.4 呼叫框架資訊)。
對於指定目標架構暫存器以支援呼叫堆疊的虛擬解堆疊的運算元,這是必需的。
例如,
DW_OP_*reg*
運算元。如果指定,它必須是目前執行緒中的活動呼叫框架。如果指定了目前的 lane,則該 lane 必須在進入呼叫框架時處於活動狀態(請參閱
DW_AT_LLVM_lane_pc
屬性)。否則,結果是未定義的。如果是目前正在執行的呼叫框架,則稱為頂層呼叫框架。
目前的程式位置
對應於目前執行緒的目前呼叫框架的目標架構程式位置。
頂層呼叫框架的程式位置是目前執行緒的目標架構程式計數器。呼叫框架資訊用於獲取返回位址暫存器的值,以確定其他呼叫框架的程式位置(請參閱 A.6.4 呼叫框架資訊)。
對於評估位置列表達式以在多個程式位置範圍之間進行選擇,這是必需的。對於指定目標架構暫存器以支援呼叫堆疊的虛擬解堆疊的運算元,這是必需的(請參閱 A.6.4 呼叫框架資訊)。
如果指定
如果未指定目前的 lane
如果目前的呼叫框架是頂層呼叫框架,則它必須是目前的目標架構程式位置。
如果目前的呼叫框架 F 不是頂層呼叫框架,則它必須是與目前呼叫者框架 F 中調用被呼叫者框架的呼叫站點相關聯的程式位置。
如果指定了目前的 lane,並且目前的 lane 的
DW_AT_LLVM_lane_pc
屬性計算出的架構程式位置 LPC 不是未定義的位置描述(表示 lane 在進入呼叫框架時未處於活動狀態),則它必須是 LPC。否則,結果是未定義的。
目前的編譯單元
包含正在評估的 DWARF 表達式的編譯單元偵錯資訊條目。
對於參考與同一編譯單元相關聯的偵錯資訊的運算元,包括指示此類參考是否使用 32 位元或 64 位元 DWARF 格式,這是必需的。如果未指定目前的目標架構,它也可以提供預設位址空間位址大小。
例如,
DW_OP_constx
和DW_OP_addrx
運算元。請注意,此編譯單元可能與從對應於目前程式位置的已載入程式碼物件確定的編譯單元不同。例如,與
DW_OP_call*
運算元的偵錯資訊條目運算元的DW_AT_location
屬性相關聯的表達式 E 的評估是使用包含 E 的編譯單元而不是包含DW_OP_call*
運算元表達式的編譯單元來評估的。
目前的目標架構
目標架構。
對於指定目標架構特定實體的運算元,這是必需的。
例如,目標架構特定實體包括 DWARF 暫存器識別符、DWARF lane 識別符、DWARF 位址空間識別符、預設位址空間以及位址空間位址大小。
如果指定
如果指定了目前的框架,則目前的目標架構必須與目前框架的目標架構相同。
如果指定了目前的框架並且是頂層框架,並且如果指定了目前的執行緒,則目前的目標架構必須與目前執行緒的目標架構相同。
如果指定了目前的編譯單元,則目前的目標架構預設位址空間位址大小必須與目前編譯單元標頭中的
address_size
欄位以及.debug_aranges
區段中任何相關聯的條目相同。如果指定了目前的程式位置,則目前的目標架構必須與對應於目前程式位置的任何行號資訊條目(請參閱 A.6.2 行號資訊)的目標架構相同。
如果指定了目前的程式位置,則目前的目標架構預設位址空間位址大小必須與
.debug_addr
、.debug_line
、.debug_rnglists
、.debug_rnglists.dwo
、.debug_loclists
和.debug_loclists.dwo
區段中對應於目前程式位置的任何條目的標頭中的address_size
欄位相同。否則,結果是未定義的。
目前的物件
程式物件的位置描述。
對於
DW_OP_push_object_address
運算元,這是必需的。例如,類型偵錯資訊條目上的
DW_AT_data_location
屬性在評估其相關聯的表達式時,將對應於執行時間描述符的程式物件指定為目前的物件。如果位置描述無效(請參閱 A.2.5.3 DWARF 位置描述),則結果是未定義的。
初始堆疊
這是值或位置描述的列表,在開始評估運算元表達式之前,這些值或位置描述將按照提供的順序被推送到運算元表達式評估堆疊上。
某些偵錯資訊條目具有使用初始堆疊條目評估其 DWARF 表達式值的屬性。在所有其他情況下,初始堆疊為空。
如果任何位置描述無效(請參閱 A.2.5.3 DWARF 位置描述),則結果是未定義的。
如果評估需要未指定的上下文元素,則評估結果為錯誤。
位置描述的 DWARF 表達式可能能夠在沒有執行緒、lane、呼叫框架、程式位置或架構上下文的情況下進行評估。例如,全域變數的位置可能能夠在沒有此類上下文的情況下進行評估。如果表達式評估結果為錯誤,則可能表示變數已最佳化,因此需要更多上下文。
呼叫框架資訊的 DWARF 表達式(請參閱 A.6.4 呼叫框架資訊)運算元僅限於那些不需要指定編譯單元上下文的運算元。
如果與任何給定程式位置對應的 .debug_info
、.debug_addr
、.debug_line
、.debug_rnglists
、.debug_rnglists.dwo
、.debug_loclists
和 .debug_loclists.dwo
區段中所有條目的標頭中的所有 address_size
欄位不匹配,則 DWARF 格式不正確。
A.2.5.2 DWARF 表達式值¶
一個值具有類型和常值。它可以表示目標架構任何支援的基礎類型的常值。基礎類型指定常值的 size、編碼和 endianity。
注意
可能需要新增隱含指標基礎類型編碼。它將用於當 DW_OP_deref*
運算元檢索由 DW_OP_implicit_pointer
或 DW_OP_LLVM_aspace_implicit_pointer
運算元建立的隱含指標位置儲存的完整內容時產生的值的類型。常值將記錄相關聯的 DW_OP_implicit_pointer
或 DW_OP_LLVM_aspace_implicit_pointer
運算元指定的偵錯資訊條目和位元組位移。
有一個稱為泛型類型的獨特基礎類型,它是一種整數類型,其大小與目標架構預設位址空間中的位址大小相同,目標架構定義的 endianity,以及未指定的符號性。
泛型類型與 DWARF 版本 4 及更早版本中定義的堆疊運算元使用的未指定類型相同。
整數類型是一種基礎類型,其編碼為 DW_ATE_signed
、DW_ATE_signed_char
、DW_ATE_unsigned
、DW_ATE_unsigned_char
、DW_ATE_boolean
或在包含範圍 DW_ATE_lo_user
到 DW_ATE_hi_user
內的任何目標架構定義的整數編碼。
注意
目前尚不清楚 DW_ATE_address
是否為整數類型。GDB 似乎不認為它是整數類型。
A.2.5.3 DWARF 位置描述¶
偵錯資訊必須為消費者提供一種方法來尋找程式變數的位置、確定動態陣列和字串的邊界,並可能找到子程式呼叫框架的基礎位址或子程式的返回位址。此外,為了滿足最新電腦架構和最佳化技術的需求,偵錯資訊必須能夠描述物件的位置,該物件的位置在其生命週期內會發生變化,並且在物件生命週期的某些部分可能同時駐留在多個位置。
關於程式物件位置的資訊由位置描述提供。
位置描述可以包含一個或多個單一位置描述。
單一位置描述指定保存程式物件的位置儲存以及程式物件開始的位置儲存內的位置。位置儲存內的位置表示為相對於位置儲存開始位置的位元偏移。
位置儲存是一個可以保存值的線性位元流。每個位置儲存都有一個以位元為單位的 size,並且可以使用從零開始的位元偏移來存取。位置儲存內位元的排序使用適用於目標架構上目前語言的位元編號和方向慣例。
位置儲存有五種類型
- 記憶體位置儲存
對應於目標架構記憶體位址空間。
- 暫存器位置儲存
對應於目標架構暫存器。
- 隱含位置儲存
對應於只能讀取的固定值。
- 未定義位置儲存
表示沒有可用的值,因此無法讀取或寫入。
- 複合位置儲存
允許這些位置儲存的混合,其中一些位元來自一個位置儲存,而另一些位元來自另一個位置儲存,或來自同一位置儲存的不相交部分。
注意
最好新增一個隱含指標位置儲存類型,供 DW_OP_implicit_pointer
和 DW_OP_LLVM_aspace_implicit_pointer
運算元使用。它將指定運算元提供的偵錯資訊條目和位元組偏移。
位置描述是定址規則的語言獨立表示形式。
它們可以是評估偵錯資訊條目屬性的結果,該屬性指定任意複雜度的運算元表達式。在此用法中,它們可以描述物件的位置,只要物件的生命週期是靜態的,或者與擁有它的詞法區塊(請參閱 :ref:`amdgpu-dwarf-lexical-block-entries`)相同,並且在物件的生命週期內不會移動。
它們可以是評估偵錯資訊條目屬性的結果,該屬性指定位置列表達式。在此用法中,它們可以描述具有有限生命週期、在其生命週期內更改其位置或在其生命週期的部分或全部時間內具有多個位置的物件的位置。
如果位置描述有多個單一位置描述,則如果每個單一位置描述的位置儲存內的位置中保存的物件值不是相同的值(未初始化的值部分除外),則 DWARF 表達式格式不正確。
具有多個單一位置描述的位置描述只能由具有重疊程式位置範圍的位置列表達式或對具有多個單一位置描述的位置描述起作用的某些表達式運算元來建立。沒有可以直接建立具有多個單一位置描述的位置描述的運算元表達式運算元。
具有多個單一位置描述的位置描述可用於描述同時駐留在多個儲存區的物件。物件可能由於最佳化而有多個位置。例如,僅讀取的值可能會從記憶體提升到程式碼的某些區域的暫存器,但稍後的程式碼可能會恢復從記憶體讀取該值,因為該暫存器可能用於其他目的。對於值位於暫存器的程式碼區域,對物件值的任何更改都必須在暫存器和記憶體中進行,以便兩個程式碼區域都將讀取更新後的值。
具有多個單一位置描述的位置描述的消費者可以從任何單一位置描述中讀取物件的值(因為它們都參考具有相同值的位置儲存),但必須將任何更改的值寫入所有單一位置描述。
表達式的評估可能需要上下文元素來建立位置描述。如果存取了這樣的位置描述,則它表示的儲存是與建立位置描述時指定的上下文元素值相關聯的儲存,這可能與存取時的上下文不同。
例如,建立暫存器位置描述需要執行緒上下文:位置儲存是用於該執行緒的指定暫存器的儲存。為位址空間建立記憶體位置描述可能需要執行緒和 lane 上下文:位置儲存是與該執行緒和 lane 相關聯的記憶體。
如果建立位置描述所需的任何上下文元素發生更改,則位置描述將變為無效,並且存取它是未定義的。
可能使位置描述無效的上下文範例包括
需要執行緒上下文,並且執行導致執行緒終止。
需要呼叫框架上下文,並且進一步執行導致呼叫框架返回到呼叫框架。
需要程式位置,並且執行緒的進一步執行發生。這可能會更改適用的位置列表條目或呼叫框架資訊條目。
運算元使用呼叫框架資訊
虛擬呼叫框架解堆疊中使用的任何框架返回。
使用頂層呼叫框架,程式位置用於選擇呼叫框架資訊條目,並且執行緒的進一步執行發生。
DWARF 表達式可用於計算物件的位置描述。隨後的 DWARF 表達式評估可以給定物件位置描述作為物件上下文或初始堆疊上下文,以計算物件的元件。如果物件位置描述在兩個表達式評估之間變為無效,則最終結果是未定義的。
執行緒的程式位置的更改可能不會使位置描述無效,但可能仍然使其不再有意義。存取此類位置描述,或將其用作表達式評估的物件上下文或初始堆疊上下文,可能會產生未定義的結果。
例如,位置描述可能指定一個暫存器,該暫存器在程式位置更改後不再保存預期的程式物件。避免此類問題的一種方法是在執行緒的程式位置更改時重新計算與執行緒相關聯的位置描述。
A.2.5.4 DWARF 運算元表達式¶
運算元表達式由運算元流組成,每個運算元都包含一個運算碼,後跟零或多個運算元。運算元的數量由運算碼隱含。
運算元表示簡單堆疊機器上的後綴運算元。每個堆疊條目都可以保存值或位置描述。運算元可以對堆疊上的條目執行運算,包括新增條目和移除條目。如果堆疊條目的種類與運算元所需的種類不符,並且不能隱式轉換為所需的種類(請參閱 A.2.5.4.4.3 記憶體位置描述運算元),則 DWARF 運算元表達式格式不正確。
運算元表達式的評估從空堆疊開始,上下文提供的初始堆疊中的條目按照提供的順序被推送到空堆疊上。然後評估運算元,從運算元流的第一個運算元開始。評估持續進行,直到運算元出現評估錯誤,或直到到達運算元流的最後一個運算元之後的一個位置。
評估的結果是
如果運算元出現評估錯誤,或運算元評估的表達式出現評估錯誤,則結果為評估錯誤。
如果目前的結果種類指定位置描述,則
如果堆疊為空,則結果為具有一個未定義位置描述的位置描述。
此規則是為了向後相容 DWARF 版本 5,DWARF 版本 5 沒有用於建立未定義位置描述的顯式運算元,並且為此目的使用了空運算元表達式。
如果頂層堆疊條目是位置描述,或可以轉換為位置描述(請參閱 A.2.5.4.4.3 記憶體位置描述運算元),則結果是該位置描述(可能已轉換)。堆疊上的任何其他條目都將被丟棄。
否則,DWARF 表達式格式不正確。
注意
可以將此情況定義為傳回隱含位置描述,就像執行了
DW_OP_implicit
運算元一樣。
如果目前的結果種類指定值,則
如果頂層堆疊條目是值,或可以轉換為值(請參閱 A.2.5.4.4.3 記憶體位置描述運算元),則結果是該值(可能已轉換)。堆疊上的任何其他條目都將被丟棄。
否則,DWARF 表達式格式不正確。
如果未指定目前的結果種類,則
如果堆疊為空,則結果為具有一個未定義位置描述的位置描述。
此規則是為了向後相容 DWARF 版本 5,DWARF 版本 5 沒有用於建立未定義位置描述的顯式運算元,並且為此目的使用了空運算元表達式。
注意
此規則與上面針對請求位置描述時的規則一致。但是,GDB 似乎將此報告為錯誤,並且沒有 GDB 測試似乎會導致在這種情況下堆疊為空。
否則,將傳回頂層堆疊條目。堆疊上的任何其他條目都將被丟棄。
運算元表達式編碼為位元組區塊,帶有某種形式的前綴,用於指定位元組計數。它可以
用作使用類別
exprloc
編碼的偵錯資訊條目屬性的值(請參閱 A.7.5.5 類別和格式),用作某些運算元表達式運算元的運算元,
用作某些呼叫框架資訊運算元的運算元(請參閱 A.6.4 呼叫框架資訊),
以及在位置列表條目中(請參閱 A.2.5.5 DWARF 位置列表達式)。
A.2.5.4.0 供應商擴充運算元¶
DW_OP_LLVM_user
DW_OP_LLVM_user
編碼供應商擴充運算元。它至少有一個運算元:一個 ULEB128 常數,用於識別供應商擴充運算元。剩餘的運算元由供應商擴充定義。供應商擴充運算碼 0 是保留的,任何供應商擴充都不能使用。DW_OP_user 編碼空間可以理解為補充由 DW_OP_lo_user 和 DW_OP_hi_user 定義的空間,標準為相同的目的分配了該空間。
A.2.5.4.1 堆疊運算元¶
注意
本節取代 DWARF 版本 5 第 2.5.1.3 節。
以下運算元操作 DWARF 堆疊。索引堆疊的運算元假設堆疊頂層(最近新增的條目)的索引為 0。它們允許堆疊條目為值或位置描述。
如果堆疊運算元存取的任何堆疊條目是不完整的複合位置描述(請參閱 A.2.5.4.4.6 複合位置描述運算元),則 DWARF 表達式格式不正確。
注意
這些運算元現在支援作為值和位置描述的堆疊條目。
注意
如果也希望它們與不完整的複合位置描述一起使用,則需要定義在推送副本時也複製由不完整的複合位置描述指定的複合位置儲存。這確保了不完整的複合位置描述的每個副本都可以獨立更新它們指定的複合位置儲存。
DW_OP_dup
DW_OP_dup
複製堆疊頂層的堆疊條目。DW_OP_drop
DW_OP_drop
彈出堆疊頂層的堆疊條目並丟棄它。DW_OP_pick
DW_OP_pick
有一個單一位元組無符號運算元,表示索引 I。索引為 I 的堆疊條目的副本被推送到堆疊上。DW_OP_over
DW_OP_over
推送索引為 1 的條目的副本。這等效於
DW_OP_pick 1
運算元。DW_OP_swap
DW_OP_swap
交換頂層的兩個堆疊條目。堆疊頂層的條目變為第二個堆疊條目,第二個堆疊條目變為堆疊頂層。DW_OP_rot
DW_OP_rot
旋轉前三個堆疊條目。堆疊頂層的條目變為第三個堆疊條目,第二個條目變為堆疊頂層,第三個條目變為第二個條目。
說明許多這些堆疊運算元的範例可在第 289 頁的附錄 D.1.2 中找到。
A.2.5.4.2 控制流程運算元¶
注意
本節取代 DWARF 版本 5 第 2.5.1.5 節。
以下運算元提供對 DWARF 運算元表達式流程的簡單控制。
DW_OP_nop
DW_OP_nop
是一個佔位符。它對 DWARF 堆疊條目沒有影響。DW_OP_le
、DW_OP_ge
、DW_OP_eq
、DW_OP_lt
、DW_OP_gt
、DW_OP_ne
注意
與 DWARF 版本 5 第 2.5.1.5 節相同。
DW_OP_skip
DW_OP_skip
是一個無條件分支。它的單一運算元是一個 2 位元組帶符號整數常數。2 位元組常數是要從目前運算元向前或向後跳過的 DWARF 表達式的位元組數,從 2 位元組常數之後開始。如果更新後的位置在最後一個運算元之後的一個位置,則運算元表達式評估完成。
否則,如果更新的操作位置不在包含第一個到最後一個操作的範圍內,或不是在操作的開始位置,則 DWARF 表達式格式不正確。
DW_OP_bra
DW_OP_bra
是一個條件分支。它唯一的運算元是一個 2 位元組的有號整數常數。此操作會彈出堆疊頂端的值。如果彈出的值不是常數 0,則 2 位元組常數運算元是 DWARF 操作表達式要從當前操作向前或向後跳過的位元組數,從 2 位元組常數之後開始計算。如果更新後的位置在最後一個運算元之後的一個位置,則運算元表達式評估完成。
否則,如果更新的操作位置不在包含第一個到最後一個操作的範圍內,或不是在操作的開始位置,則 DWARF 表達式格式不正確。
DW_OP_call2, DW_OP_call4, DW_OP_call_ref
DW_OP_call2
、DW_OP_call4
和DW_OP_call_ref
在評估 DWARF 操作表達式期間執行 DWARF 程序呼叫。DW_OP_call2
和DW_OP_call4
各自有一個運算元,分別是 2 位元組或 4 位元組的無號偏移量 DR,它表示相對於當前編譯單元起始位置的偵錯資訊條目 D 的位元組偏移量。DW_OP_call_ref
有一個運算元,它是在 32 位元 DWARF 格式中的 4 位元組無號值,或是在 64 位元 DWARF 格式中的 8 位元組無號值,它表示相對於包含當前編譯單元的.debug_info
區段起始位置的偵錯資訊條目 D 的位元組偏移量 DR。D 可能不在當前編譯單元中。注意
DWARF 版本 5 聲明 DR 可以是在
.debug_info
區段中的偏移量,而不是包含當前編譯單元的區段。它聲明從一個可執行檔或共享物件檔案到另一個檔案的參考重定位必須由消費者執行。但是,鑑於 DR 被定義為.debug_info
區段中的偏移量,這似乎是不可能的。如果 DR 被定義為實作定義的值,那麼消費者可以選擇以實作定義的方式解釋該值,以參考另一個可執行檔或共享物件中的偵錯資訊。在 ELF 中,
.debug_info
區段位於非PT_LOAD
區段中,因此無法使用標準動態重定位。但是,即使它們是已載入的區段且使用了動態重定位,DR 也需要是 D 的位址,而不是.debug_info
區段中的偏移量。這也需要 DR 具有全域位址的大小。因此,在 64 位元全域位址空間中,不可能使用 32 位元 DWARF 格式。此外,消費者需要確定重定位的位址位於哪個可執行檔或共享物件中,以便它可以確定包含的編譯單元。GDB 僅將 DR 解釋為包含當前編譯單元的
.debug_info
區段中的偏移量。此註解也適用於
DW_OP_implicit_pointer
和DW_OP_LLVM_aspace_implicit_pointer
。DW_OP_call2
、DW_OP_call4
和DW_OP_call_ref
的運算元解釋與DW_FORM_ref2
、 ``DW_FORM_ref4``* 和DW_FORM_ref_addr
的運算元解釋完全相同。呼叫操作的評估方式如下:
如果 D 具有
DW_AT_location
屬性,該屬性編碼為exprloc
,指定操作表達式 E,則當前操作表達式的執行會從 E 的第一個操作繼續。執行會持續到到達 E 的最後一個操作之後,此時執行會繼續執行呼叫操作之後的操作。E 的操作在相同的當前內容中評估,除了當前編譯單元是包含 D 的單元,並且堆疊與呼叫操作使用的堆疊相同。在評估呼叫操作之後,堆疊因此與 E 的操作評估後的狀態相同。由於 E 是在與呼叫操作相同的堆疊上評估的,因此 E 可以使用和/或移除堆疊上已有的條目,並且可以向堆疊新增新的條目。呼叫時堆疊上的值可以被呼叫的表達式用作參數,而呼叫的表達式留在堆疊上的值可以通過呼叫和被呼叫表達式之間的先前協議用作傳回值。
如果 D 具有
DW_AT_location
屬性,該屬性編碼為loclist
或loclistsptr
,則評估指定的位置列表表達式 E。E 的評估使用當前內容,除了結果類型是位置描述,編譯單元是包含 D 的單元,且初始堆疊為空。位置描述結果會被推入堆疊。注意
此規則避免了必須定義如何在與呼叫相同的堆疊上執行匹配的位置列表條目操作表達式(當有多個匹配項時)。但它允許呼叫取得變數或形式參數的位置描述,這些變數或形式參數可能會使用位置列表表達式。
另一種替代方案是將 D 具有
DW_AT_location
屬性(編碼為loclist
或loclistsptr
)的情況,以及指定的位置列表表達式 E' 匹配具有操作表達式 E 的單個位置列表條目的情況,視為與exprloc
情況相同,並在相同的堆疊上評估。但這沒有吸引力,因為如果屬性是針對一個碰巧以非單例堆疊結尾的變數,它將不會僅僅在堆疊上放置位置描述。據推測,在變數或形式參數偵錯資訊條目上使用
DW_OP_call*
的目的是僅在堆疊上推入一個位置描述。該位置描述可能有多個單個位置描述。先前針對
exprloc
的規則也存在相同的問題,因為通常變數或形式參數位置表達式可能會在堆疊上留下多個條目,並且僅傳回頂端條目。GDB 透過始終在相同的堆疊上執行 E 來實作
DW_OP_call*
。如果位置列表有多個匹配的條目,它只會選擇第一個並忽略其餘的。這似乎從根本上與支援變數多個位置的願望相悖。因此,感覺
DW_OP_call*
應該同時支援在堆疊上推入變數或形式參數的位置描述,以及支援能夠在相同的堆疊上執行操作表達式。能夠為不同的程式位置指定不同的操作表達式似乎是一個值得保留的功能。對此的一個解決方案是為
DW_TAG_dwarf_procedure
偵錯資訊條目提供一個不同的DW_AT_LLVM_proc
屬性。然後,DW_AT_location
屬性表達式始終單獨執行,並推入位置描述(可能有多個單個位置描述),而DW_AT_LLVM_proc
屬性表達式始終在相同的堆疊上執行,並且可以在堆疊上留下任何內容。DW_AT_LLVM_proc
屬性可以具有新的類別exprproc
、loclistproc
和loclistsptrproc
,以指示表達式在相同的堆疊上執行。exprproc
與exprloc
的編碼相同。loclistproc
和loclistsptrproc
與其非proc
對應項的編碼相同,除非位置列表未完全匹配一個位置列表條目並且需要預設條目,否則 DWARF 格式不正確。這些形式明確指示匹配的單個操作表達式必須在相同的堆疊上執行。這比針對loclistproc
和loclistsptrproc
的臨時特殊規則更好,這些規則目前明確定義為始終傳回位置描述。然後,產生器透過屬性類別明確指示意圖。對於 GDB 如何實作
DW_OP_call*
而言,這種變更將會是重大變更。但是,實際情況中是否真的發生了重大變更案例?GDB 可以針對 DWARF 版本 5 實作目前的方法,並針對 DWARF 版本 6 實作新的語意,這已針對其他一些功能完成。另一種選擇是將執行限制為僅在相同的堆疊上,以評估表達式 E,該表達式 E 是
DW_TAG_dwarf_procedure
偵錯資訊條目的DW_AT_location
屬性的值。如果 E 是不完全匹配一個位置列表條目的位置列表表達式,則 DWARF 格式不正確。在所有其他情況下,評估表達式 E(它是DW_AT_location
屬性的值)將在當前內容中評估 E,除了結果類型是位置描述,編譯單元是包含 D 的單元,且初始堆疊為空。位置描述結果會被推入堆疊。如果 D 具有值為 V 的
DW_AT_const_value
屬性,則如同執行了DW_OP_implicit_value V
操作一樣。這允許使用呼叫操作來計算任何變數或形式參數的位置描述,無論產生器是否已將其最佳化為常數。這與
DW_OP_implicit_pointer
操作一致。注意
或者,可以棄用針對常數的
DW_TAG_variable
和DW_TAG_formal_parameter
偵錯資訊條目使用DW_AT_const_value
,而是改用DW_AT_location
以及操作表達式,該表達式會產生具有一個隱含位置描述的位置描述。那麼就不需要此規則。否則,不會產生任何影響,並且堆疊也不會進行任何變更。
注意
在 DWARF 版本 5 中,如果 D 沒有
DW_AT_location
,則DW_OP_call*
定義為無效。目前尚不清楚這是否是正確的定義,因為產生器應該能夠依賴使用DW_OP_call*
來取得任何非DW_TAG_dwarf_procedure
偵錯資訊條目的位置描述。此外,產生器不應建立針對沒有DW_AT_location
屬性的DW_TAG_dwarf_procedure
的DW_OP_call*
的 DWARF。因此,這種情況是否應該定義為格式不正確的 DWARF 表達式?
DW_TAG_dwarf_procedure
偵錯資訊條目可以用於定義可以呼叫的 DWARF 程序。
A.2.5.4.3 值操作¶
本節描述將值推入堆疊的操作。
每個值堆疊條目都有一個類型和一個文字值。它可以表示目標架構任何支援的基礎類型的文字值。基礎類型指定文字值的大小、編碼和位元組序。
值堆疊條目的基礎類型可以是區分的泛型類型。
A.2.5.4.3.1 文字操作¶
注意
本節取代 DWARF 版本 5 第 2.5.1.1 節。
以下操作都會將文字值推入 DWARF 堆疊。
除了 DW_OP_const_type
之外的操作都會推送具有泛型類型的值 V。如果 V 大於泛型類型,則 V 會被截斷為泛型類型大小,並使用低位元。
DW_OP_lit0
、DW_OP_lit1
、 …、DW_OP_lit31
DW_OP_lit<N>
操作會編碼從 0 到 31(含)的無號文字值 N。它們會推送具有泛型類型的值 N。DW_OP_const1u
、DW_OP_const2u
、DW_OP_const4u
、DW_OP_const8u
DW_OP_const<N>u
操作有一個運算元,分別是 1、2、4 或 8 位元組的無號整數常數 U。它們會推送具有泛型類型的值 U。DW_OP_const1s
、DW_OP_const2s
、DW_OP_const4s
、DW_OP_const8s
DW_OP_const<N>s
操作有一個運算元,分別是 1、2、4 或 8 位元組的有號整數常數 S。它們會推送具有泛型類型的值 S。DW_OP_constu
DW_OP_constu
有一個無號 LEB128 整數運算元 N。它會推送具有泛型類型的值 N。DW_OP_consts
DW_OP_consts
有一個有號 LEB128 整數運算元 N。它會推送具有泛型類型的值 N。DW_OP_constx
DW_OP_constx
有一個無號 LEB128 整數運算元,它表示相對於關聯編譯單元的DW_AT_addr_base
屬性值的.debug_addr
區段中從零開始的索引。.debug_addr
區段中的值 N 具有泛型類型的大小。它會推送具有泛型類型的值 N。提供
DW_OP_constx
操作是為了用於需要連結時間重定位的常數,但不應被消費者解釋為可重定位的位址(例如,執行緒本機儲存的偏移量)。DW_OP_const_type
DW_OP_const_type
有三個運算元。第一個是無號 LEB128 整數 DR,它表示相對於當前編譯單元起始位置的偵錯資訊條目 D 的位元組偏移量,該條目提供常數值 T 的類型。第二個是 1 位元組的無號整數常數 S。第三個是位元組區塊 B,其長度等於 S。TS 是類型 T 的位元大小。B 的最低有效 TS 位元被解釋為類型 D 的值 V。它會推送具有類型 D 的值 V。
如果 D 不是當前編譯單元中的
DW_TAG_base_type
偵錯資訊條目,或者如果 TS 除以 8(位元組大小)並向上捨入為整數不等於 S,則 DWARF 格式不正確。雖然位元組區塊 B 的大小可以從類型 D 定義推斷出來,但它被明確編碼到操作中,以便可以在不參考
.debug_info
區段的情況下輕鬆剖析操作。DW_OP_LLVM_push_lane
新增DW_OP_LLVM_push_lane
將當前通道作為具有泛型類型的值推送。對於使用 SIMT 執行模型實作的來源語言,這是從零開始的通道號碼,對應於使用者關注的來源語言執行緒。
該值必須大於或等於 0 且小於
DW_AT_LLVM_lanes
屬性的值,否則 DWARF 表達式格式不正確。請參閱 A.3.3.5 低階資訊。DW_OP_LLVM_push_iteration
新增DW_OP_LLVM_push_iteration
將當前迭代作為具有泛型類型的值推送。對於具有最佳化功能的來源語言實作(這些最佳化功能會導致多個迴圈迭代同時執行),這是從零開始的迭代號碼,對應於使用者關注的來源語言並行迴圈迭代。
該值必須大於或等於 0 且小於
DW_AT_LLVM_iterations
屬性的值,否則 DWARF 表達式格式不正確。請參閱 A.3.3.5 低階資訊。
A.2.5.4.3.2 算術和邏輯運算¶
注意
本節與 DWARF 版本 5 第 2.5.1.4 節相同。
A.2.5.4.3.3 類型轉換運算¶
注意
本節與 DWARF 版本 5 第 2.5.1.6 節相同。
A.2.5.4.3.4 特殊值運算¶
注意
本節取代 DWARF 版本 5 第 2.5.1.2 節、2.5.1.3 節和 2.5.1.7 節的部分內容。
目前已定義以下這些特殊值運算
DW_OP_regval_type
DW_OP_regval_type
有兩個運算元。第一個是無號 LEB128 整數,表示暫存器號碼 R。第二個是無號 LEB128 整數 DR,表示相對於當前編譯單元起始位置的偵錯資訊條目 D 的位元組偏移量,該條目提供暫存器值 T 的類型。此操作等效於執行
DW_OP_regx R; DW_OP_deref_type DR
。注意
DWARF 是否應該允許類型 T 的大小大於暫存器 R 的大小?限制更大的位元大小可以避免任何轉換問題,因為暫存器(可能被截斷)的位元內容會被簡單地解釋為類型 T 的值。如果需要轉換,可以使用
DW_OP_convert
操作顯式完成。GDB 具有每個暫存器的掛鉤,允許在每個暫存器的基礎上進行目標特定的轉換。預設情況下,它會截斷較大的暫存器。移除目標掛鉤的使用不會導致常見架構中的任何測試失敗。如果目標架構的編譯器確實需要某種形式的轉換(包括更大的結果類型),它可以始終顯式使用
DW_OP_convert
操作。如果 T 是大於暫存器大小的類型,則預設的 GDB 暫存器掛鉤會從下一個暫存器讀取位元組(或讀取最後一個暫存器的界限之外!)。移除目標掛鉤的使用不會導致常見架構中的任何測試失敗(除了非法的手寫組合語言測試)。如果目標架構需要此行為,這些擴充功能允許使用複合位置描述來組合多個暫存器。
DW_OP_deref
S 是泛型類型的位元大小除以 8(位元組大小)並向上捨入為整數的值。DR 是假設的偵錯資訊條目 D 在當前編譯單元中針對泛型類型基礎類型的偏移量。
此操作等效於執行
DW_OP_deref_type S, DR
。DW_OP_deref_size
DW_OP_deref_size
有一個 1 位元組的無號整數常數,表示位元組結果大小 S。TS 是泛型類型位元大小與 S 乘以 8(位元組大小)中較小的值。如果 TS 小於泛型類型位元大小,則 T 是位元大小為 TS 的無號整數類型,否則 T 是泛型類型。DR 是假設的偵錯資訊條目 D 在當前編譯單元中針對基礎類型 T 的偏移量。
注意
當 S 大於泛型類型時,截斷值與 GDB 的行為一致。這允許泛型類型大小不是整數位元組大小。它確實允許 S 任意大。S 是否應限制為捨入為 8 的倍數的泛型類型大小?
此操作等效於執行
DW_OP_deref_type S, DR
,除非 T 不是泛型類型,否則推送的值 V 會零擴展到泛型類型位元大小,並且其類型會變更為泛型類型。DW_OP_deref_type
DW_OP_deref_type
有兩個運算元。第一個是 1 位元組的無號整數常數 S。第二個是無號 LEB128 整數 DR,表示相對於當前編譯單元起始位置的偵錯資訊條目 D 的位元組偏移量,該條目提供結果值 T 的類型。TS 是類型 T 的位元大小。
雖然推送的值 V 的大小可以從類型 T 推斷出來,但它被明確編碼為運算元 S,以便可以在不參考
.debug_info
區段的情況下輕鬆剖析操作。注意
目前尚不清楚為什麼需要運算元 S。與
DW_OP_const_type
不同,剖析不需要大小。任何評估都需要取得基礎類型 T 以與值一起推送,以了解其編碼和位元大小。它會彈出一個堆疊條目,該條目必須是位置描述 L。
從 L 的單個位置描述 SL 之一指定的位置儲存 LS 檢索 TS 位元的值 V。
如果 L 或作為 L 子元件的任何複合位置描述部分的位置描述有多個單個位置描述,則可以選擇其中任何一個,因為它們都必須具有相同的值。對於任何單個位置描述 SL,位元會從與 SL 指定的位元偏移量開始的關聯儲存位置檢索。對於複合位置描述,檢索到的位元是每個複合位置部分 PL 的 N 個位元的串連,其中 N 限制為 PL 的大小。
V 會與類型 T 一起推入堆疊。
注意
如果 L 是暫存器位置描述,且暫存器儲存中剩餘的位元少於 TS 位元,則此定義使其成為評估錯誤。特別是因為這些擴充功能擴充了位置描述以具有位元偏移量,因此將其定義為根據類型執行符號擴充或依賴目標架構將會很奇怪,因為剩餘位元的數量可以是任何數字。這與 GDB 針對
DW_OP_deref_type
的實作相符。這些擴充功能根據
DW_OP_regval_type
定義DW_OP_*breg*
。DW_OP_regval_type
根據DW_OP_regx
(使用 0 位元偏移量)和DW_OP_deref_type
定義。因此,它要求暫存器大小大於或等於位址空間的位址大小。這與 GDB 針對DW_OP_*breg*
的實作相符。如果 D 不在當前編譯單元中,D 不是
DW_TAG_base_type
偵錯資訊條目,或者如果 TS 除以 8(位元組大小)並向上捨入為整數不等於 S,則 DWARF 格式不正確。注意
此定義允許基礎類型為位元大小,因為似乎沒有理由限制它。
如果從未定義的位置儲存檢索到值的任何位元,或者任何位元的偏移量超過 L 的任何單個位置描述 SL 指定的位置儲存 LS 的大小,則會發生評估錯誤。
有關
DW_OP_implicit_pointer
和DW_OP_LLVM_aspace_implicit_pointer
操作建立的隱含位置描述的特殊規則,請參閱 A.2.5.4.4.5 隱含位置描述操作。DW_OP_xderef
已棄用DW_OP_xderef
會彈出兩個堆疊條目。第一個必須是表示位址 A 的整數類型值。第二個必須是表示目標架構特定的位址空間識別碼 AS 的整數類型值。此操作等效於執行
DW_OP_swap; DW_OP_LLVM_form_aspace_address; DW_OP_deref
。檢索到的值 V 會與泛型類型一起留在堆疊上。此操作已棄用,因為可以使用
DW_OP_LLVM_form_aspace_address
操作,並且它提供更大的表達能力。DW_OP_xderef_size
已棄用DW_OP_xderef_size
有一個 1 位元組的無號整數常數,表示位元組結果大小 S。它會彈出兩個堆疊條目。第一個必須是表示位址 A 的整數類型值。第二個必須是表示目標架構特定的位址空間識別碼 AS 的整數類型值。
此操作等效於執行
DW_OP_swap; DW_OP_LLVM_form_aspace_address; DW_OP_deref_size S
。檢索到的零擴展值 V 會與泛型類型一起留在堆疊上。此操作已棄用,因為可以使用
DW_OP_LLVM_form_aspace_address
操作,並且它提供更大的表達能力。DW_OP_xderef_type
已棄用DW_OP_xderef_type
有兩個運算元。第一個是 1 位元組的無號整數常數 S。第二個運算元是無號 LEB128 整數 DR,表示相對於當前編譯單元起始位置的偵錯資訊條目 D 的位元組偏移量,該條目提供結果值 T 的類型。它會彈出兩個堆疊條目。第一個必須是表示位址 A 的整數類型值。第二個必須是表示目標架構特定的位址空間識別碼 AS 的整數類型值。
此操作等效於執行
DW_OP_swap; DW_OP_LLVM_form_aspace_address;
DW_OP_deref_type S DR
。檢索到的值 V 會與類型 T 一起留在堆疊上。此操作已棄用,因為可以使用
DW_OP_LLVM_form_aspace_address
操作,並且它提供更大的表達能力。DW_OP_entry_value
已棄用DW_OP_entry_value
會推送在呼叫框架的上下文中評估的表達式的值。它可用於判斷輸入到當前呼叫框架的引數值,前提是這些引數未被覆寫。
它有兩個運算元。第一個是無號 LEB128 整數 S。第二個是位元組區塊,長度等於 S,被解釋為 DWARF 運算式 E。
E 會在目前的上下文環境中求值,但結果類型未指定,調用幀是調用目前幀的那個幀,程式位置是調用幀中的調用站點,物件未指定,且初始堆疊為空。調用幀資訊是透過虛擬地展開目前調用幀並使用調用幀資訊來取得的(請參閱 A.6.4 調用幀資訊)。
如果 E 的結果是位置描述 L(請參閱 A.2.5.4.4.4 暫存器位置描述運算),且 E 執行的最後一個運算是針對暫存器 R 且具有目標架構特定基本類型 T 的
DW_OP_reg*
,則會檢索暫存器的內容,如同執行了DW_OP_deref_type DR
運算一樣,其中 DR 是類型 T 在目前編譯單元中假設的除錯資訊條目的偏移量。產生的值 V 會被推送到堆疊上。使用
DW_OP_reg*
對於值在進入子程式時已在暫存器中的情況,提供了更精簡的形式。注意
目前尚不清楚這如何提供更精簡的運算式,因為可以使用
DW_OP_regval_type
,而這只稍微大一些。如果 E 的結果是值 V,則 V 會被推送到堆疊上。
否則,DWARF 運算式格式不正確。
DW_OP_entry_value
運算已被棄用,因為其主要用途已由其他方式提供。DWARF 版本 5 新增了用於調用站點的DW_TAG_call_site_parameter
除錯資訊條目,其具有DW_AT_call_value
、DW_AT_call_data_location
和DW_AT_call_data_value
屬性,這些屬性提供了 DWARF 運算式來計算調用時的實際參數值,並要求產生器確保運算式即使在虛擬展開時也有效。DW_OP_LLVM_call_frame_entry_reg
運算提供了對虛擬展開調用幀中暫存器的存取。注意
GDB 僅在 E 完全是
DW_OP_reg*
或DW_OP_breg*; DW_OP_deref*
時實作DW_OP_entry_value
。
A.2.5.4.4 位置描述運算¶
本節描述將位置描述推送到堆疊上的運算。
A.2.5.4.4.1 一般位置描述運算¶
注意
本節取代 DWARF 版本 5 第 2.5.1.3 節的部分內容。
DW_OP_LLVM_offset
新增DW_OP_LLVM_offset
會彈出兩個堆疊條目。第一個必須是表示位元組位移量 B 的整數類型值。第二個必須是位置描述 L。它將 B 的值乘以 8(位元組大小)後加到 L 的每個單一位置描述 SL 的位元偏移量上,並推送更新後的 L。
如果任何 SL 的更新後位元偏移量小於 0 或大於或等於 SL 指定的位置儲存大小,則會發生求值錯誤。
DW_OP_LLVM_offset_uconst
新增DW_OP_LLVM_offset_uconst
有一個單一的無號 LEB128 整數運算元,表示位元組位移量 B。此運算等同於執行
DW_OP_constu B; DW_OP_LLVM_offset
。提供此運算的目的是為了能夠在兩個位元組中編碼比使用
DW_OP_lit*; DW_OP_LLVM_offset
所能完成的更多的欄位位移量。注意
應該將其命名為
DW_OP_LLVM_offset_uconst
以匹配DW_OP_plus_uconst
,還是命名為DW_OP_LLVM_offset_constu
以匹配DW_OP_constu
呢?DW_OP_LLVM_bit_offset
新增DW_OP_LLVM_bit_offset
會彈出兩個堆疊條目。第一個必須是表示位元位移量 B 的整數類型值。第二個必須是位置描述 L。它將 B 的值加到 L 的每個單一位置描述 SL 的位元偏移量上,並推送更新後的 L。
如果任何 SL 的更新後位元偏移量小於 0 或大於或等於 SL 指定的位置儲存大小,則會發生求值錯誤。
DW_OP_push_object_address
DW_OP_push_object_address
會推送目前物件的位置描述 L。此物件可能對應於使用者呈現的正在求值的運算式中的獨立變數。物件位置描述可以從變數自身的除錯資訊條目中確定,或者它可能是陣列、結構或類別的組件,其地址已在使用者運算式求值期間的較早步驟中動態確定。
此運算提供了顯式功能(特別是用於涉及描述器的陣列),該功能類似於在求值
DW_AT_data_member_location
以存取結構的資料成員之前,隱式推送結構的基底位置描述。注意
可以移除此運算,並將物件位置描述指定為初始堆疊,如同
DW_AT_data_member_location
一樣。或者可以使用此運算來代替需要指定初始堆疊。後一種方法更具可組合性,因為可能需要在運算式的任何點存取物件,而將其作為初始堆疊傳遞需要整個運算式都意識到它在堆疊上的位置。如果這樣做,
DW_AT_use_location
將需要DW_OP_push_object2_address
運算來處理第二個物件。或者,更通用的方法是傳遞任意數量的參數,並使用一個運算來取得第 N 個參數,例如
DW_OP_arg N
。然後,將參數向量傳遞到運算式上下文中,而不是初始堆疊。這也可以解決DW_OP_call*
的問題,方法是允許指定傳入和傳回的特定參數數量。然後,DW_OP_call*
運算可以始終在單獨的堆疊上執行:參數的數量將在新的調用運算中指定,並從調用者的堆疊中取得,類似地,傳回結果的數量將被指定,並在被調用運算式完成時從被調用者的堆疊複製回調用者的堆疊。唯一指定目前物件的屬性是
DW_AT_data_location
,因此非規範性文字似乎誇大了其使用方式。還是有其他屬性需要聲明它們傳遞物件?DW_OP_LLVM_call_frame_entry_reg
新增DW_OP_LLVM_call_frame_entry_reg
有一個單一的無號 LEB128 整數運算元,表示目標架構暫存器編號 R。它會推送位置描述 L,該描述 L 保留了在進入目前子程式時暫存器 R 的值,如調用幀資訊所定義(請參閱 A.6.4 調用幀資訊)。
如果未定義調用幀資訊,則使用目標架構的預設規則。如果暫存器規則為 未定義,則會推送未定義的位置描述。如果暫存器規則為 相同值,則會推送 R 的暫存器位置描述。
A.2.5.4.4.2 未定義位置描述運算¶
注意
本節取代 DWARF 版本 5 第 2.6.1.1.1 節。
未定義的位置儲存代表物件的一部分或全部,這些物件存在於原始碼中,但不存在於目標碼中(可能是由於最佳化)。讀取或寫入未定義的位置儲存都沒有意義。
未定義的位置描述指定了未定義的位置儲存。未定義的位置儲存沒有大小的概念,未定義的位置描述也沒有位元偏移量的概念。DW_OP_LLVM_*offset
運算會使未定義的位置描述保持不變。DW_OP_*piece
運算可以顯式或隱式地指定未定義的位置描述,允許指定任何大小和偏移量,並產生具有所有未定義位元的部分。
DW_OP_LLVM_undefined
新增DW_OP_LLVM_undefined
會推送位置描述 L,該描述 L 包含一個未定義的位置描述 SL。
A.2.5.4.4.3 記憶體位置描述運算¶
注意
本節取代 DWARF 版本 5 第 2.5.1.1、2.5.1.2、2.5.1.3 和 2.6.1.1.2 節的部分內容。
每個目標架構特定的位址空間都有一個對應的記憶體位置儲存,用於表示該位址空間的線性可定址記憶體。每個記憶體位置儲存的大小對應於對應位址空間中位址的範圍。
目標架構定義了位址空間位置儲存如何映射到目標架構實體記憶體。例如,它們可以是獨立記憶體,或者多個位置儲存可以別名相同的實體記憶體,可能在不同的偏移量和具有不同的交錯方式。映射也可能由原始語言位址類別決定。
記憶體位置描述指定了記憶體位置儲存。位元偏移量對應於記憶體位元組內的位元位置。使用記憶體位置描述存取的位元,會存取對應的目標架構記憶體,從位元偏移量指定的位元組內的位元位置開始。
位元偏移量是 8(位元組大小)的倍數的記憶體位置描述,被定義為位元組位址記憶體位置描述。它具有一個記憶體位元組位址 A,等於位元偏移量除以 8。
位元偏移量不是 8(位元組大小)的倍數的記憶體位置描述,被定義為位元欄位記憶體位置描述。它具有一個位元位置 B,等於位元偏移量模數 8,以及一個記憶體位元組位址 A,等於位元偏移量減去 B,然後除以 8。
記憶體位置描述的位址空間 AS 被定義為對應於與記憶體位置描述相關聯的記憶體位置儲存的位址空間。
由一個位元組位址記憶體位置描述 SL 組成的位置描述被定義為記憶體位元組位址位置描述。它具有一個等於 A 的位元組位址和一個等於對應 SL 的 AS 的位址空間。
DW_ASPACE_LLVM_none
被定義為目標架構預設位址空間。請參閱 A.2.13 位址空間。
如果堆疊條目需要是位置描述,但它是具有通用類型的值 V,則它會被隱式轉換為具有一個記憶體位置描述 SL 的位置描述 L。SL 指定對應於目標架構預設位址空間的記憶體位置儲存,其位元偏移量等於 V 乘以 8(位元組大小)。
注意
如果希望允許任何整數類型值隱式轉換為目標架構預設位址空間中的記憶體位置描述
如果堆疊條目需要是位置描述,但它是具有整數類型的值 V,則它會被隱式轉換為具有一個記憶體位置描述 SL 的位置描述 L。如果 V 的類型大小小於通用類型大小,則值 V 會被零擴展到通用類型的大小。最低有效通用類型大小位元被視為無號值,用作位址 A。SL 指定對應於目標架構預設位址空間的記憶體位置儲存,其位元偏移量等於 A 乘以 8(位元組大小)。
隱式轉換也可以定義為目標架構特定的。例如,GDB 檢查 V 是否為整數類型。如果不是,則會產生錯誤。否則,GDB 會將 V 零擴展到 64 位元。如果 GDB 目標定義了鉤子函數,則會調用它。目標特定的鉤子函數可以修改 64 位元值,可能會根據原始值類型進行符號擴展。最後,GDB 將 64 位元值 V 視為記憶體位置位址。
如果堆疊條目需要是位置描述,但它是具有目標架構預設位址空間的隱式指標值 IPV,則它會被隱式轉換為具有一個單一位置描述的位置描述,該位置描述由 IPV 指定。請參閱 A.2.5.4.4.5 隱式位置描述運算。
注意
此規則是 DWARF 版本 5 向後相容性所必需的嗎?如果不是,則可以消除它,並且產生器可以使用 DW_OP_LLVM_form_aspace_address
。
如果堆疊條目需要是值,但它是具有一個記憶體位置描述 SL 的位置描述 L,該 SL 在目標架構預設位址空間中且位元偏移量 B 是 8 的倍數,則它會被隱式轉換為一個值,該值等於 B 除以 8(位元組大小),且具有通用類型。
DW_OP_addr
DW_OP_addr
有一個單一位元組常數值運算元,其大小與通用類型的大小相同,表示位址 A。它會將具有一個記憶體位置描述 SL 的位置描述 L 推送到堆疊上。SL 指定對應於目標架構預設位址空間的記憶體位置儲存,其位元偏移量等於 A 乘以 8(位元組大小)。
如果 DWARF 是程式碼物件的一部分,則可能需要重新定位 A。例如,在 ELF 程式碼物件格式中,A 必須根據 ELF 段虛擬位址與段載入時的虛擬位址之間的差異進行調整。
DW_OP_addrx
DW_OP_addrx
有一個單一的無號 LEB128 整數運算元,表示相對於關聯編譯單元的DW_AT_addr_base
屬性值的.debug_addr
區段中從零開始的索引。.debug_addr
區段中的位址值 A 的大小與通用類型的大小相同。它會將具有一個記憶體位置描述 SL 的位置描述 L 推送到堆疊上。SL 指定對應於目標架構預設位址空間的記憶體位置儲存,其位元偏移量等於 A 乘以 8(位元組大小)。
如果 DWARF 是程式碼物件的一部分,則可能需要重新定位 A。例如,在 ELF 程式碼物件格式中,A 必須根據 ELF 段虛擬位址與段載入時的虛擬位址之間的差異進行調整。
DW_OP_LLVM_form_aspace_address
新增DW_OP_LLVM_form_aspace_address
會彈出最上面的兩個堆疊條目。第一個必須是表示目標架構特定位址空間識別符 AS 的整數類型值。第二個必須是表示位址 A 的整數類型值。位址大小 S 定義為對應於 AS 的目標架構特定位址空間的位址位元大小。
A 會被調整為 S 位元,必要時透過零擴展,然後將最低有效 S 位元視為無號值 A'。
它會將具有一個記憶體位置描述 SL 的位置描述 L 推送到堆疊上。SL 指定對應於 AS 的記憶體位置儲存 LS,其位元偏移量等於 A' 乘以 8(位元組大小)。
如果 AS 是特定於上下文元素的位址空間,則 LS 對應於與目前上下文相關聯的位置儲存。
例如,如果 AS 用於每個執行緒的儲存,則 LS 是目前執行緒的位置儲存。對於使用 SIMT 執行模型實作的語言,如果 AS 用於每個通道的儲存,則 LS 是目前執行緒的目前通道的位置儲存。因此,如果 L 由運算存取,則會存取在建立位置描述時選擇的位置儲存,而不是與存取運算的目前上下文相關聯的位置儲存。
如果 AS 不是目標架構特定
DW_ASPACE_LLVM_*
值定義的值之一,則 DWARF 運算式格式不正確。有關
DW_OP_implicit_pointer
和DW_OP_LLVM_aspace_implicit_pointer
運算建立的隱式位置描述所產生的隱式指標值的特殊規則,請參閱 A.2.5.4.4.5 隱式位置描述運算。DW_OP_form_tls_address
DW_OP_form_tls_address
會彈出一個堆疊條目,該條目必須是整數類型值,並將其視為執行緒本機儲存位址 TA。它會將具有一個記憶體位置描述 SL 的位置描述 L 推送到堆疊上。SL 是目標架構特定的記憶體位置描述,對應於執行緒本機儲存位址 TA。
執行緒本機儲存位址 TA 的含義由執行時期環境定義。如果執行時期環境支援單個執行緒的多個執行緒本機儲存區塊,則會使用對應於包含此 DWARF 運算式的可執行檔或共享程式庫的區塊。
C、C++、Fortran 和其他語言的某些實作支援執行緒本機儲存類別。具有此儲存類別的變數在不同的執行緒中具有不同的值和位址,就像自動變數在每個子程式調用中具有不同的值和位址一樣。通常,有一個儲存區塊包含在主可執行檔中宣告的所有執行緒本機變數,以及一個單獨的區塊用於在每個共享程式庫中宣告的變數。然後可以使用識別符在其區塊中存取每個執行緒本機變數。此識別符通常是一個位元組偏移量,偏移到區塊中,並在
DW_OP_form_tls_address
運算之前,由DW_OP_const*
運算之一推送到 DWARF 堆疊上。計算適當區塊的位址可能很複雜(在某些情況下,編譯器會發出函數調用來執行此操作),並且難以使用普通的 DWARF 位置描述來描述。與其強制將複雜的執行緒本機儲存計算放入 DWARF 運算式中,不如使用DW_OP_form_tls_address
,它允許消費者根據目標架構特定的執行時期環境來執行計算。DW_OP_call_frame_cfa
DW_OP_call_frame_cfa
會將目前子程式的標準幀位址 (CFA) 的位置描述 L 從堆疊上的調用幀資訊中推送。請參閱 A.6.4 調用幀資訊。雖然可以使用位置列表運算式計算對應於目前子程式的除錯資訊條目的
DW_AT_frame_base
屬性的值,但在某些情況下,這需要廣泛的位置列表,因為用於計算 CFA 的暫存器的值在子程式執行期間會發生變化。如果調用幀資訊存在,則它已經編碼了這些變化,並且使用DW_OP_call_frame_cfa
運算來引用它是節省空間的。DW_OP_fbreg
DW_OP_fbreg
有一個單一的帶號 LEB128 整數運算元,表示位元組位移量 B。目前子程式的幀基底的位置描述 L 是從對應於目前子程式的除錯資訊條目的
DW_AT_frame_base
屬性中取得的,如 A.3.3.5 低階資訊 中所述。位置描述 L 會被更新,如同應用了
DW_OP_LLVM_offset_uconst B
運算一樣。更新後的 L 會被推送到堆疊上。DW_OP_breg0
、DW_OP_breg1
、 …、DW_OP_breg31
DW_OP_breg<N>
運算編碼了最多 32 個暫存器的編號,編號從 0 到 31,包含 0 和 31。暫存器編號 R 對應於運算名稱中的 N。它們有一個單一的帶號 LEB128 整數運算元,表示位元組位移量 B。
位址空間識別符 AS 被定義為對應於目標架構特定預設位址空間的識別符。
位址大小 S 定義為對應於 AS 的目標架構特定位址空間的位址位元大小。
會檢索由 R 指定的暫存器的內容,如同執行了
DW_OP_regval_type R, DR
運算一樣,其中 DR 是類型大小為 S 位元的無號整數基本類型在目前編譯單元中假設的除錯資訊條目的偏移量。B 會被加上,並且最低有效 S 位元會被視為無號值,用作位址 A。它們會推送位置描述 L,該描述 L 包含一個記憶體位置描述 LS 在堆疊上。LS 指定對應於 AS 的記憶體位置儲存,其位元偏移量等於 A 乘以 8(位元組大小)。
DW_OP_bregx
DW_OP_bregx
有兩個運算元。第一個是表示暫存器編號 R 的無號 LEB128 整數。第二個是表示位元組位移量 B 的帶號 LEB128 整數。其動作與
DW_OP_breg<N>
相同,不同之處在於 R 用作暫存器編號,B 用作位元組位移量。DW_OP_LLVM_aspace_bregx
新增DW_OP_LLVM_aspace_bregx
有兩個運算元。第一個是表示暫存器編號 R 的無號 LEB128 整數。第二個是表示位元組位移量 B 的帶號 LEB128 整數。它會彈出一個堆疊條目,該條目必須是表示目標架構特定位址空間識別符 AS 的整數類型值。其動作與
DW_OP_breg<N>
相同,不同之處在於 R 用作暫存器編號,B 用作位元組位移量,AS 用作位址空間識別符。如果 AS 不是目標架構特定
DW_ASPACE_LLVM_*
值定義的值之一,則 DWARF 運算式格式不正確。注意
也可以考慮新增
DW_OP_LLVM_aspace_breg0, DW_OP_LLVM_aspace_breg1, ..., DW_OP_LLVM_aspace_breg31
,這將節省編碼大小。
A.2.5.4.4.4 暫存器位置描述運算¶
注意
本節取代 DWARF 版本 5 第 2.6.1.1.3 節。
每個目標架構暫存器都有一個對應的暫存器位置儲存。每個暫存器位置儲存的大小對應於對應目標架構暫存器的大小。
暫存器位置描述指定了暫存器位置儲存。位元偏移量對應於暫存器內的位元位置。使用暫存器位置描述存取的位元,會存取對應的目標架構暫存器,從指定的位元偏移量開始。
DW_OP_reg0
、DW_OP_reg1
、 …、DW_OP_reg31
DW_OP_reg<N>
運算編碼了最多 32 個暫存器的編號,編號從 0 到 31,包含 0 和 31。目標架構暫存器編號 R 對應於運算名稱中的 N。此運算等同於執行
DW_OP_regx R
。DW_OP_regx
DW_OP_regx
有一個單一的無號 LEB128 整數運算元,表示目標架構暫存器編號 R。如果目前的調用幀是最上層調用幀,它會推送位置描述 L,該描述 L 在堆疊上指定一個暫存器位置描述 SL。SL 指定對應於 R 的暫存器位置儲存,且對於目前執行緒的位元偏移量為 0。
如果目前的調用幀不是最上層調用幀,則會使用調用幀資訊(請參閱 A.6.4 調用幀資訊)來確定位置描述,該位置描述保留目前調用幀和目前執行緒的目前程式位置的暫存器。產生的位置描述 L 會被推送。
請注意,如果使用了調用幀資訊,則產生的位置描述可能是暫存器、記憶體或未定義。
實作可以立即求值調用幀資訊,或者可以延遲求值,直到 L 被運算存取。如果延遲求值,則 R 和目前的上下文可以記錄在 L 中。當存取時,會使用記錄的上下文來求值調用幀資訊,而不是存取運算的目前上下文。
這些運算取得暫存器位置。若要提取暫存器的內容,必須使用 DW_OP_regval_type
,使用 DW_OP_breg*
基於暫存器的定址運算之一,或對暫存器位置描述使用 DW_OP_deref*
。
A.2.5.4.4.5 隱式位置描述運算¶
注意
本節取代 DWARF 版本 5 第 2.6.1.1.4 節。
隱式位置儲存代表物件的一部分或全部,這些物件在程式中沒有實際位置,但其內容仍然是已知的,可以作為常數,也可以從程式中的其他位置和值計算出來。
隱式位置描述指定了隱式位置儲存。位元偏移量對應於隱式位置儲存內的位元位置。使用隱式位置描述存取的位元,會存取對應的隱式儲存值,從位元偏移量開始。
DW_OP_implicit_value
DW_OP_implicit_value
有兩個運算元。第一個是表示位元組大小 S 的無號 LEB128 整數。第二個是位元組區塊,其長度等於 S,被視為常值 V。會建立一個隱式位置儲存 LS,其中包含常值 V 和大小 S。
它會推送位置描述 L,該描述 L 在堆疊上指定一個隱式位置描述 SL。SL 指定 LS,且位元偏移量為 0。
DW_OP_stack_value
DW_OP_stack_value
會彈出一個堆疊條目,該條目必須是值 V。會使用 V 的基本類型指定的大小、編碼和位元組序來建立一個隱式位置儲存 LS,其中包含常值 V。
它會推送位置描述 L,該描述 L 在堆疊上指定一個隱式位置描述 SL。SL 指定 LS,且位元偏移量為 0。
DW_OP_stack_value
運算指定物件不存在於記憶體中,但其值仍然是已知的。在此形式中,位置描述指定了物件的實際值,而不是指定保留該值的記憶體或暫存器儲存。有關
DW_OP_implicit_pointer
(如下)的特殊規則,請參閱DW_OP_implicit_pointer
和DW_OP_LLVM_aspace_implicit_pointer
運算建立的隱式位置描述所產生的隱式指標值。注意:由於位置描述允許在堆疊上,因此
DW_OP_stack_value
運算不再像 DWARF 版本 5 中那樣終止 DWARF 運算式執行。DW_OP_implicit_pointer
最佳化編譯器可能會消除指標,同時仍然保留指標所定址的值。
DW_OP_implicit_pointer
允許產生器描述此值。DW_OP_implicit_pointer
指定物件是指向目標架構預設位址空間的指標,即使它可以指向的值可以被描述,但它也無法表示為真實指標。在此形式中,位置描述指定了一個除錯資訊條目,該條目表示指標將指向的物件的實際位置描述。因此,除錯資訊的消費者將能夠存取已取值的指標,即使它無法存取指標本身。DW_OP_implicit_pointer
有兩個運算元。第一個運算元是 32 位元 DWARF 格式的 4 位元組無號值,或 64 位元 DWARF 格式的 8 位元組無號值,表示相對於包含目前編譯單元的.debug_info
區段開頭的除錯資訊條目 D 的位元組偏移量 DR。第二個運算元是表示位元組位移量 B 的帶號 LEB128 整數。請注意,D 可能不在目前的編譯單元中。
第一個運算元的解釋與
DW_FORM_ref_addr
完全相同。位址空間識別符 AS 被定義為對應於目標架構特定預設位址空間的識別符。
位址大小 S 定義為對應於 AS 的目標架構特定位址空間的位址位元大小。
會建立一個隱式位置儲存 LS,其中包含除錯資訊條目 D、位址空間 AS 和大小 S。
它會推送位置描述 L,該描述 L 在堆疊上包含一個隱式位置描述 SL。SL 指定 LS,且位元偏移量為 0。
如果
DW_OP_deref*
運算彈出位置描述 L' 並檢索 S 位元,使得任何檢索到的位元都來自與 LS 相同的隱式位置儲存,除非滿足以下兩個條件,否則會發生求值錯誤所有檢索到的位元都來自一個隱式位置描述,該描述引用與 LS 相同的隱式位置儲存。
請注意,所有位元不必來自同一個隱式位置描述,因為 L' 可能涉及複合位置描述。
這些位元來自其各自隱式位置儲存中連續的遞增偏移量。
這些規則等同於檢索 LS 的完整內容。
如果上述兩個條件皆滿足,則
DW_OP_deref*
操作推送的值 V 是一個隱含指標值 IPV,其目標架構特定位址空間為 AS,除錯資訊條目為 D,且基礎類型為 T。如果 AS 是目標架構預設位址空間,則 T 是通用類型。否則,T 是一個目標架構特定的整數類型,其位元大小等於 S。如果 IPV 隱含地轉換為位置描述(僅當 AS 是目標架構預設位址空間時才執行),或被
DW_OP_LLVM_form_aspace_address
使用(僅當由DW_OP_LLVM_form_aspace_address
彈出的位址空間為 AS 時才執行),則產生的位置描述 RL 為如果 D 具有
DW_AT_location
屬性,則來自DW_AT_location
屬性的 DWARF 運算式 E 會在當前上下文中評估,但結果種類是位置描述,編譯單元是包含 D 的單元,物件未指定,且初始堆疊為空。RL 是運算式結果。請注意,E 是在存取 IPV 的運算式上下文中評估,而不是包含
DW_OP_implicit_pointer
或DW_OP_LLVM_aspace_implicit_pointer
操作(建立 L)的運算式上下文。如果 D 具有
DW_AT_const_value
屬性,則會從DW_AT_const_value
屬性的值建立一個隱含位置儲存 RLS,其大小與DW_AT_const_value
屬性的值大小相符。RL 包含一個隱含位置描述 SRL。SRL 指定 RLS,位元偏移量為 0。注意
如果對於變數和形式參數使用
DW_AT_const_value
已被棄用,而是使用具有隱含位置描述的DW_AT_location
,則此規則將不再需要。否則,這是一個評估錯誤。
RL 的位元偏移量會更新,如同應用了
DW_OP_LLVM_offset_uconst B
操作一樣。如果
DW_OP_stack_value
操作彈出一個與 IPV 相同的值,則它會推送一個與 L 相同的位置描述。如果在任何其他方式中存取 LS 或 IPV,則會發生評估錯誤。
對由
DW_OP_implicit_pointer
和DW_OP_LLVM_aspace_implicit_pointer
建立的隱含指標位置描述的使用方式的限制,是為了簡化 DWARF 消費者。對於由DW_OP_deref*
和DW_OP_stack_value
建立的隱含指標值也是如此。DW_OP_LLVM_aspace_implicit_pointer
新功能DW_OP_LLVM_aspace_implicit_pointer
具有與DW_OP_implicit_pointer
相同的兩個運算元。它彈出一個堆疊條目,該條目必須是一個整數類型值,代表目標架構特定的位址空間識別符 AS。
推送至堆疊的位置描述 L 與
DW_OP_implicit_pointer
的位置描述 L 相同,除了使用的位址空間識別符是 AS 之外。如果 AS 不是目標架構特定
DW_ASPACE_LLVM_*
值定義的值之一,則 DWARF 運算式格式不正確。注意
當完整支援位址類別(OpenCL/SyCL 等語言所需)加入時,
DW_OP_LLVM_aspace_implicit_pointer
的此定義可能會變更。
通常, DW_OP_implicit_pointer
或 DW_OP_LLVM_aspace_implicit_pointer
操作用於 DW_TAG_variable
或 DW_TAG_formal_parameter
除錯資訊條目 D1 的 DW_AT_location
屬性的 DWARF 運算式 E1 中。由 DW_OP_implicit_pointer
或 DW_OP_LLVM_aspace_implicit_pointer
操作引用的除錯資訊條目通常本身是一個 DW_TAG_variable
或 DW_TAG_formal_parameter
除錯資訊條目 D2,其 DW_AT_location
屬性給出第二個 DWARF 運算式 E2。
D1 和 E1 描述指標類型物件的位置。D2 和 E2 描述該指標物件指向的物件的位置。
然而,D2 可以是任何包含 DW_AT_location
或 DW_AT_const_value
屬性的除錯資訊條目(例如, DW_TAG_dwarf_procedure
)。透過使用 E2,消費者可以在被要求取消引用 E1 描述的指標時,重建物件的值,E1 包含 DW_OP_implicit_pointer
或 DW_OP_LLVM_aspace_implicit_pointer
操作。
A.2.5.4.4.6 複合位置描述操作¶
注意
本節取代 DWARF 版本 5 第 2.6.1.2 節。
複合位置儲存代表一個物件或值,它可能包含在另一個位置儲存的一部分中,或包含在多個位置儲存的部分中。
每個部分都有一個部分位置描述 L 和一個部分位元大小 S。L 可以有一個或多個單一位置描述 SL。如果有多個 SL,則表示該部分位於多個位置。該部分每個位置的位元包含來自 SL 指定的位置儲存 LS 的 S 個連續位元,從 SL 指定的位元偏移量開始。所有位元都必須在 LS 的大小範圍內,否則 DWARF 運算式格式不正確。
一個複合位置儲存可以有零個或多個部分。這些部分是連續的,因此從零開始的位置儲存位元索引將涵蓋每個部分,且部分之間沒有間隙。因此,複合位置儲存的大小是其各部分大小的總和。如果連續位置儲存的大小大於與最大目標架構特定位址空間對應的記憶體位置儲存的大小,則 DWARF 運算式格式不正確。
複合位置描述指定一個複合位置儲存。位元偏移量對應於複合位置儲存中的位元位置。
有些操作會建立複合位置儲存。
還有其他操作允許逐步建立複合位置儲存。每個部分都由一個獨立的操作建立。可能有一個或多個操作來建立最終的複合位置儲存。一系列這樣的操作描述了複合位置儲存的各部分,這些部分的順序與相關部分操作的執行順序相同。
為了支援逐步建立,複合位置儲存可以處於不完整狀態。當一個逐步操作作用於一個不完整的複合位置儲存時,它會新增一個新的部分,否則它會建立一個新的複合位置儲存。DW_OP_LLVM_piece_end
操作明確地使一個不完整的複合位置儲存完整。
指定不完整複合位置儲存的複合位置描述稱為不完整複合位置描述。指定完整複合位置儲存的複合位置描述稱為完整複合位置描述。
如果在操作運算式執行完成後,堆疊頂端條目是一個位置描述,該位置描述具有一個不完整複合位置描述 SL,則 SL 會轉換為完整複合位置描述。
請注意,此轉換不會在由 DW_OP_call*
操作在同一個堆疊上評估的操作運算式完成後發生。此類執行不是對操作運算式的單獨評估,而是包含 DW_OP_call*
操作的同一個操作運算式的持續評估。
如果堆疊條目需要是位置描述 L,但 L 具有不完整的複合位置描述,則 DWARF 運算式格式不正確。例外情況是用於逐步建立複合位置描述的操作,如下所述。
請注意,DWARF 操作運算式可以任意組合來自任何其他位置描述的複合位置描述,包括那些具有多個單一位置描述的位置描述,以及那些具有複合位置描述的位置描述。
逐步複合位置描述操作的定義與 DWARF 版本 5 中的定義相容。
DW_OP_piece
DW_OP_piece
有一個單一的無符號 LEB128 整數,代表位元組大小 S。動作基於上下文
如果堆疊為空,則會將一個位置描述 L 推送到堆疊上,該位置描述 L 由一個不完整複合位置描述 SL 組成。
建立一個不完整複合位置儲存 LS,其中包含一個部分 P。P 指定一個位置描述 PL,且位元大小為 S 乘以 8(位元組大小)。PL 由一個未定義位置描述 PSL 組成。
SL 指定 LS,位元偏移量為 0。
否則,如果堆疊頂端條目是一個位置描述 L,該位置描述由一個不完整複合位置描述 SL 組成,則 SL 指定的不完整複合位置儲存 LS 會被更新以附加一個新的部分 P。P 指定一個位置描述 PL,且位元大小為 S 乘以 8(位元組大小)。L 留在堆疊上。
否則,如果堆疊頂端條目是一個位置描述或可以轉換為位置描述,則它會被彈出並視為部分位置描述 PL。然後
如果堆疊頂端條目(在彈出 PL 之後)是一個位置描述 L,該位置描述由一個不完整複合位置描述 SL 組成,則 SL 指定的不完整複合位置儲存 LS 會被更新以附加一個新的部分 P。P 指定位置描述 PL,且位元大小為 S 乘以 8(位元組大小)。L 留在堆疊上。
否則,會將一個位置描述 L 推送到堆疊上,該位置描述 L 由一個不完整複合位置描述 SL 組成。
建立一個不完整複合位置儲存 LS,其中包含一個部分 P。P 指定位置描述 PL,且位元大小為 S 乘以 8(位元組大小)。
SL 指定 LS,位元偏移量為 0。
否則,DWARF 運算式格式不正確
許多編譯器將單個變數儲存在多組暫存器中,或將變數部分儲存在記憶體中,部分儲存在暫存器中。
DW_OP_piece
提供了一種描述變數部分位置的方法。如果需要非 0 位元組位移,則可以在使用
DW_OP_LLVM_offset
操作更新位置描述後,將其用作DW_OP_piece
操作的部分位置描述。DW_OP_piece
操作的評估規則使其與 DWARF 版本 5 的定義相容。注意
由於這些擴充功能允許位置描述作為堆疊上的條目,因此可以定義一個更簡單的操作來建立複合位置描述。例如,只需一個操作來指定多少個部分,然後彈出部分大小和位置描述的配對堆疊條目。這不僅會是一個更簡單的操作,並避免不完整複合位置描述的複雜性,而且在實務中也可能具有更小的編碼。然而,與 DWARF 版本 5 相容的期望可能是一個更強大的考量因素。
DW_OP_bit_piece
DW_OP_bit_piece
有兩個運算元。第一個是無符號 LEB128 整數,代表部分位元大小 S。第二個是無符號 LEB128 整數,代表位元位移 B。動作與
DW_OP_piece
相同,除了任何建立的部分都具有位元大小 S,並且任何建立的部分的位置描述 PL 都會更新,如同應用了DW_OP_constu B; DW_OP_LLVM_bit_offset
操作一樣。DW_OP_bit_piece
在要組裝的部分不是位元組大小或不在部分位置描述的開頭時使用,而不是DW_OP_piece
。如果需要計算的位元位移,則可以在使用
DW_OP_LLVM_bit_offset
操作更新位置描述後,將其用作DW_OP_bit_piece
操作的部分位置描述。注意
位元偏移量運算元是不需要的,因為
DW_OP_LLVM_bit_offset
可以用於部分的位置描述。DW_OP_LLVM_piece_end
新功能如果堆疊頂端條目不是一個位置描述 L,該位置描述由一個不完整複合位置描述 SL 組成,則 DWARF 運算式格式不正確。
否則,SL 指定的不完整複合位置儲存 LS 會更新為完整複合位置描述,並具有相同的部分。
DW_OP_LLVM_extend
新功能DW_OP_LLVM_extend
有兩個運算元。第一個是無符號 LEB128 整數,代表元素位元大小 S。第二個是無符號 LEB128 整數,代表計數 C。它彈出一個堆疊條目,該條目必須是一個位置描述,並被視為部分位置描述 PL。
會將一個位置描述 L 推送到堆疊上,該位置描述 L 由一個完整複合位置描述 SL 組成。
建立一個完整複合位置儲存 LS,其中包含 C 個相同的部分 P。每個 P 指定 PL,且位元大小為 S。
SL 指定 LS,位元偏移量為 0。
如果元素位元大小或計數為 0,則 DWARF 運算式格式不正確。
DW_OP_LLVM_select_bit_piece
新功能DW_OP_LLVM_select_bit_piece
有兩個運算元。第一個是無符號 LEB128 整數,代表元素位元大小 S。第二個是無符號 LEB128 整數,代表計數 C。它彈出三個堆疊條目。第一個必須是一個整數類型值,代表位元遮罩值 M。第二個必須是一個位置描述,代表單一位置描述 L1。第三個必須是一個位置描述,代表零位置描述 L0。
建立一個完整複合位置儲存 LS,其中包含 C 個部分 PN,依 N 從 0 到 C-1(包含)的升序排列。每個 PN 指定位置描述 PLN,且位元大小為 S。
PLN 就像是對 PLXN 應用了
DW_OP_LLVM_bit_offset N*S
操作一樣。如果 M 的第 N 個最低有效位元為零,則 PLXN 與 L0 相同,否則與 L1 相同。
會將一個位置描述 L 推送到堆疊上,該位置描述 L 由一個完整複合位置描述 SL 組成。SL 指定 LS,位元偏移量為 0。
如果 S 或 C 為 0,或 M 的位元大小小於 C,則 DWARF 運算式格式不正確。
注意
是否應該更改 DW_OP_extend 和 DW_OP_select_bit_piece 的計數運算元,以從堆疊取得計數值?這將允許支援具有可變長度向量指令的架構,例如 ARM 和 RISC-V。
DW_OP_LLVM_overlay
新功能DW_OP_LLVM_overlay
彈出四個堆疊條目。第一個必須是一個整數類型值,代表覆蓋位元組大小值 S。第二個必須是一個整數類型值,代表覆蓋位元組偏移量值 O。第三個必須是一個位置描述,代表覆蓋位置描述 OL。第四個必須是一個位置描述,代表基礎位置描述 BL。動作與
DW_OP_LLVM_bit_overlay
相同,除了使用的覆蓋位元大小 BS 和覆蓋位元偏移量 BO 分別是 S 和 O 乘以 8(位元組大小)。DW_OP_LLVM_bit_overlay
新功能DW_OP_LLVM_bit_overlay
彈出四個堆疊條目。第一個必須是一個整數類型值,代表覆蓋位元大小值 BS。第二個必須是一個整數類型值,代表覆蓋位元偏移量值 BO。第三個必須是一個位置描述,代表覆蓋位置描述 OL。第四個必須是一個位置描述,代表基礎位置描述 BL。如果 BS 或 BO 為負值,則 DWARF 運算式格式不正確。
rbss(L) 是 L 的最小剩餘位元儲存大小,定義如下。LS 是位置儲存,LO 是 L 的單一位置描述 SL 指定的位置位元偏移量。SL 的剩餘位元儲存大小 RBSS 是 LS 的位元大小減去 LO。rbss(L) 是 L 的每個單一位置描述 SL 的最小 RBSS。
如果 rbss(BL) 小於 BO 加 BS,則 DWARF 運算式格式不正確。
如果 BS 為 0,則操作推送 BL。
如果 BO 為 0 且 BS 等於 rbss(BL),則操作推送 OL。
否則,該操作等效於執行以下步驟來推送複合位置描述。
複合位置描述在概念上是基礎位置描述 BL,其中覆蓋位置描述 OL 作為覆蓋層定位,從覆蓋偏移量 BO 開始,並覆蓋覆蓋位元大小 BS。
如果 BO 不為 0,則推送 BL,然後執行
DW_OP_bit_piece BO, 0
操作。推送 OL,然後執行
DW_OP_bit_piece BS, 0
操作。如果 rbss(BL) 大於 BO 加 BS,則推送 BL,然後執行
DW_OP_bit_piece (rbss(BL) - BO - BS), (BO + BS)
操作。執行
DW_OP_LLVM_piece_end
操作。
A.2.5.5 DWARF 位置列表運算式¶
注意
本節取代 DWARF 版本 5 第 2.6.2 節。
為了滿足近期電腦架構和最佳化技術的需求,除錯資訊必須能夠描述物件的位置,該物件的位置在其生命週期內會發生變化,並且在物件生命週期的某些部分可能位於多個位置。位置列表運算式用於取代操作運算式,每當要描述位置的物件具有這些需求時。
位置列表運算式由一系列位置列表條目組成。每個位置列表條目都是以下種類之一
有界位置描述
此類位置列表條目提供一個操作運算式,該運算式評估為在由起始和結束位址限定的生命週期內有效的物件的位置描述。起始位址是位置有效的位址範圍的最低位址。結束位址是超出位址範圍最高位址的第一個位置的位址。
當目前程式位置在給定範圍內時,位置列表條目會匹配。
有幾種有界位置描述條目,它們在指定起始和結束位址的方式上有所不同。
預設位置描述
此類位置列表條目提供一個操作運算式,該運算式評估為在沒有有界位置描述條目適用時有效的物件的位置描述。
當目前程式位置不在任何有界位置描述條目的範圍內時,位置列表條目會匹配。
基準位址
此類位置列表條目提供一個位址,該位址用作在某些種類的有界位置描述條目中給出的起始和結束位址偏移量的基準位址。有界位置描述條目的適用基準位址是同一位置列表中最接近的前一個基準位址條目指定的位址。如果沒有前一個基準位址條目,則適用基準位址預設為編譯單元的基準位址(請參閱 DWARF 版本 5 第 3.1.1 節)。
在所有機器程式碼都包含在單一連續區段中的編譯單元的情況下,不需要基準位址條目。
列表結束
此類位置列表條目標記位置列表運算式的結束。
位置列表運算式的有界位置描述條目定義的位址範圍可能會重疊。當它們重疊時,它們描述物件同時存在於多個位置的情況。
如果給定位置列表運算式中的所有位址範圍沒有共同涵蓋物件定義的整個範圍,並且沒有後續的預設位置描述條目,則假定物件在未涵蓋的範圍部分不可用。
DWARF 位置列表運算式的評估結果是
如果未指定目前程式位置,則會發生評估錯誤。
注意
如果位置列表只有單一預設條目,那麼在沒有程式位置的情況下,是否應該將其視為匹配?如果有非預設條目,那麼當沒有程式位置時,似乎必須發生評估錯誤,因為這表示位置取決於未知的程式位置。
如果沒有匹配的位置列表條目,則結果是一個位置描述,該位置描述包含一個未定義位置描述。
否則,每個匹配的位置列表條目的操作運算式 E 會在當前上下文中評估,但結果種類是位置描述,物件未指定,且初始堆疊為空。位置列表條目結果是 E 評估返回的位置描述。
結果是一個位置描述,該位置描述由每個匹配的位置列表條目的位置描述結果的單一位置描述的聯集組成。
位置列表運算式只能用作使用類別 loclist
或 loclistsptr
編碼的除錯資訊條目屬性的值(請參閱 A.7.5.5 類別和形式)。屬性的值提供一個索引,指向一個單獨的物件檔案區段,稱為 .debug_loclists
或 .debug_loclists.dwo
(對於分割的 DWARF 物件檔案),其中包含位置列表條目。
DW_OP_call*
和 DW_OP_implicit_pointer
操作可以用於指定具有位置列表運算式的除錯資訊條目屬性。多個除錯資訊條目屬性允許 DWARF 運算式,這些運算式在初始堆疊中評估,初始堆疊包含一個位置描述,該位置描述可能源自位置列表運算式的評估。
此位置列表表示法、 loclist
和 loclistsptr
類別,以及相關的 DW_AT_loclists_base
屬性是 DWARF 版本 5 中的新功能。它們共同消除了先前位置列表運算式所需的大部分或全部程式碼物件重定位。
注意
本節的其餘部分與 DWARF 版本 5 第 2.6.2 節相同。
A.2.13 位址空間¶
注意
這是 DWARF 版本 5 第 2.12 節分段位址之後的新節。
DWARF 位址空間對應於目標架構特定的線性可定址記憶體區域。它們在 DWARF 運算式位置描述中用於描述資料駐留在哪個目標架構特定的記憶體區域中。
目標架構特定的 DWARF 位址空間可能對應於硬體支援的功能,例如利用基準位址暫存器的記憶體、暫存記憶體和具有特殊交錯的記憶體。這些位址空間中位址的大小可能會有所不同。它們的存取和分配可以由硬體管理,每個執行緒或執行緒組都可以存取獨立的儲存空間。由於這些原因,它們可能具有一些屬性,使其無法被視為所有執行緒都可存取的統一全域虛擬位址空間的一部分。
是否支援多個 DWARF 位址空間以及原始碼語言記憶體空間如何對應到目標架構特定的 DWARF 位址空間是目標架構特定的。目標架構可能會將多個原始碼語言記憶體空間對應到相同的目標架構特定的 DWARF 位址類別。最佳化可能會決定變數生命週期和存取模式允許將它們分配到更快的暫存記憶體中,該暫存記憶體由與原始碼語言記憶體空間預設值不同的 DWARF 位址空間表示。
雖然 DWARF 位址空間識別符是目標架構特定的,但 DW_ASPACE_LLVM_none
是所有目標架構都支援的通用位址空間,並定義為目標架構預設位址空間。
DWARF 位址空間識別符由以下項目使用
DW_AT_LLVM_address_space
屬性。DWARF 運算式操作:
DW_OP_aspace_bregx
、DW_OP_form_aspace_address
、DW_OP_aspace_implicit_pointer
和DW_OP_xderef*
。CFI 指令:
DW_CFA_def_aspace_cfa
和DW_CFA_def_aspace_cfa_sf
。
注意
目前,DWARF 將位址類別值定義為目標架構特定的,並定義了 DW_AT_address_class 屬性。隨著 DWARF 6 中 DW_AT_segment 的移除,不清楚位址類別的預期用途,因為該術語在其他地方未使用。這些是否應該被此提案更完整的位址空間取代?或者它們是否旨在表示原始碼語言記憶體空間,例如在 OpenCL 中?
A.2.14 記憶體空間¶
注意
這是 DWARF 版本 5 第 2.12 節分段位址之後的新節。
DWARF 記憶體空間用於具有記憶體空間概念的原始碼語言。它們在指標類型、參考類型、變數、形式參數和常數除錯資訊條目的 DW_AT_LLVM_memory_space
屬性中使用。
每個 DWARF 記憶體空間在概念上都是一個單獨的原始碼語言記憶體空間,具有自己的生命週期和別名規則。DWARF 記憶體空間用於指定指標類型和參考類型值引用的原始碼語言記憶體空間,以及指定變數分配的原始碼語言記憶體空間。
雖然 DWARF 記憶體空間識別符是原始碼語言特定的,但 DW_MSPACE_LLVM_none
是所有原始碼語言都支援的通用記憶體空間,並定義為原始碼語言預設記憶體空間。
目前定義的 DWARF 記憶體空間集合,以及原始碼語言對應,在 原始碼語言記憶體空間 中給出。
供應商定義的原始語言記憶體空間可以使用 DW_MSPACE_LLVM_lo_user
到 DW_MSPACE_LLVM_hi_user
範圍內的代碼來定義。
記憶體空間名稱 |
意義 |
C/C++ |
OpenCL |
CUDA/HIP |
---|---|---|---|---|
|
通用 (generic) |
預設 (default) |
通用 (generic) |
預設 (default) |
|
全域 (global) |
全域 (global) |
||
|
常數 (constant) |
常數 (constant) |
常數 (constant) |
|
|
執行緒群組 (thread-group) |
區域 (local) |
共享 (shared) |
|
|
執行緒 (thread) |
私有 (private) |
||
|
||||
|
注意
在原始語言記憶體空間中提出的方法是將預設的 DW_MSPACE_LLVM_none
定義為通用位址類別,而不是全域位址類別。這與 CLANG 和 LLVM 如何在現有的 C++ 語言支援之上添加對類似 CUDA 語言的支援相符。這允許所有位址預設為通用,這與類似 CUDA 的語言相符。
另一種方法是將 DW_MSPACE_LLVM_none
定義為全域記憶體空間,然後將 DW_MSPACE_LLVM_global
變更為 DW_MSPACE_LLVM_generic
。這將符合不支援多個記憶體空間的語言實際上只有一個預設全域記憶體空間的事實。通常,在這些語言中,如果它們公開目標架構支援多個記憶體空間,則預設空間仍然是全域記憶體空間。然後,支援多個記憶體空間的語言必須明確指出哪些指標具有引用超出全域記憶體空間的能力。然而,為類似 CUDA 語言產生 DWARF 的編譯器將必須為每個類似 CUDA 語言的指標類型或參考類型定義一個 DW_AT_LLVM_memory_space
屬性,其值為 DW_MSPACE_LLVM_generic
,以符合語言語意。
A.3 程式作用域條目¶
注意
本節提供對現有除錯資訊條目屬性的變更。這些變更將被納入相應的 DWARF 版本 5 第 3 章節。
A.3.1 單元條目¶
A.3.1.1 完整和部分編譯單元條目¶
注意
本節擴充了 DWARF 版本 5 第 3.1.1 節和表 3.1。
用於 DW_AT_language
屬性的其他語言代碼在語言名稱中定義。
語言名稱 |
意義 |
---|---|
|
HIP 語言。 |
HIP 語言 [HIP] 可以通過擴展 C++ 語言來支援。
注意
新增以下屬性。
編譯單元的
DW_TAG_compile_unit
除錯資訊條目可能具有DW_AT_LLVM_augmentation
屬性,其值為擴充字串。擴充字串允許產生器指示除錯資訊條目中存在額外的供應商或目標特定資訊。例如,這可能是關於正在使用的供應商特定擴充版本的資訊。
如果不存在,或者字串為空,則編譯單元沒有擴充字串。
擴充字串的格式為
[
vendor:v
X.
Y[:
options]]
*其中 vendor 是產生器,
vX.Y
指定所使用擴充的主要版本號 X 和次要版本號 Y,而 options 是一個可選字串,提供關於擴充的額外資訊。版本號必須符合語義化版本控制 [SEMVER]。options 字串不得包含 “]
“ 字元。例如
[abc:v0.0][def:v1.2:feature-a=on,feature-b=3]
A.3.3 子程式和進入點條目¶
A.3.3.5 低階資訊¶
DW_TAG_subprogram
、DW_TAG_inlined_subroutine
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_return_addr
屬性,其值為 DWARF 運算式 E。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。評估的結果是儲存目前呼叫框架的子程式或進入點的返回位址的位置描述 L。
如果 L 不是由目標架構特定位址空間之一的一個記憶體位置描述組成,則 DWARF 格式不正確。
注意
不清楚為什麼
DW_TAG_inlined_subroutine
具有DW_AT_return_addr
屬性,但沒有DW_AT_frame_base
或DW_AT_static_link
屬性。似乎它應該全部擁有,或全部沒有。由於內聯子程式沒有呼叫框架,因此它們似乎不會有這些屬性。DW_TAG_subprogram
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_frame_base
屬性,其值為 DWARF 運算式 E。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。
如果 E 包含
DW_OP_fbreg
運算,或者產生的位置描述 L 不是由一個單一位置描述 SL 組成,則 DWARF 格式不正確。如果 SL 是暫存器 R 的暫存器位置描述,則 L 將被替換為評估
DW_OP_bregx R, 0
運算的結果。這將計算目標架構預設位址空間中的框架基底記憶體位置描述。這允許使用更精簡的
DW_OP_reg*
來代替DW_OP_breg* 0
。注意
可以移除此規則,並要求產生器直接使用
DW_OP_call_frame_cfa
、DW_OP_breg*
或DW_OP_LLVM_aspace_bregx
建立所需的位置描述。這也將允許目標在大型暫存器中實現呼叫框架。否則,如果 SL 不是任何目標架構特定位址空間中的記憶體位置描述,則 DWARF 格式不正確。
產生的 L 是子程式或進入點的框架基底。
通常,E 將使用
DW_OP_call_frame_cfa
運算,或是堆疊指標暫存器加上或減去一些偏移量。子程式的框架基底通常是相對於為子程式的堆疊框架分配的第一個儲存單位的位址。
DW_AT_frame_base
屬性可以通過多種方式使用:在需要位置列表來定位區域變數的子程式中,
DW_AT_frame_base
可以保存所需的位置列表,而所有變數的位置描述可以是涉及框架基底的更簡單的描述。它可以用于解析巢狀常式中的“向上層級”定址。(另請參閱下面的
DW_AT_static_link
)
某些語言支援巢狀子程式。在這種語言中,可以從內部子程式引用外部子程式的區域變數。
DW_AT_static_link
和DW_AT_frame_base
屬性允許除錯器支援這種相同的引用方式。如果
DW_TAG_subprogram
或DW_TAG_entry_point
除錯資訊條目在詞法上是巢狀的,則它可能具有DW_AT_static_link
屬性,其值為 DWARF 運算式 E。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。評估的結果是規範框架位址的位置描述 L(請參閱A.6.4 呼叫框架資訊),該位址屬於在詞法上直接封閉目前呼叫框架的子程式或進入點的子程式實例的相關呼叫框架。
如果 L 不是由目標架構特定位址空間之一的一個記憶體位置描述組成,則 DWARF 格式不正確。
在支援巢狀子程式的上下文中,DW_AT_frame_base 屬性值遵守以下約束
它計算一個在子程式生命週期內不會變化的值,並且
計算出的值在同一子程式的實例中是唯一的。
對於典型的 DW_AT_frame_base 用法,這意味著遞迴子程式的堆疊框架必須具有非零大小。
如果除錯器嘗試解析對變數的向上層級引用,它會使用 DWARF 的巢狀結構來確定哪個子程式是詞法父程式,並使用
DW_AT_static_link
值來識別父程式的適當活動框架。然後,它可以嘗試在父程式的上下文中找到引用。注意
新增以下新屬性。
對於使用 SIMT 執行模型實現的語言,
DW_TAG_subprogram
、DW_TAG_inlined_subroutine
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_LLVM_lanes
屬性,其值為整數常數,該常數是每個目標架構執行緒的原始語言執行緒數量。例如,編譯器可以使用 SIMT 執行模型將原始語言執行緒映射到目標架構執行緒的通道 (lane) 上。
它是每個目標架構執行緒的原始語言執行緒的靜態數量。它不是目標架構執行緒啟動的原始語言執行緒的動態數量,例如,由於較小或部分工作群組。
如果不存在,則使用預設值 1。
如果該值小於或等於 0,則 DWARF 格式不正確。
對於使用 SIMT 執行模型實現的原始語言,
DW_TAG_subprogram
、DW_TAG_inlined_subroutine
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_LLVM_lane_pc
屬性,其值為 DWARF 運算式 E。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。
產生的位置描述 L 用於通道計數大小的通用類型元素向量。通道計數是
DW_AT_LLVM_lanes
屬性的值。每個元素都保存對應通道的概念程式位置。如果通道在呼叫目前的子程式時未處於活動狀態,則其元素是未定義的位置描述。如果 L 沒有恰好一個單一位置描述,則 DWARF 格式不正確。
DW_AT_LLVM_lane_pc
允許編譯器指示目標架構執行緒的每個 SIMT 通道在概念上的位置,即使它處於非活動的分散控制流程中。通常,結果是一個位置描述,其中包含一個複合位置描述,每個部分都是一個位置描述,其中包含一個未定義的位置描述或一個記憶體位置描述。
如果不存在,則目標架構執行緒未使用 SIMT 方式,並使用執行緒目前的程式位置。
對於使用 SIMT 執行模型實現的語言,
DW_TAG_subprogram
、DW_TAG_inlined_subroutine
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_LLVM_active_lane
屬性,其值為 DWARF 運算式 E。E 在評估上下文下評估,該上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。
如果 L 沒有恰好一個單一位置描述 SL,則 DWARF 格式不正確。
目前的程式位置的活動通道位元遮罩 V 是通過使用目標架構特定的整數基底類型 T 從 SL 讀取獲得的,該基底類型 T 的位元大小等於與上下文框架和程式位置相對應的子程式的
DW_AT_LLVM_lanes
屬性的值。遮罩的第 N 個最低有效位元對應於第 N 個通道。如果該位元為 1,則通道處於活動狀態,否則通道處於非活動狀態。屬性的結果是值 V。某些目標可能會更新目標架構執行遮罩,以用於必須以與目前活動通道不同的通道集執行的程式碼區域。例如,某些程式碼必須以所有通道臨時處於活動狀態的方式執行。
DW_AT_LLVM_active_lane
允許編譯器提供一種方法來確定任何程式位置的原始語言活動通道。通常,此屬性將使用位置列表 (loclist) 來表示不同程式位置的活動通道遮罩的不同位置。如果不存在且
DW_AT_LLVM_lanes
大於 1,則使用目標架構執行遮罩。DW_TAG_subprogram
、DW_TAG_inlined_subroutine
或DW_TAG_entry_point
除錯資訊條目可能具有DW_AT_LLVM_iterations
屬性,其值為整數常數或 DWARF 運算式 E。其值是目標架構為單個原始語言執行緒並行執行的原始語言迴圈迭代次數。編譯器可能會產生程式碼,該程式碼使用軟體管線或 SIMD 向量化等最佳化技術並行執行原始語言迴圈的多個迭代。並行迭代的次數可能因同一子程式中的不同迴圈巢狀結構而異。通常,此屬性將使用位置列表 (loclist) 來表示不同程式位置的不同值。
如果屬性是整數常數,則該值是常數。如果常數小於或等於 0,則 DWARF 格式不正確。
否則,E 在評估上下文下評估,該上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。如果結果不是由一個隱式位置描述組成的位置描述,並且當以通用類型讀取時,結果值 V 小於或等於 0,則 DWARF 格式不正確。屬性的結果是值 V。
如果不存在,則使用預設值 1。
A.3.4 呼叫站點條目和參數¶
A.3.4.2 呼叫站點參數¶
呼叫站點條目可以擁有
DW_TAG_call_site_parameter
除錯資訊條目,表示傳遞給呼叫的參數。呼叫站點參數條目的順序與原始碼中對應參數的順序相同。每個這樣的條目都有一個DW_AT_location
屬性,它是一個位置描述。此位置描述描述了參數的傳遞位置(通常是某些暫存器,或可表示為堆疊暫存器的內容加上一些偏移量的記憶體位置)。DW_TAG_call_site_parameter
除錯資訊條目可能具有DW_AT_call_value
屬性,其值為 DWARF 運算式 E1。DW_AT_call_value
屬性的結果是通過評估 E1 獲得的,評估上下文具有值的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。產生的值 V1 是呼叫站點進行呼叫時參數的值。對於按引用傳遞的參數,其中程式碼傳遞指向包含參數的位置的指標,或者對於參考類型參數,
DW_TAG_call_site_parameter
除錯資訊條目也可能具有DW_AT_call_data_location
屬性,其值為 DWARF 運算式 E2,以及DW_AT_call_data_value
屬性,其值為 DWARF 運算式 E3。DW_AT_call_data_location
屬性的值是通過評估 E2 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。產生的位置描述 L2 是在呼叫站點進行呼叫期間參考參數所在的位置。如果 E2 只是DW_OP_push_object_address
,則可以省略DW_AT_call_data_location
屬性。注意
DWARF 版本 5 暗示可以使用
DW_OP_push_object_address
,但未說明必須在上下文中指定哪個物件。要么不能使用DW_OP_push_object_address
,要么必須定義上下文中要傳遞的物件。DW_AT_call_data_value
屬性的值是通過評估 E3 獲得的,評估上下文具有值的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。產生的值 V3 是呼叫站點進行呼叫時 L2 中的值。如果目前的呼叫框架不是用於包含
DW_TAG_call_site_parameter
除錯資訊條目的子程式,或者目前的程式位置不是用於目前呼叫框架中包含DW_TAG_call_site_parameter
除錯資訊條目的呼叫站點,則這些屬性的結果未定義。消費者可能必須虛擬地回溯到呼叫站點(請參閱A.6.4 呼叫框架資訊)才能評估這些屬性。這將確保使用者關注的原始語言執行緒對應於評估運算式所需的呼叫站點。
如果無法避免這些屬性的運算式訪問可能被呼叫站點呼叫的子程式破壞的暫存器或記憶體位置,則不應提供關聯的屬性。
限制的原因是可能需要在被呼叫者的執行期間訪問參數。消費者可以從被呼叫的子程式虛擬地回溯到呼叫者,然後評估屬性運算式。呼叫框架資訊(請參閱A.6.4 呼叫框架資訊)將無法恢復已被破壞的暫存器,並且被破壞的記憶體將不再具有呼叫時的值。
每個呼叫站點參數條目也可能具有
DW_AT_call_parameter
屬性,其中包含對DW_TAG_formal_parameter
條目的參考、參考參數類型的DW_AT_type attribute
屬性或描述參數名稱的DW_AT_name
屬性。
使用呼叫站點條目和相關屬性的範例可在附錄 D.15 中找到。
A.3.5 詞法區塊條目¶
注意
本節與 DWARF 版本 5 第 3.5 節相同。
A.4 資料物件和物件列表條目¶
注意
本節提供對現有除錯資訊條目屬性的變更。這些變更將被納入相應的 DWARF 版本 5 第 4 章節。
A.4.1 資料物件條目¶
程式變數、形式參數和常數分別由帶有標籤 DW_TAG_variable
、DW_TAG_formal_parameter
和 DW_TAG_constant
的除錯資訊條目表示。
標籤 DW_TAG_constant 用於具有真正命名常數的語言。
程式變數、形式參數或常數的除錯資訊條目可能具有以下屬性
DW_AT_location
屬性,其值為 DWARF 運算式 E,描述變數或參數在執行時的位置。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。評估的結果是資料物件基底的位置描述。
有關
DW_OP_call*
運算使用的特殊評估規則,請參閱A.2.5.4.2 控制流程運算。注意
刪除關於
DW_OP_call*
運算如何評估DW_AT_location
屬性的描述,因為現在已在運算中描述了這一點。注意
請參閱關於
DW_OP_call*
運算中DW_AT_location
屬性的討論。讓每個屬性僅具有單一目的和單一執行語意似乎是理想的。這使得消費者更容易,因為不再需要追蹤上下文。這也使產生器更容易,因為它可以依賴每個屬性的單一語意。因此,將
DW_AT_location
屬性限制為僅支援評估物件的位置描述,並對同一運算式堆疊上的 DWARF 運算式程序的評估使用不同的屬性和編碼類別似乎是理想的。DW_AT_const_value
注意
可以棄用將
DW_AT_const_value
屬性用於DW_TAG_variable
或DW_TAG_formal_parameter
除錯資訊條目,這些條目已被最佳化為常數。相反,DW_AT_location
可以與產生隱式位置描述的 DWARF 運算式一起使用,因為現在任何位置描述都可以在 DWARF 運算式中使用。這允許使用DW_OP_call*
運算來推送任何變數的位置描述,無論其如何最佳化。DW_AT_LLVM_memory_space
DW_AT_memory_space
屬性,其常數值表示原始語言特定的 DWARF 記憶體空間(請參閱 2.14 “記憶體空間”)。如果省略,則預設為DW_MSPACE_none
。
A.4.2 公用區塊條目¶
公用區塊條目也具有 DW_AT_location
屬性,其值為 DWARF 運算式 E,描述公用區塊在執行時的位置。屬性的結果是通過評估 E 獲得的,評估上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、空的初始堆疊以及對應於使用者關注的原始語言執行緒的其他上下文元素(如果有的話)。評估的結果是公用區塊基底的位置描述。有關 A.2.5.4.2 控制流程運算 中 DW_OP_call*
運算使用的特殊評估規則,請參閱。
A.5 類型條目¶
注意
本節提供對現有除錯資訊條目屬性的變更。這些變更將被納入相應的 DWARF 版本 5 第 5 章節。
A.5.1 基本類型條目¶
注意
新增以下屬性。
基本類型 T 的
DW_TAG_base_type
除錯資訊條目可能具有DW_AT_LLVM_vector_size
屬性,其值為整數常數,該常數是向量類型大小 N。向量基本類型的表示形式為 N 個連續的元素,每個元素都具有基本類型 T' 的表示形式,該基本類型 T' 與沒有
DW_AT_LLVM_vector_size
屬性的 T 相同。如果
DW_TAG_base_type
除錯資訊條目沒有DW_AT_LLVM_vector_size
屬性,則基本類型不是向量類型。如果 N 不大於 0,則 DWARF 格式不正確。
注意
LLVM 提到了非上游的除錯資訊條目,旨在支援向量類型。但是,那不是用於基本類型,因此不適合作為堆疊值條目的類型。但是,也許可以使用此屬性替換它。
注意
將此與 GNU 支援的
DW_AT_GNU_vector
擴充進行比較。是為現有的DW_TAG_base_type
除錯條目添加屬性更好,還是允許將某些形式的DW_TAG_array_type
(那些具有DW_AT_GNU_vector
屬性的形式)用作堆疊條目值類型?編碼為
DW_ATE_address
的DW_TAG_base_type
除錯資訊條目可能具有DW_AT_LLVM_address_space
屬性,其值是架構特定的位址空間(請參閱A.2.13 位址空間)。如果省略,則預設為DW_ASPACE_LLVM_none
。
A.5.3 類型修飾符條目¶
注意
本節擴充了 DWARF 版本 5 第 5.3 節。
描述指標或參考類型(使用 DW_TAG_pointer_type
、DW_TAG_reference_type
或 DW_TAG_rvalue_reference_type
)的修改類型條目可能具有 DW_AT_LLVM_memory_space
屬性,其常數值表示原始語言特定的 DWARF 記憶體空間(請參閱A.2.14 記憶體空間)。如果省略,則預設為 DW_MSPACE_LLVM_none。
修改後的類型條目描述指標或參考類型 (使用 DW_TAG_pointer_type
、DW_TAG_reference_type
或 DW_TAG_rvalue_reference_type
),可能具有 DW_AT_LLVM_address_space
屬性,其常數值 AS 代表特定於架構的 DWARF 位址空間 (請參閱 A.2.13 位址空間)。 如果省略,則預設為 DW_ASPACE_LLVM_none
。 DR 是假設的除錯資訊條目 D 在目前編譯單元中的偏移量,適用於符合 AS 位址大小的整數基本類型。 具有給定指標或參考類型的物件 P 會被解引用,就好像評估了 DW_OP_push_object_address; DW_OP_deref_type DR; DW_OP_constu AS; DW_OP_form_aspace_address
運算式一樣,使用目前的上下文,但以下情況除外:結果種類是位置描述;初始堆疊為空;且物件是 P 的位置描述。
注意
如果目前的上下文沒有定義目前的目標架構,該怎麼辦?
注意
隨著對 DWARF 位址空間的擴展支援,可能值得研究它們是否可以用於先前由 DWARF 5 段支援的功能。 這將包括指定所有程式碼位址(編譯單元、子程式、子程式條目、標籤、子程式類型等)的位址空間。 可以擴展程式碼位址屬性以允許 exprloc 形式 (以便可以使用 DW_OP_form_aspace_address
),或者允許在所有允許 DW_AT_segment
的 DIE 上使用 DW_AT_LLVM_address_space
屬性。
A.5.7 結構、聯合、類別和介面類型條目¶
A.5.7.3 衍生或擴展的結構、類別和介面¶
對於
DW_AT_data_member_location
屬性,有兩種情況如果屬性是整數常數 B,則它提供從包含實體開始的位元組偏移量。
屬性的結果是透過評估
DW_OP_LLVM_offset B
運算,並以包含實體開始位置的位置描述作為初始堆疊而獲得。 評估的結果是成員條目基底的位置描述。如果包含實體的開始位置未對齊位元組,則成員條目的開始位置在位元組內具有相同的位元位移。
否則,屬性必須是 DWARF 運算式 E,該運算式在上下文中評估,該上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、包含包含實體開始位置的位置描述的初始堆疊,以及對應於使用者關注的原始語言執行緒的其他上下文元素 (如果有的話)。 評估的結果是成員條目基底的位置描述。
注意
包含實體的開始位置現在可以是任何位置描述,包括具有多個單一位置描述的位置描述,以及具有任何種類且具有任何位元偏移的單一位置描述。
A.5.7.8 成員函數條目¶
虛擬函數的條目也具有
DW_AT_vtable_elem_location
屬性,其值為 DWARF 運算式 E。屬性的結果是透過在上下文中評估 E 而獲得的,該上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、包含封閉類型物件的位置描述的初始堆疊,以及對應於使用者關注的原始語言執行緒的其他上下文元素 (如果有的話)。 評估的結果是封閉類別的虛擬函數表中函數槽的位置描述。
A.5.14 成員指標類型條目¶
DW_TAG_ptr_to_member_type
除錯資訊條目具有DW_AT_use_location
屬性,其值為 DWARF 運算式 E。 它用於計算成員指標條目指向的類別成員的位置描述。用於查找給定類別、結構或聯合成員的位置描述的方法,對於該類別、結構或聯合的任何實例以及成員指標類型的任何實例都是通用的。 因此,該方法與成員指標類型相關聯,而不是與每個具有成員指標類型的物件相關聯。
DW_AT_use_location
DWARF 運算式與給定成員指標類型的特定物件以及特定結構或類別實例的位置描述結合使用。屬性的結果是透過在上下文中評估 E 而獲得的,該上下文具有位置描述的結果種類、未指定的物件、包含 E 的編譯單元、包含兩個條目的初始堆疊,以及對應於使用者關注的原始語言執行緒的其他上下文元素 (如果有的話)。 第一個堆疊條目是成員指標物件本身的值。 第二個堆疊條目是包含正在計算其位置的成員的整個類別、結構或聯合實例的基底位置描述。 評估的結果是成員指標條目指向的類別成員的位置描述。
A.5.18 類型的動態屬性¶
A.5.18.1 資料位置¶
某些語言可能會使用描述符來表示物件,以保存資訊,包括位置和/或運行時參數,關於表示該物件值的資料。
DW_AT_data_location
屬性可以用於任何在其表示中提供一或多層隱藏間接和/或運行時參數的類型。 其值是一個 DWARF 運算式 E,用於計算物件資料的位置描述。 當省略此屬性時,資料的位置描述與物件的位置描述相同。屬性的結果是透過在上下文中評估 E 而獲得的,該上下文具有位置描述的結果種類、作為資料描述符位置描述的物件、包含 E 的編譯單元、空的初始堆疊,以及對應於使用者關注的原始語言執行緒的其他上下文元素 (如果有的話)。 評估的結果是成員條目基底的位置描述。
E 通常會涉及一個以
DW_OP_push_object_address
運算開始的運算式,該運算載入物件的位置描述,然後可以作為後續計算中的描述符。注意
既然
DW_AT_data_member_location
、DW_AT_use_location
和DW_AT_vtable_elem_location
都允許運算式和位置列表達式,為什麼DW_AT_data_location
不允許兩者? 在所有情況下,它們都適用於資料物件,因此優化不太可能導致不同程式位置範圍的不同運算式。 但是如果支援某些,則應該支援所有。似乎很奇怪,此屬性與
DW_AT_data_member_location
不同,因為它沒有具有物件位置描述的初始堆疊,因為運算式必須需要它。
A.6 其他除錯資訊¶
注意
本節提供對現有除錯器資訊條目屬性的變更。 這些變更將被納入對應的 DWARF 版本 5 第 6 章節中。
A.6.1 加速存取¶
A.6.1.1 按名稱查找¶
A.6.1.1.1 名稱索引的內容¶
注意
以下提供對 DWARF 版本 5 第 6.1.1.1 節的變更。
可選的 .debug_names
區段中名稱索引中包含的除錯器資訊條目的規則已擴展為也包括具有 DW_AT_location
屬性的具名 DW_TAG_variable
除錯資訊條目,該屬性包含 DW_OP_LLVM_form_aspace_address
運算。
名稱索引必須包含每個除錯資訊條目的條目,這些條目定義了具名的子程式、標籤、變數、類型或命名空間,但須遵守以下規則
具有
DW_AT_location
屬性的DW_TAG_variable
除錯資訊條目,該屬性包含DW_OP_addr
、DW_OP_LLVM_form_aspace_address
或DW_OP_form_tls_address
運算,則包含在內;否則,將排除在外。
A.6.1.1.4 名稱索引的資料表示¶
A.6.1.1.4.1 區段標頭¶
注意
以下提供對 DWARF 版本 5 第 6.1.1.4.1 節項目 14 augmentation_string
的新增內容。
一個以 null 終止的 UTF-8 供應商特定擴充字串,它提供有關此索引內容的其他資訊。 如果提供,建議的擴充字串格式為
[
vendor:v
X.
Y[:
options]]
*
其中 vendor 是生產商,vX.Y
指定編譯單元 DWARF 中使用的擴展的主要 X 和次要 Y 版本號,而 options 是一個可選字串,提供有關擴展的其他資訊。 版本號必須符合語義版本控制 [SEMVER]。 options 字串不得包含 “]
” 字元。
例如
[abc:v0.0][def:v1.2:feature-a=on,feature-b=3]
注意
這與 DWARF 版本 5 中的定義不同,但與其他擴充字串一致,並允許支援多個供應商擴展。
A.6.2 行號資訊¶
A.6.2.4 行號程式標頭¶
A.6.2.4.1 標準內容描述¶
注意
這擴充了 DWARF 版本 5 第 6.2.4.1 節。
DW_LNCT_LLVM_source
組件是以 “
\n
” 行尾結束的 null 終止 UTF-8 原始碼文字字串。 此內容代碼與DW_LNCT_path
的形式配對。 它可以用于檔案名稱條目。如果沒有原始碼可用,則該值為空的 null 終止字串。 如果原始碼可用但為空檔案,則該值為 null 終止的單個 “
\n
”。當原始碼欄位存在時,消費者可以使用嵌入的原始碼,而不是嘗試使用
DW_LNCT_path
欄位提供的檔案路徑在磁碟上發現原始碼。 當原始碼欄位不存在時,消費者可以存取檔案以取得原始碼文字。這對於支援運行時編譯和運行時生成原始碼文字的程式語言特別有用。 在這些情況下,原始碼文字不駐留在任何永久檔案中。 例如,OpenCL 語言 [:ref:`OpenCL
`] 支援線上編譯。 DW_LNCT_LLVM_is_MD5
DW_LNCT_LLVM_is_MD5
指示DW_LNCT_MD5
內容種類 (如果存在) 是否有效:當為 0 時無效,當為 1 時有效。 如果DW_LNCT_LLVM_is_MD5
內容種類不存在,且DW_LNCT_MD5
內容種類存在,則 MD5 總和檢查碼有效。DW_LNCT_LLVM_is_MD5
始終與DW_FORM_udata
形式配對。這允許編譯單元混合使用具有和不具有 MD5 總和檢查碼的檔案。 當多個可重定位檔案連結在一起時,可能會發生這種情況。
A.6.4 呼叫框架資訊¶
注意
本節提供對現有呼叫框架資訊的變更,並定義了這些擴展新增的指令。 為位址空間新增了額外支援。 暫存器展開 DWARF 運算式已通用化,以允許任何位置描述,包括具有複合和隱含位置描述的位置描述。
這些變更將被納入 DWARF 版本 5 第 6.4 節中。
A.6.4.1 呼叫框架資訊的結構¶
暫存器規則為
- 未定義
具有此規則的暫存器在前一個框架中沒有可恢復的值。 此暫存器的先前值是未定義的位置描述 (請參閱 A.2.5.4.4.2 未定義位置描述運算)。
依照慣例,此暫存器不會被被呼叫者保留。
- 相同的值
此暫存器自前一個呼叫者框架以來未被修改。
如果目前的框架是最頂層框架,則此暫存器的先前值是位置描述 L,它指定一個暫存器位置描述 SL。 SL 指定暫存器位置儲存,該儲存對應於目前執行緒位元偏移為 0 的暫存器。
如果目前的框架不是最頂層框架,則此暫存器的先前值是使用被呼叫者框架和被呼叫者程式位置的呼叫框架資訊獲得的位置描述,這些資訊由目前呼叫者框架針對同一暫存器調用。
依照慣例,此暫存器被被呼叫者保留,但被呼叫者未修改它。
- offset(N)
N 是帶符號的位元組偏移量。 此暫存器的先前值保存在位置描述中,該位置描述的計算方式就好像在目前的上下文中評估了 DWARF 運算式
DW_OP_LLVM_offset N
,但結果種類是位置描述,編譯單元未指定,物件未指定,並且初始堆疊包含目前 CFA 的位置描述 (請參閱 A.2.5.4 DWARF 運算式)。- val_offset(N)
N 是帶符號的位元組偏移量。 此暫存器的先前值是位置描述的記憶體位元組位址,該位置描述的計算方式就好像在目前的上下文中評估了 DWARF 運算式
DW_OP_LLVM_offset N
,但結果種類是位置描述,編譯單元未指定,物件未指定,並且初始堆疊包含目前 CFA 的位置描述 (請參閱 A.2.5.4 DWARF 運算式)。如果 CFA 位置描述不是記憶體位元組位址位置描述,或者如果暫存器大小與目前 CFA 位置描述的位址空間中位址的大小不符,則 DWARF 格式錯誤。
由於 CFA 位置描述必須是記憶體位元組位址位置描述,因此
val_offset(N)
的值也將是記憶體位元組位址位置描述,因為它是將 CFA 位置描述偏移 N 個位元組。 此外,val_offset(N)
的值將是與 CFA 位置描述相同的位址空間中的記憶體位元組位址。注意
DWARF 是否應該允許位址大小與暫存器大小不同? 要求它們具有相同的位元大小可以避免任何轉換問題,因為暫存器的位元內容僅被解釋為位址的值。
GDB 有一個每個暫存器的鉤子,允許在每個暫存器的基礎上進行目標特定的轉換。 預設情況下,較大的暫存器會被截斷,而較小的暫存器實際上會從下一個暫存器讀取位元組 (或對於最後一個暫存器,會超出範圍讀取)。 沒有 GDB 測試會超出範圍讀取暫存器 (除了非法的手寫組合語言測試)。
- register(R)
此暫存器已儲存在另一個編號為 R 的暫存器中。
此暫存器的先前值是使用目前框架和暫存器 R 的目前程式位置的呼叫框架資訊獲得的位置描述。
如果此暫存器的大小與暫存器 R 的大小不符,或者呼叫框架資訊中存在循環依賴關係,則 DWARF 格式錯誤。
注意
這是否也應該允許 R 比此暫存器更大? 如果是這樣,值是否儲存在低位位元中,而額外的上位位元中儲存的内容是否未定義?
- expression(E)
此暫存器的先前值位於透過評估 DWARF 運算式 E 而產生的位置描述中 (請參閱 A.2.5.4 DWARF 運算式)。
E 在目前的上下文中評估,但結果種類是位置描述,編譯單元未指定,物件未指定,並且初始堆疊包含目前 CFA 的位置描述 (請參閱 A.2.5.4 DWARF 運算式)。
- val_expression(E)
此暫存器的先前值位於從評估 DWARF 運算式 E 產生的值建立的隱含位置描述中 (請參閱 A.2.5.4 DWARF 運算式)。
E 在目前的上下文中評估,但結果種類是一個值,編譯單元未指定,物件未指定,並且初始堆疊包含目前 CFA 的位置描述 (請參閱 A.2.5.4 DWARF 運算式)。
如果產生的值類型大小與暫存器大小不符,則 DWARF 格式錯誤。
注意
這具有有限的用途,因為 DWARF 運算式 E 只能產生最大為通用類型大小的值。 這是因為不允許在 CFI 運算式中使用任何指定類型的運算。 這使得它無法用於大於通用類型的暫存器。 然而,expression(E) 可用於建立任何大小的隱含位置描述。
- 架構定義
此規則由擴充器在本規範之外定義。
如果實際上按照描述的方式建構此表,它將會非常大。 表中任何點的大多數條目都與它們上面的條目相同。 整個表可以非常緊湊地表示,只需記錄從程式中每個子例程的起始位址開始的差異即可。
虛擬展開資訊編碼在一個稱為 .debug_frame
的獨立區段中。 .debug_frame
區段中的條目相對於區段的開始位置按位址大小的倍數對齊,並且有兩種形式:通用資訊條目 (CIE) 和框架描述條目 (FDE)。
如果函數的程式碼位址範圍不連續,則可能有多個對應於該函數各部分的 CIE 和 FDE。
通用資訊條目 (CIE) 保存許多框架描述條目 (FDE) 之間共享的資訊。 每個非空的 .debug_frame
區段中至少有一個 CIE。 CIE 依序包含以下欄位
length(初始長度)
一個常數,給出 CIE 結構的位元組數,不包括長度欄位本身 (請參閱第 7.2.2 節初始長度值)。 長度欄位的大小加上長度的值必須是
address_size
欄位中指定的位址大小的整數倍數。CIE_id(4 或 8 個位元組,請參閱 A.7.4 32 位元和 64 位元 DWARF 格式)
用於區分 CIE 和 FDE 的常數。
在 32 位元 DWARF 格式中,CIE 標頭中 CIE id 的值為 0xffffffff;在 64 位元 DWARF 格式中,該值為 0xffffffffffffffff。
version(ubyte)
版本號 (請參閱第 7.24 節呼叫框架資訊)。 此數字特定於呼叫框架資訊,並且獨立於 DWARF 版本號。
CIE 版本號的值為 4。
注意
這會增加到 5 以反映這些擴展中的變更嗎?
augmentation(UTF-8 字元序列)
一個 null 終止的 UTF-8 字串,用於識別此 CIE 或使用它的 FDE 的擴充。 如果讀取器遇到意外的擴充字串,則只能讀取以下欄位
CIE:length、CIE_id、version、augmentation
FDE:length、CIE_pointer、initial_location、address_range
如果沒有擴充,則此值為零位元組。
擴充字串允許使用者指示 CIE 或 FDE 中存在其他供應商和目標架構特定的資訊,這些資訊是虛擬展開堆疊框架所必需的。 例如,這可能是關於動態分配資料的資訊,這些資料需要在例程退出時釋放。
由於
.debug_frame
區段獨立於任何.debug_info
區段都很有用,因此擴充字串始終使用 UTF-8 編碼。建議的擴充字串格式為
[
vendor:v
X.
Y[:
options]]
*其中 vendor 是產生器,
vX.Y
指定所使用擴充的主要版本號 X 和次要版本號 Y,而 options 是一個可選字串,提供關於擴充的額外資訊。版本號必須符合語義化版本控制 [SEMVER]。options 字串不得包含 “]
“ 字元。例如
[abc:v0.0][def:v1.2:feature-a=on,feature-b=3]
address_size(ubyte)
此 CIE 和任何使用它的 FDE 中目標位址的大小,以位元組為單位。 如果此框架存在編譯單元,則其位址大小必須與此處的位址大小相符。
segment_selector_size(ubyte)
此 CIE 和任何使用它的 FDE 中區段選擇器的大小,以位元組為單位。
code_alignment_factor(unsigned LEB128)
一個常數,從所有 advance location 指令中分解出來 (請參閱 A.6.4.2.1 列建立指令)。 結果值為
(operand * code_alignment_factor)
。data_alignment_factor(signed LEB128)
一個常數,從某些 offset 指令中分解出來 (請參閱 A.6.4.2.2 CFA 定義指令 和 A.6.4.2.3 暫存器規則指令)。 結果值為
(operand * data_alignment_factor)
。return_address_register(unsigned LEB128)
一個 unsigned LEB128 常數,指示規則表中哪一列表示子程式的返回位址。 請注意,此列可能不對應於實際的機器暫存器。
返回位址暫存器的值用於確定呼叫者框架的程式位置。 最頂層框架的程式位置是目前執行緒的目標架構程式計數器值。
initial_instructions(ubyte 陣列)
一系列規則,這些規則被解釋為建立表中每列的初始設定。
在解釋初始指令之前,所有列的預設規則是未定義規則。 然而,ABI 撰寫機構或編譯系統撰寫機構可以為任何或所有列指定替代預設值。
padding(ubyte 陣列)
足夠的
DW_CFA_nop
指令,使此條目的大小與上面的長度值相符。
FDE 依序包含以下欄位
length(初始長度)
一個常數,給出此子程式的標頭和指令流的位元組數,不包括長度欄位本身 (請參閱第 7.2.2 節初始長度值)。 長度欄位的大小加上長度的值必須是位址大小的整數倍數。
CIE_pointer(4 或 8 個位元組,請參閱 A.7.4 32 位元和 64 位元 DWARF 格式)
.debug_frame
區段中的常數偏移量,表示與此 FDE 關聯的 CIE。initial_location
(區段選擇器和目標位址)與此表格項目關聯的第一個位置的位址。如果此 FDE 的 CIE 的 segment_selector_size 欄位為非零值,則初始位置前面會加上給定長度的區段選擇器。
address_range
(目標位址)此項目描述的程式指令的位元組數。
instructions
(ubyte 陣列)定義表格指令的序列,這些指令在A.6.4.2 呼叫框架指令中描述。
padding(ubyte 陣列)
足夠的
DW_CFA_nop
指令,使此條目的大小與上面的長度值相符。
A.6.4.2 呼叫框架指令¶
每個呼叫框架指令都定義為接受 0 個或多個運算元。某些運算元可能會編碼為運算碼的一部分(請參閱A.7.24 呼叫框架資訊)。這些指令在以下章節中定義。
某些呼叫框架指令的運算元編碼為 DWARF 運算式 E(請參閱A.2.5.4 DWARF 運算式)。可用於 E 的 DWARF 運算有以下限制
DW_OP_addrx
、DW_OP_call2
、DW_OP_call4
、DW_OP_call_ref
、DW_OP_const_type
、DW_OP_constx
、DW_OP_convert
、DW_OP_deref_type
、DW_OP_fbreg
、DW_OP_implicit_pointer
、DW_OP_regval_type
、DW_OP_reinterpret
和DW_OP_xderef_type
運算不允許使用,因為呼叫框架資訊不得依賴其他偵錯區段。DW_OP_push_object_address
不允許使用,因為沒有物件上下文來提供要推送的值。DW_OP_LLVM_push_lane
和DW_OP_LLVM_push_iteration
不允許使用,因為呼叫框架指令描述的是整個目標架構執行緒的動作,而不是個別通道或迭代。DW_OP_call_frame_cfa
和DW_OP_entry_value
不允許使用,因為它們的使用會造成循環依賴。DW_OP_LLVM_call_frame_entry_reg
如果評估 E 會導致DW_OP_LLVM_call_frame_entry_reg
運算之間產生循環依賴,則不允許使用。例如,如果暫存器 R1 具有
DW_CFA_def_cfa_expression
指令,該指令評估指定暫存器 R2 的DW_OP_LLVM_call_frame_entry_reg
運算,而暫存器 R2 具有DW_CFA_def_cfa_expression
指令,該指令評估指定暫存器 R1 的DW_OP_LLVM_call_frame_entry_reg
運算。
這些限制適用的呼叫框架指令包括 DW_CFA_def_cfa_expression
、 DW_CFA_expression
和 DW_CFA_val_expression
。
A.6.4.2.1 列建立指令¶
注意
這些指令與 DWARF 版本 5 第 6.4.2.1 節中的指令相同。
A.6.4.2.2 CFA 定義指令¶
DW_CFA_def_cfa
DW_CFA_def_cfa
指令接受兩個無號 LEB128 運算元,分別代表暫存器編號 R 和(非因數)位元組位移量 B。AS 設定為目標架構預設位址空間識別符。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B
作為位置描述的結果。DW_CFA_def_cfa_sf
DW_CFA_def_cfa_sf
指令接受兩個運算元:一個無號 LEB128 值,代表暫存器編號 R,以及一個有號 LEB128 因數化位元組位移量 B。AS 設定為目標架構預設位址空間識別符。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B * data_alignment_factor
作為位置描述的結果。此動作與
DW_CFA_def_cfa
相同,只是第二個運算元是有號且因數化的。DW_CFA_LLVM_def_aspace_cfa
新指令DW_CFA_LLVM_def_aspace_cfa
指令接受三個無號 LEB128 運算元,分別代表暫存器編號 R、一個(非因數)位元組位移量 B 和一個目標架構特定的位址空間識別符 AS。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B
作為位置描述的結果。如果 AS 不是目標架構特定的
DW_ASPACE_LLVM_*
值定義的值之一,則 DWARF 運算式格式錯誤。DW_CFA_LLVM_def_aspace_cfa_sf
新指令DW_CFA_LLVM_def_aspace_cfa_sf
指令接受三個運算元:一個無號 LEB128 值,代表暫存器編號 R、一個有號 LEB128 因數化位元組位移量 B 和一個無號 LEB128 值,代表目標架構特定的位址空間識別符 AS。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B * data_alignment_factor
作為位置描述的結果。如果 AS 不是目標架構特定的
DW_ASPACE_LLVM_*
值定義的值之一,則 DWARF 運算式格式錯誤。此動作與
DW_CFA_aspace_def_cfa
相同,只是第二個運算元是有號且因數化的。DW_CFA_def_cfa_register
DW_CFA_def_cfa_register
指令接受單個無號 LEB128 運算元,代表暫存器編號 R。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B
作為位置描述的結果。B 和 AS 分別是舊的 CFA 位元組位移量和位址空間。如果子程式沒有目前的 CFA 規則,或規則是由
DW_CFA_def_cfa_expression
指令定義的,則 DWARF 格式錯誤。DW_CFA_def_cfa_offset
DW_CFA_def_cfa_offset
指令接受單個無號 LEB128 運算元,代表一個(非因數)位元組位移量 B。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B
作為位置描述的結果。R 和 AS 分別是舊的 CFA 暫存器編號和位址空間。如果子程式沒有目前的 CFA 規則,或規則是由
DW_CFA_def_cfa_expression
指令定義的,則 DWARF 格式錯誤。DW_CFA_def_cfa_offset_sf
DW_CFA_def_cfa_offset_sf
指令接受一個有號 LEB128 運算元,代表一個因數化位元組位移量 B。所需的動作是將目前的 CFA 規則定義為等效於評估 DWARF 運算式DW_OP_constu AS; DW_OP_LLVM_aspace_bregx R, B * data_alignment_factor
作為位置描述的結果。R 和 AS 分別是舊的 CFA 暫存器編號和位址空間。如果子程式沒有目前的 CFA 規則,或規則是由
DW_CFA_def_cfa_expression
指令定義的,則 DWARF 格式錯誤。此動作與
DW_CFA_def_cfa_offset
相同,只是運算元是有號且因數化的。DW_CFA_def_cfa_expression
DW_CFA_def_cfa_expression
指令接受單個運算元,該運算元編碼為DW_FORM_exprloc
值,代表 DWARF 運算式 E。所需的動作是將目前的 CFA 規則定義為等效於評估具有目前上下文的 E 的結果,但結果類型為位置描述,編譯單元未指定,物件未指定,且初始堆疊為空。請參閱 A.6.4.2 呼叫框架指令 中關於可用於 E 的 DWARF 運算式運算的限制。
如果評估 E 的結果不是記憶體位元組位址位置描述,則 DWARF 格式錯誤。
A.6.4.2.3 暫存器規則指令¶
DW_CFA_undefined
DW_CFA_undefined
指令接受單個無號 LEB128 運算元,代表暫存器編號 R。所需的動作是將 R 指定的暫存器的規則設定為undefined
。DW_CFA_same_value
DW_CFA_same_value
指令接受單個無號 LEB128 運算元,代表暫存器編號 R。所需的動作是將 R 指定的暫存器的規則設定為same value
。DW_CFA_offset
DW_CFA_offset
指令接受兩個運算元:一個暫存器編號 R(使用運算碼編碼)和一個無號 LEB128 常數,代表因數化位移量 B。所需的動作是將 R 指定的暫存器的規則變更為 offset(B * data_alignment_factor) 規則。注意
似乎應該將其命名為
DW_CFA_offset_uf
,因為位移量是無號因數化的。DW_CFA_offset_extended
DW_CFA_offset_extended
指令接受兩個無號 LEB128 運算元,分別代表暫存器編號 R 和因數化位移量 B。此指令與DW_CFA_offset
相同,只是暫存器運算元的編碼和大小不同。注意
似乎應該將其命名為
DW_CFA_offset_extended_uf
,因為位移量是無號因數化的。DW_CFA_offset_extended_sf
DW_CFA_offset_extended_sf
指令接受兩個運算元:一個無號 LEB128 值,代表暫存器編號 R,以及一個有號 LEB128 因數化位移量 B。此指令與DW_CFA_offset_extended
相同,只是 B 是有號的。DW_CFA_val_offset
DW_CFA_val_offset
指令接受兩個無號 LEB128 運算元,分別代表暫存器編號 R 和因數化位移量 B。所需的動作是將 R 指示的暫存器的規則變更為 val_offset(B * data_alignment_factor) 規則。注意
似乎應該將其命名為
DW_CFA_val_offset_uf
,因為位移量是無號因數化的。注意
另一種方法是定義
DW_CFA_val_offset
以隱含地使用目標架構預設位址空間,並新增另一個指定位址空間的運算。DW_CFA_val_offset_sf
DW_CFA_val_offset_sf
指令接受兩個運算元:一個無號 LEB128 值,代表暫存器編號 R,以及一個有號 LEB128 因數化位移量 B。此指令與DW_CFA_val_offset
相同,只是 B 是有號的。DW_CFA_register
DW_CFA_register
指令接受兩個無號 LEB128 運算元,分別代表暫存器編號 R1 和 R2。所需的動作是將 R1 指定的暫存器的規則設定為 register(R2) 規則。DW_CFA_expression
DW_CFA_expression
指令接受兩個運算元:一個無號 LEB128 值,代表暫存器編號 R,以及一個DW_FORM_block
值,代表 DWARF 運算式 E。所需的動作是將 R 指定的暫存器的規則變更為 expression(E) 規則。也就是說,E 計算可以擷取暫存器值的位置描述。
請參閱 A.6.4.2 呼叫框架指令 中關於可用於 E 的 DWARF 運算式運算的限制。
DW_CFA_val_expression
DW_CFA_val_expression
指令接受兩個運算元:一個無號 LEB128 值,代表暫存器編號 R,以及一個DW_FORM_block
值,代表 DWARF 運算式 E。所需的動作是將 R 指定的暫存器的規則變更為 val_expression(E) 規則。也就是說,E 計算暫存器 R 的值。
請參閱 A.6.4.2 呼叫框架指令 中關於可用於 E 的 DWARF 運算式運算的限制。
如果評估 E 的結果不是具有與暫存器大小相符的基礎類型大小的值,則 DWARF 格式錯誤。
DW_CFA_restore
DW_CFA_restore
指令接受單個運算元(使用運算碼編碼),代表暫存器編號 R。所需的動作是將 R 指定的暫存器的規則變更為 CIE 中initial_instructions
為其指派的規則。DW_CFA_restore_extended
DW_CFA_restore_extended
指令接受單個無號 LEB128 運算元,代表暫存器編號 R。此指令與DW_CFA_restore
相同,只是暫存器運算元的編碼和大小不同。
A.6.4.2.4 列狀態指令¶
注意
這些指令與 DWARF 版本 5 第 6.4.2.4 節中的指令相同。
A.6.4.2.5 填充指令¶
注意
這些指令與 DWARF 版本 5 第 6.4.2.5 節中的指令相同。
A.6.4.3 呼叫框架指令用法¶
注意
與 DWARF 版本 5 第 6.4.3 節相同。
A.6.4.4 呼叫框架呼叫位址¶
注意
與 DWARF 版本 5 第 6.4.4 節相同。
A.7 資料表示法¶
注意
本節提供對現有偵錯資訊項目屬性的變更。這些變更將納入對應的 DWARF 版本 5 第 7 章節中。
A.7.4 32 位元和 64 位元 DWARF 格式¶
注意
這擴充了 DWARF 版本 5 第 7.4 節清單項目 3 的表格。
形式 |
角色 |
---|---|
DW_OP_LLVM_aspace_implicit_pointer |
|
A.7.5 偵錯資訊的格式¶
A.7.5.4 屬性編碼¶
注意
這擴充了 DWARF 版本 5 第 7.5.4 節和表 7.5。
下表列出額外偵錯資訊項目屬性的編碼。
屬性名稱 |
值 |
類別 |
---|---|---|
|
0x3e08 |
exprloc、loclist |
|
0x3e09 |
字串 |
|
0x3e0a |
常數 (constant) |
|
0x3e0b |
exprloc、loclist |
|
0x3e0c |
常數 (constant) |
|
0x3e0a |
常數、exprloc、loclist |
|
TBA |
常數 (constant) |
|
TBA |
常數 (constant) |
A.7.5.5 類別和形式¶
注意
以下修改 DWARF 版本 5 第 7.5.5 節中的相符文字。
- 參考
參考有四種類型。
第一種類型的參考…
第二種類型的參考可以識別
.debug_info
區段內的任何偵錯資訊項目;特別是,它可以參照與包含參考的單元不同的編譯單元中的項目,並且可以參照不同共用物件檔案中的項目。此類型的參考 (DW_FORM_ref_addr) 是從目標可執行檔或共用物件檔案的.debug_info
區段開頭的位移量,或者,對於補充物件檔案中的參考,是從本機.debug_info
區段開頭的位移量;它在可重定位物件檔案中是可重定位的,並且在可執行檔或共用物件檔案中經常被重定位。在 32 位元 DWARF 格式中,此位移量是一個 4 位元組無號值;在 64 位元 DWARF 格式中,它是一個 8 位元組無號值(請參閱A.7.4 32 位元和 64 位元 DWARF 格式)。可能會被另一個使用 DW_FORM_ref_addr 的編譯單元參照的偵錯資訊項目,必須具有全域符號名稱。
對於從一個可執行檔或共用物件檔案到另一個可執行檔或共用物件檔案的參考,偵錯器會解析此參考,以識別可執行檔或共用物件檔案,以及該檔案的
.debug_info
區段中的位移量,其方式與執行階段載入器相同,無論是在首次讀取偵錯資訊時,還是在使用參考時。
A.7.7 DWARF 運算式¶
注意
重新命名 DWARF 版本 5 第 7.7 節,以反映位置描述統一為 DWARF 運算式。
A.7.7.1 運算式¶
注意
重新命名 DWARF 版本 5 第 7.7.1 節,並刪除第 7.7.2 節,以反映位置描述統一為 DWARF 運算式。
這擴充了 DWARF 版本 5 第 7.7.1 節和表 7.9,並新增了一個新表格,描述 DW_OP_LLVM_user
的供應商擴充運算。
DWARF 運算式儲存在連續位元組區塊中。這些位元組形成一系列運算。每個運算都是一個 1 位元組代碼,用於識別該運算,後跟零個或多個位元組的額外資料。DW_OP_LLVM_user
運算的編碼在DWARF 運算編碼中描述,而所有 DW_OP_LLVM_user
供應商擴充運算的編碼在DWARF DW_OP_LLVM_user 供應商擴充運算編碼中描述。
運算 |
代碼 |
運算元數量 |
註解 |
---|---|---|---|
|
0xe9 |
1+ |
ULEB128 供應商擴充運算碼,後跟 DWARF DW_OP_LLVM_user 供應商擴充運算編碼 中定義的供應商擴充運算元 |
運算 |
供應商擴充運算碼 |
額外運算元數量 |
註解 |
---|---|---|---|
|
0x02 |
0 |
|
|
0x03 |
0 |
|
|
0x04 |
0 |
|
|
0x05 |
1 |
ULEB128 位元組位移量 |
|
0x06 |
0 |
|
|
0x07 |
1 |
ULEB128 暫存器編號 |
|
0x08 |
0 |
|
|
0x09 |
2 |
ULEB128 暫存器編號、SLEB128 位元組位移量 |
|
0x0a |
0 |
|
|
0x0b |
2 |
ULEB128 位元大小、ULEB128 計數 |
|
0x0c |
2 |
ULEB128 位元大小、ULEB128 計數 |
|
TBA |
2 |
4 位元組或 8 位元組 DIE 位移量、SLEB128 位元組位移量 |
|
TBA |
0 |
|
|
TBA |
0 |
|
|
TBA |
0 |
A.7.7.3 位置清單運算式¶
注意
重新命名 DWARF 版本 5 第 7.7.3 節,以反映位置清單是一種 DWARF 運算式。
A.7.12 原始語言¶
注意
這擴充了 DWARF 版本 5 第 7.12 節和表 7.17。
下表列出額外 DWARF 語言的編碼。
語言名稱 |
值 |
預設下限 |
---|---|---|
|
0x8100 |
0 |
A.7.14 位址空間編碼¶
注意
這是 DWARF 版本 5 第 7.13 節「位址類別和位址空間編碼」之後的新增章節。
通用位址空間編碼 DW_ASPACE_LLVM_none
的值為 0。
A.7.15 記憶體空間編碼¶
注意
這是 DWARF 版本 5 第 7.13 節「位址類別和位址空間編碼」之後的新增章節。
目前定義的記憶體空間所使用的常數編碼在記憶體空間編碼中給出。
記憶體空間名稱 |
值 |
---|---|
|
0x0000 |
|
0x0001 |
|
0x0002 |
|
0x0003 |
|
0x0004 |
|
0x8000 |
|
0xffff |
A.7.22 行號資訊¶
注意
這擴充了 DWARF 版本 5 第 7.22 節和表 7.27。
下表列出行號標頭項目格式的額外編碼。
行號標頭項目格式名稱 |
值 |
---|---|
|
0x2001 |
|
0x2002 |
A.7.24 呼叫框架資訊¶
注意
這擴充了 DWARF 版本 5 第 7.24 節和表 7.29。
下表列出額外呼叫框架資訊指令的編碼。
指令 |
高位元 2 位元 |
低位元 6 位元 |
運算元 1 |
運算元 2 |
運算元 3 |
---|---|---|---|---|---|
|
0 |
0x30 |
ULEB128 暫存器 |
ULEB128 位移量 |
ULEB128 位址空間 |
|
0 |
0x31 |
ULEB128 暫存器 |
SLEB128 位移量 |
ULEB128 位址空間 |
A.7.32 類型簽章計算¶
注意
這(依字母順序)擴充了 DWARF 版本 5 第 7.32 節,表 7.32。
|
|
|
|
|
A. 依標籤值劃分的屬性 (資訊性)¶
注意
這擴充了 DWARF 版本 5 附錄 A 和表 A.1。
下表提供適用於偵錯資訊項目的額外屬性。
標籤名稱 |
適用的屬性 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
D. 範例 (資訊性)¶
注意
這修改了對應的 DWARF 第 5 版附錄 D 範例。
D.1 一般描述範例¶
D.1.3 DWARF 位置描述範例¶
DW_OP_offset_uconst 4
結構成員距離結構實例的起始位置為四個位元組。結構實例基準位置的位置描述假設已在堆疊上。
DW_OP_entry_value 1 DW_OP_reg5 DW_OP_offset_uconst 16
記憶體位置的位址計算方式為:將 16 加到進入目前子程式時暫存器 5 中所包含的值。
D.2 聚合範例¶
D.2.1 Fortran 簡單陣列範例¶
圖 D.4:Fortran 陣列範例:DWARF 描述
1-------------------------------------------------------------------------------
2! Description for type of 'ap'
3!
41$: DW_TAG_array_type
5 ! No name, default (Fortran) ordering, default stride
6 DW_AT_type(reference to REAL)
7 DW_AT_associated(expression= ! Test 'ptr_assoc' flag
8 DW_OP_push_object_address
9 DW_OP_lit<n> ! where n == offset(ptr_assoc)
10 DW_OP_offset
11 DW_OP_deref
12 DW_OP_lit1 ! mask for 'ptr_assoc' flag
13 DW_OP_and)
14 DW_AT_data_location(expression= ! Get raw data address
15 DW_OP_push_object_address
16 DW_OP_lit<n> ! where n == offset(base)
17 DW_OP_offset
18 DW_OP_deref) ! Type of index of array 'ap'
192$: DW_TAG_subrange_type
20 ! No name, default stride
21 DW_AT_type(reference to INTEGER)
22 DW_AT_lower_bound(expression=
23 DW_OP_push_object_address
24 DW_OP_lit<n> ! where n ==
25 ! offset(desc, dims) +
26 ! offset(dims_str, lower_bound)
27 DW_OP_offset
28 DW_OP_deref)
29 DW_AT_upper_bound(expression=
30 DW_OP_push_object_address
31 DW_OP_lit<n> ! where n ==
32 ! offset(desc, dims) +
33 ! offset(dims_str, upper_bound)
34 DW_OP_offset
35 DW_OP_deref)
36! Note: for the m'th dimension, the second operator becomes
37! DW_OP_lit<n> where
38! n == offset(desc, dims) +
39! (m-1)*sizeof(dims_str) +
40! offset(dims_str, [lower|upper]_bound)
41! That is, the expression does not get longer for each successive
42! dimension (other than to express the larger offsets involved).
433$: DW_TAG_structure_type
44 DW_AT_name("array_ptr")
45 DW_AT_byte_size(constant sizeof(REAL) + sizeof(desc<1>))
464$: DW_TAG_member
47 DW_AT_name("myvar")
48 DW_AT_type(reference to REAL)
49 DW_AT_data_member_location(constant 0)
505$: DW_TAG_member
51 DW_AT_name("ap");
52 DW_AT_type(reference to 1$)
53 DW_AT_data_member_location(constant sizeof(REAL))
546$: DW_TAG_array_type
55 ! No name, default (Fortran) ordering, default stride
56 DW_AT_type(reference to 3$)
57 DW_AT_allocated(expression= ! Test 'ptr_alloc' flag
58 DW_OP_push_object_address
59 DW_OP_lit<n> ! where n == offset(ptr_alloc)
60 DW_OP_offset
61 DW_OP_deref
62 DW_OP_lit2 ! Mask for 'ptr_alloc' flag
63 DW_OP_and)
64 DW_AT_data_location(expression= ! Get raw data address
65 DW_OP_push_object_address
66 DW_OP_lit<n> ! where n == offset(base)
67 DW_OP_offset
68 DW_OP_deref)
697$: DW_TAG_subrange_type
70 ! No name, default stride
71 DW_AT_type(reference to INTEGER)
72 DW_AT_lower_bound(expression=
73 DW_OP_push_object_address
74 DW_OP_lit<n> ! where n == ...
75 DW_OP_offset
76 DW_OP_deref)
77 DW_AT_upper_bound(expression=
78 DW_OP_push_object_address
79 DW_OP_lit<n> ! where n == ...
80 DW_OP_offset
81 DW_OP_deref)
828$: DW_TAG_variable
83 DW_AT_name("arrayvar")
84 DW_AT_type(reference to 6$)
85 DW_AT_location(expression=
86 ...as appropriate...) ! Assume static allocation
87-------------------------------------------------------------------------------
D.2.3 Fortran 2008 假定秩陣列範例¶
圖 D.13:圖 D.12 中陣列描述子的範例 DWARF
1----------------------------------------------------------------------------
210$: DW_TAG_array_type
3 DW_AT_type(reference to real)
4 DW_AT_rank(expression=
5 DW_OP_push_object_address
6 DW_OP_lit<n>
7 DW_OP_offset
8 DW_OP_deref)
9 DW_AT_data_location(expression=
10 DW_OP_push_object_address
11 DW_OP_lit<n>
12 DW_OP_offset
13 DW_OP_deref)
1411$: DW_TAG_generic_subrange
15 DW_AT_type(reference to integer)
16 ! offset of rank in descriptor
17 ! offset of data in descriptor
18 DW_AT_lower_bound(expression=
19 ! Looks up the lower bound of dimension i.
20 ! Operation ! Stack effect
21 ! (implicit) ! i
22 DW_OP_lit<n> ! i sizeof(dim)
23 DW_OP_mul ! dim[i]
24 DW_OP_lit<n> ! dim[i] offsetof(dim)
25 DW_OP_plus ! dim[i]+offset
26 DW_OP_push_object_address ! dim[i]+offsetof(dim) objptr
27 DW_OP_swap ! objptr dim[i]+offsetof(dim)
28 DW_OP_offset ! objptr.dim[i]
29 DW_OP_lit<n> ! objptr.dim[i] offsetof(lb)
30 DW_OP_offset ! objptr.dim[i].lowerbound
31 DW_OP_deref) ! *objptr.dim[i].lowerbound
32 DW_AT_upper_bound(expression=
33 ! Looks up the upper bound of dimension i.
34 DW_OP_lit<n> ! sizeof(dim)
35 DW_OP_mul
36 DW_OP_lit<n> ! offsetof(dim)
37 DW_OP_plus
38 DW_OP_push_object_address
39 DW_OP_swap
40 DW_OP_offset
41 DW_OP_lit<n> ! offset of upperbound in dim
42 DW_OP_offset
43 DW_OP_deref)
44 DW_AT_byte_stride(expression=
45 ! Looks up the byte stride of dimension i.
46 ...
47 ! (analogous to DW_AT_upper_bound)
48 )
49----------------------------------------------------------------------------
注意
此範例建議 DW_AT_lower_bound
和 DW_AT_upper_bound
評估 exprloc,其初始堆疊包含秩值。應更新屬性定義以說明這一點。
D.2.6 Ada 範例¶
圖 D.20:Ada 範例:DWARF 描述
1----------------------------------------------------------------------------
211$: DW_TAG_variable
3 DW_AT_name("M")
4 DW_AT_type(reference to INTEGER)
512$: DW_TAG_array_type
6 ! No name, default (Ada) order, default stride
7 DW_AT_type(reference to INTEGER)
813$: DW_TAG_subrange_type
9 DW_AT_type(reference to INTEGER)
10 DW_AT_lower_bound(constant 1)
11 DW_AT_upper_bound(reference to variable M at 11$)
1214$: DW_TAG_variable
13 DW_AT_name("VEC1")
14 DW_AT_type(reference to array type at 12$)
15 ...
1621$: DW_TAG_subrange_type
17 DW_AT_name("TEENY")
18 DW_AT_type(reference to INTEGER)
19 DW_AT_lower_bound(constant 1)
20 DW_AT_upper_bound(constant 100)
21 ...
2226$: DW_TAG_structure_type
23 DW_AT_name("REC2")
2427$: DW_TAG_member
25 DW_AT_name("N")
26 DW_AT_type(reference to subtype TEENY at 21$)
27 DW_AT_data_member_location(constant 0)
2828$: DW_TAG_array_type
29 ! No name, default (Ada) order, default stride
30 ! Default data location
31 DW_AT_type(reference to INTEGER)
3229$: DW_TAG_subrange_type
33 DW_AT_type(reference to subrange TEENY at 21$)
34 DW_AT_lower_bound(constant 1)
35 DW_AT_upper_bound(reference to member N at 27$)
3630$: DW_TAG_member
37 DW_AT_name("VEC2")
38 DW_AT_type(reference to array "subtype" at 28$)
39 DW_AT_data_member_location(machine=
40 DW_OP_lit<n> ! where n == offset(REC2, VEC2)
41 DW_OP_offset)
42 ...
4341$: DW_TAG_variable
44 DW_AT_name("OBJ2B")
45 DW_AT_type(reference to REC2 at 26$)
46 DW_AT_location(...as appropriate...)
47----------------------------------------------------------------------------
C. 更多範例¶
這些擴充功能在 AMD GPU 中的特定用法,包括範例,可在AMDGPU 後端使用者指南的 DWARF 偵錯資訊 章節中找到。
注意
變更範例以使用 DW_OP_LLVM_offset
而非 DW_OP_add
,當作用於位置描述時。
需要提供新功能的範例。
D. 參考文獻¶
[AMD] Advanced Micro Devices
[AMD-ROCgdb] AMD ROCm Debugger (ROCgdb)
[AMD-ROCm] AMD ROCm Platform
[AMDGPU-DWARF-LOC] Allow Location Descriptions on the DWARF Expression Stack
[AMDGPU-LLVM] User Guide for AMDGPU LLVM Backend
[CUDA] Nvidia CUDA Language
[HIP] HIP Programming Guide
[OpenCL] The OpenCL Specification Version 2.0
[Perforce-TotalView] Perforce TotalView HPC Debugging Software
[SEMVER] Semantic Versioning