130fdc8d8SChris Lattner //===-- PathMappingList.cpp -------------------------------------*- C++ -*-===// 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. 3386188d8aSGreg Clayton ConstString NormalizePath(const 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 //---------------------------------------------------------------------- 4030fdc8d8SChris Lattner // PathMappingList constructor 4130fdc8d8SChris Lattner //---------------------------------------------------------------------- 42b9c1b51eSKate Stone PathMappingList::PathMappingList() 43b9c1b51eSKate Stone : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {} 44d804d285SGreg Clayton 45b9c1b51eSKate Stone PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) 46b9c1b51eSKate Stone : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), 47b9c1b51eSKate Stone m_mod_id(0) {} 4830fdc8d8SChris Lattner 49b9c1b51eSKate Stone PathMappingList::PathMappingList(const PathMappingList &rhs) 50b9c1b51eSKate Stone : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), 51b9c1b51eSKate Stone m_mod_id(0) {} 527e14f91dSGreg Clayton 53b9c1b51eSKate Stone const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { 54b9c1b51eSKate Stone if (this != &rhs) { 557e14f91dSGreg Clayton m_pairs = rhs.m_pairs; 569394d772SEugene Zelenko m_callback = nullptr; 579394d772SEugene Zelenko m_callback_baton = nullptr; 584a89501fSGreg Clayton m_mod_id = rhs.m_mod_id; 597e14f91dSGreg Clayton } 607e14f91dSGreg Clayton return *this; 617e14f91dSGreg Clayton } 627e14f91dSGreg Clayton 639394d772SEugene Zelenko PathMappingList::~PathMappingList() = default; 6430fdc8d8SChris Lattner 65b9c1b51eSKate Stone void PathMappingList::Append(const ConstString &path, 66b9c1b51eSKate Stone const ConstString &replacement, bool notify) { 674a89501fSGreg Clayton ++m_mod_id; 6886188d8aSGreg Clayton m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); 6930fdc8d8SChris Lattner if (notify && m_callback) 7030fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 7130fdc8d8SChris Lattner } 7230fdc8d8SChris Lattner 73b9c1b51eSKate Stone void PathMappingList::Append(const PathMappingList &rhs, bool notify) { 744a89501fSGreg Clayton ++m_mod_id; 75b9c1b51eSKate Stone if (!rhs.m_pairs.empty()) { 76d804d285SGreg Clayton const_iterator pos, end = rhs.m_pairs.end(); 77d804d285SGreg Clayton for (pos = rhs.m_pairs.begin(); pos != end; ++pos) 78d804d285SGreg Clayton m_pairs.push_back(*pos); 79d804d285SGreg Clayton if (notify && m_callback) 80d804d285SGreg Clayton m_callback(*this, m_callback_baton); 81d804d285SGreg Clayton } 82d804d285SGreg Clayton } 83d804d285SGreg Clayton 84b9c1b51eSKate Stone void PathMappingList::Insert(const ConstString &path, 85b9c1b51eSKate Stone const ConstString &replacement, uint32_t index, 86b9c1b51eSKate Stone bool notify) { 874a89501fSGreg Clayton ++m_mod_id; 8830fdc8d8SChris Lattner iterator insert_iter; 8930fdc8d8SChris Lattner if (index >= m_pairs.size()) 9030fdc8d8SChris Lattner insert_iter = m_pairs.end(); 9130fdc8d8SChris Lattner else 9230fdc8d8SChris Lattner insert_iter = m_pairs.begin() + index; 9386188d8aSGreg Clayton m_pairs.emplace(insert_iter, pair(NormalizePath(path), 9486188d8aSGreg Clayton NormalizePath(replacement))); 9530fdc8d8SChris Lattner if (notify && m_callback) 9630fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 9730fdc8d8SChris Lattner } 9830fdc8d8SChris Lattner 99b9c1b51eSKate Stone bool PathMappingList::Replace(const ConstString &path, 100b9c1b51eSKate Stone const ConstString &replacement, uint32_t index, 101b9c1b51eSKate Stone bool notify) { 10267cc0636SGreg Clayton if (index >= m_pairs.size()) 10367cc0636SGreg Clayton return false; 1044a89501fSGreg Clayton ++m_mod_id; 10586188d8aSGreg Clayton m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement)); 10667cc0636SGreg Clayton if (notify && m_callback) 10767cc0636SGreg Clayton m_callback(*this, m_callback_baton); 10867cc0636SGreg Clayton return true; 10967cc0636SGreg Clayton } 11067cc0636SGreg Clayton 111b9c1b51eSKate Stone bool PathMappingList::Remove(size_t index, bool notify) { 112a746e8e5SZachary Turner if (index >= m_pairs.size()) 11330fdc8d8SChris Lattner return false; 11430fdc8d8SChris Lattner 1154a89501fSGreg Clayton ++m_mod_id; 11630fdc8d8SChris Lattner iterator iter = m_pairs.begin() + index; 11730fdc8d8SChris Lattner m_pairs.erase(iter); 11830fdc8d8SChris Lattner if (notify && m_callback) 11930fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 12030fdc8d8SChris Lattner return true; 12130fdc8d8SChris Lattner } 12230fdc8d8SChris Lattner 12364bab489SJohnny Chen // For clients which do not need the pair index dumped, pass a pair_index >= 0 12464bab489SJohnny Chen // to only dump the indicated pair. 125b9c1b51eSKate Stone void PathMappingList::Dump(Stream *s, int pair_index) { 12630fdc8d8SChris Lattner unsigned int numPairs = m_pairs.size(); 12730fdc8d8SChris Lattner 128b9c1b51eSKate Stone if (pair_index < 0) { 12964bab489SJohnny Chen unsigned int index; 13064bab489SJohnny Chen for (index = 0; index < numPairs; ++index) 131b9c1b51eSKate Stone s->Printf("[%d] \"%s\" -> \"%s\"\n", index, 132b9c1b51eSKate Stone m_pairs[index].first.GetCString(), 133b9c1b51eSKate Stone m_pairs[index].second.GetCString()); 134b9c1b51eSKate Stone } else { 1353985c8c6SSaleem Abdulrasool if (static_cast<unsigned int>(pair_index) < numPairs) 136b9c1b51eSKate Stone s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(), 137b9c1b51eSKate Stone m_pairs[pair_index].second.GetCString()); 13864bab489SJohnny Chen } 13930fdc8d8SChris Lattner } 14030fdc8d8SChris Lattner 141b9c1b51eSKate Stone void PathMappingList::Clear(bool notify) { 1424a89501fSGreg Clayton if (!m_pairs.empty()) 1434a89501fSGreg Clayton ++m_mod_id; 14430fdc8d8SChris Lattner m_pairs.clear(); 14530fdc8d8SChris Lattner if (notify && m_callback) 14630fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 14730fdc8d8SChris Lattner } 14830fdc8d8SChris Lattner 149b9c1b51eSKate Stone bool PathMappingList::RemapPath(const ConstString &path, 150b9c1b51eSKate Stone ConstString &new_path) const { 15186188d8aSGreg Clayton std::string remapped; 15286188d8aSGreg Clayton if (RemapPath(path.GetStringRef(), remapped)) { 15386188d8aSGreg Clayton new_path.SetString(remapped); 15430fdc8d8SChris Lattner return true; 15530fdc8d8SChris Lattner } 15630fdc8d8SChris Lattner return false; 15730fdc8d8SChris Lattner } 1587e14f91dSGreg Clayton 159a498f0ecSZachary Turner bool PathMappingList::RemapPath(llvm::StringRef path, 160a498f0ecSZachary Turner std::string &new_path) const { 161a498f0ecSZachary Turner if (m_pairs.empty() || path.empty()) 162f9be6933SGreg Clayton return false; 16386188d8aSGreg Clayton LazyBool path_is_relative = eLazyBoolCalculate; 164b9c1b51eSKate Stone for (const auto &it : m_pairs) { 16586188d8aSGreg Clayton auto prefix = it.first.GetStringRef(); 16686188d8aSGreg Clayton if (!path.consume_front(prefix)) { 16786188d8aSGreg Clayton // Relative paths won't have a leading "./" in them unless "." is the 16886188d8aSGreg Clayton // only thing in the relative path so we need to work around "." 16986188d8aSGreg Clayton // carefully. 17086188d8aSGreg Clayton if (prefix != ".") 17186188d8aSGreg Clayton continue; 17286188d8aSGreg Clayton // We need to figure out if the "path" argument is relative. If it is, 17386188d8aSGreg Clayton // then we should remap, else skip this entry. 17486188d8aSGreg Clayton if (path_is_relative == eLazyBoolCalculate) { 1758f3be7a3SJonas Devlieghere path_is_relative = 1768f3be7a3SJonas Devlieghere FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo; 17786188d8aSGreg Clayton } 17886188d8aSGreg Clayton if (!path_is_relative) 17986188d8aSGreg Clayton continue; 18086188d8aSGreg Clayton } 1818f3be7a3SJonas Devlieghere FileSpec remapped(it.second.GetStringRef()); 18286188d8aSGreg Clayton remapped.AppendPathComponent(path); 18386188d8aSGreg Clayton new_path = remapped.GetPath(); 184b0b1ea36STamas Berghammer return true; 185b0b1ea36STamas Berghammer } 18686188d8aSGreg Clayton return false; 18786188d8aSGreg Clayton } 18886188d8aSGreg Clayton 18986188d8aSGreg Clayton bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { 19086188d8aSGreg Clayton std::string path = file.GetPath(); 19186188d8aSGreg Clayton llvm::StringRef path_ref(path); 19286188d8aSGreg Clayton for (const auto &it : m_pairs) { 19386188d8aSGreg Clayton if (!path_ref.consume_front(it.second.GetStringRef())) 19486188d8aSGreg Clayton continue; 1958f3be7a3SJonas Devlieghere fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native); 19686188d8aSGreg Clayton fixed.AppendPathComponent(path_ref); 19786188d8aSGreg Clayton return true; 198b0b1ea36STamas Berghammer } 199b0b1ea36STamas Berghammer return false; 200b0b1ea36STamas Berghammer } 201b0b1ea36STamas Berghammer 202b9c1b51eSKate Stone bool PathMappingList::FindFile(const FileSpec &orig_spec, 203b9c1b51eSKate Stone FileSpec &new_spec) const { 204*052f7ff9SJim Ingham if (m_pairs.empty()) 205*052f7ff9SJim Ingham return false; 206*052f7ff9SJim Ingham 207*052f7ff9SJim Ingham std::string orig_path = orig_spec.GetPath(); 208*052f7ff9SJim Ingham 209*052f7ff9SJim Ingham if (orig_path.empty()) 210*052f7ff9SJim Ingham return false; 211*052f7ff9SJim Ingham 212*052f7ff9SJim Ingham bool orig_is_relative = orig_spec.IsRelative(); 213*052f7ff9SJim Ingham 214d804d285SGreg Clayton const_iterator pos, end = m_pairs.end(); 215b9c1b51eSKate Stone for (pos = m_pairs.begin(); pos != end; ++pos) { 216*052f7ff9SJim Ingham llvm::StringRef orig_ref(orig_path); 217*052f7ff9SJim Ingham llvm::StringRef prefix_ref = pos->first.GetStringRef(); 218*052f7ff9SJim Ingham if (orig_ref.size() >= prefix_ref.size()) { 219*052f7ff9SJim Ingham // We consider a relative prefix or one of just "." to 220*052f7ff9SJim Ingham // mean "only apply to relative paths". 221*052f7ff9SJim Ingham bool prefix_is_relative = false; 222d804d285SGreg Clayton 223*052f7ff9SJim Ingham if (prefix_ref == ".") { 224*052f7ff9SJim Ingham prefix_is_relative = true; 225*052f7ff9SJim Ingham // Remove the "." since it will have been removed from the 226*052f7ff9SJim Ingham // FileSpec paths already. 227*052f7ff9SJim Ingham prefix_ref = prefix_ref.drop_front(); 228*052f7ff9SJim Ingham } else { 229*052f7ff9SJim Ingham FileSpec prefix_spec(prefix_ref, FileSpec::Style::native); 230*052f7ff9SJim Ingham prefix_is_relative = prefix_spec.IsRelative(); 231*052f7ff9SJim Ingham } 232*052f7ff9SJim Ingham if (prefix_is_relative != orig_is_relative) 233*052f7ff9SJim Ingham continue; 234*052f7ff9SJim Ingham 235*052f7ff9SJim Ingham if (orig_ref.consume_front(prefix_ref)) { 2368f3be7a3SJonas Devlieghere new_spec.SetFile(pos->second.GetCString(), FileSpec::Style::native); 237*052f7ff9SJim Ingham new_spec.AppendPathComponent(orig_ref); 238dbd7fabaSJonas Devlieghere if (FileSystem::Instance().Exists(new_spec)) 239d804d285SGreg Clayton return true; 240d804d285SGreg Clayton } 241d804d285SGreg Clayton } 242d804d285SGreg Clayton } 243*052f7ff9SJim Ingham 244d804d285SGreg Clayton new_spec.Clear(); 245d804d285SGreg Clayton return false; 246d804d285SGreg Clayton } 247d804d285SGreg Clayton 248b9c1b51eSKate Stone bool PathMappingList::Replace(const ConstString &path, 249b9c1b51eSKate Stone const ConstString &new_path, bool notify) { 2507e14f91dSGreg Clayton uint32_t idx = FindIndexForPath(path); 251b9c1b51eSKate Stone if (idx < m_pairs.size()) { 2524a89501fSGreg Clayton ++m_mod_id; 2537e14f91dSGreg Clayton m_pairs[idx].second = new_path; 2547e14f91dSGreg Clayton if (notify && m_callback) 2557e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2567e14f91dSGreg Clayton return true; 2577e14f91dSGreg Clayton } 2587e14f91dSGreg Clayton return false; 2597e14f91dSGreg Clayton } 2607e14f91dSGreg Clayton 261b9c1b51eSKate Stone bool PathMappingList::Remove(const ConstString &path, bool notify) { 2627e14f91dSGreg Clayton iterator pos = FindIteratorForPath(path); 263b9c1b51eSKate Stone if (pos != m_pairs.end()) { 2644a89501fSGreg Clayton ++m_mod_id; 2657e14f91dSGreg Clayton m_pairs.erase(pos); 2667e14f91dSGreg Clayton if (notify && m_callback) 2677e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2687e14f91dSGreg Clayton return true; 2697e14f91dSGreg Clayton } 2707e14f91dSGreg Clayton return false; 2717e14f91dSGreg Clayton } 2727e14f91dSGreg Clayton 2737e14f91dSGreg Clayton PathMappingList::const_iterator 274b9c1b51eSKate Stone PathMappingList::FindIteratorForPath(const ConstString &path) const { 2757e14f91dSGreg Clayton const_iterator pos; 2767e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 2777e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 2787e14f91dSGreg Clayton 279b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2807e14f91dSGreg Clayton if (pos->first == path) 2817e14f91dSGreg Clayton break; 2827e14f91dSGreg Clayton } 2837e14f91dSGreg Clayton return pos; 2847e14f91dSGreg Clayton } 2857e14f91dSGreg Clayton 2867e14f91dSGreg Clayton PathMappingList::iterator 287b9c1b51eSKate Stone PathMappingList::FindIteratorForPath(const ConstString &path) { 2887e14f91dSGreg Clayton iterator pos; 2897e14f91dSGreg Clayton iterator begin = m_pairs.begin(); 2907e14f91dSGreg Clayton iterator end = m_pairs.end(); 2917e14f91dSGreg Clayton 292b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2937e14f91dSGreg Clayton if (pos->first == path) 2947e14f91dSGreg Clayton break; 2957e14f91dSGreg Clayton } 2967e14f91dSGreg Clayton return pos; 2977e14f91dSGreg Clayton } 2987e14f91dSGreg Clayton 299b9c1b51eSKate Stone bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, 300b9c1b51eSKate Stone ConstString &new_path) const { 301b9c1b51eSKate Stone if (idx < m_pairs.size()) { 3027e14f91dSGreg Clayton path = m_pairs[idx].first; 3037e14f91dSGreg Clayton new_path = m_pairs[idx].second; 3047e14f91dSGreg Clayton return true; 3057e14f91dSGreg Clayton } 3067e14f91dSGreg Clayton return false; 3077e14f91dSGreg Clayton } 3087e14f91dSGreg Clayton 30986188d8aSGreg Clayton uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const { 31086188d8aSGreg Clayton const ConstString path = NormalizePath(orig_path); 3117e14f91dSGreg Clayton const_iterator pos; 3127e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 3137e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 3147e14f91dSGreg Clayton 315b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 3167e14f91dSGreg Clayton if (pos->first == path) 3177e14f91dSGreg Clayton return std::distance(begin, pos); 3187e14f91dSGreg Clayton } 3197e14f91dSGreg Clayton return UINT32_MAX; 3207e14f91dSGreg Clayton } 321