llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: nerix (Nerixyz) <details> <summary>Changes</summary> Similar to DWARF's DWO, we should look for PDBs in `target.debug-file-search-paths` if the PDB isn't at the original location or next to the executable. With this PR, the search order is as follows: 1. PDB path specified in the PE/COFF file 2. Next to the executable 3. In `target.debug-file-search-paths` This roughly matches [the order Visual Studio uses](https://learn.microsoft.com/en-us/visualstudio/debugger/specify-symbol-dot-pdb-and-source-files-in-the-visual-studio-debugger?view=vs-2022#where-the-debugger-looks-for-symbols), 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: - (modified) lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (+43-9) - (added) lldb/test/Shell/SymbolFile/NativePDB/find-pdb-next-to-exe.test (+81) ``````````diff 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 `````````` </details> https://github.com/llvm/llvm-project/pull/169719 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
