-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[LLDB][NativePDB] Look for PDBs in target.debug-file-search-paths
#169719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesSimilar to DWARF's DWO, we should look for PDBs in With this PR, the search order is as follows:
This roughly matches the order Visual Studio uses, except that we don't have a project folder and don't support symbol servers. Closes #125355 (though I think this is already fixed in the native plugin). Full diff: https://github.com/llvm/llvm-project/pull/169719.diff 2 Files Affected:
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index aaec1600dacff..4ee1b0759a10e 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -86,6 +86,40 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) {
}
}
+static std::optional<std::string>
+findMatchingPDBFilePath(llvm::StringRef original_pdb_path,
+ llvm::StringRef exe_path) {
+ const FileSystem &fs = FileSystem::Instance();
+
+ if (fs.Exists(original_pdb_path))
+ return std::string(original_pdb_path);
+
+ const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent();
+ // While the exe_path uses the native style, the exe might be compiled on a
+ // different OS, so try to guess the style used.
+ const FileSpec original_pdb_spec(original_pdb_path,
+ FileSpec::GuessPathStyle(original_pdb_path)
+ .value_or(FileSpec::Style::native));
+ const llvm::StringRef pdb_filename = original_pdb_spec.GetFilename();
+
+ // 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.
+ const FileSpec local_pdb = exe_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(local_pdb))
+ return local_pdb.GetPath();
+
+ // Otherwise, search for one in target.debug-file-search-paths
+ FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+ for (const FileSpec &search_dir : search_paths) {
+ FileSpec pdb_path = search_dir.CopyByAppendingPathComponent(pdb_filename);
+ if (fs.Exists(pdb_path))
+ return pdb_path.GetPath();
+ }
+
+ return std::nullopt;
+}
+
static std::unique_ptr<PDBFile>
loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
// Try to find a matching PDB for an EXE.
@@ -113,17 +147,14 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
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();
- }
+ std::optional<std::string> resolved_pdb_path =
+ findMatchingPDBFilePath(pdb_file, exe_path);
+ if (!resolved_pdb_path)
+ return nullptr;
// 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);
+ auto pdb =
+ ObjectFilePDB::loadPDBFile(*std::move(resolved_pdb_path), allocator);
if (!pdb)
return nullptr;
@@ -137,6 +168,9 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
if (expected_info->getGuid() != guid)
return nullptr;
+
+ LLDB_LOG(GetLog(LLDBLog::Symbols), "Loading {0} for {1}", pdb->getFilePath(),
+ exe_path);
return pdb;
}
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test
new file mode 100644
index 0000000000000..9ca850b1fd5b6
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test
@@ -0,0 +1,81 @@
+# REQUIRES: lld, target-windows
+
+# Test where LLDB looks for PDBs.
+# RUN: split-file %s %t
+
+# RUN: mkdir -p %t/build
+# RUN: mkdir -p %t/dir1
+# RUN: mkdir -p %t/dir2
+# RUN: mkdir -p %t/dir3
+
+# RUN: echo "settings append target.debug-file-search-paths %t/dir2" >> %t/init.input
+# RUN: echo "settings append target.debug-file-search-paths %t/dir3" >> %t/init.input
+
+# RUN: %build --compiler=clang-cl --nodefaultlib --output=%t/build/a.exe %t/main.cpp
+
+# Regular setup - PDB is at the original path
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/build/a.exe > %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}build{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# Move the executable to a different directory but keep the PDB.
+# RUN: mv %t/build/a.exe %t/dir1
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe >> %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# Copy the PDB to the same directory and all search dirs. LLDB should prefer the original PDB.
+# RUN: cp %t/build/a.pdb %t/dir1
+# RUN: cp %t/build/a.pdb %t/dir2
+# RUN: cp %t/build/a.pdb %t/dir3
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe >> %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}build{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# Remove the original PDB. LLDB should now use the one next to the exe.
+# RUN: rm %t/build/a.pdb
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe >> %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}dir1{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# Remove the PDB next to the exe. LLDB should now use the one in dir2 (first in list).
+# RUN: rm %t/dir1/a.pdb
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe >> %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}dir2{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# Remove the PDB in dir2. LLDB should now use the one in dir3 (second in list).
+# RUN: rm %t/dir2/a.pdb
+# RUN: %lldb -S %t/init.input -s %t/check.input %t/dir1/a.exe >> %t.out.txt
+# CHECK: (lldb) target create
+# CHECK-NEXT: Loading {{.*[/\\]}}dir3{{[/\\]}}a.pdb for {{.*[/\\]}}dir1{{[/\\]}}a.exe
+# CHECK: (A) a = (x = 47)
+
+# RUN: cat %t.out.txt | FileCheck %s
+
+# Remove the last PDB in dir3. Now, there's no matching PDB anymore.
+# RUN: rm %t/dir3/a.pdb
+# RUN: %lldb -S %t/init.input -s %t/check.input -f %t/dir1/a.exe 2>&1 | FileCheck --check-prefix=NOPDB %s
+# NOPDB: error: can't find global variable 'a'
+
+#--- main.cpp
+
+struct A {
+ int x = 47;
+};
+A a;
+int main() {}
+
+#--- init.input
+
+log enable lldb symbol
+
+#--- check.input
+
+target variable a
+q
|
Similar to DWARF's DWO, we should look for PDBs in
target.debug-file-search-pathsif the PDB isn't at the original location or next to the executable.With this PR, the search order is as follows:
target.debug-file-search-pathsThis roughly matches the order Visual Studio uses, except that we don't have a project folder and don't support symbol servers.
Closes #125355 (though I think this is already fixed in the native plugin).