130fdc8d8SChris Lattner //===-- PathMappingList.cpp -------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner // C Includes 1130fdc8d8SChris Lattner // C++ Includes 129394d772SEugene Zelenko #include <climits> 139394d772SEugene Zelenko #include <cstring> 149394d772SEugene Zelenko 1530fdc8d8SChris Lattner // Other libraries and framework includes 16d804d285SGreg Clayton // Project includes 17*dbd7fabaSJonas Devlieghere #include "lldb/Host/FileSystem.h" 18f343968fSZachary Turner #include "lldb/Host/PosixApi.h" 1948862d45SEli Friedman #include "lldb/Target/PathMappingList.h" 205713a05bSZachary Turner #include "lldb/Utility/FileSpec.h" 2197206d57SZachary Turner #include "lldb/Utility/Status.h" 22bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 23*dbd7fabaSJonas Devlieghere #include "lldb/lldb-private-enumerations.h" 2430fdc8d8SChris Lattner 2530fdc8d8SChris Lattner using namespace lldb; 2630fdc8d8SChris Lattner using namespace lldb_private; 2730fdc8d8SChris Lattner 2886188d8aSGreg Clayton namespace { 2986188d8aSGreg Clayton // We must normalize our path pairs that we store because if we don't then 3086188d8aSGreg Clayton // things won't always work. We found a case where if we did: 3186188d8aSGreg Clayton // (lldb) settings set target.source-map . /tmp 3286188d8aSGreg Clayton // We would store a path pairs of "." and "/tmp" as raw strings. If the debug 3386188d8aSGreg Clayton // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c". 3486188d8aSGreg Clayton // When PathMappingList::RemapPath() is called, it expects the path to start 3586188d8aSGreg Clayton // with the raw path pair, which doesn't work anymore because the paths have 3686188d8aSGreg Clayton // been normalized when the debug info was loaded. So we need to store 3786188d8aSGreg Clayton // nomalized path pairs to ensure things match up. 3886188d8aSGreg Clayton ConstString NormalizePath(const ConstString &path) { 3986188d8aSGreg Clayton // If we use "path" to construct a FileSpec, it will normalize the path for 4086188d8aSGreg Clayton // us. We then grab the string and turn it back into a ConstString. 4186188d8aSGreg Clayton return ConstString(FileSpec(path.GetStringRef(), false).GetPath()); 4286188d8aSGreg Clayton } 4386188d8aSGreg Clayton } 4430fdc8d8SChris Lattner //---------------------------------------------------------------------- 4530fdc8d8SChris Lattner // PathMappingList constructor 4630fdc8d8SChris Lattner //---------------------------------------------------------------------- 47b9c1b51eSKate Stone PathMappingList::PathMappingList() 48b9c1b51eSKate Stone : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {} 49d804d285SGreg Clayton 50b9c1b51eSKate Stone PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) 51b9c1b51eSKate Stone : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), 52b9c1b51eSKate Stone m_mod_id(0) {} 5330fdc8d8SChris Lattner 54b9c1b51eSKate Stone PathMappingList::PathMappingList(const PathMappingList &rhs) 55b9c1b51eSKate Stone : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), 56b9c1b51eSKate Stone m_mod_id(0) {} 577e14f91dSGreg Clayton 58b9c1b51eSKate Stone const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { 59b9c1b51eSKate Stone if (this != &rhs) { 607e14f91dSGreg Clayton m_pairs = rhs.m_pairs; 619394d772SEugene Zelenko m_callback = nullptr; 629394d772SEugene Zelenko m_callback_baton = nullptr; 634a89501fSGreg Clayton m_mod_id = rhs.m_mod_id; 647e14f91dSGreg Clayton } 657e14f91dSGreg Clayton return *this; 667e14f91dSGreg Clayton } 677e14f91dSGreg Clayton 689394d772SEugene Zelenko PathMappingList::~PathMappingList() = default; 6930fdc8d8SChris Lattner 70b9c1b51eSKate Stone void PathMappingList::Append(const ConstString &path, 71b9c1b51eSKate Stone const ConstString &replacement, bool notify) { 724a89501fSGreg Clayton ++m_mod_id; 7386188d8aSGreg Clayton m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); 7430fdc8d8SChris Lattner if (notify && m_callback) 7530fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 7630fdc8d8SChris Lattner } 7730fdc8d8SChris Lattner 78b9c1b51eSKate Stone void PathMappingList::Append(const PathMappingList &rhs, bool notify) { 794a89501fSGreg Clayton ++m_mod_id; 80b9c1b51eSKate Stone if (!rhs.m_pairs.empty()) { 81d804d285SGreg Clayton const_iterator pos, end = rhs.m_pairs.end(); 82d804d285SGreg Clayton for (pos = rhs.m_pairs.begin(); pos != end; ++pos) 83d804d285SGreg Clayton m_pairs.push_back(*pos); 84d804d285SGreg Clayton if (notify && m_callback) 85d804d285SGreg Clayton m_callback(*this, m_callback_baton); 86d804d285SGreg Clayton } 87d804d285SGreg Clayton } 88d804d285SGreg Clayton 89b9c1b51eSKate Stone void PathMappingList::Insert(const ConstString &path, 90b9c1b51eSKate Stone const ConstString &replacement, uint32_t index, 91b9c1b51eSKate Stone bool notify) { 924a89501fSGreg Clayton ++m_mod_id; 9330fdc8d8SChris Lattner iterator insert_iter; 9430fdc8d8SChris Lattner if (index >= m_pairs.size()) 9530fdc8d8SChris Lattner insert_iter = m_pairs.end(); 9630fdc8d8SChris Lattner else 9730fdc8d8SChris Lattner insert_iter = m_pairs.begin() + index; 9886188d8aSGreg Clayton m_pairs.emplace(insert_iter, pair(NormalizePath(path), 9986188d8aSGreg Clayton NormalizePath(replacement))); 10030fdc8d8SChris Lattner if (notify && m_callback) 10130fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 10230fdc8d8SChris Lattner } 10330fdc8d8SChris Lattner 104b9c1b51eSKate Stone bool PathMappingList::Replace(const ConstString &path, 105b9c1b51eSKate Stone const ConstString &replacement, uint32_t index, 106b9c1b51eSKate Stone bool notify) { 10767cc0636SGreg Clayton if (index >= m_pairs.size()) 10867cc0636SGreg Clayton return false; 1094a89501fSGreg Clayton ++m_mod_id; 11086188d8aSGreg Clayton m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement)); 11167cc0636SGreg Clayton if (notify && m_callback) 11267cc0636SGreg Clayton m_callback(*this, m_callback_baton); 11367cc0636SGreg Clayton return true; 11467cc0636SGreg Clayton } 11567cc0636SGreg Clayton 116b9c1b51eSKate Stone bool PathMappingList::Remove(size_t index, bool notify) { 117a746e8e5SZachary Turner if (index >= m_pairs.size()) 11830fdc8d8SChris Lattner return false; 11930fdc8d8SChris Lattner 1204a89501fSGreg Clayton ++m_mod_id; 12130fdc8d8SChris Lattner iterator iter = m_pairs.begin() + index; 12230fdc8d8SChris Lattner m_pairs.erase(iter); 12330fdc8d8SChris Lattner if (notify && m_callback) 12430fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 12530fdc8d8SChris Lattner return true; 12630fdc8d8SChris Lattner } 12730fdc8d8SChris Lattner 12864bab489SJohnny Chen // For clients which do not need the pair index dumped, pass a pair_index >= 0 12964bab489SJohnny Chen // to only dump the indicated pair. 130b9c1b51eSKate Stone void PathMappingList::Dump(Stream *s, int pair_index) { 13130fdc8d8SChris Lattner unsigned int numPairs = m_pairs.size(); 13230fdc8d8SChris Lattner 133b9c1b51eSKate Stone if (pair_index < 0) { 13464bab489SJohnny Chen unsigned int index; 13564bab489SJohnny Chen for (index = 0; index < numPairs; ++index) 136b9c1b51eSKate Stone s->Printf("[%d] \"%s\" -> \"%s\"\n", index, 137b9c1b51eSKate Stone m_pairs[index].first.GetCString(), 138b9c1b51eSKate Stone m_pairs[index].second.GetCString()); 139b9c1b51eSKate Stone } else { 1403985c8c6SSaleem Abdulrasool if (static_cast<unsigned int>(pair_index) < numPairs) 141b9c1b51eSKate Stone s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(), 142b9c1b51eSKate Stone m_pairs[pair_index].second.GetCString()); 14364bab489SJohnny Chen } 14430fdc8d8SChris Lattner } 14530fdc8d8SChris Lattner 146b9c1b51eSKate Stone void PathMappingList::Clear(bool notify) { 1474a89501fSGreg Clayton if (!m_pairs.empty()) 1484a89501fSGreg Clayton ++m_mod_id; 14930fdc8d8SChris Lattner m_pairs.clear(); 15030fdc8d8SChris Lattner if (notify && m_callback) 15130fdc8d8SChris Lattner m_callback(*this, m_callback_baton); 15230fdc8d8SChris Lattner } 15330fdc8d8SChris Lattner 154b9c1b51eSKate Stone bool PathMappingList::RemapPath(const ConstString &path, 155b9c1b51eSKate Stone ConstString &new_path) const { 15686188d8aSGreg Clayton std::string remapped; 15786188d8aSGreg Clayton if (RemapPath(path.GetStringRef(), remapped)) { 15886188d8aSGreg Clayton new_path.SetString(remapped); 15930fdc8d8SChris Lattner return true; 16030fdc8d8SChris Lattner } 16130fdc8d8SChris Lattner return false; 16230fdc8d8SChris Lattner } 1637e14f91dSGreg Clayton 164a498f0ecSZachary Turner bool PathMappingList::RemapPath(llvm::StringRef path, 165a498f0ecSZachary Turner std::string &new_path) const { 166a498f0ecSZachary Turner if (m_pairs.empty() || path.empty()) 167f9be6933SGreg Clayton return false; 16886188d8aSGreg Clayton LazyBool path_is_relative = eLazyBoolCalculate; 169b9c1b51eSKate Stone for (const auto &it : m_pairs) { 17086188d8aSGreg Clayton auto prefix = it.first.GetStringRef(); 17186188d8aSGreg Clayton if (!path.consume_front(prefix)) { 17286188d8aSGreg Clayton // Relative paths won't have a leading "./" in them unless "." is the 17386188d8aSGreg Clayton // only thing in the relative path so we need to work around "." 17486188d8aSGreg Clayton // carefully. 17586188d8aSGreg Clayton if (prefix != ".") 17686188d8aSGreg Clayton continue; 17786188d8aSGreg Clayton // We need to figure out if the "path" argument is relative. If it is, 17886188d8aSGreg Clayton // then we should remap, else skip this entry. 17986188d8aSGreg Clayton if (path_is_relative == eLazyBoolCalculate) { 18086188d8aSGreg Clayton path_is_relative = FileSpec(path, false).IsRelative() ? eLazyBoolYes : 18186188d8aSGreg Clayton eLazyBoolNo; 18286188d8aSGreg Clayton } 18386188d8aSGreg Clayton if (!path_is_relative) 18486188d8aSGreg Clayton continue; 18586188d8aSGreg Clayton } 18686188d8aSGreg Clayton FileSpec remapped(it.second.GetStringRef(), false); 18786188d8aSGreg Clayton remapped.AppendPathComponent(path); 18886188d8aSGreg Clayton new_path = remapped.GetPath(); 189b0b1ea36STamas Berghammer return true; 190b0b1ea36STamas Berghammer } 19186188d8aSGreg Clayton return false; 19286188d8aSGreg Clayton } 19386188d8aSGreg Clayton 19486188d8aSGreg Clayton bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { 19586188d8aSGreg Clayton std::string path = file.GetPath(); 19686188d8aSGreg Clayton llvm::StringRef path_ref(path); 19786188d8aSGreg Clayton for (const auto &it : m_pairs) { 19886188d8aSGreg Clayton if (!path_ref.consume_front(it.second.GetStringRef())) 19986188d8aSGreg Clayton continue; 200937348cdSJonas Devlieghere fixed.SetFile(it.first.GetStringRef(), false, FileSpec::Style::native); 20186188d8aSGreg Clayton fixed.AppendPathComponent(path_ref); 20286188d8aSGreg Clayton return true; 203b0b1ea36STamas Berghammer } 204b0b1ea36STamas Berghammer return false; 205b0b1ea36STamas Berghammer } 206b0b1ea36STamas Berghammer 207b9c1b51eSKate Stone bool PathMappingList::FindFile(const FileSpec &orig_spec, 208b9c1b51eSKate Stone FileSpec &new_spec) const { 209b9c1b51eSKate Stone if (!m_pairs.empty()) { 210d804d285SGreg Clayton char orig_path[PATH_MAX]; 211b9c1b51eSKate Stone const size_t orig_path_len = 212b9c1b51eSKate Stone orig_spec.GetPath(orig_path, sizeof(orig_path)); 213b9c1b51eSKate Stone if (orig_path_len > 0) { 214d804d285SGreg Clayton const_iterator pos, end = m_pairs.end(); 215b9c1b51eSKate Stone for (pos = m_pairs.begin(); pos != end; ++pos) { 216d804d285SGreg Clayton const size_t prefix_len = pos->first.GetLength(); 217d804d285SGreg Clayton 218b9c1b51eSKate Stone if (orig_path_len >= prefix_len) { 219b9c1b51eSKate Stone if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) { 220937348cdSJonas Devlieghere new_spec.SetFile(pos->second.GetCString(), false, 221937348cdSJonas Devlieghere FileSpec::Style::native); 222291fd350SJim Ingham new_spec.AppendPathComponent(orig_path + prefix_len); 223*dbd7fabaSJonas Devlieghere if (FileSystem::Instance().Exists(new_spec)) 224d804d285SGreg Clayton return true; 225d804d285SGreg Clayton } 226d804d285SGreg Clayton } 227d804d285SGreg Clayton } 228d804d285SGreg Clayton } 229d804d285SGreg Clayton } 230d804d285SGreg Clayton new_spec.Clear(); 231d804d285SGreg Clayton return false; 232d804d285SGreg Clayton } 233d804d285SGreg Clayton 234b9c1b51eSKate Stone bool PathMappingList::Replace(const ConstString &path, 235b9c1b51eSKate Stone const ConstString &new_path, bool notify) { 2367e14f91dSGreg Clayton uint32_t idx = FindIndexForPath(path); 237b9c1b51eSKate Stone if (idx < m_pairs.size()) { 2384a89501fSGreg Clayton ++m_mod_id; 2397e14f91dSGreg Clayton m_pairs[idx].second = new_path; 2407e14f91dSGreg Clayton if (notify && m_callback) 2417e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2427e14f91dSGreg Clayton return true; 2437e14f91dSGreg Clayton } 2447e14f91dSGreg Clayton return false; 2457e14f91dSGreg Clayton } 2467e14f91dSGreg Clayton 247b9c1b51eSKate Stone bool PathMappingList::Remove(const ConstString &path, bool notify) { 2487e14f91dSGreg Clayton iterator pos = FindIteratorForPath(path); 249b9c1b51eSKate Stone if (pos != m_pairs.end()) { 2504a89501fSGreg Clayton ++m_mod_id; 2517e14f91dSGreg Clayton m_pairs.erase(pos); 2527e14f91dSGreg Clayton if (notify && m_callback) 2537e14f91dSGreg Clayton m_callback(*this, m_callback_baton); 2547e14f91dSGreg Clayton return true; 2557e14f91dSGreg Clayton } 2567e14f91dSGreg Clayton return false; 2577e14f91dSGreg Clayton } 2587e14f91dSGreg Clayton 2597e14f91dSGreg Clayton PathMappingList::const_iterator 260b9c1b51eSKate Stone PathMappingList::FindIteratorForPath(const ConstString &path) const { 2617e14f91dSGreg Clayton const_iterator pos; 2627e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 2637e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 2647e14f91dSGreg Clayton 265b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2667e14f91dSGreg Clayton if (pos->first == path) 2677e14f91dSGreg Clayton break; 2687e14f91dSGreg Clayton } 2697e14f91dSGreg Clayton return pos; 2707e14f91dSGreg Clayton } 2717e14f91dSGreg Clayton 2727e14f91dSGreg Clayton PathMappingList::iterator 273b9c1b51eSKate Stone PathMappingList::FindIteratorForPath(const ConstString &path) { 2747e14f91dSGreg Clayton iterator pos; 2757e14f91dSGreg Clayton iterator begin = m_pairs.begin(); 2767e14f91dSGreg Clayton iterator end = m_pairs.end(); 2777e14f91dSGreg Clayton 278b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 2797e14f91dSGreg Clayton if (pos->first == path) 2807e14f91dSGreg Clayton break; 2817e14f91dSGreg Clayton } 2827e14f91dSGreg Clayton return pos; 2837e14f91dSGreg Clayton } 2847e14f91dSGreg Clayton 285b9c1b51eSKate Stone bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, 286b9c1b51eSKate Stone ConstString &new_path) const { 287b9c1b51eSKate Stone if (idx < m_pairs.size()) { 2887e14f91dSGreg Clayton path = m_pairs[idx].first; 2897e14f91dSGreg Clayton new_path = m_pairs[idx].second; 2907e14f91dSGreg Clayton return true; 2917e14f91dSGreg Clayton } 2927e14f91dSGreg Clayton return false; 2937e14f91dSGreg Clayton } 2947e14f91dSGreg Clayton 29586188d8aSGreg Clayton uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const { 29686188d8aSGreg Clayton const ConstString path = NormalizePath(orig_path); 2977e14f91dSGreg Clayton const_iterator pos; 2987e14f91dSGreg Clayton const_iterator begin = m_pairs.begin(); 2997e14f91dSGreg Clayton const_iterator end = m_pairs.end(); 3007e14f91dSGreg Clayton 301b9c1b51eSKate Stone for (pos = begin; pos != end; ++pos) { 3027e14f91dSGreg Clayton if (pos->first == path) 3037e14f91dSGreg Clayton return std::distance(begin, pos); 3047e14f91dSGreg Clayton } 3057e14f91dSGreg Clayton return UINT32_MAX; 3067e14f91dSGreg Clayton } 307