Skip to content

Conversation

@Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Sep 17, 2025

When creating LLDB types from LF_MODIFIER records, the type name of the modified type was used. This didn't include the modifiers (const/volatile/__unaligned). With this PR, they're included.

The DIA plugin had a test for this. That test also assumed that function types had a name. I removed that check here, because function/procedure types themselves in PDB don't have a name:

  0x1015 | LF_ARGLIST [size = 20, hash = 0xBCB6]
           0x0074 (int): `int`
           0x1013: `int* __restrict`
           0x1014: `int& __restrict`
  0x1016 | LF_PROCEDURE [size = 16, hash = 0x3F611]
           return type = 0x0003 (void), # args = 3, param list = 0x1015
           calling conv = cdecl, options = None

I assume DIA gets the name from the function symbol itself. In the native plugin, that name isn't included and multiple functions with the same signature will reuse one type, whereas DIA would create a new type for each function. The Shell/SymbolFile/PDB/func-symbols.test also relies on this.

@llvmbot
Copy link
Member

llvmbot commented Sep 17, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

When creating LLDB types from LF_MODIFIER records, the type name of the modified type was used. This didn't include the modifiers (const/volatile/__unaligned). With this PR, they're included.

The DIA plugin had a test for this. That test also assumed that function types had a name. I removed that check here, because function/procedure types themselves in PDB don't have a name:

  0x1015 | LF_ARGLIST [size = 20, hash = 0xBCB6]
           0x0074 (int): `int`
           0x1013: `int* __restrict`
           0x1014: `int& __restrict`
  0x1016 | LF_PROCEDURE [size = 16, hash = 0x3F611]
           return type = 0x0003 (void), # args = 3, param list = 0x1015
           calling conv = cdecl, options = None

I assume DIA gets the name from the function symbol itself. In the native plugin, that name isn't included and multiple functions with the same signature will reuse one type, whereas DIA would create a new type for each function. The Shell/SymbolFile/PDB/func-symbols.test also relies on this.


Full diff: https://github.com/llvm/llvm-project/pull/159296.diff

2 Files Affected:

  • (modified) lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (+10-2)
  • (modified) lldb/test/Shell/SymbolFile/PDB/type-quals.test (+10-8)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index cfecda4817976..f081965a76183 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -549,10 +549,18 @@ lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id,
   TpiStream &stream = m_index->tpi();
 
   std::string name;
+
+  if ((mr.Modifiers & ModifierOptions::Const) != ModifierOptions::None)
+    name += "const ";
+  if ((mr.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None)
+    name += "volatile ";
+  if ((mr.Modifiers & ModifierOptions::Unaligned) != ModifierOptions::None)
+    name += "__unaligned ";
+
   if (mr.ModifiedType.isSimple())
-    name = std::string(GetSimpleTypeName(mr.ModifiedType.getSimpleKind()));
+    name += GetSimpleTypeName(mr.ModifiedType.getSimpleKind());
   else
-    name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+    name += computeTypeName(stream.typeCollection(), mr.ModifiedType);
   Declaration decl;
   lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType);
 
diff --git a/lldb/test/Shell/SymbolFile/PDB/type-quals.test b/lldb/test/Shell/SymbolFile/PDB/type-quals.test
index e0d79ac0b7529..370c0a21b093a 100644
--- a/lldb/test/Shell/SymbolFile/PDB/type-quals.test
+++ b/lldb/test/Shell/SymbolFile/PDB/type-quals.test
@@ -2,35 +2,37 @@ REQUIRES: target-windows, msvc
 RUN: mkdir -p %t.dir
 RUN: %build --compiler=clang-cl --mode=compile --arch=32 --nodefaultlib --output=%t.dir/TypeQualsTest.cpp.obj %S/Inputs/TypeQualsTest.cpp
 RUN: %build --compiler=msvc --mode=link --arch=32 --nodefaultlib --output=%t.dir/TypeQualsTest.cpp.exe %t.dir/TypeQualsTest.cpp.obj
-RUN: lldb-test symbols %t.dir/TypeQualsTest.cpp.exe | FileCheck %s
+RUN: env LLDB_USE_NATIVE_PDB_READER=0 lldb-test symbols %t.dir/TypeQualsTest.cpp.exe | FileCheck %s
+RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols %t.dir/TypeQualsTest.cpp.exe | FileCheck %s
 
 CHECK: Module [[MOD:.*]]
-CHECK-DAG: SymbolFile pdb ([[MOD]])
+CHECK-DAG: SymbolFile {{(native-)?}}pdb ([[MOD]])
 CHECK-DAG:      Type{{.*}} , name = "const int", size = 4, compiler_type = {{.*}} const int
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} const int *
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} const int **const
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} const int *const
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} const int *const *
-CHECK-DAG:      Type{{.*}} , name = "Func1", {{.*}}, compiler_type = {{.*}} void (const int *, const int *, const int **const, const int *const *)
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (const int *, const int *, const int **const, const int *const *)
 
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} volatile int *
-CHECK-DAG:      Type{{.*}} , name = "Func2", {{.*}}, compiler_type = {{.*}} void (volatile int *, volatile int *)
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (volatile int *, volatile int *)
 
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int *
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int *&
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int &&
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int &
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} const int &
-CHECK-DAG:      Type{{.*}} , name = "Func3", {{.*}}, compiler_type = {{.*}} void (int *&, int &, const int &, int &&)
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (int *&, int &, const int &, int &&)
 
 // FIXME: __unaligned is not supported.
-CHECK-DAG:      Type{{.*}} , name = "Func4", {{.*}}, compiler_type = {{.*}} void (int *, int *)
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (int *, int *)
 
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int *__restrict
 CHECK-DAG:      Type{{.*}} , size = 4, compiler_type = {{.*}} int &__restrict
-CHECK-DAG:      Type{{.*}} , name = "Func5", {{.*}}, compiler_type = {{.*}} void (int, int *__restrict, int &__restrict)
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (int, int *__restrict, int &__restrict)
 
-CHECK-DAG:      Type{{.*}} , name = "Func6", {{.*}}, compiler_type = {{.*}} void (const volatile int *__restrict)
+CHECK-DAG:      Type{{.*}} , name = "{{volatile const|const volatile}} int", size = 4, compiler_type = {{.*}} {{volatile const|const volatile}} int
+CHECK-DAG:      Type{{.*}} , {{.*}}, compiler_type = {{.*}} void (const volatile int *__restrict)
 
 CHECK-DAG:      Type{{.*}} , size = 400, compiler_type = {{.*}} volatile int *[100]
 CHECK-DAG:      Type{{.*}} , size = 4000, compiler_type = {{.*}} volatile int *[10][100]

@Nerixyz Nerixyz merged commit 4625c8f into llvm:main Sep 18, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants