aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp748
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp248
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h108
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp300
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h57
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp1454
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h159
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp103
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h28
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp196
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h159
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp160
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h125
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp1120
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h157
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp2336
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h286
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp501
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h146
20 files changed, 8416 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp
new file mode 100644
index 000000000000..3c10d4aa314b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.cpp
@@ -0,0 +1,748 @@
+//===-- CodeViewRegisterMapping.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/lldb-defines.h"
+
+#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+static const uint32_t g_code_view_to_lldb_registers_arm64[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_w0_arm64, // ARM64_W0, 10)
+ gpr_w1_arm64, // ARM64_W1, 11)
+ gpr_w2_arm64, // ARM64_W2, 12)
+ gpr_w3_arm64, // ARM64_W3, 13)
+ gpr_w4_arm64, // ARM64_W4, 14)
+ gpr_w5_arm64, // ARM64_W5, 15)
+ gpr_w6_arm64, // ARM64_W6, 16)
+ gpr_w7_arm64, // ARM64_W7, 17)
+ gpr_w8_arm64, // ARM64_W8, 18)
+ gpr_w9_arm64, // ARM64_W9, 19)
+ gpr_w10_arm64, // ARM64_W10, 20)
+ gpr_w11_arm64, // ARM64_W11, 21)
+ gpr_w12_arm64, // ARM64_W12, 22)
+ gpr_w13_arm64, // ARM64_W13, 23)
+ gpr_w14_arm64, // ARM64_W14, 24)
+ gpr_w15_arm64, // ARM64_W15, 25)
+ gpr_w16_arm64, // ARM64_W16, 26)
+ gpr_w17_arm64, // ARM64_W17, 27)
+ gpr_w18_arm64, // ARM64_W18, 28)
+ gpr_w19_arm64, // ARM64_W19, 29)
+ gpr_w20_arm64, // ARM64_W20, 30)
+ gpr_w21_arm64, // ARM64_W21, 31)
+ gpr_w22_arm64, // ARM64_W22, 32)
+ gpr_w23_arm64, // ARM64_W23, 33)
+ gpr_w24_arm64, // ARM64_W24, 34)
+ gpr_w25_arm64, // ARM64_W25, 35)
+ gpr_w26_arm64, // ARM64_W26, 36)
+ gpr_w27_arm64, // ARM64_W27, 37)
+ gpr_w28_arm64, // ARM64_W28, 38)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_x0_arm64, // ARM64_X0, 50)
+ gpr_x1_arm64, // ARM64_X1, 51)
+ gpr_x2_arm64, // ARM64_X2, 52)
+ gpr_x3_arm64, // ARM64_X3, 53)
+ gpr_x4_arm64, // ARM64_X4, 54)
+ gpr_x5_arm64, // ARM64_X5, 55)
+ gpr_x6_arm64, // ARM64_X6, 56)
+ gpr_x7_arm64, // ARM64_X7, 57)
+ gpr_x8_arm64, // ARM64_X8, 58)
+ gpr_x9_arm64, // ARM64_X9, 59)
+ gpr_x10_arm64, // ARM64_X10, 60)
+ gpr_x11_arm64, // ARM64_X11, 61)
+ gpr_x12_arm64, // ARM64_X12, 62)
+ gpr_x13_arm64, // ARM64_X13, 63)
+ gpr_x14_arm64, // ARM64_X14, 64)
+ gpr_x15_arm64, // ARM64_X15, 65)
+ gpr_x16_arm64, // ARM64_X16, 66)
+ gpr_x17_arm64, // ARM64_X17, 67)
+ gpr_x18_arm64, // ARM64_X18, 68)
+ gpr_x19_arm64, // ARM64_X19, 69)
+ gpr_x20_arm64, // ARM64_X20, 70)
+ gpr_x21_arm64, // ARM64_X21, 71)
+ gpr_x22_arm64, // ARM64_X22, 72)
+ gpr_x23_arm64, // ARM64_X23, 73)
+ gpr_x24_arm64, // ARM64_X24, 74)
+ gpr_x25_arm64, // ARM64_X25, 75)
+ gpr_x26_arm64, // ARM64_X26, 76)
+ gpr_x27_arm64, // ARM64_X27, 77)
+ gpr_x28_arm64, // ARM64_X28, 78)
+ gpr_fp_arm64, // ARM64_FP, 79)
+ gpr_lr_arm64, // ARM64_LR, 80)
+ gpr_sp_arm64, // ARM64_SP, 81)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ gpr_cpsr_arm64, // ARM64_NZCV, 90)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_s0_arm64, // (ARM64_S0, 100)
+ fpu_s1_arm64, // (ARM64_S1, 101)
+ fpu_s2_arm64, // (ARM64_S2, 102)
+ fpu_s3_arm64, // (ARM64_S3, 103)
+ fpu_s4_arm64, // (ARM64_S4, 104)
+ fpu_s5_arm64, // (ARM64_S5, 105)
+ fpu_s6_arm64, // (ARM64_S6, 106)
+ fpu_s7_arm64, // (ARM64_S7, 107)
+ fpu_s8_arm64, // (ARM64_S8, 108)
+ fpu_s9_arm64, // (ARM64_S9, 109)
+ fpu_s10_arm64, // (ARM64_S10, 110)
+ fpu_s11_arm64, // (ARM64_S11, 111)
+ fpu_s12_arm64, // (ARM64_S12, 112)
+ fpu_s13_arm64, // (ARM64_S13, 113)
+ fpu_s14_arm64, // (ARM64_S14, 114)
+ fpu_s15_arm64, // (ARM64_S15, 115)
+ fpu_s16_arm64, // (ARM64_S16, 116)
+ fpu_s17_arm64, // (ARM64_S17, 117)
+ fpu_s18_arm64, // (ARM64_S18, 118)
+ fpu_s19_arm64, // (ARM64_S19, 119)
+ fpu_s20_arm64, // (ARM64_S20, 120)
+ fpu_s21_arm64, // (ARM64_S21, 121)
+ fpu_s22_arm64, // (ARM64_S22, 122)
+ fpu_s23_arm64, // (ARM64_S23, 123)
+ fpu_s24_arm64, // (ARM64_S24, 124)
+ fpu_s25_arm64, // (ARM64_S25, 125)
+ fpu_s26_arm64, // (ARM64_S26, 126)
+ fpu_s27_arm64, // (ARM64_S27, 127)
+ fpu_s28_arm64, // (ARM64_S28, 128)
+ fpu_s29_arm64, // (ARM64_S29, 129)
+ fpu_s30_arm64, // (ARM64_S30, 130)
+ fpu_s31_arm64, // (ARM64_S31, 131)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_d0_arm64, // (ARM64_D0, 140)
+ fpu_d1_arm64, // (ARM64_D1, 141)
+ fpu_d2_arm64, // (ARM64_D2, 142)
+ fpu_d3_arm64, // (ARM64_D3, 143)
+ fpu_d4_arm64, // (ARM64_D4, 144)
+ fpu_d5_arm64, // (ARM64_D5, 145)
+ fpu_d6_arm64, // (ARM64_D6, 146)
+ fpu_d7_arm64, // (ARM64_D7, 147)
+ fpu_d8_arm64, // (ARM64_D8, 148)
+ fpu_d9_arm64, // (ARM64_D9, 149)
+ fpu_d10_arm64, // (ARM64_D10, 150)
+ fpu_d11_arm64, // (ARM64_D11, 151)
+ fpu_d12_arm64, // (ARM64_D12, 152)
+ fpu_d13_arm64, // (ARM64_D13, 153)
+ fpu_d14_arm64, // (ARM64_D14, 154)
+ fpu_d15_arm64, // (ARM64_D15, 155)
+ fpu_d16_arm64, // (ARM64_D16, 156)
+ fpu_d17_arm64, // (ARM64_D17, 157)
+ fpu_d18_arm64, // (ARM64_D18, 158)
+ fpu_d19_arm64, // (ARM64_D19, 159)
+ fpu_d20_arm64, // (ARM64_D20, 160)
+ fpu_d21_arm64, // (ARM64_D21, 161)
+ fpu_d22_arm64, // (ARM64_D22, 162)
+ fpu_d23_arm64, // (ARM64_D23, 163)
+ fpu_d24_arm64, // (ARM64_D24, 164)
+ fpu_d25_arm64, // (ARM64_D25, 165)
+ fpu_d26_arm64, // (ARM64_D26, 166)
+ fpu_d27_arm64, // (ARM64_D27, 167)
+ fpu_d28_arm64, // (ARM64_D28, 168)
+ fpu_d29_arm64, // (ARM64_D29, 169)
+ fpu_d30_arm64, // (ARM64_D30, 170)
+ fpu_d31_arm64, // (ARM64_D31, 171)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_v0_arm64, // (ARM64_Q0, 180)
+ fpu_v1_arm64, // (ARM64_Q1, 181)
+ fpu_v2_arm64, // (ARM64_Q2, 182)
+ fpu_v3_arm64, // (ARM64_Q3, 183)
+ fpu_v4_arm64, // (ARM64_Q4, 184)
+ fpu_v5_arm64, // (ARM64_Q5, 185)
+ fpu_v6_arm64, // (ARM64_Q6, 186)
+ fpu_v7_arm64, // (ARM64_Q7, 187)
+ fpu_v8_arm64, // (ARM64_Q8, 188)
+ fpu_v9_arm64, // (ARM64_Q9, 189)
+ fpu_v10_arm64, // (ARM64_Q10, 190)
+ fpu_v11_arm64, // (ARM64_Q11, 191)
+ fpu_v12_arm64, // (ARM64_Q12, 192)
+ fpu_v13_arm64, // (ARM64_Q13, 193)
+ fpu_v14_arm64, // (ARM64_Q14, 194)
+ fpu_v15_arm64, // (ARM64_Q15, 195)
+ fpu_v16_arm64, // (ARM64_Q16, 196)
+ fpu_v17_arm64, // (ARM64_Q17, 197)
+ fpu_v18_arm64, // (ARM64_Q18, 198)
+ fpu_v19_arm64, // (ARM64_Q19, 199)
+ fpu_v20_arm64, // (ARM64_Q20, 200)
+ fpu_v21_arm64, // (ARM64_Q21, 201)
+ fpu_v22_arm64, // (ARM64_Q22, 202)
+ fpu_v23_arm64, // (ARM64_Q23, 203)
+ fpu_v24_arm64, // (ARM64_Q24, 204)
+ fpu_v25_arm64, // (ARM64_Q25, 205)
+ fpu_v26_arm64, // (ARM64_Q26, 206)
+ fpu_v27_arm64, // (ARM64_Q27, 207)
+ fpu_v28_arm64, // (ARM64_Q28, 208)
+ fpu_v29_arm64, // (ARM64_Q29, 209)
+ fpu_v30_arm64, // (ARM64_Q30, 210)
+ fpu_v31_arm64, // (ARM64_Q31, 211)
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ fpu_fpsr_arm64 // ARM64_FPSR, 220)
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_i386, // AL
+ lldb_cl_i386, // CL
+ lldb_dl_i386, // DL
+ lldb_bl_i386, // BL
+ lldb_ah_i386, // AH
+ lldb_ch_i386, // CH
+ lldb_dh_i386, // DH
+ lldb_bh_i386, // BH
+ lldb_ax_i386, // AX
+ lldb_cx_i386, // CX
+ lldb_dx_i386, // DX
+ lldb_bx_i386, // BX
+ lldb_sp_i386, // SP
+ lldb_bp_i386, // BP
+ lldb_si_i386, // SI
+ lldb_di_i386, // DI
+ lldb_eax_i386, // EAX
+ lldb_ecx_i386, // ECX
+ lldb_edx_i386, // EDX
+ lldb_ebx_i386, // EBX
+ lldb_esp_i386, // ESP
+ lldb_ebp_i386, // EBP
+ lldb_esi_i386, // ESI
+ lldb_edi_i386, // EDI
+ lldb_es_i386, // ES
+ lldb_cs_i386, // CS
+ lldb_ss_i386, // SS
+ lldb_ds_i386, // DS
+ lldb_fs_i386, // FS
+ lldb_gs_i386, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ lldb_eip_i386, // EIP
+ lldb_eflags_i386, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_i386, // DR0
+ lldb_dr1_i386, // DR1
+ lldb_dr2_i386, // DR2
+ lldb_dr3_i386, // DR3
+ lldb_dr4_i386, // DR4
+ lldb_dr5_i386, // DR5
+ lldb_dr6_i386, // DR6
+ lldb_dr7_i386, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_i386, // ST0
+ lldb_st1_i386, // ST1
+ lldb_st2_i386, // ST2
+ lldb_st3_i386, // ST3
+ lldb_st4_i386, // ST4
+ lldb_st5_i386, // ST5
+ lldb_st6_i386, // ST6
+ lldb_st7_i386, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_i386, // MM0
+ lldb_mm1_i386, // MM1
+ lldb_mm2_i386, // MM2
+ lldb_mm3_i386, // MM3
+ lldb_mm4_i386, // MM4
+ lldb_mm5_i386, // MM5
+ lldb_mm6_i386, // MM6
+ lldb_mm7_i386, // MM7
+ lldb_xmm0_i386, // XMM0
+ lldb_xmm1_i386, // XMM1
+ lldb_xmm2_i386, // XMM2
+ lldb_xmm3_i386, // XMM3
+ lldb_xmm4_i386, // XMM4
+ lldb_xmm5_i386, // XMM5
+ lldb_xmm6_i386, // XMM6
+ lldb_xmm7_i386 // XMM7
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
+ LLDB_INVALID_REGNUM, // NONE
+ lldb_al_x86_64, // AL
+ lldb_cl_x86_64, // CL
+ lldb_dl_x86_64, // DL
+ lldb_bl_x86_64, // BL
+ lldb_ah_x86_64, // AH
+ lldb_ch_x86_64, // CH
+ lldb_dh_x86_64, // DH
+ lldb_bh_x86_64, // BH
+ lldb_ax_x86_64, // AX
+ lldb_cx_x86_64, // CX
+ lldb_dx_x86_64, // DX
+ lldb_bx_x86_64, // BX
+ lldb_sp_x86_64, // SP
+ lldb_bp_x86_64, // BP
+ lldb_si_x86_64, // SI
+ lldb_di_x86_64, // DI
+ lldb_eax_x86_64, // EAX
+ lldb_ecx_x86_64, // ECX
+ lldb_edx_x86_64, // EDX
+ lldb_ebx_x86_64, // EBX
+ lldb_esp_x86_64, // ESP
+ lldb_ebp_x86_64, // EBP
+ lldb_esi_x86_64, // ESI
+ lldb_edi_x86_64, // EDI
+ lldb_es_x86_64, // ES
+ lldb_cs_x86_64, // CS
+ lldb_ss_x86_64, // SS
+ lldb_ds_x86_64, // DS
+ lldb_fs_x86_64, // FS
+ lldb_gs_x86_64, // GS
+ LLDB_INVALID_REGNUM, // IP
+ LLDB_INVALID_REGNUM, // FLAGS
+ LLDB_INVALID_REGNUM, // EIP
+ LLDB_INVALID_REGNUM, // EFLAGS
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // TEMP
+ LLDB_INVALID_REGNUM, // TEMPH
+ LLDB_INVALID_REGNUM, // QUOTE
+ LLDB_INVALID_REGNUM, // PCDR3
+ LLDB_INVALID_REGNUM, // PCDR4
+ LLDB_INVALID_REGNUM, // PCDR5
+ LLDB_INVALID_REGNUM, // PCDR6
+ LLDB_INVALID_REGNUM, // PCDR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // CR0
+ LLDB_INVALID_REGNUM, // CR1
+ LLDB_INVALID_REGNUM, // CR2
+ LLDB_INVALID_REGNUM, // CR3
+ LLDB_INVALID_REGNUM, // CR4
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_dr0_x86_64, // DR0
+ lldb_dr1_x86_64, // DR1
+ lldb_dr2_x86_64, // DR2
+ lldb_dr3_x86_64, // DR3
+ lldb_dr4_x86_64, // DR4
+ lldb_dr5_x86_64, // DR5
+ lldb_dr6_x86_64, // DR6
+ lldb_dr7_x86_64, // DR7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // GDTR
+ LLDB_INVALID_REGNUM, // GDTL
+ LLDB_INVALID_REGNUM, // IDTR
+ LLDB_INVALID_REGNUM, // IDTL
+ LLDB_INVALID_REGNUM, // LDTR
+ LLDB_INVALID_REGNUM, // TR
+ LLDB_INVALID_REGNUM, // PSEUDO1
+ LLDB_INVALID_REGNUM, // PSEUDO2
+ LLDB_INVALID_REGNUM, // PSEUDO3
+ LLDB_INVALID_REGNUM, // PSEUDO4
+ LLDB_INVALID_REGNUM, // PSEUDO5
+ LLDB_INVALID_REGNUM, // PSEUDO6
+ LLDB_INVALID_REGNUM, // PSEUDO7
+ LLDB_INVALID_REGNUM, // PSEUDO8
+ LLDB_INVALID_REGNUM, // PSEUDO9
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_st0_x86_64, // ST0
+ lldb_st1_x86_64, // ST1
+ lldb_st2_x86_64, // ST2
+ lldb_st3_x86_64, // ST3
+ lldb_st4_x86_64, // ST4
+ lldb_st5_x86_64, // ST5
+ lldb_st6_x86_64, // ST6
+ lldb_st7_x86_64, // ST7
+ LLDB_INVALID_REGNUM, // CTRL
+ LLDB_INVALID_REGNUM, // STAT
+ LLDB_INVALID_REGNUM, // TAG
+ LLDB_INVALID_REGNUM, // FPIP
+ LLDB_INVALID_REGNUM, // FPCS
+ LLDB_INVALID_REGNUM, // FPDO
+ LLDB_INVALID_REGNUM, // FPDS
+ LLDB_INVALID_REGNUM, // ISEM
+ LLDB_INVALID_REGNUM, // FPEIP
+ LLDB_INVALID_REGNUM, // FPEDO
+ lldb_mm0_x86_64, // MM0
+ lldb_mm1_x86_64, // MM1
+ lldb_mm2_x86_64, // MM2
+ lldb_mm3_x86_64, // MM3
+ lldb_mm4_x86_64, // MM4
+ lldb_mm5_x86_64, // MM5
+ lldb_mm6_x86_64, // MM6
+ lldb_mm7_x86_64, // MM7
+ lldb_xmm0_x86_64, // XMM0
+ lldb_xmm1_x86_64, // XMM1
+ lldb_xmm2_x86_64, // XMM2
+ lldb_xmm3_x86_64, // XMM3
+ lldb_xmm4_x86_64, // XMM4
+ lldb_xmm5_x86_64, // XMM5
+ lldb_xmm6_x86_64, // XMM6
+ lldb_xmm7_x86_64, // XMM7
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_mxcsr_x86_64, // MXCSR
+ LLDB_INVALID_REGNUM, // EDXEAX
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, // EMM0L
+ LLDB_INVALID_REGNUM, // EMM1L
+ LLDB_INVALID_REGNUM, // EMM2L
+ LLDB_INVALID_REGNUM, // EMM3L
+ LLDB_INVALID_REGNUM, // EMM4L
+ LLDB_INVALID_REGNUM, // EMM5L
+ LLDB_INVALID_REGNUM, // EMM6L
+ LLDB_INVALID_REGNUM, // EMM7L
+ LLDB_INVALID_REGNUM, // EMM0H
+ LLDB_INVALID_REGNUM, // EMM1H
+ LLDB_INVALID_REGNUM, // EMM2H
+ LLDB_INVALID_REGNUM, // EMM3H
+ LLDB_INVALID_REGNUM, // EMM4H
+ LLDB_INVALID_REGNUM, // EMM5H
+ LLDB_INVALID_REGNUM, // EMM6H
+ LLDB_INVALID_REGNUM, // EMM7H
+ LLDB_INVALID_REGNUM, // MM00
+ LLDB_INVALID_REGNUM, // MM01
+ LLDB_INVALID_REGNUM, // MM10
+ LLDB_INVALID_REGNUM, // MM11
+ LLDB_INVALID_REGNUM, // MM20
+ LLDB_INVALID_REGNUM, // MM21
+ LLDB_INVALID_REGNUM, // MM30
+ LLDB_INVALID_REGNUM, // MM31
+ LLDB_INVALID_REGNUM, // MM40
+ LLDB_INVALID_REGNUM, // MM41
+ LLDB_INVALID_REGNUM, // MM50
+ LLDB_INVALID_REGNUM, // MM51
+ LLDB_INVALID_REGNUM, // MM60
+ LLDB_INVALID_REGNUM, // MM61
+ LLDB_INVALID_REGNUM, // MM70
+ LLDB_INVALID_REGNUM, // MM71
+ lldb_xmm8_x86_64, // XMM8
+ lldb_xmm9_x86_64, // XMM9
+ lldb_xmm10_x86_64, // XMM10
+ lldb_xmm11_x86_64, // XMM11
+ lldb_xmm12_x86_64, // XMM12
+ lldb_xmm13_x86_64, // XMM13
+ lldb_xmm14_x86_64, // XMM14
+ lldb_xmm15_x86_64, // XMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM,
+ lldb_sil_x86_64, // SIL
+ lldb_dil_x86_64, // DIL
+ lldb_bpl_x86_64, // BPL
+ lldb_spl_x86_64, // SPL
+ lldb_rax_x86_64, // RAX
+ lldb_rbx_x86_64, // RBX
+ lldb_rcx_x86_64, // RCX
+ lldb_rdx_x86_64, // RDX
+ lldb_rsi_x86_64, // RSI
+ lldb_rdi_x86_64, // RDI
+ lldb_rbp_x86_64, // RBP
+ lldb_rsp_x86_64, // RSP
+ lldb_r8_x86_64, // R8
+ lldb_r9_x86_64, // R9
+ lldb_r10_x86_64, // R10
+ lldb_r11_x86_64, // R11
+ lldb_r12_x86_64, // R12
+ lldb_r13_x86_64, // R13
+ lldb_r14_x86_64, // R14
+ lldb_r15_x86_64, // R15
+ lldb_r8l_x86_64, // R8B
+ lldb_r9l_x86_64, // R9B
+ lldb_r10l_x86_64, // R10B
+ lldb_r11l_x86_64, // R11B
+ lldb_r12l_x86_64, // R12B
+ lldb_r13l_x86_64, // R13B
+ lldb_r14l_x86_64, // R14B
+ lldb_r15l_x86_64, // R15B
+ lldb_r8w_x86_64, // R8W
+ lldb_r9w_x86_64, // R9W
+ lldb_r10w_x86_64, // R10W
+ lldb_r11w_x86_64, // R11W
+ lldb_r12w_x86_64, // R12W
+ lldb_r13w_x86_64, // R13W
+ lldb_r14w_x86_64, // R14W
+ lldb_r15w_x86_64, // R15W
+ lldb_r8d_x86_64, // R8D
+ lldb_r9d_x86_64, // R9D
+ lldb_r10d_x86_64, // R10D
+ lldb_r11d_x86_64, // R11D
+ lldb_r12d_x86_64, // R12D
+ lldb_r13d_x86_64, // R13D
+ lldb_r14d_x86_64, // R14D
+ lldb_r15d_x86_64, // R15D
+ lldb_ymm0_x86_64, // AMD64_YMM0
+ lldb_ymm1_x86_64, // AMD64_YMM1
+ lldb_ymm2_x86_64, // AMD64_YMM2
+ lldb_ymm3_x86_64, // AMD64_YMM3
+ lldb_ymm4_x86_64, // AMD64_YMM4
+ lldb_ymm5_x86_64, // AMD64_YMM5
+ lldb_ymm6_x86_64, // AMD64_YMM6
+ lldb_ymm7_x86_64, // AMD64_YMM7
+ lldb_ymm8_x86_64, // AMD64_YMM8
+ lldb_ymm9_x86_64, // AMD64_YMM9
+ lldb_ymm10_x86_64, // AMD64_YMM10
+ lldb_ymm11_x86_64, // AMD64_YMM11
+ lldb_ymm12_x86_64, // AMD64_YMM12
+ lldb_ymm13_x86_64, // AMD64_YMM13
+ lldb_ymm14_x86_64, // AMD64_YMM14
+ lldb_ymm15_x86_64, // AMD64_YMM15
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+ lldb_bnd0_x86_64, // BND0
+ lldb_bnd1_x86_64, // BND1
+ lldb_bnd2_x86_64 // BND2
+};
+
+uint32_t lldb_private::npdb::GetLLDBRegisterNumber(
+ llvm::Triple::ArchType arch_type, llvm::codeview::RegisterId register_id) {
+ switch (arch_type) {
+ case llvm::Triple::aarch64:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_arm64) /
+ sizeof(g_code_view_to_lldb_registers_arm64[0]))
+ return g_code_view_to_lldb_registers_arm64[static_cast<uint16_t>(
+ register_id)];
+
+ return LLDB_INVALID_REGNUM;
+ case llvm::Triple::x86:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86) /
+ sizeof(g_code_view_to_lldb_registers_x86[0]))
+ return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
+ register_id)];
+
+ switch (register_id) {
+ case llvm::codeview::RegisterId::MXCSR:
+ return lldb_mxcsr_i386;
+ case llvm::codeview::RegisterId::BND0:
+ return lldb_bnd0_i386;
+ case llvm::codeview::RegisterId::BND1:
+ return lldb_bnd1_i386;
+ case llvm::codeview::RegisterId::BND2:
+ return lldb_bnd2_i386;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ case llvm::Triple::x86_64:
+ if (static_cast<uint16_t>(register_id) <
+ sizeof(g_code_view_to_lldb_registers_x86_64) /
+ sizeof(g_code_view_to_lldb_registers_x86_64[0]))
+ return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
+ register_id)];
+
+ return LLDB_INVALID_REGNUM;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+}
+
+uint32_t
+lldb_private::npdb::GetRegisterSize(llvm::codeview::RegisterId register_id) {
+ switch(register_id) {
+ case llvm::codeview::RegisterId::AL:
+ case llvm::codeview::RegisterId::BL:
+ case llvm::codeview::RegisterId::CL:
+ case llvm::codeview::RegisterId::DL:
+ case llvm::codeview::RegisterId::AH:
+ case llvm::codeview::RegisterId::BH:
+ case llvm::codeview::RegisterId::CH:
+ case llvm::codeview::RegisterId::DH:
+ case llvm::codeview::RegisterId::SIL:
+ case llvm::codeview::RegisterId::DIL:
+ case llvm::codeview::RegisterId::BPL:
+ case llvm::codeview::RegisterId::SPL:
+ case llvm::codeview::RegisterId::R8B:
+ case llvm::codeview::RegisterId::R9B:
+ case llvm::codeview::RegisterId::R10B:
+ case llvm::codeview::RegisterId::R11B:
+ case llvm::codeview::RegisterId::R12B:
+ case llvm::codeview::RegisterId::R13B:
+ case llvm::codeview::RegisterId::R14B:
+ case llvm::codeview::RegisterId::R15B:
+ return 1;
+ case llvm::codeview::RegisterId::AX:
+ case llvm::codeview::RegisterId::BX:
+ case llvm::codeview::RegisterId::CX:
+ case llvm::codeview::RegisterId::DX:
+ case llvm::codeview::RegisterId::SP:
+ case llvm::codeview::RegisterId::BP:
+ case llvm::codeview::RegisterId::SI:
+ case llvm::codeview::RegisterId::DI:
+ case llvm::codeview::RegisterId::R8W:
+ case llvm::codeview::RegisterId::R9W:
+ case llvm::codeview::RegisterId::R10W:
+ case llvm::codeview::RegisterId::R11W:
+ case llvm::codeview::RegisterId::R12W:
+ case llvm::codeview::RegisterId::R13W:
+ case llvm::codeview::RegisterId::R14W:
+ case llvm::codeview::RegisterId::R15W:
+ return 2;
+ case llvm::codeview::RegisterId::EAX:
+ case llvm::codeview::RegisterId::EBX:
+ case llvm::codeview::RegisterId::ECX:
+ case llvm::codeview::RegisterId::EDX:
+ case llvm::codeview::RegisterId::ESP:
+ case llvm::codeview::RegisterId::EBP:
+ case llvm::codeview::RegisterId::ESI:
+ case llvm::codeview::RegisterId::EDI:
+ case llvm::codeview::RegisterId::R8D:
+ case llvm::codeview::RegisterId::R9D:
+ case llvm::codeview::RegisterId::R10D:
+ case llvm::codeview::RegisterId::R11D:
+ case llvm::codeview::RegisterId::R12D:
+ case llvm::codeview::RegisterId::R13D:
+ case llvm::codeview::RegisterId::R14D:
+ case llvm::codeview::RegisterId::R15D:
+ return 4;
+ case llvm::codeview::RegisterId::RAX:
+ case llvm::codeview::RegisterId::RBX:
+ case llvm::codeview::RegisterId::RCX:
+ case llvm::codeview::RegisterId::RDX:
+ case llvm::codeview::RegisterId::RSI:
+ case llvm::codeview::RegisterId::RDI:
+ case llvm::codeview::RegisterId::RBP:
+ case llvm::codeview::RegisterId::RSP:
+ case llvm::codeview::RegisterId::R8:
+ case llvm::codeview::RegisterId::R9:
+ case llvm::codeview::RegisterId::R10:
+ case llvm::codeview::RegisterId::R11:
+ case llvm::codeview::RegisterId::R12:
+ case llvm::codeview::RegisterId::R13:
+ case llvm::codeview::RegisterId::R14:
+ case llvm::codeview::RegisterId::R15:
+ return 8;
+ case llvm::codeview::RegisterId::XMM0:
+ case llvm::codeview::RegisterId::XMM1:
+ case llvm::codeview::RegisterId::XMM2:
+ case llvm::codeview::RegisterId::XMM3:
+ case llvm::codeview::RegisterId::XMM4:
+ case llvm::codeview::RegisterId::XMM5:
+ case llvm::codeview::RegisterId::XMM6:
+ case llvm::codeview::RegisterId::XMM7:
+ case llvm::codeview::RegisterId::XMM8:
+ case llvm::codeview::RegisterId::XMM9:
+ case llvm::codeview::RegisterId::XMM10:
+ case llvm::codeview::RegisterId::XMM11:
+ case llvm::codeview::RegisterId::XMM12:
+ case llvm::codeview::RegisterId::XMM13:
+ case llvm::codeview::RegisterId::XMM14:
+ case llvm::codeview::RegisterId::XMM15:
+ return 16;
+ default:
+ return 0;
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h
new file mode 100644
index 000000000000..4717fdcf11e3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h
@@ -0,0 +1,25 @@
+//===-- CodeViewRegisterMapping.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_CODEVIEWREGISTERMAPPING_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_CODEVIEWREGISTERMAPPING_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace lldb_private {
+namespace npdb {
+
+uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id);
+uint32_t GetRegisterSize(llvm::codeview::RegisterId register_id);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
new file mode 100644
index 000000000000..25d04f999ad6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -0,0 +1,248 @@
+//===-- CompileUnitIndex.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompileUnitIndex.h"
+
+#include "PdbIndex.h"
+#include "PdbUtil.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/Path.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) {
+ if (main == other)
+ return true;
+
+ // If the files refer to the local file system, we can just ask the file
+ // system if they're equivalent. But if the source isn't present on disk
+ // then we still want to try.
+ if (llvm::sys::fs::equivalent(main, other))
+ return true;
+
+ llvm::SmallString<64> normalized(other);
+ llvm::sys::path::native(normalized);
+ return main.equals_insensitive(normalized);
+}
+
+static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) {
+ cci.m_compile_opts.emplace();
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<Compile3Sym>(sym, *cci.m_compile_opts));
+}
+
+static void ParseObjname(const CVSymbol &sym, CompilandIndexItem &cci) {
+ cci.m_obj_name.emplace();
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ObjNameSym>(sym, *cci.m_obj_name));
+}
+
+static void ParseBuildInfo(PdbIndex &index, const CVSymbol &sym,
+ CompilandIndexItem &cci) {
+ BuildInfoSym bis(SymbolRecordKind::BuildInfoSym);
+ llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis));
+
+ // S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do
+ // a little extra work to pull out the LF_BUILDINFO.
+ LazyRandomTypeCollection &types = index.ipi().typeCollection();
+ std::optional<CVType> cvt = types.tryGetType(bis.BuildId);
+
+ if (!cvt || cvt->kind() != LF_BUILDINFO)
+ return;
+
+ BuildInfoRecord bir;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BuildInfoRecord>(*cvt, bir));
+ cci.m_build_info.assign(bir.ArgIndices.begin(), bir.ArgIndices.end());
+}
+
+static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
+ const CVSymbolArray &syms = item.m_debug_stream.getSymbolArray();
+
+ // This is a private function, it shouldn't be called if the information
+ // has already been parsed.
+ lldbassert(!item.m_obj_name);
+ lldbassert(!item.m_compile_opts);
+ lldbassert(item.m_build_info.empty());
+
+ // We're looking for 3 things. S_COMPILE3, S_OBJNAME, and S_BUILDINFO.
+ int found = 0;
+ for (const CVSymbol &sym : syms) {
+ switch (sym.kind()) {
+ case S_COMPILE3:
+ ParseCompile3(sym, item);
+ break;
+ case S_OBJNAME:
+ ParseObjname(sym, item);
+ break;
+ case S_BUILDINFO:
+ ParseBuildInfo(index, sym, item);
+ break;
+ default:
+ continue;
+ }
+ if (++found >= 3)
+ break;
+ }
+}
+
+static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {
+ for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {
+ if (ss.kind() != DebugSubsectionKind::InlineeLines)
+ continue;
+
+ DebugInlineeLinesSubsectionRef inlinee_lines;
+ llvm::BinaryStreamReader reader(ss.getRecordData());
+ if (llvm::Error error = inlinee_lines.initialize(reader)) {
+ consumeError(std::move(error));
+ continue;
+ }
+
+ for (const InlineeSourceLine &Line : inlinee_lines) {
+ item.m_inline_map[Line.Header->Inlinee] = Line;
+ }
+ }
+}
+
+CompilandIndexItem::CompilandIndexItem(
+ PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
+ llvm::pdb::DbiModuleDescriptor descriptor)
+ : m_id(id), m_debug_stream(std::move(debug_stream)),
+ m_module_descriptor(std::move(descriptor)) {}
+
+CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
+ auto result = m_comp_units.try_emplace(modi, nullptr);
+ if (!result.second)
+ return *result.first->second;
+
+ // Find the module list and load its debug information stream and cache it
+ // since we need to use it for almost all interesting operations.
+ const DbiModuleList &modules = m_index.dbi().modules();
+ llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);
+ uint16_t stream = descriptor.getModuleStreamIndex();
+ std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =
+ m_index.pdb().createIndexedStream(stream);
+
+
+ std::unique_ptr<CompilandIndexItem>& cci = result.first->second;
+
+ if (!stream_data) {
+ llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor, nullptr);
+ cci = std::make_unique<CompilandIndexItem>(PdbCompilandId{ modi }, debug_stream, std::move(descriptor));
+ return *cci;
+ }
+
+ llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
+ std::move(stream_data));
+
+ cantFail(debug_stream.reload());
+
+ cci = std::make_unique<CompilandIndexItem>(
+ PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
+ ParseExtendedInfo(m_index, *cci);
+ ParseInlineeLineTableForCompileUnit(*cci);
+
+ auto strings = m_index.pdb().getStringTable();
+ if (strings) {
+ cci->m_strings.initialize(cci->m_debug_stream.getSubsectionsArray());
+ cci->m_strings.setStrings(strings->getStringTable());
+ } else {
+ consumeError(strings.takeError());
+ }
+
+ // We want the main source file to always comes first. Note that we can't
+ // just push_back the main file onto the front because `GetMainSourceFile`
+ // computes it in such a way that it doesn't own the resulting memory. So we
+ // have to iterate the module file list comparing each one to the main file
+ // name until we find it, and we can cache that one since the memory is backed
+ // by a contiguous chunk inside the mapped PDB.
+ llvm::SmallString<64> main_file = GetMainSourceFile(*cci);
+ std::string s = std::string(main_file.str());
+ llvm::sys::path::native(main_file);
+
+ uint32_t file_count = modules.getSourceFileCount(modi);
+ cci->m_file_list.reserve(file_count);
+ bool found_main_file = false;
+ for (llvm::StringRef file : modules.source_files(modi)) {
+ if (!found_main_file && IsMainFile(main_file, file)) {
+ cci->m_file_list.insert(cci->m_file_list.begin(), file);
+ found_main_file = true;
+ continue;
+ }
+ cci->m_file_list.push_back(file);
+ }
+
+ return *cci;
+}
+
+const CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) const {
+ auto iter = m_comp_units.find(modi);
+ if (iter == m_comp_units.end())
+ return nullptr;
+ return iter->second.get();
+}
+
+CompilandIndexItem *CompileUnitIndex::GetCompiland(uint16_t modi) {
+ auto iter = m_comp_units.find(modi);
+ if (iter == m_comp_units.end())
+ return nullptr;
+ return iter->second.get();
+}
+
+llvm::SmallString<64>
+CompileUnitIndex::GetMainSourceFile(const CompilandIndexItem &item) const {
+ // LF_BUILDINFO contains a list of arg indices which point to LF_STRING_ID
+ // records in the IPI stream. The order of the arg indices is as follows:
+ // [0] - working directory where compiler was invoked.
+ // [1] - absolute path to compiler binary
+ // [2] - source file name
+ // [3] - path to compiler generated PDB (the /Zi PDB, although this entry gets
+ // added even when using /Z7)
+ // [4] - full command line invocation.
+ //
+ // We need to form the path [0]\[2] to generate the full path to the main
+ // file.source
+ if (item.m_build_info.size() < 3)
+ return {""};
+
+ LazyRandomTypeCollection &types = m_index.ipi().typeCollection();
+
+ StringIdRecord working_dir;
+ StringIdRecord file_name;
+ CVType dir_cvt = types.getType(item.m_build_info[0]);
+ CVType file_cvt = types.getType(item.m_build_info[2]);
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(dir_cvt, working_dir));
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(file_cvt, file_name));
+
+ llvm::sys::path::Style style = working_dir.String.starts_with("/")
+ ? llvm::sys::path::Style::posix
+ : llvm::sys::path::Style::windows;
+ if (llvm::sys::path::is_absolute(file_name.String, style))
+ return file_name.String;
+
+ llvm::SmallString<64> absolute_path = working_dir.String;
+ llvm::sys::path::append(absolute_path, file_name.String);
+ return absolute_path;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
new file mode 100644
index 000000000000..3e6766a204dd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -0,0 +1,108 @@
+//===-- CompileUnitIndex.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
+
+#include "lldb/Utility/RangeMap.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "PdbSymUid.h"
+
+#include <map>
+#include <memory>
+#include <optional>
+
+namespace lldb_private {
+
+namespace npdb {
+class PdbIndex;
+
+/// Represents a single compile unit. This class is useful for collecting the
+/// important accessors and information about a compile unit from disparate
+/// parts of the PDB into a single place, simplifying acess to compile unit
+/// information for the callers.
+struct CompilandIndexItem {
+ CompilandIndexItem(PdbCompilandId m_id,
+ llvm::pdb::ModuleDebugStreamRef debug_stream,
+ llvm::pdb::DbiModuleDescriptor descriptor);
+
+ // index of this compile unit.
+ PdbCompilandId m_id;
+
+ // debug stream.
+ llvm::pdb::ModuleDebugStreamRef m_debug_stream;
+
+ // dbi module descriptor.
+ llvm::pdb::DbiModuleDescriptor m_module_descriptor;
+
+ llvm::codeview::StringsAndChecksumsRef m_strings;
+
+ // List of files which contribute to this compiland.
+ std::vector<llvm::StringRef> m_file_list;
+
+ // Maps virtual address to global symbol id, which can then be used to
+ // locate the exact compile unit and offset of the symbol. Note that this
+ // is intentionally an ordered map so that we can find all symbols up to a
+ // given starting address.
+ std::map<lldb::addr_t, PdbSymUid> m_symbols_by_va;
+
+ // S_COMPILE3 sym describing compilation settings for the module.
+ std::optional<llvm::codeview::Compile3Sym> m_compile_opts;
+
+ // S_OBJNAME sym describing object name.
+ std::optional<llvm::codeview::ObjNameSym> m_obj_name;
+
+ // LF_BUILDINFO sym describing source file name, working directory,
+ // command line, etc. This usually contains exactly 5 items which
+ // are references to other strings.
+ llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
+
+ // Inlinee lines table in this compile unit.
+ std::map<llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine>
+ m_inline_map;
+
+ // It's the line table parsed from DEBUG_S_LINES sections, mapping the file
+ // address range to file index and source line number.
+ using GlobalLineTable =
+ lldb_private::RangeDataVector<lldb::addr_t, uint32_t,
+ std::pair<uint32_t, uint32_t>>;
+ GlobalLineTable m_global_line_table;
+};
+
+/// Indexes information about all compile units. This is really just a map of
+/// global compile unit index to |CompilandIndexItem| structures.
+class CompileUnitIndex {
+ PdbIndex &m_index;
+ llvm::DenseMap<uint16_t, std::unique_ptr<CompilandIndexItem>> m_comp_units;
+
+public:
+ explicit CompileUnitIndex(PdbIndex &index) : m_index(index) {}
+
+ CompilandIndexItem &GetOrCreateCompiland(uint16_t modi);
+
+ const CompilandIndexItem *GetCompiland(uint16_t modi) const;
+
+ CompilandIndexItem *GetCompiland(uint16_t modi);
+
+ llvm::SmallString<64> GetMainSourceFile(const CompilandIndexItem &item) const;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
new file mode 100644
index 000000000000..75adf7302f00
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -0,0 +1,300 @@
+//===-- DWARFLocationExpression.cpp ---------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationExpression.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/StreamBuffer.h"
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/Endian.h"
+
+#include "PdbUtil.h"
+#include "CodeViewRegisterMapping.h"
+#include "PdbFPOProgramToDWARFExpression.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
+ if (register_id == llvm::codeview::RegisterId::VFRAME)
+ return LLDB_REGNUM_GENERIC_FP;
+
+ return LLDB_INVALID_REGNUM;
+}
+
+static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
+ llvm::codeview::RegisterId register_id,
+ RegisterKind &register_kind) {
+ register_kind = eRegisterKindLLDB;
+ uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
+ if (reg_num != LLDB_INVALID_REGNUM)
+ return reg_num;
+
+ register_kind = eRegisterKindGeneric;
+ return GetGenericRegisterNumber(register_id);
+}
+
+static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti,
+ TpiStream &tpi) {
+ if (ti.isSimple()) {
+ SimpleTypeKind stk = ti.getSimpleKind();
+ return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
+ }
+
+ CVType cvt = tpi.getType(ti);
+ switch (cvt.kind()) {
+ case LF_MODIFIER: {
+ ModifierRecord mfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
+ return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
+ }
+ case LF_POINTER: {
+ PointerRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
+ return GetIntegralTypeInfo(pr.ReferentType, tpi);
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return GetIntegralTypeInfo(er.UnderlyingType, tpi);
+ }
+ default:
+ assert(false && "Type is not integral!");
+ return {0, false};
+ }
+}
+
+template <typename StreamWriter>
+static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
+ StreamWriter &&writer) {
+ const ArchSpec &architecture = module->GetArchitecture();
+ ByteOrder byte_order = architecture.GetByteOrder();
+ uint32_t address_size = architecture.GetAddressByteSize();
+ uint32_t byte_size = architecture.GetDataByteSize();
+ if (byte_order == eByteOrderInvalid || address_size == 0)
+ return DWARFExpression();
+
+ RegisterKind register_kind = eRegisterKindDWARF;
+ StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+
+ if (!writer(stream, register_kind))
+ return DWARFExpression();
+
+ DataBufferSP buffer =
+ std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+ DataExtractor extractor(buffer, byte_order, address_size, byte_size);
+ DWARFExpression result(extractor);
+ result.SetRegisterKind(register_kind);
+
+ return result;
+}
+
+static bool MakeRegisterBasedLocationExpressionInternal(
+ Stream &stream, llvm::codeview::RegisterId reg, RegisterKind &register_kind,
+ std::optional<int32_t> relative_offset, lldb::ModuleSP module) {
+ uint32_t reg_num = GetRegisterNumber(module->GetArchitecture().GetMachine(),
+ reg, register_kind);
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ if (reg_num > 31) {
+ llvm::dwarf::LocationAtom base =
+ relative_offset ? llvm::dwarf::DW_OP_bregx : llvm::dwarf::DW_OP_regx;
+ stream.PutHex8(base);
+ stream.PutULEB128(reg_num);
+ } else {
+ llvm::dwarf::LocationAtom base =
+ relative_offset ? llvm::dwarf::DW_OP_breg0 : llvm::dwarf::DW_OP_reg0;
+ stream.PutHex8(base + reg_num);
+ }
+
+ if (relative_offset)
+ stream.PutSLEB128(*relative_offset);
+
+ return true;
+}
+
+static DWARFExpression MakeRegisterBasedLocationExpressionInternal(
+ llvm::codeview::RegisterId reg, std::optional<int32_t> relative_offset,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ return MakeRegisterBasedLocationExpressionInternal(
+ stream, reg, register_kind, relative_offset, module);
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression(
+ llvm::codeview::RegisterId reg, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, std::nullopt, module);
+}
+
+DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression(
+ llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) {
+ return MakeRegisterBasedLocationExpressionInternal(reg, offset, module);
+}
+
+static bool EmitVFrameEvaluationDWARFExpression(
+ llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
+ // VFrame value always stored in $TO pseudo-register
+ return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
+ stream);
+}
+
+DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
+ llvm::StringRef fpo_program, int32_t offset, lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ const ArchSpec &architecture = module->GetArchitecture();
+
+ if (!EmitVFrameEvaluationDWARFExpression(fpo_program, architecture.GetMachine(),
+ stream))
+ return false;
+
+ stream.PutHex8(llvm::dwarf::DW_OP_consts);
+ stream.PutSLEB128(offset);
+ stream.PutHex8(llvm::dwarf::DW_OP_plus);
+
+ register_kind = eRegisterKindLLDB;
+
+ return true;
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
+ uint16_t section, uint32_t offset, ModuleSP module) {
+ assert(section > 0);
+ assert(module);
+
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ stream.PutHex8(llvm::dwarf::DW_OP_addr);
+
+ SectionList *section_list = module->GetSectionList();
+ assert(section_list);
+
+ auto section_ptr = section_list->FindSectionByID(section);
+ if (!section_ptr)
+ return false;
+
+ stream.PutMaxHex64(section_ptr->GetFileAddress() + offset,
+ stream.GetAddressByteSize(), stream.GetByteOrder());
+
+ return true;
+ });
+}
+
+DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
+ TypeIndex underlying_ti, TpiStream &tpi, const llvm::APSInt &constant,
+ ModuleSP module) {
+ const ArchSpec &architecture = module->GetArchitecture();
+ uint32_t address_size = architecture.GetAddressByteSize();
+
+ size_t size = 0;
+ bool is_signed = false;
+ std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
+
+ union {
+ llvm::support::little64_t I;
+ llvm::support::ulittle64_t U;
+ } Value;
+
+ std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
+ buffer->SetByteSize(size);
+
+ llvm::ArrayRef<uint8_t> bytes;
+ if (is_signed) {
+ Value.I = constant.getSExtValue();
+ } else {
+ Value.U = constant.getZExtValue();
+ }
+
+ bytes = llvm::ArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
+ .take_front(size);
+ buffer->CopyData(bytes.data(), size);
+ DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
+ DWARFExpression result(extractor);
+ return result;
+}
+
+DWARFExpression
+lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite(
+ const std::map<uint64_t, MemberValLocation> &offset_to_location,
+ std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
+ lldb::ModuleSP module) {
+ return MakeLocationExpressionInternal(
+ module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
+ size_t cur_offset = 0;
+ bool is_simple_type = offset_to_size.empty();
+ // Iterate through offset_to_location because offset_to_size might be
+ // empty if the variable is a simple type.
+ for (const auto &offset_loc : offset_to_location) {
+ if (cur_offset < offset_loc.first) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(offset_loc.first - cur_offset);
+ cur_offset = offset_loc.first;
+ }
+ MemberValLocation loc = offset_loc.second;
+ std::optional<int32_t> offset =
+ loc.is_at_reg ? std::nullopt
+ : std::optional<int32_t>(loc.reg_offset);
+ if (!MakeRegisterBasedLocationExpressionInternal(
+ stream, (RegisterId)loc.reg_id, register_kind, offset,
+ module))
+ return false;
+ if (!is_simple_type) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(offset_to_size[offset_loc.first]);
+ cur_offset = offset_loc.first + offset_to_size[offset_loc.first];
+ }
+ }
+ // For simple type, it specifies the byte size of the value described by
+ // the previous dwarf expr. For udt, it's the remaining byte size at end
+ // of a struct.
+ if (total_size > cur_offset) {
+ stream.PutHex8(llvm::dwarf::DW_OP_piece);
+ stream.PutULEB128(total_size - cur_offset);
+ }
+ return true;
+ });
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
new file mode 100644
index 000000000000..2f12d8bf0dd7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h
@@ -0,0 +1,57 @@
+//===-- DWARFLocationExpression.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
+
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include <map>
+
+namespace llvm {
+class APSInt;
+class StringRef;
+namespace codeview {
+class TypeIndex;
+}
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+namespace lldb_private {
+namespace npdb {
+struct MemberValLocation {
+ uint16_t reg_id;
+ uint16_t reg_offset;
+ bool is_at_reg = true;
+};
+
+DWARFExpression
+MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg,
+ lldb::ModuleSP module);
+
+DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg,
+ int32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
+ int32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
+ lldb::ModuleSP module);
+DWARFExpression MakeConstantLocationExpression(
+ llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi,
+ const llvm::APSInt &constant, lldb::ModuleSP module);
+DWARFExpression MakeEnregisteredLocationExpressionForComposite(
+ const std::map<uint64_t, MemberValLocation> &offset_to_location,
+ std::map<uint64_t, size_t> &offset_to_size, size_t total_size,
+ lldb::ModuleSP module);
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
new file mode 100644
index 000000000000..b79d3e63f72b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -0,0 +1,1454 @@
+#include "PdbAstBuilder.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
+
+#include "PdbUtil.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "SymbolFileNativePDB.h"
+#include "UdtRecordCompleter.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include <optional>
+#include <string_view>
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+struct CreateMethodDecl : public TypeVisitorCallbacks {
+ CreateMethodDecl(PdbIndex &m_index, TypeSystemClang &m_clang,
+ TypeIndex func_type_index,
+ clang::FunctionDecl *&function_decl,
+ lldb::opaque_compiler_type_t parent_ty,
+ llvm::StringRef proc_name, CompilerType func_ct)
+ : m_index(m_index), m_clang(m_clang), func_type_index(func_type_index),
+ function_decl(function_decl), parent_ty(parent_ty),
+ proc_name(proc_name), func_ct(func_ct) {}
+ PdbIndex &m_index;
+ TypeSystemClang &m_clang;
+ TypeIndex func_type_index;
+ clang::FunctionDecl *&function_decl;
+ lldb::opaque_compiler_type_t parent_ty;
+ llvm::StringRef proc_name;
+ CompilerType func_ct;
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) override {
+ TypeIndex method_list_idx = overloaded.MethodList;
+
+ CVType method_list_type = m_index.tpi().getType(method_list_idx);
+ assert(method_list_type.kind() == LF_METHODLIST);
+
+ MethodOverloadListRecord method_list;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods) {
+ if (method.getType().getIndex() == func_type_index.getIndex())
+ AddMethod(overloaded.Name, method.getAccess(), method.getOptions(),
+ method.Attrs);
+ }
+
+ return llvm::Error::success();
+ }
+
+ llvm::Error visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &record) override {
+ AddMethod(record.getName(), record.getAccess(), record.getOptions(),
+ record.Attrs);
+ return llvm::Error::success();
+ }
+
+ void AddMethod(llvm::StringRef name, MemberAccess access,
+ MethodOptions options, MemberAttributes attrs) {
+ if (name != proc_name || function_decl)
+ return;
+ lldb::AccessType access_type = TranslateMemberAccess(access);
+ bool is_virtual = attrs.isVirtual();
+ bool is_static = attrs.isStatic();
+ bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
+ MethodOptions::CompilerGenerated;
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_ty, proc_name,
+ /*mangled_name=*/nullptr, func_ct, /*access=*/access_type,
+ /*is_virtual=*/is_virtual, /*is_static=*/is_static,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/is_artificial);
+ }
+};
+} // namespace
+
+static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
+ switch (cr.Kind) {
+ case TypeRecordKind::Class:
+ return clang::TagTypeKind::Class;
+ case TypeRecordKind::Struct:
+ return clang::TagTypeKind::Struct;
+ case TypeRecordKind::Union:
+ return clang::TagTypeKind::Union;
+ case TypeRecordKind::Interface:
+ return clang::TagTypeKind::Interface;
+ case TypeRecordKind::Enum:
+ return clang::TagTypeKind::Enum;
+ default:
+ lldbassert(false && "Invalid tag record kind!");
+ return clang::TagTypeKind::Struct;
+ }
+}
+
+static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) {
+ if (args.empty())
+ return false;
+ return args.back() == TypeIndex::None();
+}
+
+static bool
+AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) {
+ for (llvm::ms_demangle::Node *n : scopes) {
+ auto *idn = static_cast<llvm::ms_demangle::IdentifierNode *>(n);
+ if (idn->TemplateParams)
+ return true;
+ }
+ return false;
+}
+
+static std::optional<clang::CallingConv>
+TranslateCallingConvention(llvm::codeview::CallingConvention conv) {
+ using CC = llvm::codeview::CallingConvention;
+ switch (conv) {
+
+ case CC::NearC:
+ case CC::FarC:
+ return clang::CallingConv::CC_C;
+ case CC::NearPascal:
+ case CC::FarPascal:
+ return clang::CallingConv::CC_X86Pascal;
+ case CC::NearFast:
+ case CC::FarFast:
+ return clang::CallingConv::CC_X86FastCall;
+ case CC::NearStdCall:
+ case CC::FarStdCall:
+ return clang::CallingConv::CC_X86StdCall;
+ case CC::ThisCall:
+ return clang::CallingConv::CC_X86ThisCall;
+ case CC::NearVector:
+ return clang::CallingConv::CC_X86VectorCall;
+ default:
+ return std::nullopt;
+ }
+}
+
+static bool IsAnonymousNamespaceName(llvm::StringRef name) {
+ return name == "`anonymous namespace'" || name == "`anonymous-namespace'";
+}
+
+PdbAstBuilder::PdbAstBuilder(TypeSystemClang &clang) : m_clang(clang) {}
+
+lldb_private::CompilerDeclContext PdbAstBuilder::GetTranslationUnitDecl() {
+ return ToCompilerDeclContext(*m_clang.GetTranslationUnitDecl());
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ // FIXME: Move this to GetDeclContextContainingUID.
+ if (!record.hasUniqueName())
+ return CreateDeclInfoForUndecoratedName(record.Name);
+
+ llvm::ms_demangle::Demangler demangler;
+ std::string_view sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return {m_clang.GetTranslationUnitDecl(), std::string(record.UniqueName)};
+
+ llvm::ms_demangle::IdentifierNode *idn =
+ ttn->QualifiedName->getUnqualifiedIdentifier();
+ std::string uname = idn->toString(llvm::ms_demangle::OF_NoTagSpecifier);
+
+ llvm::ms_demangle::NodeArrayNode *name_components =
+ ttn->QualifiedName->Components;
+ llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes,
+ name_components->Count - 1);
+
+ clang::DeclContext *context = m_clang.GetTranslationUnitDecl();
+
+ // If this type doesn't have a parent type in the debug info, then the best we
+ // can do is to say that it's either a series of namespaces (if the scope is
+ // non-empty), or the translation unit (if the scope is empty).
+ std::optional<TypeIndex> parent_index = pdb->GetParentType(ti);
+ if (!parent_index) {
+ if (scopes.empty())
+ return {context, uname};
+
+ // If there is no parent in the debug info, but some of the scopes have
+ // template params, then this is a case of bad debug info. See, for
+ // example, llvm.org/pr39607. We don't want to create an ambiguity between
+ // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at
+ // global scope with the fully qualified name.
+ if (AnyScopesHaveTemplateParams(scopes))
+ return {context, std::string(record.Name)};
+
+ for (llvm::ms_demangle::Node *scope : scopes) {
+ auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope);
+ std::string str = nii->toString();
+ context = GetOrCreateNamespaceDecl(str.c_str(), *context);
+ }
+ return {context, uname};
+ }
+
+ // Otherwise, all we need to do is get the parent type of this type and
+ // recurse into our lazy type creation / AST reconstruction logic to get an
+ // LLDB TypeSP for the parent. This will cause the AST to automatically get
+ // the right DeclContext created for any parent.
+ clang::QualType parent_qt = GetOrCreateType(*parent_index);
+ if (parent_qt.isNull())
+ return {nullptr, ""};
+
+ context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl());
+ return {context, uname};
+}
+
+static bool isLocalVariableType(SymbolKind K) {
+ switch (K) {
+ case S_REGISTER:
+ case S_REGREL32:
+ case S_LOCAL:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol cvs = index.ReadSymbolRecord(id);
+
+ if (isLocalVariableType(cvs.kind())) {
+ clang::DeclContext *scope = GetParentDeclContext(id);
+ if (!scope)
+ return nullptr;
+ clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
+ PdbCompilandSymId scope_id =
+ PdbSymUid(m_decl_to_status[scope_decl].uid).asCompilandSym();
+ return GetOrCreateVariableDecl(scope_id, id);
+ }
+
+ switch (cvs.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ return GetOrCreateFunctionDecl(id);
+ case S_GDATA32:
+ case S_LDATA32:
+ case S_GTHREAD32:
+ case S_CONSTANT:
+ // global variable
+ return nullptr;
+ case S_BLOCK32:
+ return GetOrCreateBlockDecl(id);
+ case S_INLINESITE:
+ return GetOrCreateInlinedFunctionDecl(id);
+ default:
+ return nullptr;
+ }
+}
+
+std::optional<CompilerDecl>
+PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) {
+ if (clang::Decl *result = TryGetDecl(uid))
+ return ToCompilerDecl(*result);
+
+ clang::Decl *result = nullptr;
+ switch (uid.kind()) {
+ case PdbSymUidKind::CompilandSym:
+ result = GetOrCreateSymbolForId(uid.asCompilandSym());
+ break;
+ case PdbSymUidKind::Type: {
+ clang::QualType qt = GetOrCreateType(uid.asTypeSym());
+ if (qt.isNull())
+ return std::nullopt;
+ if (auto *tag = qt->getAsTagDecl()) {
+ result = tag;
+ break;
+ }
+ return std::nullopt;
+ }
+ default:
+ return std::nullopt;
+ }
+
+ if (!result)
+ return std::nullopt;
+ m_uid_to_decl[toOpaqueUid(uid)] = result;
+ return ToCompilerDecl(*result);
+}
+
+clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) {
+ if (uid.kind() == PdbSymUidKind::CompilandSym) {
+ if (uid.asCompilandSym().offset == 0)
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+ }
+ auto option = GetOrCreateDeclForUid(uid);
+ if (!option)
+ return nullptr;
+ clang::Decl *decl = FromCompilerDecl(*option);
+ if (!decl)
+ return nullptr;
+
+ return clang::Decl::castToDeclContext(decl);
+}
+
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ auto *context = FromCompilerDeclContext(GetTranslationUnitDecl());
+
+ llvm::StringRef uname = specs.back().GetBaseName();
+ specs = specs.drop_back();
+ if (specs.empty())
+ return {context, std::string(name)};
+
+ llvm::StringRef scope_name = specs.back().GetFullName();
+
+ // It might be a class name, try that first.
+ std::vector<TypeIndex> types = index.tpi().findRecordsByName(scope_name);
+ while (!types.empty()) {
+ clang::QualType qt = GetOrCreateType(types.back());
+ if (qt.isNull())
+ continue;
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (tag)
+ return {clang::TagDecl::castToDeclContext(tag), std::string(uname)};
+ types.pop_back();
+ }
+
+ // If that fails, treat it as a series of namespaces.
+ for (const MSVCUndecoratedNameSpecifier &spec : specs) {
+ std::string ns_name = spec.GetBaseName().str();
+ context = GetOrCreateNamespaceDecl(ns_name.c_str(), *context);
+ }
+ return {context, std::string(uname)};
+}
+
+clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) {
+ // We must do this *without* calling GetOrCreate on the current uid, as
+ // that would be an infinite recursion.
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex& index = pdb->GetIndex();
+ switch (uid.kind()) {
+ case PdbSymUidKind::CompilandSym: {
+ std::optional<PdbCompilandSymId> scope =
+ pdb->FindSymbolScope(uid.asCompilandSym());
+ if (scope)
+ return GetOrCreateDeclContextForUid(*scope);
+
+ CVSymbol sym = index.ReadSymbolRecord(uid.asCompilandSym());
+ return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first;
+ }
+ case PdbSymUidKind::Type: {
+ // It could be a namespace, class, or global. We don't support nested
+ // functions yet. Anyway, we just need to consult the parent type map.
+ PdbTypeSymId type_id = uid.asTypeSym();
+ std::optional<TypeIndex> parent_index = pdb->GetParentType(type_id.index);
+ if (!parent_index)
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+ return GetOrCreateDeclContextForUid(PdbTypeSymId(*parent_index));
+ }
+ case PdbSymUidKind::FieldListMember:
+ // In this case the parent DeclContext is the one for the class that this
+ // member is inside of.
+ break;
+ case PdbSymUidKind::GlobalSym: {
+ // If this refers to a compiland symbol, just recurse in with that symbol.
+ // The only other possibilities are S_CONSTANT and S_UDT, in which case we
+ // need to parse the undecorated name to figure out the scope, then look
+ // that up in the TPI stream. If it's found, it's a type, othewrise it's
+ // a series of namespaces.
+ // FIXME: do this.
+ CVSymbol global = index.ReadSymbolRecord(uid.asGlobalSym());
+ switch (global.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first;;
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF: {
+ ProcRefSym ref{global.kind()};
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ProcRefSym>(global, ref));
+ PdbCompilandSymId cu_sym_id{ref.modi(), ref.SymOffset};
+ return GetParentDeclContext(cu_sym_id);
+ }
+ case SymbolKind::S_CONSTANT:
+ case SymbolKind::S_UDT:
+ return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return FromCompilerDeclContext(GetTranslationUnitDecl());
+}
+
+bool PdbAstBuilder::CompleteType(clang::QualType qt) {
+ if (qt.isNull())
+ return false;
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ if (qt->isArrayType()) {
+ const clang::Type *element_type = qt->getArrayElementTypeNoTypeQual();
+ tag = element_type->getAsTagDecl();
+ }
+ if (!tag)
+ return false;
+
+ return CompleteTagDecl(*tag);
+}
+
+bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
+ // If this is not in our map, it's an error.
+ auto status_iter = m_decl_to_status.find(&tag);
+ lldbassert(status_iter != m_decl_to_status.end());
+
+ // If it's already complete, just return.
+ DeclStatus &status = status_iter->second;
+ if (status.resolved)
+ return true;
+
+ PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym();
+ PdbIndex &index = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile())
+ ->GetIndex();
+ lldbassert(IsTagRecord(type_id, index.tpi()));
+
+ clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag);
+ TypeSystemClang::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false);
+
+ TypeIndex tag_ti = type_id.index;
+ CVType cvt = index.tpi().getType(tag_ti);
+ if (cvt.kind() == LF_MODIFIER)
+ tag_ti = LookThroughModifierRecord(cvt);
+
+ PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, index.tpi());
+ cvt = index.tpi().getType(best_ti.index);
+ lldbassert(IsTagRecord(cvt));
+
+ if (IsForwardRefUdt(cvt)) {
+ // If we can't find a full decl for this forward ref anywhere in the debug
+ // info, then we have no way to complete it.
+ return false;
+ }
+
+ TypeIndex field_list_ti = GetFieldListIndex(cvt);
+ CVType field_list_cvt = index.tpi().getType(field_list_ti);
+ if (field_list_cvt.kind() != LF_FIELDLIST)
+ return false;
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+
+ // Visit all members of this class, then perform any finalization necessary
+ // to complete the class.
+ CompilerType ct = ToCompilerType(tag_qt);
+ UdtRecordCompleter completer(best_ti, ct, tag, *this, index, m_decl_to_status,
+ m_cxx_record_map);
+ llvm::Error error =
+ llvm::codeview::visitMemberRecordStream(field_list.Data, completer);
+ completer.complete();
+
+ m_decl_to_status[&tag].resolved = true;
+ if (error) {
+ llvm::consumeError(std::move(error));
+ return false;
+ }
+ return true;
+}
+
+clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) {
+ if (ti == TypeIndex::NullptrT())
+ return GetBasicType(lldb::eBasicTypeNullPtr);
+
+ if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+ clang::QualType direct_type = GetOrCreateType(ti.makeDirect());
+ if (direct_type.isNull())
+ return {};
+ return m_clang.getASTContext().getPointerType(direct_type);
+ }
+
+ if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+ return {};
+
+ lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind());
+ if (bt == lldb::eBasicTypeInvalid)
+ return {};
+
+ return GetBasicType(bt);
+}
+
+clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) {
+ clang::QualType pointee_type = GetOrCreateType(pointer.ReferentType);
+
+ // This can happen for pointers to LF_VTSHAPE records, which we shouldn't
+ // create in the AST.
+ if (pointee_type.isNull())
+ return {};
+
+ if (pointer.isPointerToMember()) {
+ MemberPointerInfo mpi = pointer.getMemberInfo();
+ clang::QualType class_type = GetOrCreateType(mpi.ContainingType);
+ if (class_type.isNull())
+ return {};
+ if (clang::TagDecl *tag = class_type->getAsTagDecl()) {
+ clang::MSInheritanceAttr::Spelling spelling;
+ switch (mpi.Representation) {
+ case llvm::codeview::PointerToMemberRepresentation::SingleInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ SingleInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::
+ MultipleInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ MultipleInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_multiple_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::
+ VirtualInheritanceData:
+ case llvm::codeview::PointerToMemberRepresentation::
+ VirtualInheritanceFunction:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_virtual_inheritance;
+ break;
+ case llvm::codeview::PointerToMemberRepresentation::Unknown:
+ spelling =
+ clang::MSInheritanceAttr::Spelling::Keyword_unspecified_inheritance;
+ break;
+ default:
+ spelling = clang::MSInheritanceAttr::Spelling::SpellingNotCalculated;
+ break;
+ }
+ tag->addAttr(clang::MSInheritanceAttr::CreateImplicit(
+ m_clang.getASTContext(), spelling));
+ }
+ return m_clang.getASTContext().getMemberPointerType(
+ pointee_type, class_type.getTypePtr());
+ }
+
+ clang::QualType pointer_type;
+ if (pointer.getMode() == PointerMode::LValueReference)
+ pointer_type = m_clang.getASTContext().getLValueReferenceType(pointee_type);
+ else if (pointer.getMode() == PointerMode::RValueReference)
+ pointer_type = m_clang.getASTContext().getRValueReferenceType(pointee_type);
+ else
+ pointer_type = m_clang.getASTContext().getPointerType(pointee_type);
+
+ if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None)
+ pointer_type.addConst();
+
+ if ((pointer.getOptions() & PointerOptions::Volatile) != PointerOptions::None)
+ pointer_type.addVolatile();
+
+ if ((pointer.getOptions() & PointerOptions::Restrict) != PointerOptions::None)
+ pointer_type.addRestrict();
+
+ return pointer_type;
+}
+
+clang::QualType
+PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) {
+ clang::QualType unmodified_type = GetOrCreateType(modifier.ModifiedType);
+ if (unmodified_type.isNull())
+ return {};
+
+ if ((modifier.Modifiers & ModifierOptions::Const) != ModifierOptions::None)
+ unmodified_type.addConst();
+ if ((modifier.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None)
+ unmodified_type.addVolatile();
+
+ return unmodified_type;
+}
+
+clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id,
+ const TagRecord &record) {
+ clang::DeclContext *context = nullptr;
+ std::string uname;
+ std::tie(context, uname) = CreateDeclInfoForType(record, id.index);
+ if (!context)
+ return {};
+
+ clang::TagTypeKind ttk = TranslateUdtKind(record);
+ lldb::AccessType access = (ttk == clang::TagTypeKind::Class)
+ ? lldb::eAccessPrivate
+ : lldb::eAccessPublic;
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(toOpaqueUid(id));
+ metadata.SetIsDynamicCXXType(false);
+
+ CompilerType ct = m_clang.CreateRecordType(
+ context, OptionalClangModuleID(), access, uname, llvm::to_underlying(ttk),
+ lldb::eLanguageTypeC_plus_plus, &metadata);
+
+ lldbassert(ct.IsValid());
+
+ TypeSystemClang::StartTagDeclarationDefinition(ct);
+
+ // Even if it's possible, don't complete it at this point. Just mark it
+ // forward resolved, and if/when LLDB needs the full definition, it can
+ // ask us.
+ clang::QualType result =
+ clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+
+ TypeSystemClang::SetHasExternalStorage(result.getAsOpaquePtr(), true);
+ return result;
+}
+
+clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const {
+ auto iter = m_uid_to_decl.find(toOpaqueUid(uid));
+ if (iter != m_uid_to_decl.end())
+ return iter->second;
+ return nullptr;
+}
+
+clang::NamespaceDecl *
+PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name,
+ clang::DeclContext &context) {
+ return m_clang.GetUniqueNamespaceDeclaration(
+ IsAnonymousNamespaceName(name) ? nullptr : name, &context,
+ OptionalClangModuleID());
+}
+
+clang::BlockDecl *
+PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) {
+ if (clang::Decl *decl = TryGetDecl(block_id))
+ return llvm::dyn_cast<clang::BlockDecl>(decl);
+
+ clang::DeclContext *scope = GetParentDeclContext(block_id);
+
+ clang::BlockDecl *block_decl =
+ m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID());
+ m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl});
+
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(block_id);
+ m_decl_to_status.insert({block_decl, status});
+
+ return block_decl;
+}
+
+clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym,
+ clang::DeclContext &scope) {
+ VariableInfo var_info = GetVariableNameInfo(sym);
+ clang::QualType qt = GetOrCreateType(var_info.type);
+ if (qt.isNull())
+ return nullptr;
+
+ clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration(
+ &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt);
+
+ m_uid_to_decl[toOpaqueUid(uid)] = var_decl;
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(uid);
+ m_decl_to_status.insert({var_decl, status});
+ return var_decl;
+}
+
+clang::VarDecl *
+PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id) {
+ if (clang::Decl *decl = TryGetDecl(var_id))
+ return llvm::dyn_cast<clang::VarDecl>(decl);
+
+ clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id);
+ if (!scope)
+ return nullptr;
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+ return CreateVariableDecl(PdbSymUid(var_id), sym, *scope);
+}
+
+clang::VarDecl *PdbAstBuilder::GetOrCreateVariableDecl(PdbGlobalSymId var_id) {
+ if (clang::Decl *decl = TryGetDecl(var_id))
+ return llvm::dyn_cast<clang::VarDecl>(decl);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+ auto context = FromCompilerDeclContext(GetTranslationUnitDecl());
+ return CreateVariableDecl(PdbSymUid(var_id), sym, *context);
+}
+
+clang::TypedefNameDecl *
+PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) {
+ if (clang::Decl *decl = TryGetDecl(id))
+ return llvm::dyn_cast<clang::TypedefNameDecl>(decl);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(id);
+ lldbassert(sym.kind() == S_UDT);
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+
+ clang::DeclContext *scope = GetParentDeclContext(id);
+
+ PdbTypeSymId real_type_id{udt.Type, false};
+ clang::QualType qt = GetOrCreateType(real_type_id);
+ if (qt.isNull() || !scope)
+ return nullptr;
+
+ std::string uname = std::string(DropNameScope(udt.Name));
+
+ CompilerType ct = ToCompilerType(qt).CreateTypedef(
+ uname.c_str(), ToCompilerDeclContext(*scope), 0);
+ clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct);
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(id);
+ m_decl_to_status.insert({tnd, status});
+ return tnd;
+}
+
+clang::QualType PdbAstBuilder::GetBasicType(lldb::BasicType type) {
+ CompilerType ct = m_clang.GetBasicType(type);
+ return clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) {
+ if (type.index.isSimple())
+ return CreateSimpleType(type.index);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVType cvt = index.tpi().getType(type.index);
+
+ if (cvt.kind() == LF_MODIFIER) {
+ ModifierRecord modifier;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+ return CreateModifierType(modifier);
+ }
+
+ if (cvt.kind() == LF_POINTER) {
+ PointerRecord pointer;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+ return CreatePointerType(pointer);
+ }
+
+ if (IsTagRecord(cvt)) {
+ CVTagRecord tag = CVTagRecord::create(cvt);
+ if (tag.kind() == CVTagRecord::Union)
+ return CreateRecordType(type.index, tag.asUnion());
+ if (tag.kind() == CVTagRecord::Enum)
+ return CreateEnumType(type.index, tag.asEnum());
+ return CreateRecordType(type.index, tag.asClass());
+ }
+
+ if (cvt.kind() == LF_ARRAY) {
+ ArrayRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
+ return CreateArrayType(ar);
+ }
+
+ if (cvt.kind() == LF_PROCEDURE) {
+ ProcedureRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
+ return CreateFunctionType(pr.ArgumentList, pr.ReturnType, pr.CallConv);
+ }
+
+ if (cvt.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<MemberFunctionRecord>(cvt, mfr));
+ return CreateFunctionType(mfr.ArgumentList, mfr.ReturnType, mfr.CallConv);
+ }
+
+ return {};
+}
+
+clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) {
+ if (type.index.isNoneType())
+ return {};
+
+ lldb::user_id_t uid = toOpaqueUid(type);
+ auto iter = m_uid_to_type.find(uid);
+ if (iter != m_uid_to_type.end())
+ return iter->second;
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ PdbTypeSymId best_type = GetBestPossibleDecl(type, index.tpi());
+
+ clang::QualType qt;
+ if (best_type.index != type.index) {
+ // This is a forward decl. Call GetOrCreate on the full decl, then map the
+ // forward decl id to the full decl QualType.
+ clang::QualType qt = GetOrCreateType(best_type);
+ if (qt.isNull())
+ return {};
+ m_uid_to_type[toOpaqueUid(type)] = qt;
+ return qt;
+ }
+
+ // This is either a full decl, or a forward decl with no matching full decl
+ // in the debug info.
+ qt = CreateType(type);
+ if (qt.isNull())
+ return {};
+
+ m_uid_to_type[toOpaqueUid(type)] = qt;
+ if (IsTagRecord(type, index.tpi())) {
+ clang::TagDecl *tag = qt->getAsTagDecl();
+ lldbassert(m_decl_to_status.count(tag) == 0);
+
+ DeclStatus &status = m_decl_to_status[tag];
+ status.uid = uid;
+ status.resolved = false;
+ }
+ return qt;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
+ llvm::StringRef func_name, TypeIndex func_ti,
+ CompilerType func_ct, uint32_t param_count,
+ clang::StorageClass func_storage,
+ bool is_inline, clang::DeclContext *parent) {
+ clang::FunctionDecl *function_decl = nullptr;
+ if (parent->isRecord()) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ clang::QualType parent_qt = llvm::cast<clang::TypeDecl>(parent)
+ ->getTypeForDecl()
+ ->getCanonicalTypeInternal();
+ lldb::opaque_compiler_type_t parent_opaque_ty =
+ ToCompilerType(parent_qt).GetOpaqueQualType();
+ // FIXME: Remove this workaround.
+ auto iter = m_cxx_record_map.find(parent_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({func_name, func_ct})) {
+ return nullptr;
+ }
+ }
+
+ CVType cvt = index.tpi().getType(func_ti);
+ MemberFunctionRecord func_record(static_cast<TypeRecordKind>(cvt.kind()));
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ cvt, func_record));
+ TypeIndex class_index = func_record.getClassType();
+
+ CVType parent_cvt = index.tpi().getType(class_index);
+ TagRecord tag_record = CVTagRecord::create(parent_cvt).asTag();
+ // If it's a forward reference, try to get the real TypeIndex.
+ if (tag_record.isForwardRef()) {
+ llvm::Expected<TypeIndex> eti =
+ index.tpi().findFullDeclForForwardRef(class_index);
+ if (eti) {
+ tag_record = CVTagRecord::create(index.tpi().getType(*eti)).asTag();
+ }
+ }
+ if (!tag_record.FieldList.isSimple()) {
+ CVType field_list_cvt = index.tpi().getType(tag_record.FieldList);
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+ CreateMethodDecl process(index, m_clang, func_ti, function_decl,
+ parent_opaque_ty, func_name, func_ct);
+ if (llvm::Error err = visitMemberRecordStream(field_list.Data, process))
+ llvm::consumeError(std::move(err));
+ }
+
+ if (!function_decl) {
+ function_decl = m_clang.AddMethodToCXXRecordType(
+ parent_opaque_ty, func_name,
+ /*mangled_name=*/nullptr, func_ct,
+ /*access=*/lldb::AccessType::eAccessPublic,
+ /*is_virtual=*/false, /*is_static=*/false,
+ /*is_inline=*/false, /*is_explicit=*/false,
+ /*is_attr_used=*/false, /*is_artificial=*/false);
+ }
+ m_cxx_record_map[parent_opaque_ty].insert({func_name, func_ct});
+ } else {
+ function_decl = m_clang.CreateFunctionDeclaration(
+ parent, OptionalClangModuleID(), func_name, func_ct, func_storage,
+ is_inline);
+ CreateFunctionParameters(func_id, *function_decl, param_count);
+ }
+ return function_decl;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::GetOrCreateInlinedFunctionDecl(PdbCompilandSymId inlinesite_id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CompilandIndexItem *cii =
+ index.compilands().GetCompiland(inlinesite_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(inlinesite_id.offset);
+ InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+
+ // Inlinee is the id index to the function id record that is inlined.
+ PdbTypeSymId func_id(inline_site.Inlinee, true);
+ // Look up the function decl by the id index to see if we have created a
+ // function decl for a different inlinesite that refers the same function.
+ if (clang::Decl *decl = TryGetDecl(func_id))
+ return llvm::dyn_cast<clang::FunctionDecl>(decl);
+ clang::FunctionDecl *function_decl =
+ CreateFunctionDeclFromId(func_id, inlinesite_id);
+ if (function_decl == nullptr)
+ return nullptr;
+
+ // Use inline site id in m_decl_to_status because it's expected to be a
+ // PdbCompilandSymId so that we can parse local variables info after it.
+ uint64_t inlinesite_uid = toOpaqueUid(inlinesite_id);
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = inlinesite_uid;
+ m_decl_to_status.insert({function_decl, status});
+ // Use the index in IPI stream as uid in m_uid_to_decl, because index in IPI
+ // stream are unique and there could be multiple inline sites (different ids)
+ // referring the same inline function. This avoid creating multiple same
+ // inline function delcs.
+ uint64_t func_uid = toOpaqueUid(func_id);
+ lldbassert(m_uid_to_decl.count(func_uid) == 0);
+ m_uid_to_decl[func_uid] = function_decl;
+ return function_decl;
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::CreateFunctionDeclFromId(PdbTypeSymId func_tid,
+ PdbCompilandSymId func_sid) {
+ lldbassert(func_tid.is_ipi);
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVType func_cvt = index.ipi().getType(func_tid.index);
+ llvm::StringRef func_name;
+ TypeIndex func_ti;
+ clang::DeclContext *parent = nullptr;
+ switch (func_cvt.kind()) {
+ case LF_MFUNC_ID: {
+ MemberFuncIdRecord mfr;
+ cantFail(
+ TypeDeserializer::deserializeAs<MemberFuncIdRecord>(func_cvt, mfr));
+ func_name = mfr.getName();
+ func_ti = mfr.getFunctionType();
+ PdbTypeSymId class_type_id(mfr.ClassType, false);
+ parent = GetOrCreateDeclContextForUid(class_type_id);
+ break;
+ }
+ case LF_FUNC_ID: {
+ FuncIdRecord fir;
+ cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(func_cvt, fir));
+ func_name = fir.getName();
+ func_ti = fir.getFunctionType();
+ parent = FromCompilerDeclContext(GetTranslationUnitDecl());
+ if (!fir.ParentScope.isNoneType()) {
+ CVType parent_cvt = index.ipi().getType(fir.ParentScope);
+ if (parent_cvt.kind() == LF_STRING_ID) {
+ StringIdRecord sir;
+ cantFail(
+ TypeDeserializer::deserializeAs<StringIdRecord>(parent_cvt, sir));
+ parent = GetOrCreateNamespaceDecl(sir.String.data(), *parent);
+ }
+ }
+ break;
+ }
+ default:
+ lldbassert(false && "Invalid function id type!");
+ }
+ clang::QualType func_qt = GetOrCreateType(func_ti);
+ if (func_qt.isNull() || !parent)
+ return nullptr;
+ CompilerType func_ct = ToCompilerType(func_qt);
+ uint32_t param_count =
+ llvm::cast<clang::FunctionProtoType>(func_qt)->getNumParams();
+ return CreateFunctionDecl(func_sid, func_name, func_ti, func_ct, param_count,
+ clang::SC_None, true, parent);
+}
+
+clang::FunctionDecl *
+PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
+ if (clang::Decl *decl = TryGetDecl(func_id))
+ return llvm::dyn_cast<clang::FunctionDecl>(decl);
+
+ clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id));
+ if (!parent)
+ return nullptr;
+ std::string context_name;
+ if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) {
+ context_name = ns->getQualifiedNameAsString();
+ } else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) {
+ context_name = tag->getQualifiedNameAsString();
+ }
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol cvs = index.ReadSymbolRecord(func_id);
+ ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind()));
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(cvs, proc));
+
+ PdbTypeSymId type_id(proc.FunctionType);
+ clang::QualType qt = GetOrCreateType(type_id);
+ if (qt.isNull())
+ return nullptr;
+
+ clang::StorageClass storage = clang::SC_None;
+ if (proc.Kind == SymbolRecordKind::ProcSym)
+ storage = clang::SC_Static;
+
+ const clang::FunctionProtoType *func_type =
+ llvm::dyn_cast<clang::FunctionProtoType>(qt);
+
+ CompilerType func_ct = ToCompilerType(qt);
+
+ llvm::StringRef proc_name = proc.Name;
+ proc_name.consume_front(context_name);
+ proc_name.consume_front("::");
+ clang::FunctionDecl *function_decl =
+ CreateFunctionDecl(func_id, proc_name, proc.FunctionType, func_ct,
+ func_type->getNumParams(), storage, false, parent);
+ if (function_decl == nullptr)
+ return nullptr;
+
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0);
+ m_uid_to_decl[toOpaqueUid(func_id)] = function_decl;
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = toOpaqueUid(func_id);
+ m_decl_to_status.insert({function_decl, status});
+
+ return function_decl;
+}
+
+void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id,
+ clang::FunctionDecl &function_decl,
+ uint32_t param_count) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CompilandIndexItem *cii = index.compilands().GetCompiland(func_id.modi);
+ CVSymbolArray scope =
+ cii->m_debug_stream.getSymbolArrayForScope(func_id.offset);
+
+ scope.drop_front();
+ auto begin = scope.begin();
+ auto end = scope.end();
+ std::vector<clang::ParmVarDecl *> params;
+ for (uint32_t i = 0; i < param_count && begin != end;) {
+ uint32_t record_offset = begin.offset();
+ CVSymbol sym = *begin++;
+
+ TypeIndex param_type;
+ llvm::StringRef param_name;
+ switch (sym.kind()) {
+ case S_REGREL32: {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ param_type = reg.Type;
+ param_name = reg.Name;
+ break;
+ }
+ case S_REGISTER: {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ param_type = reg.Index;
+ param_name = reg.Name;
+ break;
+ }
+ case S_LOCAL: {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+ if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None)
+ continue;
+ param_type = local.Type;
+ param_name = local.Name;
+ break;
+ }
+ case S_BLOCK32:
+ case S_INLINESITE:
+ case S_INLINESITE2:
+ // All parameters should come before the first block/inlinesite. If that
+ // isn't the case, then perhaps this is bad debug info that doesn't
+ // contain information about all parameters.
+ return;
+ default:
+ continue;
+ }
+
+ PdbCompilandSymId param_uid(func_id.modi, record_offset);
+ clang::QualType qt = GetOrCreateType(param_type);
+ if (qt.isNull())
+ return;
+
+ CompilerType param_type_ct = m_clang.GetType(qt);
+ clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration(
+ &function_decl, OptionalClangModuleID(), param_name.str().c_str(),
+ param_type_ct, clang::SC_None, true);
+ lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0);
+
+ m_uid_to_decl[toOpaqueUid(param_uid)] = param;
+ params.push_back(param);
+ ++i;
+ }
+
+ if (!params.empty() && params.size() == param_count)
+ m_clang.SetFunctionParameters(&function_decl, params);
+}
+
+clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id,
+ const EnumRecord &er) {
+ clang::DeclContext *decl_context = nullptr;
+ std::string uname;
+ std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index);
+ if (!decl_context)
+ return {};
+
+ clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType);
+ if (underlying_type.isNull())
+ return {};
+
+ Declaration declaration;
+ CompilerType enum_ct = m_clang.CreateEnumerationType(
+ uname, decl_context, OptionalClangModuleID(), declaration,
+ ToCompilerType(underlying_type), er.isScoped());
+
+ TypeSystemClang::StartTagDeclarationDefinition(enum_ct);
+ TypeSystemClang::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true);
+
+ return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) {
+ clang::QualType element_type = GetOrCreateType(ar.ElementType);
+
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ uint64_t element_size = GetSizeOfType({ar.ElementType}, index.tpi());
+ if (element_type.isNull() || element_size == 0)
+ return {};
+ uint64_t element_count = ar.Size / element_size;
+
+ CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type),
+ element_count, false);
+ return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType());
+}
+
+clang::QualType PdbAstBuilder::CreateFunctionType(
+ TypeIndex args_type_idx, TypeIndex return_type_idx,
+ llvm::codeview::CallingConvention calling_convention) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TpiStream &stream = index.tpi();
+ CVType args_cvt = stream.getType(args_type_idx);
+ ArgListRecord args;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args));
+
+ llvm::ArrayRef<TypeIndex> arg_indices = llvm::ArrayRef(args.ArgIndices);
+ bool is_variadic = IsCVarArgsFunction(arg_indices);
+ if (is_variadic)
+ arg_indices = arg_indices.drop_back();
+
+ std::vector<CompilerType> arg_types;
+ arg_types.reserve(arg_indices.size());
+
+ for (TypeIndex arg_index : arg_indices) {
+ clang::QualType arg_type = GetOrCreateType(arg_index);
+ if (arg_type.isNull())
+ continue;
+ arg_types.push_back(ToCompilerType(arg_type));
+ }
+
+ clang::QualType return_type = GetOrCreateType(return_type_idx);
+ if (return_type.isNull())
+ return {};
+
+ std::optional<clang::CallingConv> cc =
+ TranslateCallingConvention(calling_convention);
+ if (!cc)
+ return {};
+
+ CompilerType return_ct = ToCompilerType(return_type);
+ CompilerType func_sig_ast_type = m_clang.CreateFunctionType(
+ return_ct, arg_types.data(), arg_types.size(), is_variadic, 0, *cc);
+
+ return clang::QualType::getFromOpaquePtr(
+ func_sig_ast_type.GetOpaqueQualType());
+}
+
+static bool isTagDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::TagDecl>(&context);
+}
+
+static bool isFunctionDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::FunctionDecl>(&context);
+}
+
+static bool isBlockDecl(clang::DeclContext &context) {
+ return llvm::isa<clang::BlockDecl>(&context);
+}
+
+void PdbAstBuilder::ParseNamespace(clang::DeclContext &context) {
+ clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(&context);
+ if (m_parsed_namespaces.contains(ns))
+ return;
+ std::string qname = ns->getQualifiedNameAsString();
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TypeIndex ti{index.tpi().TypeIndexBegin()};
+ for (const CVType &cvt : index.tpi().typeArray()) {
+ PdbTypeSymId tid{ti};
+ ++ti;
+
+ if (!IsTagRecord(cvt))
+ continue;
+
+ CVTagRecord tag = CVTagRecord::create(cvt);
+
+ // Call CreateDeclInfoForType unconditionally so that the namespace info
+ // gets created. But only call CreateRecordType if the namespace name
+ // matches.
+ clang::DeclContext *context = nullptr;
+ std::string uname;
+ std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index);
+ if (!context || !context->isNamespace())
+ continue;
+
+ clang::NamespaceDecl *ns = llvm::cast<clang::NamespaceDecl>(context);
+ llvm::StringRef ns_name = ns->getName();
+ if (ns_name.starts_with(qname)) {
+ ns_name = ns_name.drop_front(qname.size());
+ if (ns_name.starts_with("::"))
+ GetOrCreateType(tid);
+ }
+ }
+ ParseAllFunctionsAndNonLocalVars();
+ m_parsed_namespaces.insert(ns);
+}
+
+void PdbAstBuilder::ParseAllTypes() {
+ llvm::call_once(m_parse_all_types, [this]() {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ TypeIndex ti{index.tpi().TypeIndexBegin()};
+ for (const CVType &cvt : index.tpi().typeArray()) {
+ PdbTypeSymId tid{ti};
+ ++ti;
+
+ if (!IsTagRecord(cvt))
+ continue;
+
+ GetOrCreateType(tid);
+ }
+ });
+}
+
+void PdbAstBuilder::ParseAllFunctionsAndNonLocalVars() {
+ llvm::call_once(m_parse_functions_and_non_local_vars, [this]() {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ uint32_t module_count = index.dbi().modules().getModuleCount();
+ for (uint16_t modi = 0; modi < module_count; ++modi) {
+ CompilandIndexItem &cii = index.compilands().GetOrCreateCompiland(modi);
+ const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray();
+ auto iter = symbols.begin();
+ while (iter != symbols.end()) {
+ PdbCompilandSymId sym_id{modi, iter.offset()};
+
+ switch (iter->kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ GetOrCreateFunctionDecl(sym_id);
+ iter = symbols.at(getScopeEndOffset(*iter));
+ break;
+ case S_GDATA32:
+ case S_GTHREAD32:
+ case S_LDATA32:
+ case S_LTHREAD32:
+ GetOrCreateVariableDecl(PdbCompilandSymId(modi, 0), sym_id);
+ ++iter;
+ break;
+ default:
+ ++iter;
+ continue;
+ }
+ }
+ }
+ });
+}
+
+static CVSymbolArray skipFunctionParameters(clang::Decl &decl,
+ const CVSymbolArray &symbols) {
+ clang::FunctionDecl *func_decl = llvm::dyn_cast<clang::FunctionDecl>(&decl);
+ if (!func_decl)
+ return symbols;
+ unsigned int params = func_decl->getNumParams();
+ if (params == 0)
+ return symbols;
+
+ CVSymbolArray result = symbols;
+
+ while (!result.empty()) {
+ if (params == 0)
+ return result;
+
+ CVSymbol sym = *result.begin();
+ result.drop_front();
+
+ if (!isLocalVariableType(sym.kind()))
+ continue;
+
+ --params;
+ }
+ return result;
+}
+
+void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ m_clang.GetSymbolFile()->GetBackingSymbolFile());
+ PdbIndex &index = pdb->GetIndex();
+ CVSymbol sym = index.ReadSymbolRecord(block_id);
+ lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 ||
+ sym.kind() == S_BLOCK32 || sym.kind() == S_INLINESITE);
+ CompilandIndexItem &cii =
+ index.compilands().GetOrCreateCompiland(block_id.modi);
+ CVSymbolArray symbols =
+ cii.m_debug_stream.getSymbolArrayForScope(block_id.offset);
+
+ // Function parameters should already have been created when the function was
+ // parsed.
+ if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32)
+ symbols =
+ skipFunctionParameters(*m_uid_to_decl[toOpaqueUid(block_id)], symbols);
+
+ symbols.drop_front();
+ auto begin = symbols.begin();
+ while (begin != symbols.end()) {
+ PdbCompilandSymId child_sym_id(block_id.modi, begin.offset());
+ GetOrCreateSymbolForId(child_sym_id);
+ if (begin->kind() == S_BLOCK32 || begin->kind() == S_INLINESITE) {
+ ParseBlockChildren(child_sym_id);
+ begin = symbols.at(getScopeEndOffset(*begin));
+ }
+ ++begin;
+ }
+}
+
+void PdbAstBuilder::ParseDeclsForSimpleContext(clang::DeclContext &context) {
+
+ clang::Decl *decl = clang::Decl::castFromDeclContext(&context);
+ lldbassert(decl);
+
+ auto iter = m_decl_to_status.find(decl);
+ lldbassert(iter != m_decl_to_status.end());
+
+ if (auto *tag = llvm::dyn_cast<clang::TagDecl>(&context)) {
+ CompleteTagDecl(*tag);
+ return;
+ }
+
+ if (isFunctionDecl(context) || isBlockDecl(context)) {
+ PdbCompilandSymId block_id = PdbSymUid(iter->second.uid).asCompilandSym();
+ ParseBlockChildren(block_id);
+ }
+}
+
+void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) {
+ // Namespaces aren't explicitly represented in the debug info, and the only
+ // way to parse them is to parse all type info, demangling every single type
+ // and trying to reconstruct the DeclContext hierarchy this way. Since this
+ // is an expensive operation, we have to special case it so that we do other
+ // work (such as parsing the items that appear within the namespaces) at the
+ // same time.
+ if (context.isTranslationUnit()) {
+ ParseAllTypes();
+ ParseAllFunctionsAndNonLocalVars();
+ return;
+ }
+
+ if (context.isNamespace()) {
+ ParseNamespace(context);
+ return;
+ }
+
+ if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) {
+ ParseDeclsForSimpleContext(context);
+ return;
+ }
+}
+
+CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) {
+ return m_clang.GetCompilerDecl(&decl);
+}
+
+CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) {
+ return {m_clang.weak_from_this(), qt.getAsOpaquePtr()};
+}
+
+CompilerDeclContext
+PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) {
+ return m_clang.CreateDeclContext(&context);
+}
+
+clang::Decl * PdbAstBuilder::FromCompilerDecl(CompilerDecl decl) {
+ return ClangUtil::GetDecl(decl);
+}
+
+clang::DeclContext *
+PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
+ return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
+}
+
+void PdbAstBuilder::Dump(Stream &stream) {
+ m_clang.Dump(stream.AsRawOstream());
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
new file mode 100644
index 000000000000..b7cad30c69c0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -0,0 +1,159 @@
+//===-- PdbAstBuilder.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Threading.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include <optional>
+
+namespace clang {
+class TagDecl;
+class DeclContext;
+class Decl;
+class QualType;
+class FunctionDecl;
+class NamespaceDecl;
+} // namespace clang
+
+namespace llvm {
+namespace codeview {
+class ProcSym;
+}
+} // namespace llvm
+
+namespace lldb_private {
+class ClangASTImporter;
+class ObjectFile;
+
+namespace npdb {
+class PdbIndex;
+struct VariableInfo;
+
+struct DeclStatus {
+ DeclStatus() = default;
+ DeclStatus(lldb::user_id_t uid, bool resolved)
+ : uid(uid), resolved(resolved) {}
+ lldb::user_id_t uid = 0;
+ bool resolved = false;
+};
+
+class PdbAstBuilder {
+public:
+ // Constructors and Destructors
+ PdbAstBuilder(TypeSystemClang &clang);
+
+ lldb_private::CompilerDeclContext GetTranslationUnitDecl();
+
+ std::optional<lldb_private::CompilerDecl>
+ GetOrCreateDeclForUid(PdbSymUid uid);
+ clang::DeclContext *GetOrCreateDeclContextForUid(PdbSymUid uid);
+ clang::DeclContext *GetParentDeclContext(PdbSymUid uid);
+
+ clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_id);
+ clang::FunctionDecl *
+ GetOrCreateInlinedFunctionDecl(PdbCompilandSymId inlinesite_id);
+ clang::BlockDecl *GetOrCreateBlockDecl(PdbCompilandSymId block_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id);
+ clang::VarDecl *GetOrCreateVariableDecl(PdbGlobalSymId var_id);
+ clang::TypedefNameDecl *GetOrCreateTypedefDecl(PdbGlobalSymId id);
+ void ParseDeclsForContext(clang::DeclContext &context);
+
+ clang::QualType GetBasicType(lldb::BasicType type);
+ clang::QualType GetOrCreateType(PdbTypeSymId type);
+
+ bool CompleteTagDecl(clang::TagDecl &tag);
+ bool CompleteType(clang::QualType qt);
+
+ CompilerDecl ToCompilerDecl(clang::Decl &decl);
+ CompilerType ToCompilerType(clang::QualType qt);
+ CompilerDeclContext ToCompilerDeclContext(clang::DeclContext &context);
+ clang::Decl *FromCompilerDecl(CompilerDecl decl);
+ clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context);
+
+ TypeSystemClang &clang() { return m_clang; }
+ ClangASTImporter &GetClangASTImporter() { return m_importer; }
+
+ void Dump(Stream &stream);
+
+private:
+ clang::Decl *TryGetDecl(PdbSymUid uid) const;
+
+ using TypeIndex = llvm::codeview::TypeIndex;
+
+ clang::QualType
+ CreatePointerType(const llvm::codeview::PointerRecord &pointer);
+ clang::QualType
+ CreateModifierType(const llvm::codeview::ModifierRecord &modifier);
+ clang::QualType CreateArrayType(const llvm::codeview::ArrayRecord &array);
+ clang::QualType CreateRecordType(PdbTypeSymId id,
+ const llvm::codeview::TagRecord &record);
+ clang::QualType CreateEnumType(PdbTypeSymId id,
+ const llvm::codeview::EnumRecord &record);
+ clang::QualType
+ CreateFunctionType(TypeIndex args_type_idx, TypeIndex return_type_idx,
+ llvm::codeview::CallingConvention calling_convention);
+ clang::QualType CreateType(PdbTypeSymId type);
+
+ void CreateFunctionParameters(PdbCompilandSymId func_id,
+ clang::FunctionDecl &function_decl,
+ uint32_t param_count);
+ clang::Decl *GetOrCreateSymbolForId(PdbCompilandSymId id);
+ clang::VarDecl *CreateVariableDecl(PdbSymUid uid,
+ llvm::codeview::CVSymbol sym,
+ clang::DeclContext &scope);
+ clang::NamespaceDecl *GetOrCreateNamespaceDecl(const char *name,
+ clang::DeclContext &context);
+ clang::FunctionDecl *CreateFunctionDeclFromId(PdbTypeSymId func_tid,
+ PdbCompilandSymId func_sid);
+ clang::FunctionDecl *
+ CreateFunctionDecl(PdbCompilandSymId func_id, llvm::StringRef func_name,
+ TypeIndex func_ti, CompilerType func_ct,
+ uint32_t param_count, clang::StorageClass func_storage,
+ bool is_inline, clang::DeclContext *parent);
+ void ParseNamespace(clang::DeclContext &parent);
+ void ParseAllTypes();
+ void ParseAllFunctionsAndNonLocalVars();
+ void ParseDeclsForSimpleContext(clang::DeclContext &context);
+ void ParseBlockChildren(PdbCompilandSymId block_id);
+
+ std::pair<clang::DeclContext *, std::string>
+ CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti);
+ std::pair<clang::DeclContext *, std::string>
+ CreateDeclInfoForUndecoratedName(llvm::StringRef uname);
+ clang::QualType CreateSimpleType(TypeIndex ti);
+
+ TypeSystemClang &m_clang;
+
+ ClangASTImporter m_importer;
+ llvm::once_flag m_parse_functions_and_non_local_vars;
+ llvm::once_flag m_parse_all_types;
+ llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status;
+ llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl;
+ llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type;
+
+ // From class/struct's opaque_compiler_type_t to a set containing the pairs of
+ // method's name and CompilerType.
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ m_cxx_record_map;
+ llvm::DenseSet<clang::NamespaceDecl *> m_parsed_namespaces;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp
new file mode 100644
index 000000000000..f28509acbf79
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp
@@ -0,0 +1,103 @@
+//===-- PdbFPOProgramToDWARFExpression.cpp --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbFPOProgramToDWARFExpression.h"
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/Symbol/PostfixExpression.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::postfix;
+
+static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
+ // lookup register name to get lldb register number
+ llvm::codeview::CPUType cpu_type;
+ switch (arch_type) {
+ case llvm::Triple::ArchType::aarch64:
+ cpu_type = llvm::codeview::CPUType::ARM64;
+ break;
+
+ default:
+ cpu_type = llvm::codeview::CPUType::X64;
+ break;
+ }
+
+ llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
+ llvm::codeview::getRegisterNames(cpu_type);
+ auto it = llvm::find_if(
+ register_names,
+ [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
+ return reg_name.compare_insensitive(register_entry.Name) == 0;
+ });
+
+ if (it == register_names.end())
+ return LLDB_INVALID_REGNUM;
+
+ auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
+ return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
+}
+
+static Node *ResolveFPOProgram(llvm::StringRef program,
+ llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type,
+ llvm::BumpPtrAllocator &alloc) {
+ std::vector<std::pair<llvm::StringRef, Node *>> parsed =
+ postfix::ParseFPOProgram(program, alloc);
+
+ for (auto it = parsed.begin(), end = parsed.end(); it != end; ++it) {
+ // Emplace valid dependent subtrees to make target assignment independent
+ // from predecessors. Resolve all other SymbolNodes as registers.
+ bool success =
+ ResolveSymbols(it->second, [&](SymbolNode &symbol) -> Node * {
+ for (const auto &pair : llvm::make_range(parsed.begin(), it)) {
+ if (pair.first == symbol.GetName())
+ return pair.second;
+ }
+
+ uint32_t reg_num =
+ ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), arch_type);
+
+ if (reg_num == LLDB_INVALID_REGNUM)
+ return nullptr;
+
+ return MakeNode<RegisterNode>(alloc, reg_num);
+ });
+ if (!success)
+ return nullptr;
+
+ if (it->first == register_name) {
+ // found target assignment program - no need to parse further
+ return it->second;
+ }
+ }
+
+ return nullptr;
+}
+
+bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
+ llvm::StringRef program, llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type, Stream &stream) {
+ llvm::BumpPtrAllocator node_alloc;
+ Node *target_program =
+ ResolveFPOProgram(program, register_name, arch_type, node_alloc);
+ if (target_program == nullptr) {
+ return false;
+ }
+
+ ToDWARF(*target_program, stream);
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h
new file mode 100644
index 000000000000..f6849f2083cc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.h
@@ -0,0 +1,28 @@
+//===-- PdbFPOProgramToDWARFExpression.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBFPOPROGRAMTODWARFEXPRESSION_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/Triple.h"
+
+namespace lldb_private {
+class Stream;
+
+namespace npdb {
+
+bool TranslateFPOProgramToDWARFExpression(llvm::StringRef program,
+ llvm::StringRef register_name,
+ llvm::Triple::ArchType arch_type,
+ lldb_private::Stream &stream);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
new file mode 100644
index 000000000000..ea778fc6cca6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -0,0 +1,196 @@
+//===-- PdbIndex.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbIndex.h"
+#include "PdbUtil.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-defines.h"
+#include <optional>
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
+
+#define ASSIGN_PTR_OR_RETURN(result_ptr, expr) \
+ { \
+ auto expected_result = expr; \
+ if (!expected_result) \
+ return expected_result.takeError(); \
+ result_ptr = &expected_result.get(); \
+ }
+
+llvm::Expected<std::unique_ptr<PdbIndex>>
+PdbIndex::create(llvm::pdb::PDBFile *file) {
+ lldbassert(file);
+
+ std::unique_ptr<PdbIndex> result(new PdbIndex());
+ ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
+ ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
+ ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
+ ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
+ ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
+
+ result->m_tpi->buildHashMap();
+
+ result->m_file = file;
+
+ return std::move(result);
+}
+
+lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
+ uint32_t offset) const {
+ uint32_t max_section = dbi().getSectionHeaders().size();
+ // Segment indices are 1-based.
+ // If this is an absolute symbol, it's indicated by the magic section index
+ // |max_section+1|. In this case, the offset is meaningless, so just return.
+ if (segment == 0 || segment > max_section)
+ return LLDB_INVALID_ADDRESS;
+
+ const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
+ return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
+ static_cast<lldb::addr_t>(offset);
+}
+
+std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,
+ uint32_t offset) const {
+ return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
+}
+
+std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
+ auto iter = m_va_to_modi.find(va);
+ if (iter == m_va_to_modi.end())
+ return std::nullopt;
+
+ return iter.value();
+}
+
+void PdbIndex::ParseSectionContribs() {
+ class Visitor : public ISectionContribVisitor {
+ PdbIndex &m_ctx;
+ llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
+
+ public:
+ Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
+ : m_ctx(ctx), m_imap(imap) {}
+
+ void visit(const SectionContrib &C) override {
+ if (C.Size == 0)
+ return;
+
+ uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
+ if (va == LLDB_INVALID_ADDRESS)
+ return;
+ uint64_t end = va + C.Size;
+ // IntervalMap's start and end represent a closed range, not a half-open
+ // range, so we have to subtract 1.
+ m_imap.insert(va, end - 1, C.Imod);
+ }
+ void visit(const SectionContrib2 &C) override { visit(C.Base); }
+ };
+ Visitor v(*this, m_va_to_modi);
+ dbi().visitSectionContributions(v);
+}
+
+void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
+ lldbassert(cci.m_symbols_by_va.empty() &&
+ "Addr to symbol map is already built!");
+ uint16_t modi = cci.m_id.modi;
+ const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ if (!SymbolHasAddress(*iter))
+ continue;
+
+ SegmentOffset so = GetSegmentAndOffset(*iter);
+ lldb::addr_t va = MakeVirtualAddress(so.segment, so.offset);
+ if (va == LLDB_INVALID_ADDRESS)
+ continue;
+
+ PdbCompilandSymId cu_sym_id(modi, iter.offset());
+
+ // It's rare, but we could have multiple symbols with the same address
+ // because of identical comdat folding. Right now, the first one will win.
+ cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
+ }
+}
+
+std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
+ std::vector<SymbolAndUid> result;
+
+ std::optional<uint16_t> modi = GetModuleIndexForVa(va);
+ if (!modi)
+ return result;
+
+ CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
+ if (cci.m_symbols_by_va.empty())
+ BuildAddrToSymbolMap(cci);
+
+ // The map is sorted by starting address of the symbol. So for example
+ // we could (in theory) have this situation
+ //
+ // [------------------]
+ // [----------]
+ // [-----------]
+ // [-------------]
+ // [----]
+ // [-----]
+ // ^ Address we're searching for
+ // In order to find this, we use the upper_bound of the key value which would
+ // be the first symbol whose starting address is higher than the element we're
+ // searching for.
+
+ auto ub = cci.m_symbols_by_va.upper_bound(va);
+
+ for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
+ PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
+ CVSymbol sym = ReadSymbolRecord(cu_sym_id);
+
+ SegmentOffsetLength sol;
+ if (SymbolIsCode(sym))
+ sol = GetSegmentOffsetAndLength(sym);
+ else
+ sol.so = GetSegmentAndOffset(sym);
+
+ lldb::addr_t start = MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (start == LLDB_INVALID_ADDRESS)
+ continue;
+
+ lldb::addr_t end = start + sol.length;
+ if (va >= start && va < end)
+ result.push_back({std::move(sym), iter->second});
+ }
+
+ return result;
+}
+
+CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {
+ const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
+ auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
+ lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
+ return *iter;
+}
+
+CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
+ return symrecords().readRecord(global.offset);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
new file mode 100644
index 000000000000..796aa4c8dfd1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h
@@ -0,0 +1,159 @@
+//===-- PdbIndex.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBINDEX_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBINDEX_H
+
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "CompileUnitIndex.h"
+#include "PdbSymUid.h"
+
+#include <map>
+#include <memory>
+#include <optional>
+
+namespace llvm {
+namespace pdb {
+class DbiStream;
+class TpiStream;
+class InfoStream;
+class PublicsStream;
+class GlobalsStream;
+class SymbolStream;
+} // namespace pdb
+} // namespace llvm
+
+namespace lldb_private {
+namespace npdb {
+struct SegmentOffset;
+
+/// PdbIndex - Lazy access to the important parts of a PDB file.
+///
+/// This is a layer on top of LLVM's native PDB support libraries which cache
+/// certain data when it is accessed the first time. The entire PDB file is
+/// mapped into memory, and the underlying support libraries vend out memory
+/// that is always backed by the file, so it is safe to hold StringRefs and
+/// ArrayRefs into the backing memory as long as the PdbIndex instance is
+/// alive.
+class PdbIndex {
+
+ /// The underlying PDB file.
+ llvm::pdb::PDBFile *m_file = nullptr;
+
+ /// The DBI stream. This contains general high level information about the
+ /// features present in the PDB file, compile units (such as the information
+ /// necessary to locate full symbol information for each compile unit),
+ /// section contributions, and other data which is not specifically symbol or
+ /// type records.
+ llvm::pdb::DbiStream *m_dbi = nullptr;
+
+ /// TPI (types) and IPI (indices) streams. These are both in the exact same
+ /// format with different data. Most type records are stored in the TPI
+ /// stream but certain specific types of records are stored in the IPI stream.
+ /// The IPI stream records can refer to the records in the TPI stream, but not
+ /// the other way around.
+ llvm::pdb::TpiStream *m_tpi = nullptr;
+ llvm::pdb::TpiStream *m_ipi = nullptr;
+
+ /// This is called the "PDB Stream" in the Microsoft reference implementation.
+ /// It contains information about the structure of the file, as well as fields
+ /// used to match EXE and PDB.
+ llvm::pdb::InfoStream *m_info = nullptr;
+
+ /// Publics stream. Is actually a serialized hash table where the keys are
+ /// addresses of symbols in the executable, and values are a record containing
+ /// mangled names and an index which can be used to locate more detailed info
+ /// about the symbol in the Symbol Records stream. The publics stream only
+ /// contains info about externally visible symbols.
+ llvm::pdb::PublicsStream *m_publics = nullptr;
+
+ /// Globals stream. Contrary to its name, this does not contain information
+ /// about all "global variables" or "global functions". Rather, it is the
+ /// "global symbol table", i.e. it contains information about *every* symbol
+ /// in the executable. It is a hash table keyed on name, whose values are
+ /// indices into the symbol records stream to find the full record.
+ llvm::pdb::GlobalsStream *m_globals = nullptr;
+
+ /// Symbol records stream. The publics and globals stream refer to records
+ /// in this stream. For some records, like constants and typedefs, the
+ /// complete record lives in this stream. For other symbol types, such as
+ /// functions, data, and other things that have been materialied into a
+ /// specific compile unit, the records here simply provide a reference
+ /// necessary to locate the full information.
+ llvm::pdb::SymbolStream *m_symrecords = nullptr;
+
+ /// Index of all compile units, mapping identifier to |CompilandIndexItem|
+ /// instance.
+ CompileUnitIndex m_cus;
+
+ /// An allocator for the interval maps
+ llvm::IntervalMap<lldb::addr_t, uint32_t>::Allocator m_allocator;
+
+ /// Maps virtual address to module index
+ llvm::IntervalMap<lldb::addr_t, uint16_t> m_va_to_modi;
+
+ /// The address at which the program has been loaded into memory.
+ lldb::addr_t m_load_address = 0;
+
+ PdbIndex();
+
+ void BuildAddrToSymbolMap(CompilandIndexItem &cci);
+
+public:
+ static llvm::Expected<std::unique_ptr<PdbIndex>> create(llvm::pdb::PDBFile *);
+
+ void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; }
+ lldb::addr_t GetLoadAddress() const { return m_load_address; }
+ void ParseSectionContribs();
+
+ llvm::pdb::PDBFile &pdb() { return *m_file; }
+ const llvm::pdb::PDBFile &pdb() const { return *m_file; }
+
+ llvm::pdb::DbiStream &dbi() { return *m_dbi; }
+ const llvm::pdb::DbiStream &dbi() const { return *m_dbi; }
+
+ llvm::pdb::TpiStream &tpi() { return *m_tpi; }
+ const llvm::pdb::TpiStream &tpi() const { return *m_tpi; }
+
+ llvm::pdb::TpiStream &ipi() { return *m_ipi; }
+ const llvm::pdb::TpiStream &ipi() const { return *m_ipi; }
+
+ llvm::pdb::InfoStream &info() { return *m_info; }
+ const llvm::pdb::InfoStream &info() const { return *m_info; }
+
+ llvm::pdb::PublicsStream &publics() { return *m_publics; }
+ const llvm::pdb::PublicsStream &publics() const { return *m_publics; }
+
+ llvm::pdb::GlobalsStream &globals() { return *m_globals; }
+ const llvm::pdb::GlobalsStream &globals() const { return *m_globals; }
+
+ llvm::pdb::SymbolStream &symrecords() { return *m_symrecords; }
+ const llvm::pdb::SymbolStream &symrecords() const { return *m_symrecords; }
+
+ CompileUnitIndex &compilands() { return m_cus; }
+ const CompileUnitIndex &compilands() const { return m_cus; }
+
+ lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const;
+
+ std::vector<SymbolAndUid> FindSymbolsByVa(lldb::addr_t va);
+
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const;
+ llvm::codeview::CVSymbol ReadSymbolRecord(PdbGlobalSymId global) const;
+
+ std::optional<uint16_t> GetModuleIndexForAddr(uint16_t segment,
+ uint32_t offset) const;
+ std::optional<uint16_t> GetModuleIndexForVa(lldb::addr_t va) const;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
new file mode 100644
index 000000000000..67397d707110
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.cpp
@@ -0,0 +1,160 @@
+//===-- PdbSymUid.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbSymUid.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+
+namespace {
+struct GenericIdRepr {
+ uint64_t tag : 4;
+ uint64_t data : 60;
+};
+
+struct CompilandIdRepr {
+ uint64_t tag : 4;
+ uint64_t modi : 16;
+ uint64_t unused : 44;
+};
+
+struct CompilandSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t modi : 16;
+ uint64_t offset : 32;
+ uint64_t unused : 12;
+};
+
+struct GlobalSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t offset : 32;
+ uint64_t pub : 1;
+ uint64_t unused : 27;
+};
+
+struct TypeSymIdRepr {
+ uint64_t tag : 4;
+ uint64_t index : 32;
+ uint64_t ipi : 1;
+ uint64_t unused : 27;
+};
+
+struct FieldListMemberIdRepr {
+ uint64_t tag : 4;
+ uint64_t index : 32;
+ uint64_t offset : 16;
+ uint64_t unused : 12;
+};
+
+static_assert(sizeof(CompilandIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(CompilandSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(GlobalSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(TypeSymIdRepr) == 8, "Invalid structure size!");
+static_assert(sizeof(FieldListMemberIdRepr) == 8, "Invalid structure size!");
+} // namespace
+
+template <typename OutT, typename InT> static OutT repr_cast(const InT &value) {
+ OutT result;
+ ::memcpy(&result, &value, sizeof(value));
+ return result;
+}
+
+PdbSymUid::PdbSymUid(const PdbCompilandId &cid) {
+ CompilandIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.modi = cid.modi;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::Compiland);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbCompilandSymId &csid) {
+ CompilandSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.modi = csid.modi;
+ repr.offset = csid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::CompilandSym);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbGlobalSymId &gsid) {
+ GlobalSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.pub = gsid.is_public;
+ repr.offset = gsid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::GlobalSym);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbTypeSymId &tsid) {
+ TypeSymIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.index = tsid.index.getIndex();
+ repr.ipi = tsid.is_ipi;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::Type);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUid::PdbSymUid(const PdbFieldListMemberId &flmid) {
+ FieldListMemberIdRepr repr;
+ ::memset(&repr, 0, sizeof(repr));
+ repr.index = flmid.index.getIndex();
+ repr.offset = flmid.offset;
+ repr.tag = static_cast<uint64_t>(PdbSymUidKind::FieldListMember);
+ m_repr = repr_cast<uint64_t>(repr);
+}
+
+PdbSymUidKind PdbSymUid::kind() const {
+ GenericIdRepr generic = repr_cast<GenericIdRepr>(m_repr);
+ return static_cast<PdbSymUidKind>(generic.tag);
+}
+
+PdbCompilandId PdbSymUid::asCompiland() const {
+ assert(kind() == PdbSymUidKind::Compiland);
+ auto repr = repr_cast<CompilandIdRepr>(m_repr);
+ PdbCompilandId result;
+ result.modi = repr.modi;
+ return result;
+}
+
+PdbCompilandSymId PdbSymUid::asCompilandSym() const {
+ assert(kind() == PdbSymUidKind::CompilandSym);
+ auto repr = repr_cast<CompilandSymIdRepr>(m_repr);
+ PdbCompilandSymId result;
+ result.modi = repr.modi;
+ result.offset = repr.offset;
+ return result;
+}
+
+PdbGlobalSymId PdbSymUid::asGlobalSym() const {
+ assert(kind() == PdbSymUidKind::GlobalSym ||
+ kind() == PdbSymUidKind::PublicSym);
+ auto repr = repr_cast<GlobalSymIdRepr>(m_repr);
+ PdbGlobalSymId result;
+ result.is_public = repr.pub;
+ result.offset = repr.offset;
+ return result;
+}
+
+PdbTypeSymId PdbSymUid::asTypeSym() const {
+ assert(kind() == PdbSymUidKind::Type);
+ auto repr = repr_cast<TypeSymIdRepr>(m_repr);
+ PdbTypeSymId result;
+ result.index.setIndex(repr.index);
+ result.is_ipi = repr.ipi;
+ return result;
+}
+
+PdbFieldListMemberId PdbSymUid::asFieldListMember() const {
+ assert(kind() == PdbSymUidKind::FieldListMember);
+ auto repr = repr_cast<FieldListMemberIdRepr>(m_repr);
+ PdbFieldListMemberId result;
+ result.index.setIndex(repr.index);
+ result.offset = repr.offset;
+ return result;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
new file mode 100644
index 000000000000..3accd38d710e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbSymUid.h
@@ -0,0 +1,125 @@
+//===-- PdbSymUid.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// A unique identification scheme for Pdb records.
+// The scheme is to partition a 64-bit integer into an 8-bit tag field, which
+// will contain some value from the PDB_SymType enumeration. The format of the
+// other 48-bits depend on the tag, but must be sufficient to locate the
+// corresponding entry in the underlying PDB file quickly. For example, for
+// a compile unit, we use 2 bytes to represent the index, which allows fast
+// access to the compile unit's information.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBSYMUID_H
+
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Support/Compiler.h"
+
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+namespace npdb {
+
+enum class PdbSymUidKind : uint8_t {
+ Compiland,
+ CompilandSym,
+ PublicSym,
+ GlobalSym,
+ Type,
+ FieldListMember
+};
+
+struct PdbCompilandId {
+ // 0-based index of module in PDB
+ uint16_t modi;
+};
+
+struct PdbCompilandSymId {
+ PdbCompilandSymId() = default;
+ PdbCompilandSymId(uint16_t modi, uint32_t offset)
+ : modi(modi), offset(offset) {}
+ // 0-based index of module in PDB
+ uint16_t modi = 0;
+
+ // Offset of symbol's record in module stream. This is
+ // offset by 4 from the CVSymbolArray's notion of offset
+ // due to the debug magic at the beginning of the stream.
+ uint32_t offset = 0;
+};
+
+struct PdbGlobalSymId {
+ PdbGlobalSymId() = default;
+ PdbGlobalSymId(uint32_t offset, bool is_public)
+ : offset(offset), is_public(is_public) {}
+
+ // Offset of symbol's record in globals or publics stream.
+ uint32_t offset = 0;
+
+ // True if this symbol is in the public stream, false if it's in the globals
+ // stream.
+ bool is_public = false;
+};
+
+struct PdbTypeSymId {
+ PdbTypeSymId() = default;
+ PdbTypeSymId(llvm::codeview::TypeIndex index, bool is_ipi = false)
+ : index(index), is_ipi(is_ipi) {}
+
+ // The index of the of the type in the TPI or IPI stream.
+ llvm::codeview::TypeIndex index;
+
+ // True if this symbol comes from the IPI stream, false if it's from the TPI
+ // stream.
+ bool is_ipi = false;
+};
+
+struct PdbFieldListMemberId {
+ // The TypeIndex of the LF_FIELDLIST record.
+ llvm::codeview::TypeIndex index;
+
+ // The offset from the beginning of the LF_FIELDLIST record to this record.
+ uint16_t offset = 0;
+};
+
+class PdbSymUid {
+ uint64_t m_repr = 0;
+
+public:
+ PdbSymUid() = default;
+ PdbSymUid(uint64_t repr) : m_repr(repr) {}
+ PdbSymUid(const PdbCompilandId &cid);
+ PdbSymUid(const PdbCompilandSymId &csid);
+ PdbSymUid(const PdbGlobalSymId &gsid);
+ PdbSymUid(const PdbTypeSymId &tsid);
+ PdbSymUid(const PdbFieldListMemberId &flmid);
+
+ uint64_t toOpaqueId() const { return m_repr; }
+
+ PdbSymUidKind kind() const;
+
+ PdbCompilandId asCompiland() const;
+ PdbCompilandSymId asCompilandSym() const;
+ PdbGlobalSymId asGlobalSym() const;
+ PdbTypeSymId asTypeSym() const;
+ PdbFieldListMemberId asFieldListMember() const;
+};
+
+template <typename T> uint64_t toOpaqueUid(const T &cid) {
+ return PdbSymUid(cid).toOpaqueId();
+}
+
+struct SymbolAndUid {
+ llvm::codeview::CVSymbol sym;
+ PdbSymUid uid;
+};
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
new file mode 100644
index 000000000000..888bd89a7262
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -0,0 +1,1120 @@
+//===-- PdbUtil.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PdbUtil.h"
+
+#include "DWARFLocationExpression.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+// The returned range list is guaranteed to be sorted and no overlaps between
+// adjacent ranges because fields in LocalVariableAddrGap are unsigned integers.
+static Variable::RangeList
+MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
+ llvm::ArrayRef<LocalVariableAddrGap> gaps) {
+ lldb::addr_t start =
+ index.MakeVirtualAddress(range.ISectStart, range.OffsetStart);
+ if (start == LLDB_INVALID_ADDRESS)
+ return {};
+ lldb::addr_t end = start + range.Range;
+
+ Variable::RangeList result;
+ while (!gaps.empty()) {
+ const LocalVariableAddrGap &gap = gaps.front();
+ lldb::addr_t gap_start = start + gap.GapStartOffset;
+ result.Append(start, gap_start - start);
+ start = gap_start + gap.Range;
+ gaps = gaps.drop_front();
+ }
+
+ result.Append(start, end - start);
+ return result;
+}
+
+namespace {
+struct MemberLocations {
+ std::map<uint64_t, MemberValLocation> offset_to_location;
+ DWARFExpression expr;
+ bool is_dwarf = false;
+
+ MemberLocations() = default;
+ MemberLocations(const DWARFExpression &expr) : expr(expr), is_dwarf(true) {}
+ MemberLocations(uint64_t offset, const MemberValLocation &member_loc) {
+ insert(offset, member_loc);
+ }
+
+ void insert(uint64_t offset, const MemberValLocation &member_loc) {
+ offset_to_location[offset] = member_loc;
+ }
+
+ struct Comparator {
+ public:
+ bool operator()(const MemberLocations &, const MemberLocations &) const {
+ return false;
+ }
+ };
+};
+
+// A range map with address ranges to a map of pair of offset and locaitons.
+typedef RangeDataVector<lldb::addr_t, lldb::addr_t, MemberLocations, 0,
+ MemberLocations::Comparator>
+ RangeMap;
+
+void AddMemberLocationRanges(RangeMap &location_map, uint64_t offset,
+ MemberValLocation member_loc,
+ const Variable::RangeList &ranges) {
+ RangeMap new_location_map;
+ auto add_overlap_region = [&](lldb::addr_t base, lldb::addr_t end,
+ RangeMap::Entry *entry) {
+ RangeMap::Entry overlap_region = {base, end - base, entry->data};
+ overlap_region.data.insert(offset, member_loc);
+ new_location_map.Append(overlap_region);
+ };
+
+ for (const auto &range : ranges) {
+ lldb::addr_t base = range.GetRangeBase();
+ lldb::addr_t end = range.GetRangeEnd();
+ uint32_t base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);
+ while (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {
+ if (base >= end || entry->base >= end)
+ break;
+ if (entry->data.is_dwarf)
+ base = entry->GetRangeEnd();
+ else {
+ lldb::addr_t entry_end = entry->GetRangeEnd();
+ if (base > entry->base) {
+ if (end < entry_end)
+ new_location_map.Append({end, entry_end - end, entry->data});
+ add_overlap_region(base, end < entry_end ? end : entry_end, entry);
+ entry->SetRangeEnd(base);
+ } else if (base < entry->base) {
+ new_location_map.Append(
+ {base, entry->base - base, {offset, member_loc}});
+ if (entry_end == end)
+ entry->data.insert(offset, member_loc);
+ else {
+ add_overlap_region(entry->base, end, entry);
+ entry->ShrinkFront(end - entry->base);
+ }
+ } else {
+ if (end < entry_end) {
+ new_location_map.Append({end, entry_end, entry->data});
+ entry->SetRangeEnd(end);
+ }
+ entry->data.insert(offset, member_loc);
+ }
+ base = entry_end;
+ }
+ ++base_idx;
+ }
+ if (base >= end)
+ continue;
+ new_location_map.Append({base, end - base, {offset, member_loc}});
+ }
+ for (const auto &entry : new_location_map)
+ location_map.Append(entry);
+ if (!new_location_map.IsEmpty())
+ location_map.Sort();
+}
+
+void AddDwarfRange(RangeMap &location_map, const DWARFExpression &expr,
+ const Variable::RangeList &ranges) {
+ if (!expr.IsValid())
+ return;
+ RangeMap new_location_map;
+ for (const auto &range : ranges) {
+ lldb::addr_t base = range.GetRangeBase();
+ lldb::addr_t end = range.GetRangeEnd();
+ uint32_t base_idx = location_map.FindEntryIndexThatContains(base);
+ uint32_t end_idx = location_map.FindEntryIndexThatContains(end - 1);
+ // range is within an entry.
+ if (base_idx == end_idx && base_idx != UINT32_MAX) {
+ auto *entry = location_map.GetMutableEntryAtIndex(base_idx);
+ if (base > entry->base) {
+ new_location_map.Append({entry->base, base - entry->base, entry->data});
+ entry->ShrinkFront(base - entry->base);
+ }
+ if (end == entry->GetRangeEnd())
+ entry->data = expr;
+ else {
+ entry->ShrinkFront(end - base);
+ new_location_map.Append({base, end - base, expr});
+ }
+ continue;
+ }
+ base_idx = location_map.FindEntryIndexThatContainsOrFollows(base);
+ if (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) {
+ if (entry->Contains(base) && entry->base != base) {
+ entry->SetRangeEnd(base);
+ ++base_idx;
+ }
+ }
+ end_idx = location_map.FindEntryIndexThatContainsOrFollows(end - 1);
+ if (auto *entry = location_map.GetMutableEntryAtIndex(end_idx)) {
+ if (entry->Contains(end - 1)) {
+ if (entry->GetRangeEnd() == end)
+ ++end_idx;
+ else
+ entry->ShrinkFront(end - entry->base);
+ }
+ }
+
+ if (end_idx == UINT32_MAX)
+ end_idx = location_map.GetSize();
+ // Erase existing ranges covered by new range.
+ location_map.Erase(base_idx, end_idx);
+ new_location_map.Append({base, end - base, expr});
+ }
+
+ for (const auto &entry : new_location_map)
+ location_map.Append(entry);
+ location_map.Sort();
+}
+} // namespace
+
+CVTagRecord CVTagRecord::create(CVType type) {
+ assert(IsTagRecord(type) && "type is not a tag record!");
+ switch (type.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE: {
+ ClassRecord cr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
+ return CVTagRecord(std::move(cr));
+ }
+ case LF_UNION: {
+ UnionRecord ur;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
+ return CVTagRecord(std::move(ur));
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
+ return CVTagRecord(std::move(er));
+ }
+ default:
+ llvm_unreachable("Unreachable!");
+ }
+}
+
+CVTagRecord::CVTagRecord(ClassRecord &&c)
+ : cvclass(std::move(c)),
+ m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
+CVTagRecord::CVTagRecord(UnionRecord &&u)
+ : cvunion(std::move(u)), m_kind(Union) {}
+CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
+
+PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
+ switch (kind) {
+ case S_COMPILE3:
+ case S_OBJNAME:
+ return PDB_SymType::CompilandDetails;
+ case S_ENVBLOCK:
+ return PDB_SymType::CompilandEnv;
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ return PDB_SymType::Thunk;
+ case S_COFFGROUP:
+ return PDB_SymType::CoffGroup;
+ case S_EXPORT:
+ return PDB_SymType::Export;
+ case S_LPROC32:
+ case S_GPROC32:
+ case S_LPROC32_DPC:
+ return PDB_SymType::Function;
+ case S_PUB32:
+ return PDB_SymType::PublicSymbol;
+ case S_INLINESITE:
+ return PDB_SymType::InlineSite;
+ case S_LOCAL:
+ case S_BPREL32:
+ case S_REGREL32:
+ case S_MANCONSTANT:
+ case S_CONSTANT:
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return PDB_SymType::Data;
+ case S_BLOCK32:
+ return PDB_SymType::Block;
+ case S_LABEL32:
+ return PDB_SymType::Label;
+ case S_CALLSITEINFO:
+ return PDB_SymType::CallSite;
+ case S_HEAPALLOCSITE:
+ return PDB_SymType::HeapAllocationSite;
+ case S_CALLEES:
+ return PDB_SymType::Callee;
+ case S_CALLERS:
+ return PDB_SymType::Caller;
+ default:
+ lldbassert(false && "Invalid symbol record kind!");
+ }
+ return PDB_SymType::None;
+}
+
+PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) {
+ switch (kind) {
+ case LF_ARRAY:
+ return PDB_SymType::ArrayType;
+ case LF_ARGLIST:
+ return PDB_SymType::FunctionSig;
+ case LF_BCLASS:
+ return PDB_SymType::BaseClass;
+ case LF_BINTERFACE:
+ return PDB_SymType::BaseInterface;
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ case LF_UNION:
+ return PDB_SymType::UDT;
+ case LF_POINTER:
+ return PDB_SymType::PointerType;
+ case LF_ENUM:
+ return PDB_SymType::Enum;
+ case LF_PROCEDURE:
+ return PDB_SymType::FunctionSig;
+ case LF_BITFIELD:
+ return PDB_SymType::BuiltinType;
+ default:
+ lldbassert(false && "Invalid type record kind!");
+ }
+ return PDB_SymType::None;
+}
+
+bool lldb_private::npdb::SymbolHasAddress(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ case S_COFFGROUP:
+ case S_BLOCK32:
+ case S_LABEL32:
+ case S_CALLSITEINFO:
+ case S_HEAPALLOCSITE:
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::SymbolIsCode(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ case S_THUNK32:
+ case S_TRAMPOLINE:
+ case S_COFFGROUP:
+ case S_BLOCK32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+template <typename RecordT> RecordT createRecord(const CVSymbol &sym) {
+ RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
+ return record;
+}
+
+template <typename RecordT>
+static SegmentOffset GetSegmentAndOffset(const CVSymbol &sym) {
+ RecordT record = createRecord<RecordT>(sym);
+ return {record.Segment, record.CodeOffset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<TrampolineSym>(const CVSymbol &sym) {
+ TrampolineSym record = createRecord<TrampolineSym>(sym);
+ return {record.ThunkSection, record.ThunkOffset};
+}
+
+template <> SegmentOffset GetSegmentAndOffset<Thunk32Sym>(const CVSymbol &sym) {
+ Thunk32Sym record = createRecord<Thunk32Sym>(sym);
+ return {record.Segment, record.Offset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<CoffGroupSym>(const CVSymbol &sym) {
+ CoffGroupSym record = createRecord<CoffGroupSym>(sym);
+ return {record.Segment, record.Offset};
+}
+
+template <> SegmentOffset GetSegmentAndOffset<DataSym>(const CVSymbol &sym) {
+ DataSym record = createRecord<DataSym>(sym);
+ return {record.Segment, record.DataOffset};
+}
+
+template <>
+SegmentOffset GetSegmentAndOffset<ThreadLocalDataSym>(const CVSymbol &sym) {
+ ThreadLocalDataSym record = createRecord<ThreadLocalDataSym>(sym);
+ return {record.Segment, record.DataOffset};
+}
+
+SegmentOffset lldb_private::npdb::GetSegmentAndOffset(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ return ::GetSegmentAndOffset<ProcSym>(sym);
+ case S_THUNK32:
+ return ::GetSegmentAndOffset<Thunk32Sym>(sym);
+ break;
+ case S_TRAMPOLINE:
+ return ::GetSegmentAndOffset<TrampolineSym>(sym);
+ break;
+ case S_COFFGROUP:
+ return ::GetSegmentAndOffset<CoffGroupSym>(sym);
+ break;
+ case S_BLOCK32:
+ return ::GetSegmentAndOffset<BlockSym>(sym);
+ break;
+ case S_LABEL32:
+ return ::GetSegmentAndOffset<LabelSym>(sym);
+ break;
+ case S_CALLSITEINFO:
+ return ::GetSegmentAndOffset<CallSiteInfoSym>(sym);
+ break;
+ case S_HEAPALLOCSITE:
+ return ::GetSegmentAndOffset<HeapAllocationSiteSym>(sym);
+ break;
+ case S_LDATA32:
+ case S_GDATA32:
+ case S_LMANDATA:
+ case S_GMANDATA:
+ return ::GetSegmentAndOffset<DataSym>(sym);
+ break;
+ case S_LTHREAD32:
+ case S_GTHREAD32:
+ return ::GetSegmentAndOffset<ThreadLocalDataSym>(sym);
+ break;
+ default:
+ lldbassert(false && "Record does not have a segment/offset!");
+ }
+ return {0, 0};
+}
+
+template <typename RecordT>
+SegmentOffsetLength GetSegmentOffsetAndLength(const CVSymbol &sym) {
+ RecordT record = createRecord<RecordT>(sym);
+ return {record.Segment, record.CodeOffset, record.CodeSize};
+}
+
+template <>
+SegmentOffsetLength
+GetSegmentOffsetAndLength<TrampolineSym>(const CVSymbol &sym) {
+ TrampolineSym record = createRecord<TrampolineSym>(sym);
+ return {record.ThunkSection, record.ThunkOffset, record.Size};
+}
+
+template <>
+SegmentOffsetLength GetSegmentOffsetAndLength<Thunk32Sym>(const CVSymbol &sym) {
+ Thunk32Sym record = createRecord<Thunk32Sym>(sym);
+ return SegmentOffsetLength{record.Segment, record.Offset, record.Length};
+}
+
+template <>
+SegmentOffsetLength
+GetSegmentOffsetAndLength<CoffGroupSym>(const CVSymbol &sym) {
+ CoffGroupSym record = createRecord<CoffGroupSym>(sym);
+ return SegmentOffsetLength{record.Segment, record.Offset, record.Size};
+}
+
+SegmentOffsetLength
+lldb_private::npdb::GetSegmentOffsetAndLength(const CVSymbol &sym) {
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32:
+ case S_GPROC32_ID:
+ case S_LPROC32_ID:
+ case S_LPROC32_DPC:
+ case S_LPROC32_DPC_ID:
+ return ::GetSegmentOffsetAndLength<ProcSym>(sym);
+ case S_THUNK32:
+ return ::GetSegmentOffsetAndLength<Thunk32Sym>(sym);
+ break;
+ case S_TRAMPOLINE:
+ return ::GetSegmentOffsetAndLength<TrampolineSym>(sym);
+ break;
+ case S_COFFGROUP:
+ return ::GetSegmentOffsetAndLength<CoffGroupSym>(sym);
+ break;
+ case S_BLOCK32:
+ return ::GetSegmentOffsetAndLength<BlockSym>(sym);
+ break;
+ default:
+ lldbassert(false && "Record does not have a segment/offset/length triple!");
+ }
+ return {0, 0, 0};
+}
+
+bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) {
+ ClassRecord cr;
+ UnionRecord ur;
+ EnumRecord er;
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return cr.isForwardRef();
+ case LF_UNION:
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return ur.isForwardRef();
+ case LF_ENUM:
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return er.isForwardRef();
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_UNION:
+ case LF_ENUM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_UNION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id,
+ TpiStream &tpi) {
+ if (id.is_ipi || id.index.isSimple())
+ return false;
+ return IsForwardRefUdt(tpi.getType(id.index));
+}
+
+bool lldb_private::npdb::IsTagRecord(const PdbTypeSymId &id, TpiStream &tpi) {
+ if (id.is_ipi || id.index.isSimple())
+ return false;
+ return IsTagRecord(tpi.getType(id.index));
+}
+
+lldb::AccessType
+lldb_private::npdb::TranslateMemberAccess(MemberAccess access) {
+ switch (access) {
+ case MemberAccess::Private:
+ return lldb::eAccessPrivate;
+ case MemberAccess::Protected:
+ return lldb::eAccessProtected;
+ case MemberAccess::Public:
+ return lldb::eAccessPublic;
+ case MemberAccess::None:
+ return lldb::eAccessNone;
+ }
+ llvm_unreachable("unreachable");
+}
+
+TypeIndex lldb_private::npdb::GetFieldListIndex(CVType cvt) {
+ switch (cvt.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE: {
+ ClassRecord cr;
+ cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return cr.FieldList;
+ }
+ case LF_UNION: {
+ UnionRecord ur;
+ cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return ur.FieldList;
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return er.FieldList;
+ }
+ default:
+ llvm_unreachable("Unreachable!");
+ }
+}
+
+TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
+ lldbassert(modifier.kind() == LF_MODIFIER);
+ ModifierRecord mr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
+ return mr.ModifiedType;
+}
+
+llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
+ return MSVCUndecoratedNameParser::DropScope(name);
+}
+
+VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
+ VariableInfo result = {};
+
+ if (sym.kind() == S_REGREL32) {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ result.type = reg.Type;
+ result.name = reg.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_REGISTER) {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ result.type = reg.Index;
+ result.name = reg.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_LOCAL) {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
+ result.type = local.Type;
+ result.name = local.Name;
+ result.is_param =
+ ((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None);
+ return result;
+ }
+
+ if (sym.kind() == S_GDATA32 || sym.kind() == S_LDATA32) {
+ DataSym data(SymbolRecordKind::DataSym);
+ cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, data));
+ result.type = data.Type;
+ result.name = data.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_GTHREAD32 || sym.kind() == S_LTHREAD32) {
+ ThreadLocalDataSym data(SymbolRecordKind::ThreadLocalDataSym);
+ cantFail(SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, data));
+ result.type = data.Type;
+ result.name = data.Name;
+ return result;
+ }
+
+ if (sym.kind() == S_CONSTANT) {
+ ConstantSym constant(SymbolRecordKind::ConstantSym);
+ cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(sym, constant));
+ result.type = constant.Type;
+ result.name = constant.Name;
+ return result;
+ }
+
+ lldbassert(false && "Invalid variable record kind!");
+ return {};
+}
+
+static llvm::FixedStreamArray<FrameData>::Iterator
+GetCorrespondingFrameData(lldb::addr_t load_addr,
+ const DebugFrameDataSubsectionRef &fpo_data,
+ const Variable::RangeList &ranges) {
+ lldbassert(!ranges.IsEmpty());
+
+ // assume that all variable ranges correspond to one frame data
+ using RangeListEntry = Variable::RangeList::Entry;
+ const RangeListEntry &range = ranges.GetEntryRef(0);
+
+ auto it = fpo_data.begin();
+
+ // start by searching first frame data range containing variable range
+ for (; it != fpo_data.end(); ++it) {
+ RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);
+
+ if (fd_range.Contains(range)) {
+ break;
+ }
+ }
+
+ // then first most nested entry that still contains variable range
+ auto found = it;
+ for (; it != fpo_data.end(); ++it) {
+ RangeListEntry fd_range(load_addr + it->RvaStart, it->CodeSize);
+
+ if (!fd_range.Contains(range)) {
+ break;
+ }
+ found = it;
+ }
+
+ return found;
+}
+
+static bool GetFrameDataProgram(PdbIndex &index,
+ const Variable::RangeList &ranges,
+ llvm::StringRef &out_program) {
+ const DebugFrameDataSubsectionRef &new_fpo_data =
+ index.dbi().getNewFpoRecords();
+
+ auto frame_data_it =
+ GetCorrespondingFrameData(index.GetLoadAddress(), new_fpo_data, ranges);
+ if (frame_data_it == new_fpo_data.end())
+ return false;
+
+ auto strings = index.pdb().getStringTable();
+ if (!strings) {
+ consumeError(strings.takeError());
+ return false;
+ }
+ out_program = cantFail(strings->getStringForID(frame_data_it->FrameFunc));
+ return true;
+}
+
+static RegisterId GetBaseFrameRegister(PdbIndex &index,
+ PdbCompilandSymId frame_proc_id,
+ bool is_parameter) {
+ CVSymbol frame_proc_cvs = index.ReadSymbolRecord(frame_proc_id);
+ if (frame_proc_cvs.kind() != S_FRAMEPROC)
+ return RegisterId::NONE;
+
+ FrameProcSym frame_proc(SymbolRecordKind::FrameProcSym);
+ cantFail(SymbolDeserializer::deserializeAs<FrameProcSym>(frame_proc_cvs,
+ frame_proc));
+
+ CPUType cpu_type = index.compilands()
+ .GetCompiland(frame_proc_id.modi)
+ ->m_compile_opts->Machine;
+
+ return is_parameter ? frame_proc.getParamFramePtrReg(cpu_type)
+ : frame_proc.getLocalFramePtrReg(cpu_type);
+}
+
+VariableInfo lldb_private::npdb::GetVariableLocationInfo(
+ PdbIndex &index, PdbCompilandSymId var_id, Block &func_block,
+ lldb::ModuleSP module) {
+
+ CVSymbol sym = index.ReadSymbolRecord(var_id);
+
+ VariableInfo result = GetVariableNameInfo(sym);
+
+ if (sym.kind() == S_REGREL32) {
+ RegRelativeSym reg(SymbolRecordKind::RegRelativeSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg));
+ result.location = DWARFExpressionList(
+ module, MakeRegRelLocationExpression(reg.Register, reg.Offset, module),
+ nullptr);
+ return result;
+ }
+
+ if (sym.kind() == S_REGISTER) {
+ RegisterSym reg(SymbolRecordKind::RegisterSym);
+ cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg));
+ result.location = DWARFExpressionList(
+ module, MakeEnregisteredLocationExpression(reg.Register, module),
+ nullptr);
+ return result;
+ }
+
+ if (sym.kind() == S_LOCAL) {
+ LocalSym local(SymbolRecordKind::LocalSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<LocalSym>(sym, local)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+
+ PdbCompilandSymId loc_specifier_id(var_id.modi,
+ var_id.offset + sym.RecordData.size());
+ CVSymbol loc_specifier_cvs;
+ // Only used for S_DEFRANGE_FRAMEPOINTER_REL.
+ RegisterId base_reg = RegisterId::NONE;
+ size_t type_size = GetSizeOfType(result.type, index.tpi());
+ // A map from offset of a field in parent to size of the field.
+ std::map<uint64_t, size_t> offset_to_size;
+
+ // When overlaps happens, always prefer the one that doesn't split the value
+ // into multiple locations and the location parsed first is perfered.
+ RangeMap location_map;
+
+ // Iterate through all location records after S_LOCAL. They describe the
+ // value of this variable at different locations.
+ bool finished = false;
+ while (!finished) {
+ loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
+ switch (loc_specifier_cvs.kind()) {
+ case S_DEFRANGE_FRAMEPOINTER_REL: {
+ DefRangeFramePointerRelSym loc(
+ SymbolRecordKind::DefRangeFramePointerRelSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ if (base_reg == RegisterId::NONE) {
+ PdbCompilandSymId func_scope_id =
+ PdbSymUid(func_block.GetID()).asCompilandSym();
+ CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id);
+ lldbassert(func_block_cvs.kind() == S_GPROC32 ||
+ func_block_cvs.kind() == S_LPROC32);
+ PdbCompilandSymId frame_proc_id(func_scope_id.modi,
+ func_scope_id.offset +
+ func_block_cvs.length());
+ base_reg =
+ GetBaseFrameRegister(index, frame_proc_id, result.is_param);
+ if (base_reg == RegisterId::NONE)
+ break;
+ }
+ DWARFExpression expr;
+ if (base_reg == RegisterId::VFRAME) {
+ llvm::StringRef program;
+ if (GetFrameDataProgram(index, raw_ranges, program))
+ expr = MakeVFrameRelLocationExpression(program, loc.Hdr.Offset,
+ module);
+ else {
+ // invalid variable
+ }
+ } else
+ expr = MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module);
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_REGISTER: {
+ DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeRegisterSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ DWARFExpression expr =
+ MakeEnregisteredLocationExpression(reg_id, module);
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_REGISTER_REL: {
+ DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+ Variable::RangeList raw_ranges =
+ MakeRangeList(index, loc.Range, loc.Gaps);
+ RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register;
+ DWARFExpression expr;
+ if (reg_id == RegisterId::VFRAME) {
+ llvm::StringRef program;
+ if (GetFrameDataProgram(index, raw_ranges, program))
+ expr = MakeVFrameRelLocationExpression(
+ program, loc.Hdr.BasePointerOffset, module);
+ else {
+ // invalid variable
+ }
+ } else {
+ expr = MakeRegRelLocationExpression(reg_id, loc.Hdr.BasePointerOffset,
+ module);
+ }
+ // FIXME: If it's UDT, we need to know the size of the value in byte.
+ if (!loc.hasSpilledUDTMember())
+ AddDwarfRange(location_map, expr, raw_ranges);
+ break;
+ }
+ case S_DEFRANGE_SUBFIELD_REGISTER: {
+ DefRangeSubfieldRegisterSym loc(
+ SymbolRecordKind::DefRangeSubfieldRegisterSym);
+ if (llvm::Error error =
+ SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>(
+ loc_specifier_cvs, loc)) {
+ llvm::consumeError(std::move(error));
+ return result;
+ }
+
+ Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps);
+ uint32_t reg_size =
+ GetRegisterSize((RegisterId)(uint16_t)loc.Hdr.Register);
+ if (reg_size == 0)
+ break;
+ offset_to_size[loc.Hdr.OffsetInParent] = reg_size;
+ AddMemberLocationRanges(location_map, loc.Hdr.OffsetInParent,
+ {loc.Hdr.Register, 0, true}, ranges);
+ break;
+ }
+ // FIXME: Handle other kinds. LLVM only generates the 4 types of records
+ // above. MSVC generates other location types.
+ case S_DEFRANGE:
+ case S_DEFRANGE_SUBFIELD:
+ case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+ break;
+ default:
+ finished = true;
+ break;
+ }
+ loc_specifier_id = PdbCompilandSymId(
+ loc_specifier_id.modi,
+ loc_specifier_id.offset + loc_specifier_cvs.RecordData.size());
+ }
+ for (const auto &entry : location_map) {
+ DWARFExpression dwarf_expr =
+ entry.data.is_dwarf ? entry.data.expr
+ : MakeEnregisteredLocationExpressionForComposite(
+ entry.data.offset_to_location,
+ offset_to_size, type_size, module);
+
+ result.location.AddExpression(entry.GetRangeBase(), entry.GetRangeEnd(),
+ dwarf_expr);
+ }
+ return result;
+ }
+ llvm_unreachable("Symbol is not a local variable!");
+ return result;
+}
+
+lldb::BasicType
+lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Boolean8:
+ return lldb::eBasicTypeBool;
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ return lldb::eBasicTypeUnsignedChar;
+ case SimpleTypeKind::NarrowCharacter:
+ return lldb::eBasicTypeChar;
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return lldb::eBasicTypeSignedChar;
+ case SimpleTypeKind::Character16:
+ return lldb::eBasicTypeChar16;
+ case SimpleTypeKind::Character32:
+ return lldb::eBasicTypeChar32;
+ case SimpleTypeKind::Character8:
+ return lldb::eBasicTypeChar8;
+ case SimpleTypeKind::Complex80:
+ return lldb::eBasicTypeLongDoubleComplex;
+ case SimpleTypeKind::Complex64:
+ return lldb::eBasicTypeDoubleComplex;
+ case SimpleTypeKind::Complex32:
+ return lldb::eBasicTypeFloatComplex;
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ return lldb::eBasicTypeLongDouble;
+ case SimpleTypeKind::Float64:
+ return lldb::eBasicTypeDouble;
+ case SimpleTypeKind::Float32:
+ return lldb::eBasicTypeFloat;
+ case SimpleTypeKind::Float16:
+ return lldb::eBasicTypeHalf;
+ case SimpleTypeKind::Int128:
+ return lldb::eBasicTypeInt128;
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return lldb::eBasicTypeLongLong;
+ case SimpleTypeKind::Int32:
+ return lldb::eBasicTypeInt;
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ return lldb::eBasicTypeShort;
+ case SimpleTypeKind::UInt128:
+ return lldb::eBasicTypeUnsignedInt128;
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ return lldb::eBasicTypeUnsignedLongLong;
+ case SimpleTypeKind::HResult:
+ case SimpleTypeKind::UInt32:
+ return lldb::eBasicTypeUnsignedInt;
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ return lldb::eBasicTypeUnsignedShort;
+ case SimpleTypeKind::Int32Long:
+ return lldb::eBasicTypeLong;
+ case SimpleTypeKind::UInt32Long:
+ return lldb::eBasicTypeUnsignedLong;
+ case SimpleTypeKind::Void:
+ return lldb::eBasicTypeVoid;
+ case SimpleTypeKind::WideCharacter:
+ return lldb::eBasicTypeWChar;
+ default:
+ return lldb::eBasicTypeInvalid;
+ }
+}
+
+size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::UInt128:
+ case SimpleTypeKind::Float128:
+ return 16;
+ case SimpleTypeKind::Complex80:
+ case SimpleTypeKind::Float80:
+ return 10;
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Complex64:
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return 8;
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Character32:
+ case SimpleTypeKind::Complex32:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::UInt32Long:
+ case SimpleTypeKind::HResult:
+ case SimpleTypeKind::UInt32:
+ return 4;
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Character16:
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ case SimpleTypeKind::WideCharacter:
+ return 2;
+ case SimpleTypeKind::Boolean8:
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ case SimpleTypeKind::Character8:
+ return 1;
+ case SimpleTypeKind::Void:
+ default:
+ return 0;
+ }
+}
+
+PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id,
+ TpiStream &tpi) {
+ if (id.index.isSimple())
+ return id;
+
+ CVType cvt = tpi.getType(id.index);
+
+ // Only tag records have a best and a worst record.
+ if (!IsTagRecord(cvt))
+ return id;
+
+ // Tag records that are not forward decls are full decls, hence they are the
+ // best.
+ if (!IsForwardRefUdt(cvt))
+ return id;
+
+ return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index));
+}
+
+template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) {
+ RecordType record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record));
+ return record.getSize();
+}
+
+size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,
+ llvm::pdb::TpiStream &tpi) {
+ if (id.index.isSimple()) {
+ switch (id.index.getSimpleMode()) {
+ case SimpleTypeMode::Direct:
+ return GetTypeSizeForSimpleKind(id.index.getSimpleKind());
+ case SimpleTypeMode::NearPointer32:
+ case SimpleTypeMode::FarPointer32:
+ return 4;
+ case SimpleTypeMode::NearPointer64:
+ return 8;
+ case SimpleTypeMode::NearPointer128:
+ return 16;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ TypeIndex index = id.index;
+ if (IsForwardRefUdt(index, tpi))
+ index = llvm::cantFail(tpi.findFullDeclForForwardRef(index));
+
+ CVType cvt = tpi.getType(index);
+ switch (cvt.kind()) {
+ case LF_MODIFIER:
+ return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi);
+ case LF_ENUM: {
+ EnumRecord record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record));
+ return GetSizeOfType({record.UnderlyingType}, tpi);
+ }
+ case LF_POINTER:
+ return GetSizeOfTypeInternal<PointerRecord>(cvt);
+ case LF_ARRAY:
+ return GetSizeOfTypeInternal<ArrayRecord>(cvt);
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ return GetSizeOfTypeInternal<ClassRecord>(cvt);
+ case LF_UNION:
+ return GetSizeOfTypeInternal<UnionRecord>(cvt);
+ case LF_BITFIELD: {
+ BitFieldRecord record;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, record));
+ return GetSizeOfType({record.Type}, tpi);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
new file mode 100644
index 000000000000..1f888f4de1fe
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -0,0 +1,157 @@
+//===-- PdbUtil.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBUTIL_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBUTIL_H
+
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "PdbSymUid.h"
+
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+namespace pdb {
+class TpiStream;
+}
+} // namespace llvm
+
+namespace lldb_private {
+namespace npdb {
+
+class PdbIndex;
+
+struct CVTagRecord {
+ enum Kind { Class, Struct, Union, Enum };
+
+ static CVTagRecord create(llvm::codeview::CVType type);
+
+ Kind kind() const { return m_kind; }
+
+ const llvm::codeview::TagRecord &asTag() const {
+ if (m_kind == Struct || m_kind == Class)
+ return cvclass;
+ if (m_kind == Enum)
+ return cvenum;
+ return cvunion;
+ }
+
+ const llvm::codeview::ClassRecord &asClass() const {
+ assert(m_kind == Struct || m_kind == Class);
+ return cvclass;
+ }
+
+ const llvm::codeview::EnumRecord &asEnum() const {
+ assert(m_kind == Enum);
+ return cvenum;
+ }
+
+ const llvm::codeview::UnionRecord &asUnion() const {
+ assert(m_kind == Union);
+ return cvunion;
+ }
+
+ llvm::StringRef name() const {
+ if (m_kind == Struct || m_kind == Union)
+ return cvclass.Name;
+ if (m_kind == Enum)
+ return cvenum.Name;
+ return cvunion.Name;
+ }
+
+private:
+ CVTagRecord(llvm::codeview::ClassRecord &&c);
+ CVTagRecord(llvm::codeview::UnionRecord &&u);
+ CVTagRecord(llvm::codeview::EnumRecord &&e);
+ union {
+ llvm::codeview::ClassRecord cvclass;
+ llvm::codeview::EnumRecord cvenum;
+ llvm::codeview::UnionRecord cvunion;
+ };
+ Kind m_kind;
+};
+
+struct SegmentOffset {
+ SegmentOffset() = default;
+ SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {}
+ uint16_t segment = 0;
+ uint32_t offset = 0;
+};
+
+struct SegmentOffsetLength {
+ SegmentOffsetLength() = default;
+ SegmentOffsetLength(uint16_t s, uint32_t o, uint32_t l)
+ : so(s, o), length(l) {}
+ SegmentOffset so;
+ uint32_t length = 0;
+};
+
+struct VariableInfo {
+ llvm::StringRef name;
+ llvm::codeview::TypeIndex type;
+ DWARFExpressionList location;
+ bool is_param;
+};
+
+llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind);
+llvm::pdb::PDB_SymType CVTypeToPDBType(llvm::codeview::TypeLeafKind kind);
+
+bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym);
+bool SymbolIsCode(const llvm::codeview::CVSymbol &sym);
+
+SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym);
+SegmentOffsetLength
+GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym);
+
+template <typename RecordT> bool IsValidRecord(const RecordT &sym) {
+ return true;
+}
+
+inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) {
+ // S_PROCREF symbols have 1-based module indices.
+ return sym.Module > 0;
+}
+
+bool IsForwardRefUdt(llvm::codeview::CVType cvt);
+bool IsTagRecord(llvm::codeview::CVType cvt);
+bool IsClassStructUnion(llvm::codeview::CVType cvt);
+
+bool IsForwardRefUdt(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi);
+bool IsTagRecord(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi);
+
+lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
+llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);
+llvm::codeview::TypeIndex
+LookThroughModifierRecord(llvm::codeview::CVType modifier);
+
+llvm::StringRef DropNameScope(llvm::StringRef name);
+
+VariableInfo GetVariableNameInfo(llvm::codeview::CVSymbol symbol);
+VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id,
+ Block &func_block, lldb::ModuleSP module);
+
+size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind);
+lldb::BasicType
+GetCompilerTypeForSimpleKind(llvm::codeview::SimpleTypeKind kind);
+
+PdbTypeSymId GetBestPossibleDecl(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
+
+size_t GetSizeOfType(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
new file mode 100644
index 000000000000..7fded6a31a3a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -0,0 +1,2336 @@
+//===-- SymbolFileNativePDB.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileNativePDB.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
+#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "DWARFLocationExpression.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
+#include <optional>
+#include <string_view>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace npdb;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+char SymbolFileNativePDB::ID;
+
+static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
+ switch (lang) {
+ case PDB_Lang::Cpp:
+ return lldb::LanguageType::eLanguageTypeC_plus_plus;
+ case PDB_Lang::C:
+ return lldb::LanguageType::eLanguageTypeC;
+ case PDB_Lang::Swift:
+ return lldb::LanguageType::eLanguageTypeSwift;
+ case PDB_Lang::Rust:
+ return lldb::LanguageType::eLanguageTypeRust;
+ case PDB_Lang::ObjC:
+ return lldb::LanguageType::eLanguageTypeObjC;
+ case PDB_Lang::ObjCpp:
+ return lldb::LanguageType::eLanguageTypeObjC_plus_plus;
+ default:
+ return lldb::LanguageType::eLanguageTypeUnknown;
+ }
+}
+
+static std::unique_ptr<PDBFile>
+loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
+ // Try to find a matching PDB for an EXE.
+ using namespace llvm::object;
+ auto expected_binary = createBinary(exe_path);
+
+ // If the file isn't a PE/COFF executable, fail.
+ if (!expected_binary) {
+ llvm::consumeError(expected_binary.takeError());
+ return nullptr;
+ }
+ OwningBinary<Binary> binary = std::move(*expected_binary);
+
+ // TODO: Avoid opening the PE/COFF binary twice by reading this information
+ // directly from the lldb_private::ObjectFile.
+ auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());
+ if (!obj)
+ return nullptr;
+ const llvm::codeview::DebugInfo *pdb_info = nullptr;
+
+ // If it doesn't have a debug directory, fail.
+ llvm::StringRef pdb_file;
+ if (llvm::Error e = obj->getDebugPDBInfo(pdb_info, pdb_file)) {
+ consumeError(std::move(e));
+ return nullptr;
+ }
+
+ // If the file doesn't exist, perhaps the path specified at build time
+ // doesn't match the PDB's current location, so check the location of the
+ // executable.
+ if (!FileSystem::Instance().Exists(pdb_file)) {
+ const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
+ const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString();
+ pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetPathAsConstString().GetStringRef();
+ }
+
+ // If the file is not a PDB or if it doesn't have a matching GUID, fail.
+ auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator);
+ if (!pdb)
+ return nullptr;
+
+ auto expected_info = pdb->getPDBInfoStream();
+ if (!expected_info) {
+ llvm::consumeError(expected_info.takeError());
+ return nullptr;
+ }
+ llvm::codeview::GUID guid;
+ memcpy(&guid, pdb_info->PDB70.Signature, 16);
+
+ if (expected_info->getGuid() != guid)
+ return nullptr;
+ return pdb;
+}
+
+static bool IsFunctionPrologue(const CompilandIndexItem &cci,
+ lldb::addr_t addr) {
+ // FIXME: Implement this.
+ return false;
+}
+
+static bool IsFunctionEpilogue(const CompilandIndexItem &cci,
+ lldb::addr_t addr) {
+ // FIXME: Implement this.
+ return false;
+}
+
+static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Boolean8:
+ return "bool";
+ case SimpleTypeKind::Byte:
+ case SimpleTypeKind::UnsignedCharacter:
+ return "unsigned char";
+ case SimpleTypeKind::NarrowCharacter:
+ return "char";
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return "signed char";
+ case SimpleTypeKind::Character16:
+ return "char16_t";
+ case SimpleTypeKind::Character32:
+ return "char32_t";
+ case SimpleTypeKind::Character8:
+ return "char8_t";
+ case SimpleTypeKind::Complex80:
+ case SimpleTypeKind::Complex64:
+ case SimpleTypeKind::Complex32:
+ return "complex";
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ return "long double";
+ case SimpleTypeKind::Float64:
+ return "double";
+ case SimpleTypeKind::Float32:
+ return "float";
+ case SimpleTypeKind::Float16:
+ return "single";
+ case SimpleTypeKind::Int128:
+ return "__int128";
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return "int64_t";
+ case SimpleTypeKind::Int32:
+ return "int";
+ case SimpleTypeKind::Int16:
+ return "short";
+ case SimpleTypeKind::UInt128:
+ return "unsigned __int128";
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ return "uint64_t";
+ case SimpleTypeKind::HResult:
+ return "HRESULT";
+ case SimpleTypeKind::UInt32:
+ return "unsigned";
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ return "unsigned short";
+ case SimpleTypeKind::Int32Long:
+ return "long";
+ case SimpleTypeKind::UInt32Long:
+ return "unsigned long";
+ case SimpleTypeKind::Void:
+ return "void";
+ case SimpleTypeKind::WideCharacter:
+ return "wchar_t";
+ default:
+ return "";
+ }
+}
+
+static bool IsClassRecord(TypeLeafKind kind) {
+ switch (kind) {
+ case LF_STRUCTURE:
+ case LF_CLASS:
+ case LF_INTERFACE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static std::optional<CVTagRecord>
+GetNestedTagDefinition(const NestedTypeRecord &Record,
+ const CVTagRecord &parent, TpiStream &tpi) {
+ // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it
+ // is also used to indicate the primary definition of a nested class. That is
+ // to say, if you have:
+ // struct A {
+ // struct B {};
+ // using C = B;
+ // };
+ // Then in the debug info, this will appear as:
+ // LF_STRUCTURE `A::B` [type index = N]
+ // LF_STRUCTURE `A`
+ // LF_NESTTYPE [name = `B`, index = N]
+ // LF_NESTTYPE [name = `C`, index = N]
+ // In order to accurately reconstruct the decl context hierarchy, we need to
+ // know which ones are actual definitions and which ones are just aliases.
+
+ // If it's a simple type, then this is something like `using foo = int`.
+ if (Record.Type.isSimple())
+ return std::nullopt;
+
+ CVType cvt = tpi.getType(Record.Type);
+
+ if (!IsTagRecord(cvt))
+ return std::nullopt;
+
+ // If it's an inner definition, then treat whatever name we have here as a
+ // single component of a mangled name. So we can inject it into the parent's
+ // mangled name to see if it matches.
+ CVTagRecord child = CVTagRecord::create(cvt);
+ std::string qname = std::string(parent.asTag().getUniqueName());
+ if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4)
+ return std::nullopt;
+
+ // qname[3] is the tag type identifier (struct, class, union, etc). Since the
+ // inner tag type is not necessarily the same as the outer tag type, re-write
+ // it to match the inner tag type.
+ qname[3] = child.asTag().getUniqueName()[3];
+ std::string piece;
+ if (qname[3] == 'W')
+ piece = "4";
+ piece += Record.Name;
+ piece.push_back('@');
+ qname.insert(4, std::move(piece));
+ if (qname != child.asTag().UniqueName)
+ return std::nullopt;
+
+ return std::move(child);
+}
+
+void SymbolFileNativePDB::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+}
+
+void SymbolFileNativePDB::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+void SymbolFileNativePDB::DebuggerInitialize(Debugger &debugger) {}
+
+llvm::StringRef SymbolFileNativePDB::GetPluginDescriptionStatic() {
+ return "Microsoft PDB debug symbol cross-platform file reader.";
+}
+
+SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFileSP objfile_sp) {
+ return new SymbolFileNativePDB(std::move(objfile_sp));
+}
+
+SymbolFileNativePDB::SymbolFileNativePDB(ObjectFileSP objfile_sp)
+ : SymbolFileCommon(std::move(objfile_sp)) {}
+
+SymbolFileNativePDB::~SymbolFileNativePDB() = default;
+
+uint32_t SymbolFileNativePDB::CalculateAbilities() {
+ uint32_t abilities = 0;
+ if (!m_objfile_sp)
+ return 0;
+
+ if (!m_index) {
+ // Lazily load and match the PDB file, but only do this once.
+ PDBFile *pdb_file;
+ if (auto *pdb = llvm::dyn_cast<ObjectFilePDB>(m_objfile_sp.get())) {
+ pdb_file = &pdb->GetPDBFile();
+ } else {
+ m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(),
+ m_allocator);
+ pdb_file = m_file_up.get();
+ }
+
+ if (!pdb_file)
+ return 0;
+
+ auto expected_index = PdbIndex::create(pdb_file);
+ if (!expected_index) {
+ llvm::consumeError(expected_index.takeError());
+ return 0;
+ }
+ m_index = std::move(*expected_index);
+ }
+ if (!m_index)
+ return 0;
+
+ // We don't especially have to be precise here. We only distinguish between
+ // stripped and not stripped.
+ abilities = kAllAbilities;
+
+ if (m_index->dbi().isStripped())
+ abilities &= ~(Blocks | LocalVariables);
+ return abilities;
+}
+
+void SymbolFileNativePDB::InitializeObject() {
+ m_obj_load_address = m_objfile_sp->GetModule()
+ ->GetObjectFile()
+ ->GetBaseAddress()
+ .GetFileAddress();
+ m_index->SetLoadAddress(m_obj_load_address);
+ m_index->ParseSectionContribs();
+
+ auto ts_or_err = m_objfile_sp->GetModule()->GetTypeSystemForLanguage(
+ lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err),
+ "Failed to initialize: {0}");
+ } else {
+ if (auto ts = *ts_or_err)
+ ts->SetSymbolFile(this);
+ BuildParentMap();
+ }
+}
+
+uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {
+ const DbiModuleList &modules = m_index->dbi().modules();
+ uint32_t count = modules.getModuleCount();
+ if (count == 0)
+ return count;
+
+ // The linker can inject an additional "dummy" compilation unit into the
+ // PDB. Ignore this special compile unit for our purposes, if it is there.
+ // It is always the last one.
+ DbiModuleDescriptor last = modules.getModuleDescriptor(count - 1);
+ if (last.getModuleName() == "* Linker *")
+ --count;
+ return count;
+}
+
+Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+ lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
+ BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return *child_block;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return *child_block;
+ PdbAstBuilder* ast_builder = ts->GetNativePDBParser();
+
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32: {
+ // This is a function. It must be global. Creating the Function entry
+ // for it automatically creates a block for it.
+ FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);
+ if (func) {
+ Block &block = func->GetBlock(false);
+ if (block.GetNumRanges() == 0)
+ block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));
+ return block;
+ }
+ break;
+ }
+ case S_BLOCK32: {
+ // This is a block. Its parent is either a function or another block. In
+ // either case, its parent can be viewed as a block (e.g. a function
+ // contains 1 big block. So just get the parent block and add this block
+ // to it.
+ BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
+ lldbassert(block.Parent != 0);
+ PdbCompilandSymId parent_id(block_id.modi, block.Parent);
+ Block &parent_block = GetOrCreateBlock(parent_id);
+ Function *func = parent_block.CalculateSymbolContextFunction();
+ lldbassert(func);
+ lldb::addr_t block_base =
+ m_index->MakeVirtualAddress(block.Segment, block.CodeOffset);
+ lldb::addr_t func_base =
+ func->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (block_base >= func_base)
+ child_block->AddRange(Block::Range(block_base - func_base, block.CodeSize));
+ else {
+ GetObjectFile()->GetModule()->ReportError(
+ "S_BLOCK32 at modi: {0:d} offset: {1:d}: adding range "
+ "[{2:x16}-{3:x16}) which has a base that is less than the "
+ "function's "
+ "low PC 0x%" PRIx64 ". Please file a bug and attach the file at the "
+ "start of this error message",
+ block_id.modi, block_id.offset, block_base,
+ block_base + block.CodeSize, func_base);
+ }
+ parent_block.AddChild(child_block);
+ ast_builder->GetOrCreateBlockDecl(block_id);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
+ }
+ case S_INLINESITE: {
+ // This ensures line table is parsed first so we have inline sites info.
+ comp_unit->GetLineTable();
+
+ std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];
+ Block &parent_block = GetOrCreateBlock(inline_site->parent_id);
+ parent_block.AddChild(child_block);
+ ast_builder->GetOrCreateInlinedFunctionDecl(block_id);
+ // Copy ranges from InlineSite to Block.
+ for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {
+ auto *entry = inline_site->ranges.GetEntryAtIndex(i);
+ child_block->AddRange(
+ Block::Range(entry->GetRangeBase(), entry->GetByteSize()));
+ }
+ child_block->FinalizeRanges();
+
+ // Get the inlined function callsite info.
+ Declaration &decl = inline_site->inline_function_info->GetDeclaration();
+ Declaration &callsite = inline_site->inline_function_info->GetCallSite();
+ child_block->SetInlinedFunctionInfo(
+ inline_site->inline_function_info->GetName().GetCString(), nullptr,
+ &decl, &callsite);
+ m_blocks.insert({opaque_block_uid, child_block});
+ break;
+ }
+ default:
+ lldbassert(false && "Symbol is not a block!");
+ }
+
+ return *child_block;
+}
+
+lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit) {
+ const CompilandIndexItem *cci =
+ m_index->compilands().GetCompiland(func_id.modi);
+ lldbassert(cci);
+ CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);
+
+ lldbassert(sym_record.kind() == S_LPROC32 || sym_record.kind() == S_GPROC32);
+ SegmentOffsetLength sol = GetSegmentOffsetAndLength(sym_record);
+
+ auto file_vm_addr =
+ m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (file_vm_addr == LLDB_INVALID_ADDRESS || file_vm_addr == 0)
+ return nullptr;
+
+ AddressRange func_range(file_vm_addr, sol.length,
+ comp_unit.GetModule()->GetSectionList());
+ if (!func_range.GetBaseAddress().IsValid())
+ return nullptr;
+
+ ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
+ if (proc.FunctionType == TypeIndex::None())
+ return nullptr;
+ TypeSP func_type = GetOrCreateType(proc.FunctionType);
+ if (!func_type)
+ return nullptr;
+
+ PdbTypeSymId sig_id(proc.FunctionType, false);
+ Mangled mangled(proc.Name);
+ FunctionSP func_sp = std::make_shared<Function>(
+ &comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
+ func_type.get(), func_range);
+
+ comp_unit.AddFunction(func_sp);
+
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit.GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return func_sp;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return func_sp;
+ ts->GetNativePDBParser()->GetOrCreateFunctionDecl(func_id);
+
+ return func_sp;
+}
+
+CompUnitSP
+SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) {
+ lldb::LanguageType lang =
+ cci.m_compile_opts ? TranslateLanguage(cci.m_compile_opts->getLanguage())
+ : lldb::eLanguageTypeUnknown;
+
+ LazyBool optimized = eLazyBoolNo;
+ if (cci.m_compile_opts && cci.m_compile_opts->hasOptimizations())
+ optimized = eLazyBoolYes;
+
+ llvm::SmallString<64> source_file_name =
+ m_index->compilands().GetMainSourceFile(cci);
+ FileSpec fs(llvm::sys::path::convert_to_slash(
+ source_file_name, llvm::sys::path::Style::windows_backslash));
+
+ CompUnitSP cu_sp = std::make_shared<CompileUnit>(
+ m_objfile_sp->GetModule(), nullptr, std::make_shared<SupportFile>(fs),
+ toOpaqueUid(cci.m_id), lang, optimized);
+
+ SetCompileUnitAtIndex(cci.m_id.modi, cu_sp);
+ return cu_sp;
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id,
+ const ModifierRecord &mr,
+ CompilerType ct) {
+ TpiStream &stream = m_index->tpi();
+
+ std::string name;
+ if (mr.ModifiedType.isSimple())
+ name = std::string(GetSimpleTypeName(mr.ModifiedType.getSimpleKind()));
+ else
+ name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+ Declaration decl;
+ lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);
+
+ return MakeType(toOpaqueUid(type_id), ConstString(name),
+ modified_type->GetByteSize(nullptr), nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id,
+ const llvm::codeview::PointerRecord &pr,
+ CompilerType ct) {
+ TypeSP pointee = GetOrCreateType(pr.ReferentType);
+ if (!pointee)
+ return nullptr;
+
+ if (pr.isPointerToMember()) {
+ MemberPointerInfo mpi = pr.getMemberInfo();
+ GetOrCreateType(mpi.ContainingType);
+ }
+
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), pr.getSize(), nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,
+ CompilerType ct) {
+ uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));
+ if (ti == TypeIndex::NullptrT()) {
+ Declaration decl;
+ return MakeType(uid, ConstString("std::nullptr_t"), 0, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Full);
+ }
+
+ if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+ TypeSP direct_sp = GetOrCreateType(ti.makeDirect());
+ uint32_t pointer_size = 0;
+ switch (ti.getSimpleMode()) {
+ case SimpleTypeMode::FarPointer32:
+ case SimpleTypeMode::NearPointer32:
+ pointer_size = 4;
+ break;
+ case SimpleTypeMode::NearPointer64:
+ pointer_size = 8;
+ break;
+ default:
+ // 128-bit and 16-bit pointers unsupported.
+ return nullptr;
+ }
+ Declaration decl;
+ return MakeType(uid, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);
+ }
+
+ if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+ return nullptr;
+
+ size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
+ llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
+
+ Declaration decl;
+ return MakeType(uid, ConstString(type_name), size, nullptr, LLDB_INVALID_UID,
+ Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full);
+}
+
+static std::string GetUnqualifiedTypeName(const TagRecord &record) {
+ if (!record.hasUniqueName()) {
+ MSVCUndecoratedNameParser parser(record.Name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ return std::string(specs.back().GetBaseName());
+ }
+
+ llvm::ms_demangle::Demangler demangler;
+ std::string_view sv(record.UniqueName.begin(), record.UniqueName.size());
+ llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+ if (demangler.Error)
+ return std::string(record.Name);
+
+ llvm::ms_demangle::IdentifierNode *idn =
+ ttn->QualifiedName->getUnqualifiedIdentifier();
+ return idn->toString();
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id,
+ const TagRecord &record,
+ size_t size, CompilerType ct) {
+
+ std::string uname = GetUnqualifiedTypeName(record);
+
+ // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr,
+ LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ Type::ResolveState::Forward);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const ClassRecord &cr,
+ CompilerType ct) {
+ return CreateClassStructUnion(type_id, cr, cr.getSize(), ct);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const UnionRecord &ur,
+ CompilerType ct) {
+ return CreateClassStructUnion(type_id, ur, ur.getSize(), ct);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id,
+ const EnumRecord &er,
+ CompilerType ct) {
+ std::string uname = GetUnqualifiedTypeName(er);
+
+ Declaration decl;
+ TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
+
+ return MakeType(toOpaqueUid(type_id), ConstString(uname),
+ underlying_type->GetByteSize(nullptr), nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Forward);
+}
+
+TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id,
+ const ArrayRecord &ar,
+ CompilerType ct) {
+ TypeSP element_type = GetOrCreateType(ar.ElementType);
+
+ Declaration decl;
+ TypeSP array_sp =
+ MakeType(toOpaqueUid(type_id), ConstString(), ar.Size, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct,
+ lldb_private::Type::ResolveState::Full);
+ array_sp->SetEncodingType(element_type.get());
+ return array_sp;
+}
+
+TypeSP SymbolFileNativePDB::CreateFunctionType(PdbTypeSymId type_id,
+ const MemberFunctionRecord &mfr,
+ CompilerType ct) {
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Full);
+}
+
+TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id,
+ const ProcedureRecord &pr,
+ CompilerType ct) {
+ Declaration decl;
+ return MakeType(toOpaqueUid(type_id), ConstString(), 0, nullptr,
+ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+ ct, lldb_private::Type::ResolveState::Full);
+}
+
+TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) {
+ if (type_id.index.isSimple())
+ return CreateSimpleType(type_id.index, ct);
+
+ TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi();
+ CVType cvt = stream.getType(type_id.index);
+
+ if (cvt.kind() == LF_MODIFIER) {
+ ModifierRecord modifier;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+ return CreateModifierType(type_id, modifier, ct);
+ }
+
+ if (cvt.kind() == LF_POINTER) {
+ PointerRecord pointer;
+ llvm::cantFail(
+ TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+ return CreatePointerType(type_id, pointer, ct);
+ }
+
+ if (IsClassRecord(cvt.kind())) {
+ ClassRecord cr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+ return CreateTagType(type_id, cr, ct);
+ }
+
+ if (cvt.kind() == LF_ENUM) {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return CreateTagType(type_id, er, ct);
+ }
+
+ if (cvt.kind() == LF_UNION) {
+ UnionRecord ur;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+ return CreateTagType(type_id, ur, ct);
+ }
+
+ if (cvt.kind() == LF_ARRAY) {
+ ArrayRecord ar;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
+ return CreateArrayType(type_id, ar, ct);
+ }
+
+ if (cvt.kind() == LF_PROCEDURE) {
+ ProcedureRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr));
+ return CreateProcedureType(type_id, pr, ct);
+ }
+ if (cvt.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord mfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(cvt, mfr));
+ return CreateFunctionType(type_id, mfr, ct);
+ }
+
+ return nullptr;
+}
+
+TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) {
+ // If they search for a UDT which is a forward ref, try and resolve the full
+ // decl and just map the forward ref uid to the full decl record.
+ std::optional<PdbTypeSymId> full_decl_uid;
+ if (IsForwardRefUdt(type_id, m_index->tpi())) {
+ auto expected_full_ti =
+ m_index->tpi().findFullDeclForForwardRef(type_id.index);
+ if (!expected_full_ti)
+ llvm::consumeError(expected_full_ti.takeError());
+ else if (*expected_full_ti != type_id.index) {
+ full_decl_uid = PdbTypeSymId(*expected_full_ti, false);
+
+ // It's possible that a lookup would occur for the full decl causing it
+ // to be cached, then a second lookup would occur for the forward decl.
+ // We don't want to create a second full decl, so make sure the full
+ // decl hasn't already been cached.
+ auto full_iter = m_types.find(toOpaqueUid(*full_decl_uid));
+ if (full_iter != m_types.end()) {
+ TypeSP result = full_iter->second;
+ // Map the forward decl to the TypeSP for the full decl so we can take
+ // the fast path next time.
+ m_types[toOpaqueUid(type_id)] = result;
+ return result;
+ }
+ }
+ }
+
+ PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id;
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ PdbAstBuilder* ast_builder = ts->GetNativePDBParser();
+ clang::QualType qt = ast_builder->GetOrCreateType(best_decl_id);
+ if (qt.isNull())
+ return nullptr;
+
+ TypeSP result = CreateType(best_decl_id, ast_builder->ToCompilerType(qt));
+ if (!result)
+ return nullptr;
+
+ uint64_t best_uid = toOpaqueUid(best_decl_id);
+ m_types[best_uid] = result;
+ // If we had both a forward decl and a full decl, make both point to the new
+ // type.
+ if (full_decl_uid)
+ m_types[toOpaqueUid(type_id)] = result;
+
+ return result;
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateType(PdbTypeSymId type_id) {
+ // We can't use try_emplace / overwrite here because the process of creating
+ // a type could create nested types, which could invalidate iterators. So
+ // we have to do a 2-phase lookup / insert.
+ auto iter = m_types.find(toOpaqueUid(type_id));
+ if (iter != m_types.end())
+ return iter->second;
+
+ TypeSP type = CreateAndCacheType(type_id);
+ if (type)
+ GetTypeList().Insert(type);
+ return type;
+}
+
+VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {
+ CVSymbol sym = m_index->symrecords().readRecord(var_id.offset);
+ if (sym.kind() == S_CONSTANT)
+ return CreateConstantSymbol(var_id, sym);
+
+ lldb::ValueType scope = eValueTypeInvalid;
+ TypeIndex ti;
+ llvm::StringRef name;
+ lldb::addr_t addr = 0;
+ uint16_t section = 0;
+ uint32_t offset = 0;
+ bool is_external = false;
+ switch (sym.kind()) {
+ case S_GDATA32:
+ is_external = true;
+ [[fallthrough]];
+ case S_LDATA32: {
+ DataSym ds(sym.kind());
+ llvm::cantFail(SymbolDeserializer::deserializeAs<DataSym>(sym, ds));
+ ti = ds.Type;
+ scope = (sym.kind() == S_GDATA32) ? eValueTypeVariableGlobal
+ : eValueTypeVariableStatic;
+ name = ds.Name;
+ section = ds.Segment;
+ offset = ds.DataOffset;
+ addr = m_index->MakeVirtualAddress(ds.Segment, ds.DataOffset);
+ break;
+ }
+ case S_GTHREAD32:
+ is_external = true;
+ [[fallthrough]];
+ case S_LTHREAD32: {
+ ThreadLocalDataSym tlds(sym.kind());
+ llvm::cantFail(
+ SymbolDeserializer::deserializeAs<ThreadLocalDataSym>(sym, tlds));
+ ti = tlds.Type;
+ name = tlds.Name;
+ section = tlds.Segment;
+ offset = tlds.DataOffset;
+ addr = m_index->MakeVirtualAddress(tlds.Segment, tlds.DataOffset);
+ scope = eValueTypeVariableThreadLocal;
+ break;
+ }
+ default:
+ llvm_unreachable("unreachable!");
+ }
+
+ CompUnitSP comp_unit;
+ std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(addr);
+ if (!modi) {
+ return nullptr;
+ }
+
+ CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi);
+ comp_unit = GetOrCreateCompileUnit(cci);
+
+ Declaration decl;
+ PdbTypeSymId tid(ti, false);
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
+ Variable::RangeList ranges;
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateVariableDecl(var_id);
+
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ DWARFExpressionList location(
+ module_sp, MakeGlobalLocationExpression(section, offset, module_sp),
+ nullptr);
+
+ std::string global_name("::");
+ global_name += name;
+ bool artificial = false;
+ bool location_is_constant_data = false;
+ bool static_member = false;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp,
+ scope, comp_unit.get(), ranges, &decl, location, is_external, artificial,
+ location_is_constant_data, static_member);
+
+ return var_sp;
+}
+
+lldb::VariableSP
+SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id,
+ const CVSymbol &cvs) {
+ TpiStream &tpi = m_index->tpi();
+ ConstantSym constant(cvs.kind());
+
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant));
+ std::string global_name("::");
+ global_name += constant.Name;
+ PdbTypeSymId tid(constant.Type, false);
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, toOpaqueUid(tid));
+
+ Declaration decl;
+ Variable::RangeList ranges;
+ ModuleSP module = GetObjectFile()->GetModule();
+ DWARFExpressionList location(module,
+ MakeConstantLocationExpression(
+ constant.Type, tpi, constant.Value, module),
+ nullptr);
+
+ bool external = false;
+ bool artificial = false;
+ bool location_is_constant_data = true;
+ bool static_member = false;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(),
+ type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location,
+ external, artificial, location_is_constant_data, static_member);
+ return var_sp;
+}
+
+VariableSP
+SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbGlobalSymId var_id) {
+ auto emplace_result = m_global_vars.try_emplace(toOpaqueUid(var_id), nullptr);
+ if (emplace_result.second) {
+ if (VariableSP var_sp = CreateGlobalVariable(var_id))
+ emplace_result.first->second = var_sp;
+ else
+ return nullptr;
+ }
+
+ return emplace_result.first->second;
+}
+
+lldb::TypeSP SymbolFileNativePDB::GetOrCreateType(TypeIndex ti) {
+ return GetOrCreateType(PdbTypeSymId(ti, false));
+}
+
+FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit) {
+ auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr);
+ if (emplace_result.second)
+ emplace_result.first->second = CreateFunction(func_id, comp_unit);
+
+ return emplace_result.first->second;
+}
+
+CompUnitSP
+SymbolFileNativePDB::GetOrCreateCompileUnit(const CompilandIndexItem &cci) {
+
+ auto emplace_result =
+ m_compilands.try_emplace(toOpaqueUid(cci.m_id), nullptr);
+ if (emplace_result.second)
+ emplace_result.first->second = CreateCompileUnit(cci);
+
+ lldbassert(emplace_result.first->second);
+ return emplace_result.first->second;
+}
+
+Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) {
+ auto iter = m_blocks.find(toOpaqueUid(block_id));
+ if (iter != m_blocks.end())
+ return *iter->second;
+
+ return CreateBlock(block_id);
+}
+
+void SymbolFileNativePDB::ParseDeclsForContext(
+ lldb_private::CompilerDeclContext decl_ctx) {
+ TypeSystem* ts_or_err = decl_ctx.GetTypeSystem();
+ if (!ts_or_err)
+ return;
+ PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser();
+ clang::DeclContext *context = ast_builder->FromCompilerDeclContext(decl_ctx);
+ if (!context)
+ return;
+ ast_builder->ParseDeclsForContext(*context);
+}
+
+lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) {
+ if (index >= GetNumCompileUnits())
+ return CompUnitSP();
+ lldbassert(index < UINT16_MAX);
+ if (index >= UINT16_MAX)
+ return nullptr;
+
+ CompilandIndexItem &item = m_index->compilands().GetOrCreateCompiland(index);
+
+ return GetOrCreateCompileUnit(item);
+}
+
+lldb::LanguageType SymbolFileNativePDB::ParseLanguage(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid uid(comp_unit.GetID());
+ lldbassert(uid.kind() == PdbSymUidKind::Compiland);
+
+ CompilandIndexItem *item =
+ m_index->compilands().GetCompiland(uid.asCompiland().modi);
+ lldbassert(item);
+ if (!item->m_compile_opts)
+ return lldb::eLanguageTypeUnknown;
+
+ return TranslateLanguage(item->m_compile_opts->getLanguage());
+}
+
+void SymbolFileNativePDB::AddSymbols(Symtab &symtab) {}
+
+size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid uid{comp_unit.GetID()};
+ lldbassert(uid.kind() == PdbSymUidKind::Compiland);
+ uint16_t modi = uid.asCompiland().modi;
+ CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(modi);
+
+ size_t count = comp_unit.GetNumFunctions();
+ const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32)
+ continue;
+
+ PdbCompilandSymId sym_id{modi, iter.offset()};
+
+ FunctionSP func = GetOrCreateFunction(sym_id, comp_unit);
+ }
+
+ size_t new_count = comp_unit.GetNumFunctions();
+ lldbassert(new_count >= count);
+ return new_count - count;
+}
+
+static bool NeedsResolvedCompileUnit(uint32_t resolve_scope) {
+ // If any of these flags are set, we need to resolve the compile unit.
+ uint32_t flags = eSymbolContextCompUnit;
+ flags |= eSymbolContextVariable;
+ flags |= eSymbolContextFunction;
+ flags |= eSymbolContextBlock;
+ flags |= eSymbolContextLineEntry;
+ return (resolve_scope & flags) != 0;
+}
+
+uint32_t SymbolFileNativePDB::ResolveSymbolContext(
+ const Address &addr, SymbolContextItem resolve_scope, SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ uint32_t resolved_flags = 0;
+ lldb::addr_t file_addr = addr.GetFileAddress();
+
+ if (NeedsResolvedCompileUnit(resolve_scope)) {
+ std::optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
+ if (!modi)
+ return 0;
+ CompUnitSP cu_sp = GetCompileUnitAtIndex(*modi);
+ if (!cu_sp)
+ return 0;
+
+ sc.comp_unit = cu_sp.get();
+ resolved_flags |= eSymbolContextCompUnit;
+ }
+
+ if (resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock) {
+ lldbassert(sc.comp_unit);
+ std::vector<SymbolAndUid> matches = m_index->FindSymbolsByVa(file_addr);
+ // Search the matches in reverse. This way if there are multiple matches
+ // (for example we are 3 levels deep in a nested scope) it will find the
+ // innermost one first.
+ for (const auto &match : llvm::reverse(matches)) {
+ if (match.uid.kind() != PdbSymUidKind::CompilandSym)
+ continue;
+
+ PdbCompilandSymId csid = match.uid.asCompilandSym();
+ CVSymbol cvs = m_index->ReadSymbolRecord(csid);
+ PDB_SymType type = CVSymToPDBSym(cvs.kind());
+ if (type != PDB_SymType::Function && type != PDB_SymType::Block)
+ continue;
+ if (type == PDB_SymType::Function) {
+ sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
+ if (sc.function) {
+ Block &block = sc.function->GetBlock(true);
+ addr_t func_base =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ addr_t offset = file_addr - func_base;
+ sc.block = block.FindInnermostBlockByOffset(offset);
+ }
+ }
+
+ if (type == PDB_SymType::Block) {
+ Block &block = GetOrCreateBlock(csid);
+ sc.function = block.CalculateSymbolContextFunction();
+ if (sc.function) {
+ sc.function->GetBlock(true);
+ addr_t func_base =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ addr_t offset = file_addr - func_base;
+ sc.block = block.FindInnermostBlockByOffset(offset);
+ }
+ }
+ if (sc.function)
+ resolved_flags |= eSymbolContextFunction;
+ if (sc.block)
+ resolved_flags |= eSymbolContextBlock;
+ break;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextLineEntry) {
+ lldbassert(sc.comp_unit);
+ if (auto *line_table = sc.comp_unit->GetLineTable()) {
+ if (line_table->FindLineEntryByAddress(addr, sc.line_entry))
+ resolved_flags |= eSymbolContextLineEntry;
+ }
+ }
+
+ return resolved_flags;
+}
+
+uint32_t SymbolFileNativePDB::ResolveSymbolContext(
+ const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit) {
+ for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
+ ++cu_idx) {
+ CompileUnit *cu = ParseCompileUnitAtIndex(cu_idx).get();
+ if (!cu)
+ continue;
+
+ bool file_spec_matches_cu_file_spec = FileSpec::Match(
+ src_location_spec.GetFileSpec(), cu->GetPrimaryFile());
+ if (file_spec_matches_cu_file_spec) {
+ cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
+ break;
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
+ // Unfortunately LLDB is set up to parse the entire compile unit line table
+ // all at once, even if all it really needs is line info for a specific
+ // function. In the future it would be nice if it could set the sc.m_function
+ // member, and we could only get the line info for the function in question.
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid cu_id(comp_unit.GetID());
+ lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
+ uint16_t modi = cu_id.asCompiland().modi;
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);
+ lldbassert(cii);
+
+ // Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records
+ // in this CU. Add line entries into the set first so that if there are line
+ // entries with same addres, the later is always more accurate than the
+ // former.
+ std::set<LineTable::Entry, LineTableEntryComparator> line_set;
+
+ // This is basically a copy of the .debug$S subsections from all original COFF
+ // object files merged together with address relocations applied. We are
+ // looking for all DEBUG_S_LINES subsections.
+ for (const DebugSubsectionRecord &dssr :
+ cii->m_debug_stream.getSubsectionsArray()) {
+ if (dssr.kind() != DebugSubsectionKind::Lines)
+ continue;
+
+ DebugLinesSubsectionRef lines;
+ llvm::BinaryStreamReader reader(dssr.getRecordData());
+ if (auto EC = lines.initialize(reader)) {
+ llvm::consumeError(std::move(EC));
+ return false;
+ }
+
+ const LineFragmentHeader *lfh = lines.header();
+ uint64_t virtual_addr =
+ m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
+ if (virtual_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ for (const LineColumnEntry &group : lines) {
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, group.NameIndex);
+ if (!file_index_or_err)
+ continue;
+ uint32_t file_index = file_index_or_err.get();
+ lldbassert(!group.LineNumbers.empty());
+ CompilandIndexItem::GlobalLineTable::Entry line_entry(
+ LLDB_INVALID_ADDRESS, 0);
+ for (const LineNumberEntry &entry : group.LineNumbers) {
+ LineInfo cur_info(entry.Flags);
+
+ if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
+ continue;
+
+ uint64_t addr = virtual_addr + entry.Offset;
+
+ bool is_statement = cur_info.isStatement();
+ bool is_prologue = IsFunctionPrologue(*cii, addr);
+ bool is_epilogue = IsFunctionEpilogue(*cii, addr);
+
+ uint32_t lno = cur_info.getStartLine();
+
+ LineTable::Entry new_entry(addr, lno, 0, file_index, is_statement, false,
+ is_prologue, is_epilogue, false);
+ // Terminal entry has lower precedence than new entry.
+ auto iter = line_set.find(new_entry);
+ if (iter != line_set.end() && iter->is_terminal_entry)
+ line_set.erase(iter);
+ line_set.insert(new_entry);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(addr);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ line_entry.SetRangeBase(addr);
+ line_entry.data = {file_index, lno};
+ }
+ LineInfo last_line(group.LineNumbers.back().Flags);
+ line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,
+ file_index, false, false, false, false, true);
+
+ if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);
+ cii->m_global_line_table.Append(line_entry);
+ }
+ }
+ }
+
+ cii->m_global_line_table.Sort();
+
+ // Parse all S_INLINESITE in this CU.
+ const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();
+ for (auto iter = syms.begin(); iter != syms.end();) {
+ if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {
+ ++iter;
+ continue;
+ }
+
+ uint32_t record_offset = iter.offset();
+ CVSymbol func_record =
+ cii->m_debug_stream.readSymbolAtOffset(record_offset);
+ SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);
+ addr_t file_vm_addr =
+ m_index->MakeVirtualAddress(sol.so.segment, sol.so.offset);
+ if (file_vm_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ AddressRange func_range(file_vm_addr, sol.length,
+ comp_unit.GetModule()->GetSectionList());
+ Address func_base = func_range.GetBaseAddress();
+ PdbCompilandSymId func_id{modi, record_offset};
+
+ // Iterate all S_INLINESITEs in the function.
+ auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind != S_INLINESITE)
+ return false;
+
+ ParseInlineSite(id, func_base);
+
+ for (const auto &line_entry :
+ m_inline_sites[toOpaqueUid(id)]->line_entries) {
+ // If line_entry is not terminal entry, remove previous line entry at
+ // the same address and insert new one. Terminal entry inside an inline
+ // site might not be terminal entry for its parent.
+ if (!line_entry.is_terminal_entry)
+ line_set.erase(line_entry);
+ line_set.insert(line_entry);
+ }
+ // No longer useful after adding to line_set.
+ m_inline_sites[toOpaqueUid(id)]->line_entries.clear();
+ return true;
+ };
+ ParseSymbolArrayInScope(func_id, parse_inline_sites);
+ // Jump to the end of the function record.
+ iter = syms.at(getScopeEndOffset(func_record));
+ }
+
+ cii->m_global_line_table.Clear();
+
+ // Add line entries in line_set to line_table.
+ auto line_table = std::make_unique<LineTable>(&comp_unit);
+ std::unique_ptr<LineSequence> sequence(
+ line_table->CreateLineSequenceContainer());
+ for (const auto &line_entry : line_set) {
+ line_table->AppendLineEntryToSequence(
+ sequence.get(), line_entry.file_addr, line_entry.line,
+ line_entry.column, line_entry.file_idx,
+ line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,
+ line_entry.is_prologue_end, line_entry.is_epilogue_begin,
+ line_entry.is_terminal_entry);
+ }
+ line_table->InsertSequence(sequence.get());
+
+ if (line_table->GetSize() == 0)
+ return false;
+
+ comp_unit.SetLineTable(line_table.release());
+ return true;
+}
+
+bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
+ // PDB doesn't contain information about macros
+ return false;
+}
+
+llvm::Expected<uint32_t>
+SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id) {
+ if (!cii.m_strings.hasChecksums() || !cii.m_strings.hasStrings())
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+ const auto &checksums = cii.m_strings.checksums().getArray();
+ const auto &strings = cii.m_strings.strings();
+ // Indices in this structure are actually offsets of records in the
+ // DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
+ // into the global PDB string table.
+ auto iter = checksums.at(file_id);
+ if (iter == checksums.end())
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+
+ llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);
+ if (!efn) {
+ return efn.takeError();
+ }
+
+ // LLDB wants the index of the file in the list of support files.
+ auto fn_iter = llvm::find(cii.m_file_list, *efn);
+ if (fn_iter != cii.m_file_list.end())
+ return std::distance(cii.m_file_list.begin(), fn_iter);
+ return llvm::make_error<RawError>(raw_error_code::no_entry);
+}
+
+bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
+ SupportFileList &support_files) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbSymUid cu_id(comp_unit.GetID());
+ lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
+ CompilandIndexItem *cci =
+ m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
+ lldbassert(cci);
+
+ for (llvm::StringRef f : cci->m_file_list) {
+ FileSpec::Style style =
+ f.starts_with("/") ? FileSpec::Style::posix : FileSpec::Style::windows;
+ FileSpec spec(f, style);
+ support_files.Append(spec);
+ }
+ return true;
+}
+
+bool SymbolFileNativePDB::ParseImportedModules(
+ const SymbolContext &sc, std::vector<SourceModule> &imported_modules) {
+ // PDB does not yet support module debug info
+ return false;
+}
+
+void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
+ Address func_addr) {
+ lldb::user_id_t opaque_uid = toOpaqueUid(id);
+ if (m_inline_sites.contains(opaque_uid))
+ return;
+
+ addr_t func_base = func_addr.GetFileAddress();
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);
+ CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
+
+ InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
+ PdbCompilandSymId parent_id(id.modi, inline_site.Parent);
+
+ std::shared_ptr<InlineSite> inline_site_sp =
+ std::make_shared<InlineSite>(parent_id);
+
+ // Get the inlined function declaration info.
+ auto iter = cii->m_inline_map.find(inline_site.Inlinee);
+ if (iter == cii->m_inline_map.end())
+ return;
+ InlineeSourceLine inlinee_line = iter->second;
+
+ const SupportFileList &files = comp_unit->GetSupportFiles();
+ FileSpec decl_file;
+ llvm::Expected<uint32_t> file_index_or_err =
+ GetFileIndex(*cii, inlinee_line.Header->FileID);
+ if (!file_index_or_err)
+ return;
+ uint32_t file_offset = file_index_or_err.get();
+ decl_file = files.GetFileSpecAtIndex(file_offset);
+ uint32_t decl_line = inlinee_line.Header->SourceLineNum;
+ std::unique_ptr<Declaration> decl_up =
+ std::make_unique<Declaration>(decl_file, decl_line);
+
+ // Parse range and line info.
+ uint32_t code_offset = 0;
+ int32_t line_offset = 0;
+ std::optional<uint32_t> code_offset_base;
+ std::optional<uint32_t> code_offset_end;
+ std::optional<int32_t> cur_line_offset;
+ std::optional<int32_t> next_line_offset;
+ std::optional<uint32_t> next_file_offset;
+
+ bool is_terminal_entry = false;
+ bool is_start_of_statement = true;
+ // The first instruction is the prologue end.
+ bool is_prologue_end = true;
+
+ auto update_code_offset = [&](uint32_t code_delta) {
+ if (!code_offset_base)
+ code_offset_base = code_offset;
+ else if (!code_offset_end)
+ code_offset_end = *code_offset_base + code_delta;
+ };
+ auto update_line_offset = [&](int32_t line_delta) {
+ line_offset += line_delta;
+ if (!code_offset_base || !cur_line_offset)
+ cur_line_offset = line_offset;
+ else
+ next_line_offset = line_offset;
+ ;
+ };
+ auto update_file_offset = [&](uint32_t offset) {
+ if (!code_offset_base)
+ file_offset = offset;
+ else
+ next_file_offset = offset;
+ };
+
+ for (auto &annot : inline_site.annotations()) {
+ switch (annot.OpCode) {
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ code_offset += annot.U1;
+ update_code_offset(annot.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ update_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ update_code_offset(annot.U1);
+ code_offset += annot.U1;
+ is_terminal_entry = true;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ code_offset += annot.U1;
+ update_code_offset(annot.U1);
+ update_line_offset(annot.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ code_offset += annot.U2;
+ update_code_offset(annot.U2);
+ update_code_offset(annot.U1);
+ code_offset += annot.U1;
+ is_terminal_entry = true;
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ update_file_offset(annot.U1);
+ break;
+ default:
+ break;
+ }
+
+ // Add range if current range is finished.
+ if (code_offset_base && code_offset_end && cur_line_offset) {
+ inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
+ *code_offset_base, *code_offset_end - *code_offset_base,
+ decl_line + *cur_line_offset));
+ // Set base, end, file offset and line offset for next range.
+ if (next_file_offset)
+ file_offset = *next_file_offset;
+ if (next_line_offset) {
+ cur_line_offset = next_line_offset;
+ next_line_offset = std::nullopt;
+ }
+ code_offset_base = is_terminal_entry ? std::nullopt : code_offset_end;
+ code_offset_end = next_file_offset = std::nullopt;
+ }
+ if (code_offset_base && cur_line_offset) {
+ if (is_terminal_entry) {
+ LineTable::Entry line_entry(
+ func_base + *code_offset_base, decl_line + *cur_line_offset, 0,
+ file_offset, false, false, false, false, true);
+ inline_site_sp->line_entries.push_back(line_entry);
+ } else {
+ LineTable::Entry line_entry(func_base + *code_offset_base,
+ decl_line + *cur_line_offset, 0,
+ file_offset, is_start_of_statement, false,
+ is_prologue_end, false, false);
+ inline_site_sp->line_entries.push_back(line_entry);
+ is_prologue_end = false;
+ is_start_of_statement = false;
+ }
+ }
+ if (is_terminal_entry)
+ is_start_of_statement = true;
+ is_terminal_entry = false;
+ }
+
+ inline_site_sp->ranges.Sort();
+
+ // Get the inlined function callsite info.
+ std::unique_ptr<Declaration> callsite_up;
+ if (!inline_site_sp->ranges.IsEmpty()) {
+ auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);
+ addr_t base_offset = entry->GetRangeBase();
+ if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==
+ S_INLINESITE) {
+ // Its parent is another inline site, lookup parent site's range vector
+ // for callsite line.
+ ParseInlineSite(parent_id, func_base);
+ std::shared_ptr<InlineSite> parent_site =
+ m_inline_sites[toOpaqueUid(parent_id)];
+ FileSpec &parent_decl_file =
+ parent_site->inline_function_info->GetDeclaration().GetFile();
+ if (auto *parent_entry =
+ parent_site->ranges.FindEntryThatContains(base_offset)) {
+ callsite_up =
+ std::make_unique<Declaration>(parent_decl_file, parent_entry->data);
+ }
+ } else {
+ // Its parent is a function, lookup global line table for callsite.
+ if (auto *entry = cii->m_global_line_table.FindEntryThatContains(
+ func_base + base_offset)) {
+ const FileSpec &callsite_file =
+ files.GetFileSpecAtIndex(entry->data.first);
+ callsite_up =
+ std::make_unique<Declaration>(callsite_file, entry->data.second);
+ }
+ }
+ }
+
+ // Get the inlined function name.
+ CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);
+ std::string inlinee_name;
+ if (inlinee_cvt.kind() == LF_MFUNC_ID) {
+ MemberFuncIdRecord mfr;
+ cantFail(
+ TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+ inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));
+ inlinee_name.append("::");
+ inlinee_name.append(mfr.getName().str());
+ } else if (inlinee_cvt.kind() == LF_FUNC_ID) {
+ FuncIdRecord fir;
+ cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));
+ TypeIndex parent_idx = fir.getParentScope();
+ if (!parent_idx.isNoneType()) {
+ LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();
+ inlinee_name.append(std::string(ids.getTypeName(parent_idx)));
+ inlinee_name.append("::");
+ }
+ inlinee_name.append(fir.getName().str());
+ }
+ inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(
+ inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),
+ callsite_up.get());
+
+ m_inline_sites[opaque_uid] = inline_site_sp;
+}
+
+size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();
+ // After we iterate through inline sites inside the function, we already get
+ // all the info needed, removing from the map to save memory.
+ std::set<uint64_t> remove_uids;
+ auto parse_blocks = [&](SymbolKind kind, PdbCompilandSymId id) {
+ if (kind == S_GPROC32 || kind == S_LPROC32 || kind == S_BLOCK32 ||
+ kind == S_INLINESITE) {
+ GetOrCreateBlock(id);
+ if (kind == S_INLINESITE)
+ remove_uids.insert(toOpaqueUid(id));
+ return true;
+ }
+ return false;
+ };
+ size_t count = ParseSymbolArrayInScope(func_id, parse_blocks);
+ for (uint64_t uid : remove_uids) {
+ m_inline_sites.erase(uid);
+ }
+ return count;
+}
+
+size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
+ PdbCompilandSymId parent_id,
+ llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);
+ CVSymbolArray syms =
+ cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);
+
+ size_t count = 1;
+ for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
+ PdbCompilandSymId child_id(parent_id.modi, iter.offset());
+ if (fn(iter->kind(), child_id))
+ ++count;
+ }
+
+ return count;
+}
+
+void SymbolFileNativePDB::DumpClangAST(Stream &s) {
+ auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+ if (!ts_or_err)
+ return;
+ auto ts = *ts_or_err;
+ TypeSystemClang *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+ if (!clang)
+ return;
+ clang->GetNativePDBParser()->Dump(s);
+}
+
+void SymbolFileNativePDB::FindGlobalVariables(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches, VariableList &variables) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+
+ std::vector<SymbolAndOffset> results = m_index->globals().findRecordsByName(
+ name.GetStringRef(), m_index->symrecords());
+ for (const SymbolAndOffset &result : results) {
+ switch (result.second.kind()) {
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ case SymbolKind::S_GTHREAD32:
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_CONSTANT: {
+ PdbGlobalSymId global(result.first, false);
+ if (VariableSP var = GetOrCreateGlobalVariable(global))
+ variables.AddVariable(var);
+ break;
+ }
+ default:
+ continue;
+ }
+ }
+}
+
+void SymbolFileNativePDB::FindFunctions(
+ const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx, bool include_inlines,
+ SymbolContextList &sc_list) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ ConstString name = lookup_info.GetLookupName();
+ FunctionNameType name_type_mask = lookup_info.GetNameTypeMask();
+ if (name_type_mask & eFunctionNameTypeFull)
+ name = lookup_info.GetName();
+
+ // For now we only support lookup by method name or full name.
+ if (!(name_type_mask & eFunctionNameTypeFull ||
+ name_type_mask & eFunctionNameTypeMethod))
+ return;
+
+ using SymbolAndOffset = std::pair<uint32_t, llvm::codeview::CVSymbol>;
+
+ std::vector<SymbolAndOffset> matches = m_index->globals().findRecordsByName(
+ name.GetStringRef(), m_index->symrecords());
+ for (const SymbolAndOffset &match : matches) {
+ if (match.second.kind() != S_PROCREF && match.second.kind() != S_LPROCREF)
+ continue;
+ ProcRefSym proc(match.second.kind());
+ cantFail(SymbolDeserializer::deserializeAs<ProcRefSym>(match.second, proc));
+
+ if (!IsValidRecord(proc))
+ continue;
+
+ CompilandIndexItem &cci =
+ m_index->compilands().GetOrCreateCompiland(proc.modi());
+ SymbolContext sc;
+
+ sc.comp_unit = GetOrCreateCompileUnit(cci).get();
+ PdbCompilandSymId func_id(proc.modi(), proc.SymOffset);
+ sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get();
+
+ sc_list.Append(sc);
+ }
+}
+
+void SymbolFileNativePDB::FindFunctions(const RegularExpression &regex,
+ bool include_inlines,
+ SymbolContextList &sc_list) {}
+
+void SymbolFileNativePDB::FindTypes(const lldb_private::TypeQuery &query,
+ lldb_private::TypeResults &results) {
+
+ // Make sure we haven't already searched this SymbolFile before.
+ if (results.AlreadySearched(this))
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+
+ std::vector<TypeIndex> matches =
+ m_index->tpi().findRecordsByName(query.GetTypeBasename().GetStringRef());
+
+ for (TypeIndex type_idx : matches) {
+ TypeSP type_sp = GetOrCreateType(type_idx);
+ if (!type_sp)
+ continue;
+
+ // We resolved a type. Get the fully qualified name to ensure it matches.
+ ConstString name = type_sp->GetQualifiedName();
+ TypeQuery type_match(name.GetStringRef(), TypeQueryOptions::e_exact_match);
+ if (query.ContextMatches(type_match.GetContextRef())) {
+ results.InsertUnique(type_sp);
+ if (results.Done(query))
+ return;
+ }
+ }
+}
+
+void SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
+ uint32_t max_matches,
+ TypeMap &types) {
+
+ std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);
+ if (max_matches > 0 && max_matches < matches.size())
+ matches.resize(max_matches);
+
+ for (TypeIndex ti : matches) {
+ TypeSP type = GetOrCreateType(ti);
+ if (!type)
+ continue;
+
+ types.Insert(type);
+ }
+}
+
+size_t SymbolFileNativePDB::ParseTypes(CompileUnit &comp_unit) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ // Only do the full type scan the first time.
+ if (m_done_full_type_scan)
+ return 0;
+
+ const size_t old_count = GetTypeList().GetSize();
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+ // First process the entire TPI stream.
+ for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+ TypeSP type = GetOrCreateType(*ti);
+ if (type)
+ (void)type->GetFullCompilerType();
+ }
+
+ // Next look for S_UDT records in the globals stream.
+ for (const uint32_t gid : m_index->globals().getGlobalsTable()) {
+ PdbGlobalSymId global{gid, false};
+ CVSymbol sym = m_index->ReadSymbolRecord(global);
+ if (sym.kind() != S_UDT)
+ continue;
+
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+ bool is_typedef = true;
+ if (IsTagRecord(PdbTypeSymId{udt.Type, false}, m_index->tpi())) {
+ CVType cvt = m_index->tpi().getType(udt.Type);
+ llvm::StringRef name = CVTagRecord::create(cvt).name();
+ if (name == udt.Name)
+ is_typedef = false;
+ }
+
+ if (is_typedef)
+ GetOrCreateTypedef(global);
+ }
+
+ const size_t new_count = GetTypeList().GetSize();
+
+ m_done_full_type_scan = true;
+
+ return new_count - old_count;
+}
+
+size_t
+SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit,
+ VariableList &variables) {
+ PdbSymUid sym_uid(comp_unit.GetID());
+ lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland);
+ return 0;
+}
+
+VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id,
+ bool is_param) {
+ ModuleSP module = GetObjectFile()->GetModule();
+ Block &block = GetOrCreateBlock(scope_id);
+ // Get function block.
+ Block *func_block = &block;
+ while (func_block->GetParent()) {
+ func_block = func_block->GetParent();
+ }
+ Address addr;
+ func_block->GetStartAddress(addr);
+ VariableInfo var_info =
+ GetVariableLocationInfo(*m_index, var_id, *func_block, module);
+ Function *func = func_block->CalculateSymbolContextFunction();
+ if (!func)
+ return nullptr;
+ // Use empty dwarf expr if optimized away so that it won't be filtered out
+ // when lookuping local variables in this scope.
+ if (!var_info.location.IsValid())
+ var_info.location = DWARFExpressionList(module, DWARFExpression(), nullptr);
+ var_info.location.SetFuncFileAddress(
+ func->GetAddressRange().GetBaseAddress().GetFileAddress());
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi);
+ CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii);
+ TypeSP type_sp = GetOrCreateType(var_info.type);
+ if (!type_sp)
+ return nullptr;
+ std::string name = var_info.name.str();
+ Declaration decl;
+ SymbolFileTypeSP sftype =
+ std::make_shared<SymbolFileType>(*this, type_sp->GetID());
+
+ is_param |= var_info.is_param;
+ ValueType var_scope =
+ is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;
+ bool external = false;
+ bool artificial = false;
+ bool location_is_constant_data = false;
+ bool static_member = false;
+ Variable::RangeList scope_ranges;
+ VariableSP var_sp = std::make_shared<Variable>(
+ toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
+ &block, scope_ranges, &decl, var_info.location, external, artificial,
+ location_is_constant_data, static_member);
+ if (!is_param) {
+ auto ts_or_err = GetTypeSystemForLanguage(comp_unit_sp->GetLanguage());
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateVariableDecl(scope_id, var_id);
+ }
+ m_local_variables[toOpaqueUid(var_id)] = var_sp;
+ return var_sp;
+}
+
+VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable(
+ PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) {
+ auto iter = m_local_variables.find(toOpaqueUid(var_id));
+ if (iter != m_local_variables.end())
+ return iter->second;
+
+ return CreateLocalVariable(scope_id, var_id, is_param);
+}
+
+TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) {
+ CVSymbol sym = m_index->ReadSymbolRecord(id);
+ lldbassert(sym.kind() == SymbolKind::S_UDT);
+
+ UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs<UDTSym>(sym));
+
+ TypeSP target_type = GetOrCreateType(udt.Type);
+
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return nullptr;
+ auto ts = *ts_or_err;
+ if (!ts)
+ return nullptr;
+
+ ts->GetNativePDBParser()->GetOrCreateTypedefDecl(id);
+
+ Declaration decl;
+ return MakeType(
+ toOpaqueUid(id), ConstString(udt.Name), target_type->GetByteSize(nullptr),
+ nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID,
+ decl, target_type->GetForwardCompilerType(),
+ lldb_private::Type::ResolveState::Forward);
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateTypedef(PdbGlobalSymId id) {
+ auto iter = m_types.find(toOpaqueUid(id));
+ if (iter != m_types.end())
+ return iter->second;
+
+ return CreateTypedef(id);
+}
+
+size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
+ Block &block = GetOrCreateBlock(block_id);
+
+ size_t count = 0;
+
+ CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
+ CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
+ uint32_t params_remaining = 0;
+ switch (sym.kind()) {
+ case S_GPROC32:
+ case S_LPROC32: {
+ ProcSym proc(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym, proc));
+ CVType signature = m_index->tpi().getType(proc.FunctionType);
+ if (signature.kind() == LF_PROCEDURE) {
+ ProcedureRecord sig;
+ if (llvm::Error e = TypeDeserializer::deserializeAs<ProcedureRecord>(
+ signature, sig)) {
+ llvm::consumeError(std::move(e));
+ return 0;
+ }
+ params_remaining = sig.getParameterCount();
+ } else if (signature.kind() == LF_MFUNCTION) {
+ MemberFunctionRecord sig;
+ if (llvm::Error e = TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ signature, sig)) {
+ llvm::consumeError(std::move(e));
+ return 0;
+ }
+ params_remaining = sig.getParameterCount();
+ } else
+ return 0;
+ break;
+ }
+ case S_BLOCK32:
+ break;
+ case S_INLINESITE:
+ break;
+ default:
+ lldbassert(false && "Symbol is not a block!");
+ return 0;
+ }
+
+ VariableListSP variables = block.GetBlockVariableList(false);
+ if (!variables) {
+ variables = std::make_shared<VariableList>();
+ block.SetVariableList(variables);
+ }
+
+ CVSymbolArray syms = limitSymbolArrayToScope(
+ cii->m_debug_stream.getSymbolArray(), block_id.offset);
+
+ // Skip the first record since it's a PROC32 or BLOCK32, and there's
+ // no point examining it since we know it's not a local variable.
+ syms.drop_front();
+ auto iter = syms.begin();
+ auto end = syms.end();
+
+ while (iter != end) {
+ uint32_t record_offset = iter.offset();
+ CVSymbol variable_cvs = *iter;
+ PdbCompilandSymId child_sym_id(block_id.modi, record_offset);
+ ++iter;
+
+ // If this is a block or inline site, recurse into its children and then
+ // skip it.
+ if (variable_cvs.kind() == S_BLOCK32 ||
+ variable_cvs.kind() == S_INLINESITE) {
+ uint32_t block_end = getScopeEndOffset(variable_cvs);
+ count += ParseVariablesForBlock(child_sym_id);
+ iter = syms.at(block_end);
+ continue;
+ }
+
+ bool is_param = params_remaining > 0;
+ VariableSP variable;
+ switch (variable_cvs.kind()) {
+ case S_REGREL32:
+ case S_REGISTER:
+ case S_LOCAL:
+ variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param);
+ if (is_param)
+ --params_remaining;
+ if (variable)
+ variables->AddVariableIfUnique(variable);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Pass false for set_children, since we call this recursively so that the
+ // children will call this for themselves.
+ block.SetDidParseVariables(true, false);
+
+ return count;
+}
+
+size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ lldbassert(sc.function || sc.comp_unit);
+
+ VariableListSP variables;
+ if (sc.block) {
+ PdbSymUid block_id(sc.block->GetID());
+
+ size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
+ return count;
+ }
+
+ if (sc.function) {
+ PdbSymUid block_id(sc.function->GetID());
+
+ size_t count = ParseVariablesForBlock(block_id.asCompilandSym());
+ return count;
+ }
+
+ if (sc.comp_unit) {
+ variables = sc.comp_unit->GetVariableList(false);
+ if (!variables) {
+ variables = std::make_shared<VariableList>();
+ sc.comp_unit->SetVariableList(variables);
+ }
+ return ParseVariablesForCompileUnit(*sc.comp_unit, *variables);
+ }
+
+ llvm_unreachable("Unreachable!");
+}
+
+CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return CompilerDecl();
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ if (auto decl = ts->GetNativePDBParser()->GetOrCreateDeclForUid(uid))
+ return *decl;
+ return CompilerDecl();
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return {};
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ PdbAstBuilder *ast_builder = ts->GetNativePDBParser();
+ clang::DeclContext *context =
+ ast_builder->GetOrCreateDeclContextForUid(PdbSymUid(uid));
+ if (!context)
+ return {};
+
+ return ast_builder->ToCompilerDeclContext(*context);
+}
+
+CompilerDeclContext
+SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) {
+ auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+ if (auto err = ts_or_err.takeError())
+ return CompilerDeclContext();
+ auto ts = *ts_or_err;
+ if (!ts)
+ return {};
+
+ PdbAstBuilder *ast_builder = ts->GetNativePDBParser();
+ clang::DeclContext *context = ast_builder->GetParentDeclContext(PdbSymUid(uid));
+ if (!context)
+ return CompilerDeclContext();
+ return ast_builder->ToCompilerDeclContext(*context);
+}
+
+Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto iter = m_types.find(type_uid);
+ // lldb should not be passing us non-sensical type uids. the only way it
+ // could have a type uid in the first place is if we handed it out, in which
+ // case we should know about the type. However, that doesn't mean we've
+ // instantiated it yet. We can vend out a UID for a future type. So if the
+ // type doesn't exist, let's instantiate it now.
+ if (iter != m_types.end())
+ return &*iter->second;
+
+ PdbSymUid uid(type_uid);
+ lldbassert(uid.kind() == PdbSymUidKind::Type);
+ PdbTypeSymId type_id = uid.asTypeSym();
+ if (type_id.index.isNoneType())
+ return nullptr;
+
+ TypeSP type_sp = CreateAndCacheType(type_id);
+ if (!type_sp)
+ return nullptr;
+ return &*type_sp;
+}
+
+std::optional<SymbolFile::ArrayInfo>
+SymbolFileNativePDB::GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) {
+ return std::nullopt;
+}
+
+bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
+ std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+ auto ts = compiler_type.GetTypeSystem();
+ auto clang_type_system = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (!clang_type_system)
+ return false;
+
+ PdbAstBuilder *ast_builder =
+ static_cast<PdbAstBuilder *>(clang_type_system->GetNativePDBParser());
+ if (ast_builder &&
+ ast_builder->GetClangASTImporter().CanImport(compiler_type))
+ return ast_builder->GetClangASTImporter().CompleteType(compiler_type);
+ clang::QualType qt =
+ clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType());
+
+ return ast_builder->CompleteType(qt);
+}
+
+void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
+ TypeClass type_mask,
+ lldb_private::TypeList &type_list) {}
+
+CompilerDeclContext SymbolFileNativePDB::FindNamespace(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx, bool) {
+ return {};
+}
+
+llvm::Expected<lldb::TypeSystemSP>
+SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) {
+ auto type_system_or_err =
+ m_objfile_sp->GetModule()->GetTypeSystemForLanguage(language);
+ if (type_system_or_err)
+ if (auto ts = *type_system_or_err)
+ ts->SetSymbolFile(this);
+ return type_system_or_err;
+}
+
+uint64_t SymbolFileNativePDB::GetDebugInfoSize(bool load_all_debug_info) {
+ // PDB files are a separate file that contains all debug info.
+ return m_index->pdb().getFileSize();
+}
+
+void SymbolFileNativePDB::BuildParentMap() {
+ LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+ llvm::DenseMap<TypeIndex, TypeIndex> forward_to_full;
+ llvm::DenseMap<TypeIndex, TypeIndex> full_to_forward;
+
+ struct RecordIndices {
+ TypeIndex forward;
+ TypeIndex full;
+ };
+
+ llvm::StringMap<RecordIndices> record_indices;
+
+ for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+ CVType type = types.getType(*ti);
+ if (!IsTagRecord(type))
+ continue;
+
+ CVTagRecord tag = CVTagRecord::create(type);
+
+ RecordIndices &indices = record_indices[tag.asTag().getUniqueName()];
+ if (tag.asTag().isForwardRef())
+ indices.forward = *ti;
+ else
+ indices.full = *ti;
+
+ if (indices.full != TypeIndex::None() &&
+ indices.forward != TypeIndex::None()) {
+ forward_to_full[indices.forward] = indices.full;
+ full_to_forward[indices.full] = indices.forward;
+ }
+
+ // We're looking for LF_NESTTYPE records in the field list, so ignore
+ // forward references (no field list), and anything without a nested class
+ // (since there won't be any LF_NESTTYPE records).
+ if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass())
+ continue;
+
+ struct ProcessTpiStream : public TypeVisitorCallbacks {
+ ProcessTpiStream(PdbIndex &index, TypeIndex parent,
+ const CVTagRecord &parent_cvt,
+ llvm::DenseMap<TypeIndex, TypeIndex> &parents)
+ : index(index), parents(parents), parent(parent),
+ parent_cvt(parent_cvt) {}
+
+ PdbIndex &index;
+ llvm::DenseMap<TypeIndex, TypeIndex> &parents;
+
+ unsigned unnamed_type_index = 1;
+ TypeIndex parent;
+ const CVTagRecord &parent_cvt;
+
+ llvm::Error visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Record) override {
+ std::string unnamed_type_name;
+ if (Record.Name.empty()) {
+ unnamed_type_name =
+ llvm::formatv("<unnamed-type-$S{0}>", unnamed_type_index).str();
+ Record.Name = unnamed_type_name;
+ ++unnamed_type_index;
+ }
+ std::optional<CVTagRecord> tag =
+ GetNestedTagDefinition(Record, parent_cvt, index.tpi());
+ if (!tag)
+ return llvm::ErrorSuccess();
+
+ parents[Record.Type] = parent;
+ return llvm::ErrorSuccess();
+ }
+ };
+
+ CVType field_list_cvt = m_index->tpi().getType(tag.asTag().FieldList);
+ ProcessTpiStream process(*m_index, *ti, tag, m_parent_types);
+ FieldListRecord field_list;
+ if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>(
+ field_list_cvt, field_list))
+ llvm::consumeError(std::move(error));
+ if (llvm::Error error = visitMemberRecordStream(field_list.Data, process))
+ llvm::consumeError(std::move(error));
+ }
+
+ // Now that we know the forward -> full mapping of all type indices, we can
+ // re-write all the indices. At the end of this process, we want a mapping
+ // consisting of fwd -> full and full -> full for all child -> parent indices.
+ // We can re-write the values in place, but for the keys, we must save them
+ // off so that we don't modify the map in place while also iterating it.
+ std::vector<TypeIndex> full_keys;
+ std::vector<TypeIndex> fwd_keys;
+ for (auto &entry : m_parent_types) {
+ TypeIndex key = entry.first;
+ TypeIndex value = entry.second;
+
+ auto iter = forward_to_full.find(value);
+ if (iter != forward_to_full.end())
+ entry.second = iter->second;
+
+ iter = forward_to_full.find(key);
+ if (iter != forward_to_full.end())
+ fwd_keys.push_back(key);
+ else
+ full_keys.push_back(key);
+ }
+ for (TypeIndex fwd : fwd_keys) {
+ TypeIndex full = forward_to_full[fwd];
+ TypeIndex parent_idx = m_parent_types[fwd];
+ m_parent_types[full] = parent_idx;
+ }
+ for (TypeIndex full : full_keys) {
+ TypeIndex fwd = full_to_forward[full];
+ m_parent_types[fwd] = m_parent_types[full];
+ }
+}
+
+std::optional<PdbCompilandSymId>
+SymbolFileNativePDB::FindSymbolScope(PdbCompilandSymId id) {
+ CVSymbol sym = m_index->ReadSymbolRecord(id);
+ if (symbolOpensScope(sym.kind())) {
+ // If this exact symbol opens a scope, we can just directly access its
+ // parent.
+ id.offset = getScopeParentOffset(sym);
+ // Global symbols have parent offset of 0. Return std::nullopt to indicate
+ // this.
+ if (id.offset == 0)
+ return std::nullopt;
+ return id;
+ }
+
+ // Otherwise we need to start at the beginning and iterate forward until we
+ // reach (or pass) this particular symbol
+ CompilandIndexItem &cii = m_index->compilands().GetOrCreateCompiland(id.modi);
+ const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray();
+
+ auto begin = syms.begin();
+ auto end = syms.at(id.offset);
+ std::vector<PdbCompilandSymId> scope_stack;
+
+ while (begin != end) {
+ if (begin.offset() > id.offset) {
+ // We passed it. We couldn't even find this symbol record.
+ lldbassert(false && "Invalid compiland symbol id!");
+ return std::nullopt;
+ }
+
+ // We haven't found the symbol yet. Check if we need to open or close the
+ // scope stack.
+ if (symbolOpensScope(begin->kind())) {
+ // We can use the end offset of the scope to determine whether or not
+ // we can just outright skip this entire scope.
+ uint32_t scope_end = getScopeEndOffset(*begin);
+ if (scope_end < id.offset) {
+ begin = syms.at(scope_end);
+ } else {
+ // The symbol we're looking for is somewhere in this scope.
+ scope_stack.emplace_back(id.modi, begin.offset());
+ }
+ } else if (symbolEndsScope(begin->kind())) {
+ scope_stack.pop_back();
+ }
+ ++begin;
+ }
+ if (scope_stack.empty())
+ return std::nullopt;
+ // We have a match! Return the top of the stack
+ return scope_stack.back();
+}
+
+std::optional<llvm::codeview::TypeIndex>
+SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) {
+ auto parent_iter = m_parent_types.find(ti);
+ if (parent_iter == m_parent_types.end())
+ return std::nullopt;
+ return parent_iter->second;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
new file mode 100644
index 000000000000..669c44aa131e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -0,0 +1,286 @@
+//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
+
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include "CompileUnitIndex.h"
+#include "PdbIndex.h"
+#include "PdbAstBuilder.h"
+#include <optional>
+
+namespace clang {
+class TagDecl;
+}
+
+namespace llvm {
+namespace codeview {
+class ClassRecord;
+class EnumRecord;
+class ModifierRecord;
+class PointerRecord;
+struct UnionRecord;
+} // namespace codeview
+} // namespace llvm
+
+namespace lldb_private {
+
+namespace npdb {
+
+class SymbolFileNativePDB : public SymbolFileCommon {
+ friend class UdtRecordCompleter;
+
+ /// LLVM RTTI support.
+ static char ID;
+
+public:
+ /// LLVM RTTI support.
+ /// \{
+ bool isA(const void *ClassID) const override {
+ return ClassID == &ID || SymbolFileCommon::isA(ClassID);
+ }
+ static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
+ /// \}
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static void DebuggerInitialize(Debugger &debugger);
+
+ static llvm::StringRef GetPluginNameStatic() { return "native-pdb"; }
+
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ static SymbolFile *CreateInstance(lldb::ObjectFileSP objfile_sp);
+
+ // Constructors and Destructors
+ SymbolFileNativePDB(lldb::ObjectFileSP objfile_sp);
+
+ ~SymbolFileNativePDB() override;
+
+ uint32_t CalculateAbilities() override;
+
+ void InitializeObject() override;
+
+ uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
+
+ // Compile Unit function calls
+
+ void
+ ParseDeclsForContext(lldb_private::CompilerDeclContext decl_ctx) override;
+
+ lldb::LanguageType
+ ParseLanguage(lldb_private::CompileUnit &comp_unit) override;
+
+ size_t ParseFunctions(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseLineTable(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseDebugMacros(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseSupportFiles(lldb_private::CompileUnit &comp_unit,
+ SupportFileList &support_files) override;
+ size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
+
+ bool ParseImportedModules(
+ const SymbolContext &sc,
+ std::vector<lldb_private::SourceModule> &imported_modules) override;
+
+ size_t ParseBlocksRecursive(Function &func) override;
+
+ void FindGlobalVariables(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ uint32_t max_matches,
+ VariableList &variables) override;
+
+ size_t ParseVariablesForContext(const SymbolContext &sc) override;
+
+ void AddSymbols(Symtab &symtab) override;
+
+ CompilerDecl GetDeclForUID(lldb::user_id_t uid) override;
+ CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override;
+ CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override;
+ Type *ResolveTypeUID(lldb::user_id_t type_uid) override;
+ std::optional<ArrayInfo> GetDynamicArrayInfoForUID(
+ lldb::user_id_t type_uid,
+ const lldb_private::ExecutionContext *exe_ctx) override;
+
+ bool CompleteType(CompilerType &compiler_type) override;
+ uint32_t ResolveSymbolContext(const Address &so_addr,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContext &sc) override;
+ uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
+ lldb::SymbolContextItem resolve_scope,
+ SymbolContextList &sc_list) override;
+
+ void GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask,
+ TypeList &type_list) override;
+
+ void FindFunctions(const Module::LookupInfo &lookup_info,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool include_inlines, SymbolContextList &sc_list) override;
+
+ void FindFunctions(const RegularExpression &regex, bool include_inlines,
+ SymbolContextList &sc_list) override;
+
+ std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id);
+
+ void FindTypes(const lldb_private::TypeQuery &match,
+ lldb_private::TypeResults &results) override;
+
+ llvm::Expected<lldb::TypeSystemSP>
+ GetTypeSystemForLanguage(lldb::LanguageType language) override;
+
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+ llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
+ const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
+
+ PdbIndex &GetIndex() { return *m_index; };
+
+ void DumpClangAST(Stream &s) override;
+
+ std::optional<llvm::codeview::TypeIndex>
+ GetParentType(llvm::codeview::TypeIndex ti);
+
+private:
+ struct LineTableEntryComparator {
+ bool operator()(const lldb_private::LineTable::Entry &lhs,
+ const lldb_private::LineTable::Entry &rhs) const {
+ return lhs.file_addr < rhs.file_addr;
+ }
+ };
+
+ // From address range relative to function base to source line number.
+ using RangeSourceLineVector =
+ lldb_private::RangeDataVector<uint32_t, uint32_t, int32_t>;
+ // InlineSite contains information in a S_INLINESITE record.
+ struct InlineSite {
+ PdbCompilandSymId parent_id;
+ std::shared_ptr<InlineFunctionInfo> inline_function_info;
+ RangeSourceLineVector ranges;
+ std::vector<lldb_private::LineTable::Entry> line_entries;
+ InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){};
+ };
+
+ void BuildParentMap();
+
+ uint32_t CalculateNumCompileUnits() override;
+
+ lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
+
+ void FindTypesByName(llvm::StringRef name, uint32_t max_matches,
+ TypeMap &types);
+
+ lldb::TypeSP CreateModifierType(PdbTypeSymId type_id,
+ const llvm::codeview::ModifierRecord &mr,
+ CompilerType ct);
+ lldb::TypeSP CreatePointerType(PdbTypeSymId type_id,
+ const llvm::codeview::PointerRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti, CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::ClassRecord &cr,
+ CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::EnumRecord &er,
+ CompilerType ct);
+ lldb::TypeSP CreateTagType(PdbTypeSymId type_id,
+ const llvm::codeview::UnionRecord &ur,
+ CompilerType ct);
+ lldb::TypeSP CreateArrayType(PdbTypeSymId type_id,
+ const llvm::codeview::ArrayRecord &ar,
+ CompilerType ct);
+ lldb::TypeSP CreateFunctionType(PdbTypeSymId type_id,
+ const llvm::codeview::MemberFunctionRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateProcedureType(PdbTypeSymId type_id,
+ const llvm::codeview::ProcedureRecord &pr,
+ CompilerType ct);
+ lldb::TypeSP CreateClassStructUnion(PdbTypeSymId type_id,
+ const llvm::codeview::TagRecord &record,
+ size_t size, CompilerType ct);
+
+ lldb::FunctionSP GetOrCreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit);
+ lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci);
+ lldb::TypeSP GetOrCreateType(PdbTypeSymId type_id);
+ lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti);
+ lldb::VariableSP GetOrCreateGlobalVariable(PdbGlobalSymId var_id);
+ Block &GetOrCreateBlock(PdbCompilandSymId block_id);
+ lldb::VariableSP GetOrCreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id,
+ bool is_param);
+ lldb::TypeSP GetOrCreateTypedef(PdbGlobalSymId id);
+
+ lldb::FunctionSP CreateFunction(PdbCompilandSymId func_id,
+ CompileUnit &comp_unit);
+ Block &CreateBlock(PdbCompilandSymId block_id);
+ lldb::VariableSP CreateLocalVariable(PdbCompilandSymId scope_id,
+ PdbCompilandSymId var_id, bool is_param);
+ lldb::TypeSP CreateTypedef(PdbGlobalSymId id);
+ lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci);
+ lldb::TypeSP CreateType(PdbTypeSymId type_id, CompilerType ct);
+ lldb::TypeSP CreateAndCacheType(PdbTypeSymId type_id);
+ lldb::VariableSP CreateGlobalVariable(PdbGlobalSymId var_id);
+ lldb::VariableSP CreateConstantSymbol(PdbGlobalSymId var_id,
+ const llvm::codeview::CVSymbol &cvs);
+ size_t ParseVariablesForCompileUnit(CompileUnit &comp_unit,
+ VariableList &variables);
+ size_t ParseVariablesForBlock(PdbCompilandSymId block_id);
+
+ llvm::Expected<uint32_t> GetFileIndex(const CompilandIndexItem &cii,
+ uint32_t file_id);
+
+ size_t ParseSymbolArrayInScope(
+ PdbCompilandSymId parent,
+ llvm::function_ref<bool(llvm::codeview::SymbolKind, PdbCompilandSymId)>
+ fn);
+
+ void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
+
+ llvm::BumpPtrAllocator m_allocator;
+
+ lldb::addr_t m_obj_load_address = 0;
+ bool m_done_full_type_scan = false;
+ // UID for anonymous union and anonymous struct as they don't have entities in
+ // pdb debug info.
+ lldb::user_id_t anonymous_id = LLDB_INVALID_UID - 1;
+
+ std::unique_ptr<llvm::pdb::PDBFile> m_file_up;
+ std::unique_ptr<PdbIndex> m_index;
+
+ llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars;
+ llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_local_variables;
+ llvm::DenseMap<lldb::user_id_t, lldb::BlockSP> m_blocks;
+ llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
+ llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
+ llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
+ llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
+ llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
+ m_parent_types;
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
new file mode 100644
index 000000000000..17c5f6118603
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -0,0 +1,501 @@
+#include "UdtRecordCompleter.h"
+
+#include "PdbAstBuilder.h"
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
+#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "SymbolFileNativePDB.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include <optional>
+
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+
+using Error = llvm::Error;
+
+UdtRecordCompleter::UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &cxx_record_map)
+ : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
+ m_ast_builder(ast_builder), m_index(index),
+ m_decl_to_status(decl_to_status), m_cxx_record_map(cxx_record_map) {
+ CVType cvt = m_index.tpi().getType(m_id.index);
+ switch (cvt.kind()) {
+ case LF_ENUM:
+ m_cvr.er.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
+ break;
+ case LF_UNION:
+ m_cvr.ur.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
+ m_layout.bit_size = m_cvr.ur.getSize() * 8;
+ m_record.record.kind = Member::Union;
+ break;
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ m_cvr.cr.Options = ClassOptions::None;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
+ m_layout.bit_size = m_cvr.cr.getSize() * 8;
+ m_record.record.kind = Member::Struct;
+ break;
+ default:
+ llvm_unreachable("unreachable!");
+ }
+}
+
+clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
+ llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
+ std::optional<uint64_t> vtable_idx) {
+ PdbTypeSymId type_id(ti);
+ clang::QualType qt = m_ast_builder.GetOrCreateType(type_id);
+
+ CVType udt_cvt = m_index.tpi().getType(ti);
+
+ std::unique_ptr<clang::CXXBaseSpecifier> base_spec =
+ m_ast_builder.clang().CreateBaseClassSpecifier(
+ qt.getAsOpaquePtr(), TranslateMemberAccess(access),
+ vtable_idx.has_value(), udt_cvt.kind() == LF_CLASS);
+ if (!base_spec)
+ return {};
+
+ m_bases.push_back(
+ std::make_pair(vtable_idx.value_or(0), std::move(base_spec)));
+
+ return qt;
+}
+
+void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
+ MemberAccess access, MethodOptions options,
+ MemberAttributes attrs) {
+ clang::QualType method_qt =
+ m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
+ if (method_qt.isNull())
+ return;
+ CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
+ TypeSystemClang::RequireCompleteType(method_ct);
+ lldb::opaque_compiler_type_t derived_opaque_ty =
+ m_derived_ct.GetOpaqueQualType();
+ auto iter = m_cxx_record_map.find(derived_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({name, method_ct})) {
+ return;
+ }
+ }
+
+ lldb::AccessType access_type = TranslateMemberAccess(access);
+ bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
+ MethodOptions::CompilerGenerated;
+ m_ast_builder.clang().AddMethodToCXXRecordType(
+ derived_opaque_ty, name.data(), nullptr, method_ct,
+ access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
+ is_artificial);
+
+ m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ BaseClassRecord &base) {
+ clang::QualType base_qt =
+ AddBaseClassForTypeIndex(base.Type, base.getAccess());
+
+ if (base_qt.isNull())
+ return llvm::Error::success();
+ auto decl =
+ m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr());
+ lldbassert(decl);
+
+ auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
+ m_layout.base_offsets.insert(std::make_pair(decl, offset));
+
+ return llvm::Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ VirtualBaseClassRecord &base) {
+ AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ ListContinuationRecord &cont) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ VFPtrRecord &vfptr) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(
+ CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
+ clang::QualType member_type =
+ m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type));
+ if (member_type.isNull())
+ return llvm::Error::success();
+
+ CompilerType member_ct = m_ast_builder.ToCompilerType(member_type);
+
+ lldb::AccessType access =
+ TranslateMemberAccess(static_data_member.getAccess());
+ auto decl = TypeSystemClang::AddVariableToRecordType(
+ m_derived_ct, static_data_member.Name, member_ct, access);
+
+ // Static constant members may be a const[expr] declaration.
+ // Query the symbol's value as the variable initializer if valid.
+ if (member_ct.IsConst() && member_ct.IsCompleteType()) {
+ std::string qual_name = decl->getQualifiedNameAsString();
+
+ auto results =
+ m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
+
+ for (const auto &result : results) {
+ if (result.second.kind() == SymbolKind::S_CONSTANT) {
+ ConstantSym constant(SymbolRecordKind::ConstantSym);
+ cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(result.second,
+ constant));
+
+ clang::QualType qual_type = decl->getType();
+ unsigned type_width = decl->getASTContext().getIntWidth(qual_type);
+ unsigned constant_width = constant.Value.getBitWidth();
+
+ if (qual_type->isIntegralOrEnumerationType()) {
+ if (type_width >= constant_width) {
+ TypeSystemClang::SetIntegerInitializerForVariable(
+ decl, constant.Value.extOrTrunc(type_width));
+ } else {
+ LLDB_LOG(GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+ "which resolves to a wider constant value ({4} bits). "
+ "Ignoring constant.",
+ m_derived_ct.GetTypeName(), static_data_member.Name,
+ member_ct.GetTypeName(), type_width, constant_width);
+ }
+ } else {
+ lldb::BasicType basic_type_enum = member_ct.GetBasicTypeEnumeration();
+ switch (basic_type_enum) {
+ case lldb::eBasicTypeFloat:
+ case lldb::eBasicTypeDouble:
+ case lldb::eBasicTypeLongDouble:
+ if (type_width == constant_width) {
+ TypeSystemClang::SetFloatingInitializerForVariable(
+ decl, basic_type_enum == lldb::eBasicTypeFloat
+ ? llvm::APFloat(constant.Value.bitsToFloat())
+ : llvm::APFloat(constant.Value.bitsToDouble()));
+ decl->setConstexpr(true);
+ } else {
+ LLDB_LOG(
+ GetLog(LLDBLog::AST),
+ "Class '{0}' has a member '{1}' of type '{2}' ({3} bits) "
+ "which resolves to a constant value of mismatched width "
+ "({4} bits). Ignoring constant.",
+ m_derived_ct.GetTypeName(), static_data_member.Name,
+ member_ct.GetTypeName(), type_width, constant_width);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ // FIXME: Add a PdbSymUid namespace for field list members and update
+ // the m_uid_to_decl map with this decl.
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ NestedTypeRecord &nested) {
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ DataMemberRecord &data_member) {
+
+ uint64_t offset = data_member.FieldOffset * 8;
+ uint32_t bitfield_width = 0;
+
+ TypeIndex ti(data_member.Type);
+ if (!ti.isSimple()) {
+ CVType cvt = m_index.tpi().getType(ti);
+ if (cvt.kind() == LF_BITFIELD) {
+ BitFieldRecord bfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr));
+ offset += bfr.BitOffset;
+ bitfield_width = bfr.BitSize;
+ ti = bfr.Type;
+ }
+ }
+
+ clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti));
+ if (member_qt.isNull())
+ return Error::success();
+ TypeSystemClang::RequireCompleteType(m_ast_builder.ToCompilerType(member_qt));
+ lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
+ size_t field_size =
+ bitfield_width ? bitfield_width : GetSizeOfType(ti, m_index.tpi()) * 8;
+ if (field_size == 0)
+ return Error::success();
+ m_record.CollectMember(data_member.Name, offset, field_size, member_qt, access,
+ bitfield_width);
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OneMethodRecord &one_method) {
+ AddMethod(one_method.Name, one_method.Type, one_method.getAccess(),
+ one_method.getOptions(), one_method.Attrs);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ OverloadedMethodRecord &overloaded) {
+ TypeIndex method_list_idx = overloaded.MethodList;
+
+ CVType method_list_type = m_index.tpi().getType(method_list_idx);
+ assert(method_list_type.kind() == LF_METHODLIST);
+
+ MethodOverloadListRecord method_list;
+ llvm::cantFail(TypeDeserializer::deserializeAs<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods)
+ AddMethod(overloaded.Name, method.Type, method.getAccess(),
+ method.getOptions(), method.Attrs);
+
+ return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+ EnumeratorRecord &enumerator) {
+ Declaration decl;
+ llvm::StringRef name = DropNameScope(enumerator.getName());
+
+ m_ast_builder.clang().AddEnumerationValueToEnumerationType(
+ m_derived_ct, decl, name.str().c_str(), enumerator.Value);
+ return Error::success();
+}
+
+void UdtRecordCompleter::complete() {
+ // Ensure the correct order for virtual bases.
+ llvm::stable_sort(m_bases, llvm::less_first());
+
+ std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
+ bases.reserve(m_bases.size());
+ for (auto &ib : m_bases)
+ bases.push_back(std::move(ib.second));
+
+ TypeSystemClang &clang = m_ast_builder.clang();
+ // Make sure all base classes refer to complete types and not forward
+ // declarations. If we don't do this, clang will crash with an
+ // assertion in the call to clang_type.TransferBaseClasses()
+ for (const auto &base_class : bases) {
+ clang::TypeSourceInfo *type_source_info =
+ base_class->getTypeSourceInfo();
+ if (type_source_info) {
+ TypeSystemClang::RequireCompleteType(
+ clang.GetType(type_source_info->getType()));
+ }
+ }
+
+ clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(bases));
+
+ clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
+ FinishRecord();
+ TypeSystemClang::BuildIndirectFields(m_derived_ct);
+ TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct);
+
+ if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
+ m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, m_layout);
+ }
+}
+
+uint64_t
+UdtRecordCompleter::AddMember(TypeSystemClang &clang, Member *field,
+ uint64_t bit_offset, CompilerType parent_ct,
+ ClangASTImporter::LayoutInfo &parent_layout,
+ clang::DeclContext *parent_decl_ctx) {
+ SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+ clang.GetSymbolFile()->GetBackingSymbolFile());
+ clang::FieldDecl *field_decl = nullptr;
+ uint64_t bit_size = 0;
+ switch (field->kind) {
+ case Member::Field: {
+ field_decl = TypeSystemClang::AddFieldToRecordType(
+ parent_ct, field->name, m_ast_builder.ToCompilerType(field->qt),
+ field->access, field->bitfield_width);
+ bit_size = field->bit_size;
+ break;
+ };
+ case Member::Struct:
+ case Member::Union: {
+ clang::TagTypeKind kind = field->kind == Member::Struct
+ ? clang::TagTypeKind::Struct
+ : clang::TagTypeKind::Union;
+ ClangASTMetadata metadata;
+ metadata.SetUserID(pdb->anonymous_id);
+ metadata.SetIsDynamicCXXType(false);
+ CompilerType record_ct = clang.CreateRecordType(
+ parent_decl_ctx, OptionalClangModuleID(), lldb::eAccessPublic, "",
+ llvm::to_underlying(kind), lldb::eLanguageTypeC_plus_plus, &metadata);
+ TypeSystemClang::StartTagDeclarationDefinition(record_ct);
+ ClangASTImporter::LayoutInfo layout;
+ clang::DeclContext *decl_ctx = clang.GetDeclContextForType(record_ct);
+ for (const auto &member : field->fields) {
+ uint64_t member_offset = field->kind == Member::Struct
+ ? member->bit_offset - field->base_offset
+ : 0;
+ uint64_t member_bit_size = AddMember(clang, member.get(), member_offset,
+ record_ct, layout, decl_ctx);
+ if (field->kind == Member::Struct)
+ bit_size = std::max(bit_size, member_offset + member_bit_size);
+ else
+ bit_size = std::max(bit_size, member_bit_size);
+ }
+ layout.bit_size = bit_size;
+ TypeSystemClang::CompleteTagDeclarationDefinition(record_ct);
+ clang::RecordDecl *record_decl = clang.GetAsRecordDecl(record_ct);
+ m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, layout);
+ field_decl = TypeSystemClang::AddFieldToRecordType(
+ parent_ct, "", record_ct, lldb::eAccessPublic, 0);
+ // Mark this record decl as completed.
+ DeclStatus status;
+ status.resolved = true;
+ status.uid = pdb->anonymous_id--;
+ m_decl_to_status.insert({record_decl, status});
+ break;
+ };
+ }
+ // FIXME: Add a PdbSymUid namespace for field list members and update
+ // the m_uid_to_decl map with this decl.
+ parent_layout.field_offsets.insert({field_decl, bit_offset});
+ return bit_size;
+}
+
+void UdtRecordCompleter::FinishRecord() {
+ TypeSystemClang &clang = m_ast_builder.clang();
+ clang::DeclContext *decl_ctx =
+ m_ast_builder.GetOrCreateDeclContextForUid(m_id);
+ m_record.ConstructRecord();
+ // Maybe we should check the construsted record size with the size in pdb. If
+ // they mismatch, it might be pdb has fields info missing.
+ for (const auto &field : m_record.record.fields) {
+ AddMember(clang, field.get(), field->bit_offset, m_derived_ct, m_layout,
+ decl_ctx);
+ }
+}
+
+void UdtRecordCompleter::Record::CollectMember(
+ llvm::StringRef name, uint64_t offset, uint64_t field_size,
+ clang::QualType qt, lldb::AccessType access, uint64_t bitfield_width) {
+ fields_map[offset].push_back(std::make_unique<Member>(
+ name, offset, field_size, qt, access, bitfield_width));
+ if (start_offset > offset)
+ start_offset = offset;
+}
+
+void UdtRecordCompleter::Record::ConstructRecord() {
+ // For anonymous unions in a struct, msvc generated pdb doesn't have the
+ // entity for that union. So, we need to construct anonymous union and struct
+ // based on field offsets. The final AST is likely not matching the exact
+ // original AST, but the memory layout is preseved.
+ // After we collecting all fields in visitKnownMember, we have all fields in
+ // increasing offset order in m_fields. Since we are iterating in increase
+ // offset order, if the current offset is equal to m_start_offset, we insert
+ // it as direct field of top level record. If the current offset is greater
+ // than m_start_offset, we should be able to find a field in end_offset_map
+ // whose end offset is less than or equal to current offset. (if not, it might
+ // be missing field info. We will ignore the field in this case. e.g. Field A
+ // starts at 0 with size 4 bytes, and Field B starts at 2 with size 4 bytes.
+ // Normally, there must be something which ends at/before 2.) Then we will
+ // append current field to the end of parent record. If parent is struct, we
+ // can just grow it. If parent is a field, it's a field inside an union. We
+ // convert it into an anonymous struct containing old field and new field.
+
+ // The end offset to a vector of field/struct that ends at the offset.
+ std::map<uint64_t, std::vector<Member *>> end_offset_map;
+ for (auto &pair : fields_map) {
+ uint64_t offset = pair.first;
+ auto &fields = pair.second;
+ lldbassert(offset >= start_offset);
+ Member *parent = &record;
+ if (offset > start_offset) {
+ // Find the field with largest end offset that is <= offset. If it's less
+ // than offset, it indicates there are padding bytes between end offset
+ // and offset.
+ lldbassert(!end_offset_map.empty());
+ auto iter = end_offset_map.lower_bound(offset);
+ if (iter == end_offset_map.end())
+ --iter;
+ else if (iter->first > offset) {
+ if (iter == end_offset_map.begin())
+ continue;
+ --iter;
+ }
+ if (iter->second.empty())
+ continue;
+ parent = iter->second.back();
+ iter->second.pop_back();
+ }
+ // If it's a field, then the field is inside a union, so we can safely
+ // increase its size by converting it to a struct to hold multiple fields.
+ if (parent->kind == Member::Field)
+ parent->ConvertToStruct();
+
+ if (fields.size() == 1) {
+ uint64_t end_offset = offset + fields.back()->bit_size;
+ parent->fields.push_back(std::move(fields.back()));
+ if (parent->kind == Member::Struct) {
+ end_offset_map[end_offset].push_back(parent);
+ } else {
+ lldbassert(parent == &record &&
+ "If parent is union, it must be the top level record.");
+ end_offset_map[end_offset].push_back(parent->fields.back().get());
+ }
+ } else {
+ if (parent->kind == Member::Struct) {
+ parent->fields.push_back(std::make_unique<Member>(Member::Union));
+ parent = parent->fields.back().get();
+ parent->bit_offset = offset;
+ } else {
+ lldbassert(parent == &record &&
+ "If parent is union, it must be the top level record.");
+ }
+ for (auto &field : fields) {
+ int64_t bit_size = field->bit_size;
+ parent->fields.push_back(std::move(field));
+ end_offset_map[offset + bit_size].push_back(
+ parent->fields.back().get());
+ }
+ }
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
new file mode 100644
index 000000000000..e6e91d0f2c3e
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -0,0 +1,146 @@
+//===-- UdtRecordCompleter.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+
+#include "PdbAstBuilder.h"
+#include "PdbSymUid.h"
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include <optional>
+
+namespace clang {
+class CXXBaseSpecifier;
+class QualType;
+class TagDecl;
+} // namespace clang
+
+namespace llvm {
+namespace pdb {
+class TpiStream;
+class GlobalsStream;
+}
+} // namespace llvm
+
+namespace lldb_private {
+class Type;
+class CompilerType;
+namespace npdb {
+class PdbAstBuilder;
+class PdbIndex;
+
+class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
+ using IndexedBase =
+ std::pair<uint64_t, std::unique_ptr<clang::CXXBaseSpecifier>>;
+
+ union UdtTagRecord {
+ UdtTagRecord() {}
+ llvm::codeview::UnionRecord ur;
+ llvm::codeview::ClassRecord cr;
+ llvm::codeview::EnumRecord er;
+ } m_cvr;
+
+ PdbTypeSymId m_id;
+ CompilerType &m_derived_ct;
+ clang::TagDecl &m_tag_decl;
+ PdbAstBuilder &m_ast_builder;
+ PdbIndex &m_index;
+ std::vector<IndexedBase> m_bases;
+ ClangASTImporter::LayoutInfo m_layout;
+ llvm::DenseMap<clang::Decl *, DeclStatus> &m_decl_to_status;
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &m_cxx_record_map;
+
+public:
+ UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<clang::Decl *, DeclStatus> &decl_to_status,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>,
+ 8>> &cxx_record_map);
+
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
+ llvm::codeview::Name##Record &Record) override;
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+ struct Member;
+ using MemberUP = std::unique_ptr<Member>;
+
+ struct Member {
+ enum Kind { Field, Struct, Union } kind;
+ // Following are only used for field.
+ llvm::StringRef name;
+ uint64_t bit_offset;
+ uint64_t bit_size;
+ clang::QualType qt;
+ lldb::AccessType access;
+ uint32_t bitfield_width;
+ // Following are Only used for struct or union.
+ uint64_t base_offset;
+ llvm::SmallVector<MemberUP, 1> fields;
+
+ Member() = default;
+ Member(Kind kind)
+ : kind(kind), name(), bit_offset(0), bit_size(0), qt(),
+ access(lldb::eAccessPublic), bitfield_width(0), base_offset(0) {}
+ Member(llvm::StringRef name, uint64_t bit_offset, uint64_t bit_size,
+ clang::QualType qt, lldb::AccessType access, uint32_t bitfield_width)
+ : kind(Field), name(name), bit_offset(bit_offset), bit_size(bit_size),
+ qt(qt), access(access), bitfield_width(bitfield_width),
+ base_offset(0) {}
+ void ConvertToStruct() {
+ kind = Struct;
+ base_offset = bit_offset;
+ fields.push_back(std::make_unique<Member>(name, bit_offset, bit_size, qt,
+ access, bitfield_width));
+ name = llvm::StringRef();
+ qt = clang::QualType();
+ access = lldb::eAccessPublic;
+ bit_offset = bit_size = bitfield_width = 0;
+ }
+ };
+
+ struct Record {
+ // Top level record.
+ Member record;
+ uint64_t start_offset = UINT64_MAX;
+ std::map<uint64_t, llvm::SmallVector<MemberUP, 1>> fields_map;
+ void CollectMember(llvm::StringRef name, uint64_t offset,
+ uint64_t field_size, clang::QualType qt,
+ lldb::AccessType access, uint64_t bitfield_width);
+ void ConstructRecord();
+ };
+ void complete();
+
+private:
+ Record m_record;
+ clang::QualType AddBaseClassForTypeIndex(
+ llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access,
+ std::optional<uint64_t> vtable_idx = std::optional<uint64_t>());
+ void AddMethod(llvm::StringRef name, llvm::codeview::TypeIndex type_idx,
+ llvm::codeview::MemberAccess access,
+ llvm::codeview::MethodOptions options,
+ llvm::codeview::MemberAttributes attrs);
+ void FinishRecord();
+ uint64_t AddMember(TypeSystemClang &clang, Member *field, uint64_t bit_offset,
+ CompilerType parent_ct,
+ ClangASTImporter::LayoutInfo &parent_layout,
+ clang::DeclContext *decl_ctx);
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H