1 //===-- PathMappingList.cpp -------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <climits> 11 #include <cstring> 12 13 #include "lldb/Host/FileSystem.h" 14 #include "lldb/Host/PosixApi.h" 15 #include "lldb/Target/PathMappingList.h" 16 #include "lldb/Utility/FileSpec.h" 17 #include "lldb/Utility/Status.h" 18 #include "lldb/Utility/Stream.h" 19 #include "lldb/lldb-private-enumerations.h" 20 21 using namespace lldb; 22 using namespace lldb_private; 23 24 namespace { 25 // We must normalize our path pairs that we store because if we don't then 26 // things won't always work. We found a case where if we did: 27 // (lldb) settings set target.source-map . /tmp 28 // We would store a path pairs of "." and "/tmp" as raw strings. If the debug 29 // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c". 30 // When PathMappingList::RemapPath() is called, it expects the path to start 31 // with the raw path pair, which doesn't work anymore because the paths have 32 // been normalized when the debug info was loaded. So we need to store 33 // nomalized path pairs to ensure things match up. 34 ConstString NormalizePath(const ConstString &path) { 35 // If we use "path" to construct a FileSpec, it will normalize the path for 36 // us. We then grab the string and turn it back into a ConstString. 37 return ConstString(FileSpec(path.GetStringRef()).GetPath()); 38 } 39 } 40 //---------------------------------------------------------------------- 41 // PathMappingList constructor 42 //---------------------------------------------------------------------- 43 PathMappingList::PathMappingList() 44 : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {} 45 46 PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) 47 : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), 48 m_mod_id(0) {} 49 50 PathMappingList::PathMappingList(const PathMappingList &rhs) 51 : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), 52 m_mod_id(0) {} 53 54 const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { 55 if (this != &rhs) { 56 m_pairs = rhs.m_pairs; 57 m_callback = nullptr; 58 m_callback_baton = nullptr; 59 m_mod_id = rhs.m_mod_id; 60 } 61 return *this; 62 } 63 64 PathMappingList::~PathMappingList() = default; 65 66 void PathMappingList::Append(const ConstString &path, 67 const ConstString &replacement, bool notify) { 68 ++m_mod_id; 69 m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement))); 70 if (notify && m_callback) 71 m_callback(*this, m_callback_baton); 72 } 73 74 void PathMappingList::Append(const PathMappingList &rhs, bool notify) { 75 ++m_mod_id; 76 if (!rhs.m_pairs.empty()) { 77 const_iterator pos, end = rhs.m_pairs.end(); 78 for (pos = rhs.m_pairs.begin(); pos != end; ++pos) 79 m_pairs.push_back(*pos); 80 if (notify && m_callback) 81 m_callback(*this, m_callback_baton); 82 } 83 } 84 85 void PathMappingList::Insert(const ConstString &path, 86 const ConstString &replacement, uint32_t index, 87 bool notify) { 88 ++m_mod_id; 89 iterator insert_iter; 90 if (index >= m_pairs.size()) 91 insert_iter = m_pairs.end(); 92 else 93 insert_iter = m_pairs.begin() + index; 94 m_pairs.emplace(insert_iter, pair(NormalizePath(path), 95 NormalizePath(replacement))); 96 if (notify && m_callback) 97 m_callback(*this, m_callback_baton); 98 } 99 100 bool PathMappingList::Replace(const ConstString &path, 101 const ConstString &replacement, uint32_t index, 102 bool notify) { 103 if (index >= m_pairs.size()) 104 return false; 105 ++m_mod_id; 106 m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement)); 107 if (notify && m_callback) 108 m_callback(*this, m_callback_baton); 109 return true; 110 } 111 112 bool PathMappingList::Remove(size_t index, bool notify) { 113 if (index >= m_pairs.size()) 114 return false; 115 116 ++m_mod_id; 117 iterator iter = m_pairs.begin() + index; 118 m_pairs.erase(iter); 119 if (notify && m_callback) 120 m_callback(*this, m_callback_baton); 121 return true; 122 } 123 124 // For clients which do not need the pair index dumped, pass a pair_index >= 0 125 // to only dump the indicated pair. 126 void PathMappingList::Dump(Stream *s, int pair_index) { 127 unsigned int numPairs = m_pairs.size(); 128 129 if (pair_index < 0) { 130 unsigned int index; 131 for (index = 0; index < numPairs; ++index) 132 s->Printf("[%d] \"%s\" -> \"%s\"\n", index, 133 m_pairs[index].first.GetCString(), 134 m_pairs[index].second.GetCString()); 135 } else { 136 if (static_cast<unsigned int>(pair_index) < numPairs) 137 s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(), 138 m_pairs[pair_index].second.GetCString()); 139 } 140 } 141 142 void PathMappingList::Clear(bool notify) { 143 if (!m_pairs.empty()) 144 ++m_mod_id; 145 m_pairs.clear(); 146 if (notify && m_callback) 147 m_callback(*this, m_callback_baton); 148 } 149 150 bool PathMappingList::RemapPath(const ConstString &path, 151 ConstString &new_path) const { 152 std::string remapped; 153 if (RemapPath(path.GetStringRef(), remapped)) { 154 new_path.SetString(remapped); 155 return true; 156 } 157 return false; 158 } 159 160 bool PathMappingList::RemapPath(llvm::StringRef path, 161 std::string &new_path) const { 162 if (m_pairs.empty() || path.empty()) 163 return false; 164 LazyBool path_is_relative = eLazyBoolCalculate; 165 for (const auto &it : m_pairs) { 166 auto prefix = it.first.GetStringRef(); 167 if (!path.consume_front(prefix)) { 168 // Relative paths won't have a leading "./" in them unless "." is the 169 // only thing in the relative path so we need to work around "." 170 // carefully. 171 if (prefix != ".") 172 continue; 173 // We need to figure out if the "path" argument is relative. If it is, 174 // then we should remap, else skip this entry. 175 if (path_is_relative == eLazyBoolCalculate) { 176 path_is_relative = 177 FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo; 178 } 179 if (!path_is_relative) 180 continue; 181 } 182 FileSpec remapped(it.second.GetStringRef()); 183 remapped.AppendPathComponent(path); 184 new_path = remapped.GetPath(); 185 return true; 186 } 187 return false; 188 } 189 190 bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { 191 std::string path = file.GetPath(); 192 llvm::StringRef path_ref(path); 193 for (const auto &it : m_pairs) { 194 if (!path_ref.consume_front(it.second.GetStringRef())) 195 continue; 196 fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native); 197 fixed.AppendPathComponent(path_ref); 198 return true; 199 } 200 return false; 201 } 202 203 bool PathMappingList::FindFile(const FileSpec &orig_spec, 204 FileSpec &new_spec) const { 205 if (!m_pairs.empty()) { 206 char orig_path[PATH_MAX]; 207 const size_t orig_path_len = 208 orig_spec.GetPath(orig_path, sizeof(orig_path)); 209 if (orig_path_len > 0) { 210 const_iterator pos, end = m_pairs.end(); 211 for (pos = m_pairs.begin(); pos != end; ++pos) { 212 const size_t prefix_len = pos->first.GetLength(); 213 214 if (orig_path_len >= prefix_len) { 215 if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) { 216 new_spec.SetFile(pos->second.GetCString(), FileSpec::Style::native); 217 new_spec.AppendPathComponent(orig_path + prefix_len); 218 if (FileSystem::Instance().Exists(new_spec)) 219 return true; 220 } 221 } 222 } 223 } 224 } 225 new_spec.Clear(); 226 return false; 227 } 228 229 bool PathMappingList::Replace(const ConstString &path, 230 const ConstString &new_path, bool notify) { 231 uint32_t idx = FindIndexForPath(path); 232 if (idx < m_pairs.size()) { 233 ++m_mod_id; 234 m_pairs[idx].second = new_path; 235 if (notify && m_callback) 236 m_callback(*this, m_callback_baton); 237 return true; 238 } 239 return false; 240 } 241 242 bool PathMappingList::Remove(const ConstString &path, bool notify) { 243 iterator pos = FindIteratorForPath(path); 244 if (pos != m_pairs.end()) { 245 ++m_mod_id; 246 m_pairs.erase(pos); 247 if (notify && m_callback) 248 m_callback(*this, m_callback_baton); 249 return true; 250 } 251 return false; 252 } 253 254 PathMappingList::const_iterator 255 PathMappingList::FindIteratorForPath(const ConstString &path) const { 256 const_iterator pos; 257 const_iterator begin = m_pairs.begin(); 258 const_iterator end = m_pairs.end(); 259 260 for (pos = begin; pos != end; ++pos) { 261 if (pos->first == path) 262 break; 263 } 264 return pos; 265 } 266 267 PathMappingList::iterator 268 PathMappingList::FindIteratorForPath(const ConstString &path) { 269 iterator pos; 270 iterator begin = m_pairs.begin(); 271 iterator end = m_pairs.end(); 272 273 for (pos = begin; pos != end; ++pos) { 274 if (pos->first == path) 275 break; 276 } 277 return pos; 278 } 279 280 bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, 281 ConstString &new_path) const { 282 if (idx < m_pairs.size()) { 283 path = m_pairs[idx].first; 284 new_path = m_pairs[idx].second; 285 return true; 286 } 287 return false; 288 } 289 290 uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const { 291 const ConstString path = NormalizePath(orig_path); 292 const_iterator pos; 293 const_iterator begin = m_pairs.begin(); 294 const_iterator end = m_pairs.end(); 295 296 for (pos = begin; pos != end; ++pos) { 297 if (pos->first == path) 298 return std::distance(begin, pos); 299 } 300 return UINT32_MAX; 301 } 302