180814287SRaphael Isemann //===-- PathMappingList.cpp -----------------------------------------------===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 99394d772SEugene Zelenko #include <climits> 109394d772SEugene Zelenko #include <cstring> 119394d772SEugene Zelenko 12dbd7fabaSJonas Devlieghere #include "lldb/Host/FileSystem.h" 13f343968fSZachary Turner #include "lldb/Host/PosixApi.h" 1448862d45SEli Friedman #include "lldb/Target/PathMappingList.h" 155713a05bSZachary Turner #include "lldb/Utility/FileSpec.h" 1697206d57SZachary Turner #include "lldb/Utility/Status.h" 17bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 18dbd7fabaSJonas Devlieghere #include "lldb/lldb-private-enumerations.h" 1930fdc8d8SChris Lattner 2030fdc8d8SChris Lattner using namespace lldb; 2130fdc8d8SChris Lattner using namespace lldb_private; 2230fdc8d8SChris Lattner 2386188d8aSGreg Clayton namespace { 2486188d8aSGreg Clayton // We must normalize our path pairs that we store because if we don't then 2586188d8aSGreg Clayton // things won't always work. We found a case where if we did: 2686188d8aSGreg Clayton // (lldb) settings set target.source-map . /tmp 2786188d8aSGreg Clayton // We would store a path pairs of "." and "/tmp" as raw strings. If the debug 2886188d8aSGreg Clayton // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c". 2986188d8aSGreg Clayton // When PathMappingList::RemapPath() is called, it expects the path to start 3086188d8aSGreg Clayton // with the raw path pair, which doesn't work anymore because the paths have 3186188d8aSGreg Clayton // been normalized when the debug info was loaded. So we need to store 3286188d8aSGreg Clayton // nomalized path pairs to ensure things match up. 330e4c4821SAdrian Prantl ConstString NormalizePath(ConstString path) { 3486188d8aSGreg Clayton // If we use "path" to construct a FileSpec, it will normalize the path for 3586188d8aSGreg Clayton // us. We then grab the string and turn it back into a ConstString. 368f3be7a3SJonas Devlieghere return ConstString(FileSpec(path.GetStringRef()).GetPath()); 3786188d8aSGreg Clayton } 3886188d8aSGreg Clayton } 3930fdc8d8SChris Lattner // PathMappingList constructor 409494c510SJonas Devlieghere PathMappingList::PathMappingList() : m_pairs() {} 41d804d285SGreg Clayton 42b9c1b51eSKate Stone PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) 43b9c1b51eSKate Stone : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), 44b9c1b51eSKate Stone m_mod_id(0) {} 4530fdc8d8SChris Lattner 46b9c1b51eSKate Stone PathMappingList::PathMappingList(const PathMappingList &rhs) 47b9c1b51eSKate Stone : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), 48b9c1b51eSKate Stone m_mod_id(0) {} 497e14f91dSGreg Clayton 50b9c1b51eSKate Stone const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { 51b9c1b51eSKate Stone if (this != &rhs) { 527e14f91dSGreg Clayton m_pairs = rhs.m_pairs; 539394d772SEugene Zelenko m_callback = nullptr; 549394d772SEugene Zelenko m_callback_baton = nullptr; 554a89501fSGreg Clayton m_mod_id = rhs.m_mod_id; 567e14f91dSGreg Clayton } 577e14f91dSGreg Clayton return *this; 587e14f91dSGreg Clayton } 597e14f91dSGreg Clayton 609394d772SEugene Zelenko PathMappingList::~PathMappingList() = default; 6130fdc8d8SChris Lattner 620e4c4821SAdrian Prantl void PathMappingList::Append(ConstString path, 630e4c4821SAdrian Prantl ConstString replacement, bool notify) { 644a89501fSGreg Clayton ++m_mod_id; 6586188d8aSGreg Clayton m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); 6630fdc8d8SChris Lattner if (notify && m_callback) 6730fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 6830fdc8d8SChris Lattner } 6930fdc8d8SChris Lattner 70b9c1b51eSKate Stone void PathMappingList::Append(const PathMappingList &rhs, bool notify) { 714a89501fSGreg Clayton ++m_mod_id; 72b9c1b51eSKate Stone if (!rhs.m_pairs.empty()) { 73d804d285SGreg Clayton const_iterator pos, end = rhs.m_pairs.end(); 74d804d285SGreg Clayton for (pos = rhs.m_pairs.begin(); pos != end; ++pos) 75d804d285SGreg Clayton m_pairs.push_back(*pos); 76d804d285SGreg Clayton if (notify && m_callback) 77d804d285SGreg Clayton m_callback(*this, m_callback_baton); 78d804d285SGreg Clayton } 79d804d285SGreg Clayton } 80d804d285SGreg Clayton 810e4c4821SAdrian Prantl void PathMappingList::Insert(ConstString path, 820e4c4821SAdrian Prantl ConstString replacement, uint32_t index, 83b9c1b51eSKate Stone bool notify) { 844a89501fSGreg Clayton ++m_mod_id; 8530fdc8d8SChris Lattner iterator insert_iter; 8630fdc8d8SChris Lattner if (index >= m_pairs.size()) 8730fdc8d8SChris Lattner insert_iter = m_pairs.end(); 8830fdc8d8SChris Lattner else 8930fdc8d8SChris Lattner insert_iter = m_pairs.begin() + index; 9086188d8aSGreg Clayton m_pairs.emplace(insert_iter, pair(NormalizePath(path), 9186188d8aSGreg Clayton NormalizePath(replacement))); 9230fdc8d8SChris Lattner if (notify && m_callback) 9330fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 9430fdc8d8SChris Lattner } 9530fdc8d8SChris Lattner 960e4c4821SAdrian Prantl bool PathMappingList::Replace(ConstString path, 970e4c4821SAdrian Prantl ConstString replacement, uint32_t index, 98b9c1b51eSKate Stone bool notify) { 9967cc0636SGreg Clayton if (index >= m_pairs.size()) 10067cc0636SGreg Clayton return false; 1014a89501fSGreg Clayton ++m_mod_id; 10286188d8aSGreg Clayton m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement)); 10367cc0636SGreg Clayton if (notify && m_callback) 10467cc0636SGreg Clayton m_callback(*this, m_callback_baton); 10567cc0636SGreg Clayton return true; 10667cc0636SGreg Clayton } 10767cc0636SGreg Clayton 108b9c1b51eSKate Stone bool PathMappingList::Remove(size_t index, bool notify) { 109a746e8e5SZachary Turner if (index >= m_pairs.size()) 11030fdc8d8SChris Lattner return false; 11130fdc8d8SChris Lattner 1124a89501fSGreg Clayton ++m_mod_id; 11330fdc8d8SChris Lattner iterator iter = m_pairs.begin() + index; 11430fdc8d8SChris Lattner m_pairs.erase(iter); 11530fdc8d8SChris Lattner if (notify && m_callback) 11630fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 11730fdc8d8SChris Lattner return true; 11830fdc8d8SChris Lattner } 11930fdc8d8SChris Lattner 12064bab489SJohnny Chen // For clients which do not need the pair index dumped, pass a pair_index >= 0 12164bab489SJohnny Chen // to only dump the indicated pair. 122b9c1b51eSKate Stone void PathMappingList::Dump(Stream *s, int pair_index) { 12330fdc8d8SChris Lattner unsigned int numPairs = m_pairs.size(); 12430fdc8d8SChris Lattner 125b9c1b51eSKate Stone if (pair_index < 0) { 12664bab489SJohnny Chen unsigned int index; 12764bab489SJohnny Chen for (index = 0; index < numPairs; ++index) 128b9c1b51eSKate Stone s->Printf("[%d] \"%s\" -> \"%s\"\n", index, 129b9c1b51eSKate Stone m_pairs[index].first.GetCString(), 130b9c1b51eSKate Stone m_pairs[index].second.GetCString()); 131b9c1b51eSKate Stone } else { 1323985c8c6SSaleem Abdulrasool if (static_cast<unsigned int>(pair_index) < numPairs) 133b9c1b51eSKate Stone s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(), 134b9c1b51eSKate Stone m_pairs[pair_index].second.GetCString()); 13564bab489SJohnny Chen } 13630fdc8d8SChris Lattner } 13730fdc8d8SChris Lattner 138b9c1b51eSKate Stone void PathMappingList::Clear(bool notify) { 1394a89501fSGreg Clayton if (!m_pairs.empty()) 1404a89501fSGreg Clayton ++m_mod_id; 14130fdc8d8SChris Lattner m_pairs.clear(); 14230fdc8d8SChris Lattner if (notify && m_callback) 14330fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 14430fdc8d8SChris Lattner } 14530fdc8d8SChris Lattner 1460e4c4821SAdrian Prantl bool PathMappingList::RemapPath(ConstString path, 147b9c1b51eSKate Stone ConstString &new_path) const { 1484cf7c6c6SAdrian Prantl if (llvm::Optional<FileSpec> remapped = RemapPath(path.GetStringRef())) { 1494cf7c6c6SAdrian Prantl new_path.SetString(remapped->GetPath()); 15030fdc8d8SChris Lattner return true; 15130fdc8d8SChris Lattner } 15230fdc8d8SChris Lattner return false; 15330fdc8d8SChris Lattner } 1547e14f91dSGreg Clayton 15521e01330SAdrian Prantl /// Append components to path, applying style. 15621e01330SAdrian Prantl static void AppendPathComponents(FileSpec &path, llvm::StringRef components, 15721e01330SAdrian Prantl llvm::sys::path::Style style) { 15821e01330SAdrian Prantl auto component = llvm::sys::path::begin(components, style); 15921e01330SAdrian Prantl auto e = llvm::sys::path::end(components); 16021e01330SAdrian Prantl while (component != e && 16121e01330SAdrian Prantl llvm::sys::path::is_separator(*component->data(), style)) 16221e01330SAdrian Prantl ++component; 16321e01330SAdrian Prantl for (; component != e; ++component) 16421e01330SAdrian Prantl path.AppendPathComponent(*component); 16521e01330SAdrian Prantl } 16621e01330SAdrian Prantl 1674cf7c6c6SAdrian Prantl llvm::Optional<FileSpec> 168ef8c6849SWalter Erquinigo PathMappingList::RemapPath(llvm::StringRef mapping_path, 169ef8c6849SWalter Erquinigo bool only_if_exists) const { 170ef8c6849SWalter Erquinigo if (m_pairs.empty() || mapping_path.empty()) 1714cf7c6c6SAdrian Prantl return {}; 17286188d8aSGreg Clayton LazyBool path_is_relative = eLazyBoolCalculate; 173ef8c6849SWalter Erquinigo 174b9c1b51eSKate Stone for (const auto &it : m_pairs) { 175ef8c6849SWalter Erquinigo llvm::StringRef prefix = it.first.GetStringRef(); 176ef8c6849SWalter Erquinigo // We create a copy of mapping_path because StringRef::consume_from 177ef8c6849SWalter Erquinigo // effectively modifies the instance itself. 178ef8c6849SWalter Erquinigo llvm::StringRef path = mapping_path; 17986188d8aSGreg Clayton if (!path.consume_front(prefix)) { 18086188d8aSGreg Clayton // Relative paths won't have a leading "./" in them unless "." is the 18186188d8aSGreg Clayton // only thing in the relative path so we need to work around "." 18286188d8aSGreg Clayton // carefully. 18386188d8aSGreg Clayton if (prefix != ".") 18486188d8aSGreg Clayton continue; 18586188d8aSGreg Clayton // We need to figure out if the "path" argument is relative. If it is, 18686188d8aSGreg Clayton // then we should remap, else skip this entry. 18786188d8aSGreg Clayton if (path_is_relative == eLazyBoolCalculate) { 1888f3be7a3SJonas Devlieghere path_is_relative = 1898f3be7a3SJonas Devlieghere FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo; 19086188d8aSGreg Clayton } 19186188d8aSGreg Clayton if (!path_is_relative) 19286188d8aSGreg Clayton continue; 19386188d8aSGreg Clayton } 1948f3be7a3SJonas Devlieghere FileSpec remapped(it.second.GetStringRef()); 19521e01330SAdrian Prantl auto orig_style = FileSpec::GuessPathStyle(prefix).getValueOr( 19621e01330SAdrian Prantl llvm::sys::path::Style::native); 19721e01330SAdrian Prantl AppendPathComponents(remapped, path, orig_style); 198ef8c6849SWalter Erquinigo if (!only_if_exists || FileSystem::Instance().Exists(remapped)) 1994cf7c6c6SAdrian Prantl return remapped; 200b0b1ea36STamas Berghammer } 2014cf7c6c6SAdrian Prantl return {}; 20286188d8aSGreg Clayton } 20386188d8aSGreg Clayton 20486188d8aSGreg Clayton bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { 20586188d8aSGreg Clayton std::string path = file.GetPath(); 20686188d8aSGreg Clayton llvm::StringRef path_ref(path); 20786188d8aSGreg Clayton for (const auto &it : m_pairs) { 20886188d8aSGreg Clayton if (!path_ref.consume_front(it.second.GetStringRef())) 20986188d8aSGreg Clayton continue; 21021e01330SAdrian Prantl auto orig_file = it.first.GetStringRef(); 21121e01330SAdrian Prantl auto orig_style = FileSpec::GuessPathStyle(orig_file).getValueOr( 21221e01330SAdrian Prantl llvm::sys::path::Style::native); 21321e01330SAdrian Prantl fixed.SetFile(orig_file, orig_style); 21421e01330SAdrian Prantl AppendPathComponents(fixed, path_ref, orig_style); 21586188d8aSGreg Clayton return true; 216b0b1ea36STamas Berghammer } 217b0b1ea36STamas Berghammer return false; 218b0b1ea36STamas Berghammer } 219b0b1ea36STamas Berghammer 220302b1b97SAdrian Prantl llvm::Optional<FileSpec> PathMappingList::FindFile(const FileSpec &orig_spec) const { 221*fe19ae35SXu Jun // We must normalize the orig_spec again using the host's path style, 222*fe19ae35SXu Jun // otherwise there will be mismatch between the host and remote platform 223*fe19ae35SXu Jun // if they use different path styles. 224*fe19ae35SXu Jun if (auto remapped = RemapPath( 225*fe19ae35SXu Jun NormalizePath(ConstString(orig_spec.GetCString())).GetStringRef(), 226*fe19ae35SXu Jun /*only_if_exists=*/true)) 227302b1b97SAdrian Prantl return remapped; 228052f7ff9SJim Ingham 229a3463722SAdrian Prantl return {}; 230d804d285SGreg Clayton } 231d804d285SGreg Clayton 2320e4c4821SAdrian Prantl bool PathMappingList::Replace(ConstString path, 2330e4c4821SAdrian Prantl ConstString new_path, bool notify) { 2347e14f91dSGreg Clayton uint32_t idx = FindIndexForPath(path); 235b9c1b51eSKate Stone if (idx < m_pairs.size()) { 2364a89501fSGreg Clayton ++m_mod_id; 2377e14f91dSGreg Clayton m_pairs[idx].second = new_path; 2387e14f91dSGreg Clayton if (notify && m_callback) 2397e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2407e14f91dSGreg Clayton return true; 2417e14f91dSGreg Clayton } 2427e14f91dSGreg Clayton return false; 2437e14f91dSGreg Clayton } 2447e14f91dSGreg Clayton 2450e4c4821SAdrian Prantl bool PathMappingList::Remove(ConstString path, bool notify) { 2467e14f91dSGreg Clayton iterator pos = FindIteratorForPath(path); 247b9c1b51eSKate Stone if (pos != m_pairs.end()) { 2484a89501fSGreg Clayton ++m_mod_id; 2497e14f91dSGreg Clayton m_pairs.erase(pos); 2507e14f91dSGreg Clayton if (notify && m_callback) 2517e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2527e14f91dSGreg Clayton return true; 2537e14f91dSGreg Clayton } 2547e14f91dSGreg Clayton return false; 2557e14f91dSGreg Clayton } 2567e14f91dSGreg Clayton 2577e14f91dSGreg Clayton PathMappingList::const_iterator 2580e4c4821SAdrian Prantl PathMappingList::FindIteratorForPath(ConstString path) const { 2597e14f91dSGreg Clayton const_iterator pos; 2607e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 2617e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 2627e14f91dSGreg Clayton 263b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2647e14f91dSGreg Clayton if (pos->first == path) 2657e14f91dSGreg Clayton break; 2667e14f91dSGreg Clayton } 2677e14f91dSGreg Clayton return pos; 2687e14f91dSGreg Clayton } 2697e14f91dSGreg Clayton 2707e14f91dSGreg Clayton PathMappingList::iterator 2710e4c4821SAdrian Prantl PathMappingList::FindIteratorForPath(ConstString path) { 2727e14f91dSGreg Clayton iterator pos; 2737e14f91dSGreg Clayton iterator begin = m_pairs.begin(); 2747e14f91dSGreg Clayton iterator end = m_pairs.end(); 2757e14f91dSGreg Clayton 276b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2777e14f91dSGreg Clayton if (pos->first == path) 2787e14f91dSGreg Clayton break; 2797e14f91dSGreg Clayton } 2807e14f91dSGreg Clayton return pos; 2817e14f91dSGreg Clayton } 2827e14f91dSGreg Clayton 283b9c1b51eSKate Stone bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, 284b9c1b51eSKate Stone ConstString &new_path) const { 285b9c1b51eSKate Stone if (idx < m_pairs.size()) { 2867e14f91dSGreg Clayton path = m_pairs[idx].first; 2877e14f91dSGreg Clayton new_path = m_pairs[idx].second; 2887e14f91dSGreg Clayton return true; 2897e14f91dSGreg Clayton } 2907e14f91dSGreg Clayton return false; 2917e14f91dSGreg Clayton } 2927e14f91dSGreg Clayton 2930e4c4821SAdrian Prantl uint32_t PathMappingList::FindIndexForPath(ConstString orig_path) const { 29486188d8aSGreg Clayton const ConstString path = NormalizePath(orig_path); 2957e14f91dSGreg Clayton const_iterator pos; 2967e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 2977e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 2987e14f91dSGreg Clayton 299b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 3007e14f91dSGreg Clayton if (pos->first == path) 3017e14f91dSGreg Clayton return std::distance(begin, pos); 3027e14f91dSGreg Clayton } 3037e14f91dSGreg Clayton return UINT32_MAX; 3047e14f91dSGreg Clayton } 305