Author: gclayton Date: Mon May 21 07:14:36 2018 New Revision: 332842 URL: http://llvm.org/viewvc/llvm-project?rev=332842&view=rev Log: Fix PathMappingList for relative and empty paths after recent FileSpec normalization changes
PathMappingList was broken for relative and empty paths after normalization changes in FileSpec. There were also no tests for PathMappingList so I added those. Changes include: Change PathMappingList::ReverseRemapPath() to take FileSpec objects instead of ConstString. The only client of this was doing work to convert to and from ConstString objects for no reason. Normalize all paths prefix and replacements that are added to the PathMappingList vector so they match the paths that have been already normalized in the debug info Unify code in the two forms of PathMappingList::RemapPath() so only one contains the actual functionality. Prior to this, there were two versions of this code. Use FileSpec::AppendPathComponent() and remove a long standing TODO so paths are correctly appended to each other. Added tests for absolute, relative and empty paths. Differential Revision: https://reviews.llvm.org/D47021 Added: lldb/trunk/unittests/Target/PathMappingListTest.cpp Modified: lldb/trunk/include/lldb/Target/PathMappingList.h lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/source/Target/PathMappingList.cpp lldb/trunk/source/Target/Target.cpp lldb/trunk/source/Utility/FileSpec.cpp lldb/trunk/unittests/Target/CMakeLists.txt lldb/trunk/unittests/Utility/FileSpecTest.cpp Modified: lldb/trunk/include/lldb/Target/PathMappingList.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/PathMappingList.h?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/PathMappingList.h (original) +++ lldb/trunk/include/lldb/Target/PathMappingList.h Mon May 21 07:14:36 2018 @@ -90,7 +90,7 @@ public: bool RemapPath(llvm::StringRef path, std::string &new_path) const; bool RemapPath(const char *, std::string &) const = delete; - bool ReverseRemapPath(const ConstString &path, ConstString &new_path) const; + bool ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const; //------------------------------------------------------------------ /// Finds a source file given a file spec using the path remappings. Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon May 21 07:14:36 2018 @@ -267,6 +267,7 @@ 26680336116005EF008E1FE4 /* SBBreakpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */; }; 26680337116005F1008E1FE4 /* SBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */; }; 2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; }; + 2668A2EE20AF417D00D94111 /* PathMappingListTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2668A2ED20AF417D00D94111 /* PathMappingListTest.cpp */; }; 266942001A6DC2AC0063BE93 /* MICmdArgContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266941601A6DC2AB0063BE93 /* MICmdArgContext.cpp */; }; 266942011A6DC2AC0063BE93 /* MICmdArgSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266941621A6DC2AB0063BE93 /* MICmdArgSet.cpp */; }; 266942021A6DC2AC0063BE93 /* MICmdArgValBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266941641A6DC2AB0063BE93 /* MICmdArgValBase.cpp */; }; @@ -1755,6 +1756,7 @@ 2666ADC31B3CB675001FAFD3 /* HexagonDYLDRendezvous.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HexagonDYLDRendezvous.cpp; sourceTree = "<group>"; }; 2666ADC41B3CB675001FAFD3 /* HexagonDYLDRendezvous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexagonDYLDRendezvous.h; sourceTree = "<group>"; }; 26680207115FD0ED008E1FE4 /* LLDB.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLDB.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2668A2ED20AF417D00D94111 /* PathMappingListTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PathMappingListTest.cpp; path = Target/PathMappingListTest.cpp; sourceTree = "<group>"; }; 2669415B1A6DC2AB0063BE93 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = "tools/lldb-mi/CMakeLists.txt"; sourceTree = SOURCE_ROOT; }; 2669415E1A6DC2AB0063BE93 /* lldb-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "lldb-Info.plist"; path = "tools/lldb-mi/lldb-Info.plist"; sourceTree = SOURCE_ROOT; }; 2669415F1A6DC2AB0063BE93 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = "tools/lldb-mi/Makefile"; sourceTree = SOURCE_ROOT; }; @@ -6709,6 +6711,7 @@ children = ( 9A2057061F3B818600F6C293 /* MemoryRegionInfoTest.cpp */, AFAFD8091E57E1B90017A14F /* ModuleCacheTest.cpp */, + 2668A2ED20AF417D00D94111 /* PathMappingListTest.cpp */, ); name = Target; sourceTree = "<group>"; @@ -7351,6 +7354,7 @@ 23CB15341D66DA9300EDDDE1 /* CPlusPlusLanguageTest.cpp in Sources */, 9A2057381F3B8E7E00F6C293 /* FileSystemTest.cpp in Sources */, 9A2057201F3B8D2500F6C293 /* UnixSignalsTest.cpp in Sources */, + 2668A2EE20AF417D00D94111 /* PathMappingListTest.cpp in Sources */, AFAFD80A1E57E1B90017A14F /* ModuleCacheTest.cpp in Sources */, 9A3D43DA1F3151C400EB767C /* StructuredDataTest.cpp in Sources */, 9A2057121F3B824B00F6C293 /* SymbolFileDWARFTests.cpp in Sources */, Modified: lldb/trunk/source/Target/PathMappingList.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/PathMappingList.cpp?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/source/Target/PathMappingList.cpp (original) +++ lldb/trunk/source/Target/PathMappingList.cpp Mon May 21 07:14:36 2018 @@ -14,6 +14,7 @@ // Other libraries and framework includes // Project includes +#include "lldb/lldb-private-enumerations.h" #include "lldb/Host/PosixApi.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Utility/FileSpec.h" @@ -23,6 +24,22 @@ using namespace lldb; using namespace lldb_private; +namespace { + // We must normalize our path pairs that we store because if we don't then + // things won't always work. We found a case where if we did: + // (lldb) settings set target.source-map . /tmp + // We would store a path pairs of "." and "/tmp" as raw strings. If the debug + // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c". + // When PathMappingList::RemapPath() is called, it expects the path to start + // with the raw path pair, which doesn't work anymore because the paths have + // been normalized when the debug info was loaded. So we need to store + // nomalized path pairs to ensure things match up. + ConstString NormalizePath(const ConstString &path) { + // If we use "path" to construct a FileSpec, it will normalize the path for + // us. We then grab the string and turn it back into a ConstString. + return ConstString(FileSpec(path.GetStringRef(), false).GetPath()); + } +} //---------------------------------------------------------------------- // PathMappingList constructor //---------------------------------------------------------------------- @@ -52,7 +69,7 @@ PathMappingList::~PathMappingList() = de void PathMappingList::Append(const ConstString &path, const ConstString &replacement, bool notify) { ++m_mod_id; - m_pairs.push_back(pair(path, replacement)); + m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); if (notify && m_callback) m_callback(*this, m_callback_baton); } @@ -77,7 +94,8 @@ void PathMappingList::Insert(const Const insert_iter = m_pairs.end(); else insert_iter = m_pairs.begin() + index; - m_pairs.insert(insert_iter, pair(path, replacement)); + m_pairs.emplace(insert_iter, pair(NormalizePath(path), + NormalizePath(replacement))); if (notify && m_callback) m_callback(*this, m_callback_baton); } @@ -88,7 +106,7 @@ bool PathMappingList::Replace(const Cons if (index >= m_pairs.size()) return false; ++m_mod_id; - m_pairs[index] = pair(path, replacement); + m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement)); if (notify && m_callback) m_callback(*this, m_callback_baton); return true; @@ -134,22 +152,10 @@ void PathMappingList::Clear(bool notify) bool PathMappingList::RemapPath(const ConstString &path, ConstString &new_path) const { - const char *path_cstr = path.GetCString(); - // CLEANUP: Convert this function to use StringRefs internally instead - // of raw c-strings. - if (!path_cstr) - return false; - - const_iterator pos, end = m_pairs.end(); - for (pos = m_pairs.begin(); pos != end; ++pos) { - const size_t prefixLen = pos->first.GetLength(); - - if (::strncmp(pos->first.GetCString(), path_cstr, prefixLen) == 0) { - std::string new_path_str(pos->second.GetCString()); - new_path_str.append(path.GetCString() + prefixLen); - new_path.SetCString(new_path_str.c_str()); - return true; - } + std::string remapped; + if (RemapPath(path.GetStringRef(), remapped)) { + new_path.SetString(remapped); + return true; } return false; } @@ -158,34 +164,41 @@ bool PathMappingList::RemapPath(llvm::St std::string &new_path) const { if (m_pairs.empty() || path.empty()) return false; - - const_iterator pos, end = m_pairs.end(); - for (pos = m_pairs.begin(); pos != end; ++pos) { - if (!path.consume_front(pos->first.GetStringRef())) - continue; - - new_path = pos->second.GetStringRef(); - new_path.append(path); + LazyBool path_is_relative = eLazyBoolCalculate; + for (const auto &it : m_pairs) { + auto prefix = it.first.GetStringRef(); + if (!path.consume_front(prefix)) { + // Relative paths won't have a leading "./" in them unless "." is the + // only thing in the relative path so we need to work around "." + // carefully. + if (prefix != ".") + continue; + // We need to figure out if the "path" argument is relative. If it is, + // then we should remap, else skip this entry. + if (path_is_relative == eLazyBoolCalculate) { + path_is_relative = FileSpec(path, false).IsRelative() ? eLazyBoolYes : + eLazyBoolNo; + } + if (!path_is_relative) + continue; + } + FileSpec remapped(it.second.GetStringRef(), false); + remapped.AppendPathComponent(path); + new_path = remapped.GetPath(); return true; } return false; } -bool PathMappingList::ReverseRemapPath(const ConstString &path, - ConstString &new_path) const { - const char *path_cstr = path.GetCString(); - if (!path_cstr) - return false; - +bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { + std::string path = file.GetPath(); + llvm::StringRef path_ref(path); for (const auto &it : m_pairs) { - // FIXME: This should be using FileSpec API's to do the path appending. - const size_t prefixLen = it.second.GetLength(); - if (::strncmp(it.second.GetCString(), path_cstr, prefixLen) == 0) { - std::string new_path_str(it.first.GetCString()); - new_path_str.append(path.GetCString() + prefixLen); - new_path.SetCString(new_path_str.c_str()); - return true; - } + if (!path_ref.consume_front(it.second.GetStringRef())) + continue; + fixed.SetFile(it.first.GetStringRef(), false); + fixed.AppendPathComponent(path_ref); + return true; } return false; } @@ -277,7 +290,8 @@ bool PathMappingList::GetPathsAtIndex(ui return false; } -uint32_t PathMappingList::FindIndexForPath(const ConstString &path) const { +uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const { + const ConstString path = NormalizePath(orig_path); const_iterator pos; const_iterator begin = m_pairs.begin(); const_iterator end = m_pairs.end(); Modified: lldb/trunk/source/Target/Target.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/source/Target/Target.cpp (original) +++ lldb/trunk/source/Target/Target.cpp Mon May 21 07:14:36 2018 @@ -328,11 +328,7 @@ BreakpointSP Target::CreateBreakpoint(co bool hardware, LazyBool move_to_nearest_code) { FileSpec remapped_file; - ConstString remapped_path; - if (GetSourcePathMap().ReverseRemapPath(ConstString(file.GetPath().c_str()), - remapped_path)) - remapped_file.SetFile(remapped_path.AsCString(), false); - else + if (!GetSourcePathMap().ReverseRemapPath(file, remapped_file)) remapped_file = file; if (check_inlines == eLazyBoolCalculate) { Modified: lldb/trunk/source/Utility/FileSpec.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/FileSpec.cpp?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/source/Utility/FileSpec.cpp (original) +++ lldb/trunk/source/Utility/FileSpec.cpp Mon May 21 07:14:36 2018 @@ -67,6 +67,31 @@ void Denormalize(llvm::SmallVectorImpl<c std::replace(path.begin(), path.end(), '/', '\\'); } + +bool PathIsRelative(llvm::StringRef path, FileSpec::Style style) { + + if (path.empty()) + return false; + + if (PathStyleIsPosix(style)) { + // If the path doesn't start with '/' or '~', return true + switch (path[0]) { + case '/': + case '~': + return false; + default: + return true; + } + } else { + if (path.size() >= 2 && path[1] == ':') + return false; + if (path[0] == '/') + return false; + return true; + } + return false; +} + } // end anonymous namespace void FileSpec::Resolve(llvm::SmallVectorImpl<char> &path) { @@ -814,31 +839,10 @@ bool FileSpec::IsSourceImplementationFil } bool FileSpec::IsRelative() const { - const char *dir = m_directory.GetCString(); - llvm::StringRef directory(dir ? dir : ""); - - if (directory.size() > 0) { - if (PathStyleIsPosix(m_style)) { - // If the path doesn't start with '/' or '~', return true - switch (directory[0]) { - case '/': - case '~': - return false; - default: - return true; - } - } else { - if (directory.size() >= 2 && directory[1] == ':') - return false; - if (directory[0] == '/') - return false; - return true; - } - } else if (m_filename) { - // No directory, just a basename, return true - return true; - } - return false; + if (m_directory) + return PathIsRelative(m_directory.GetStringRef(), m_style); + else + return PathIsRelative(m_filename.GetStringRef(), m_style); } bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); } Modified: lldb/trunk/unittests/Target/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Target/CMakeLists.txt?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/unittests/Target/CMakeLists.txt (original) +++ lldb/trunk/unittests/Target/CMakeLists.txt Mon May 21 07:14:36 2018 @@ -1,6 +1,7 @@ add_lldb_unittest(TargetTests MemoryRegionInfoTest.cpp ModuleCacheTest.cpp + PathMappingListTest.cpp LINK_LIBS lldbCore Added: lldb/trunk/unittests/Target/PathMappingListTest.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Target/PathMappingListTest.cpp?rev=332842&view=auto ============================================================================== --- lldb/trunk/unittests/Target/PathMappingListTest.cpp (added) +++ lldb/trunk/unittests/Target/PathMappingListTest.cpp Mon May 21 07:14:36 2018 @@ -0,0 +1,109 @@ +//===-- PathMappingListTest.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "lldb/Target/PathMappingList.h" +#include "lldb/Utility/FileSpec.h" +#include "gtest/gtest.h" +#include <utility> + +using namespace lldb_private; + +namespace { + struct Matches { + ConstString original; + ConstString remapped; + Matches(const char *o, const char *r) : original(o), + remapped(r) {} + }; + + void TestPathMappings(const PathMappingList &map, + llvm::ArrayRef<Matches> matches, + llvm::ArrayRef<ConstString> fails) { + ConstString actual_remapped; + for (const auto &fail: fails) { + EXPECT_FALSE(map.RemapPath(fail, actual_remapped)); + } + for (const auto &match: matches) { + FileSpec orig_spec(match.original.GetStringRef(), false); + std::string orig_normalized = orig_spec.GetPath(); + EXPECT_TRUE(map.RemapPath(match.original, actual_remapped)); + EXPECT_EQ(actual_remapped, match.remapped); + FileSpec remapped_spec(match.remapped.GetStringRef(), false); + FileSpec unmapped_spec; + EXPECT_TRUE(map.ReverseRemapPath(remapped_spec, unmapped_spec)); + std::string unmapped_path = unmapped_spec.GetPath(); + EXPECT_EQ(unmapped_path, orig_normalized); + } + } +} + +TEST(PathMappingListTest, RelativeTests) { + Matches matches[] = { + {".", "/tmp"}, + {"./", "/tmp"}, + {"./////", "/tmp"}, + {"./foo.c", "/tmp/foo.c"}, + {"foo.c", "/tmp/foo.c"}, + {"./bar/foo.c", "/tmp/bar/foo.c"}, + {"bar/foo.c", "/tmp/bar/foo.c"}, + }; + ConstString fails[] = { + ConstString("/a"), + ConstString("/"), + }; + PathMappingList map; + map.Append(ConstString("."), ConstString("/tmp"), false); + TestPathMappings(map, matches, fails); + PathMappingList map2; + map2.Append(ConstString(""), ConstString("/tmp"), false); + TestPathMappings(map, matches, fails); +} + +TEST(PathMappingListTest, AbsoluteTests) { + PathMappingList map; + map.Append(ConstString("/old"), ConstString("/new"), false); + Matches matches[] = { + {"/old", "/new"}, + {"/old/", "/new"}, + {"/old/foo/.", "/new/foo"}, + {"/old/foo.c", "/new/foo.c"}, + {"/old/foo.c/.", "/new/foo.c"}, + {"/old/./foo.c", "/new/foo.c"}, + }; + ConstString fails[] = { + ConstString("/foo"), + ConstString("/"), + ConstString("foo.c"), + ConstString("./foo.c"), + ConstString("../foo.c"), + ConstString("../bar/foo.c"), + }; + TestPathMappings(map, matches, fails); +} + +TEST(PathMappingListTest, RemapRoot) { + PathMappingList map; + map.Append(ConstString("/"), ConstString("/new"), false); + Matches matches[] = { + {"/old", "/new/old"}, + {"/old/", "/new/old"}, + {"/old/foo/.", "/new/old/foo"}, + {"/old/foo.c", "/new/old/foo.c"}, + {"/old/foo.c/.", "/new/old/foo.c"}, + {"/old/./foo.c", "/new/old/foo.c"}, + }; + ConstString fails[] = { + ConstString("foo.c"), + ConstString("./foo.c"), + ConstString("../foo.c"), + ConstString("../bar/foo.c"), + }; + TestPathMappings(map, matches, fails); +} Modified: lldb/trunk/unittests/Utility/FileSpecTest.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Utility/FileSpecTest.cpp?rev=332842&r1=332841&r2=332842&view=diff ============================================================================== --- lldb/trunk/unittests/Utility/FileSpecTest.cpp (original) +++ lldb/trunk/unittests/Utility/FileSpecTest.cpp Mon May 21 07:14:36 2018 @@ -273,3 +273,50 @@ TEST(FileSpecTest, FormatFileSpec) { EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str()); } +TEST(FileSpecTest, IsRelative) { + llvm::StringRef not_relative[] = { + "/", + "/a", + "/a/", + "/a/b", + "/a/b/", + "//", + "//a", + "//a/", + "//a/b", + "//a/b/", + "~", + "~/", + "~/a", + "~/a/", + "~/a/b" + "~/a/b/", + "/foo/.", + "/foo/..", + "/foo/../", + "/foo/../.", + }; + for (const auto &path: not_relative) { + FileSpec spec(path, false, FileSpec::Style::posix); + EXPECT_FALSE(spec.IsRelative()); + } + llvm::StringRef is_relative[] = { + ".", + "./", + ".///", + "a", + "./a", + "./a/", + "./a/", + "./a/b", + "./a/b/", + "../foo", + "foo/bar.c", + "./foo/bar.c" + }; + for (const auto &path: is_relative) { + FileSpec spec(path, false, FileSpec::Style::posix); + EXPECT_TRUE(spec.IsRelative()); + } +} + _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits