1cfca06d7SDimitry Andric //===-- PathMappingList.cpp -----------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f3fbd1c0SDimitry Andric #include <climits>
10f3fbd1c0SDimitry Andric #include <cstring>
11e3b55780SDimitry Andric #include <optional>
12f3fbd1c0SDimitry Andric
1394994d37SDimitry Andric #include "lldb/Host/FileSystem.h"
1414f1b3e8SDimitry Andric #include "lldb/Host/PosixApi.h"
15f034231aSEd Maste #include "lldb/Target/PathMappingList.h"
1674a628f7SDimitry Andric #include "lldb/Utility/FileSpec.h"
17b76161e4SDimitry Andric #include "lldb/Utility/Status.h"
1874a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
1994994d37SDimitry Andric #include "lldb/lldb-private-enumerations.h"
20f034231aSEd Maste
21f034231aSEd Maste using namespace lldb;
22f034231aSEd Maste using namespace lldb_private;
23f034231aSEd Maste
24f73363f1SDimitry Andric namespace {
25f73363f1SDimitry Andric // We must normalize our path pairs that we store because if we don't then
26f73363f1SDimitry Andric // things won't always work. We found a case where if we did:
27f73363f1SDimitry Andric // (lldb) settings set target.source-map . /tmp
28f73363f1SDimitry Andric // We would store a path pairs of "." and "/tmp" as raw strings. If the debug
29f73363f1SDimitry Andric // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c".
30f73363f1SDimitry Andric // When PathMappingList::RemapPath() is called, it expects the path to start
31f73363f1SDimitry Andric // with the raw path pair, which doesn't work anymore because the paths have
32f73363f1SDimitry Andric // been normalized when the debug info was loaded. So we need to store
33f73363f1SDimitry Andric // nomalized path pairs to ensure things match up.
NormalizePath(llvm::StringRef path)34c0981da4SDimitry Andric std::string NormalizePath(llvm::StringRef path) {
35f73363f1SDimitry Andric // If we use "path" to construct a FileSpec, it will normalize the path for
36c0981da4SDimitry Andric // us. We then grab the string.
37c0981da4SDimitry Andric return FileSpec(path).GetPath();
38f73363f1SDimitry Andric }
39f73363f1SDimitry Andric }
40f034231aSEd Maste // PathMappingList constructor
PathMappingList()41344a3780SDimitry Andric PathMappingList::PathMappingList() : m_pairs() {}
42f034231aSEd Maste
PathMappingList(ChangedCallback callback,void * callback_baton)4314f1b3e8SDimitry Andric PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
44145449b1SDimitry Andric : m_pairs(), m_callback(callback), m_callback_baton(callback_baton) {}
45f034231aSEd Maste
PathMappingList(const PathMappingList & rhs)4614f1b3e8SDimitry Andric PathMappingList::PathMappingList(const PathMappingList &rhs)
47145449b1SDimitry Andric : m_pairs(rhs.m_pairs) {}
48f034231aSEd Maste
operator =(const PathMappingList & rhs)4914f1b3e8SDimitry Andric const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
5014f1b3e8SDimitry Andric if (this != &rhs) {
517fa27ce4SDimitry Andric std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);
52f034231aSEd Maste m_pairs = rhs.m_pairs;
53f3fbd1c0SDimitry Andric m_callback = nullptr;
54f3fbd1c0SDimitry Andric m_callback_baton = nullptr;
55f034231aSEd Maste m_mod_id = rhs.m_mod_id;
56f034231aSEd Maste }
57f034231aSEd Maste return *this;
58f034231aSEd Maste }
59f034231aSEd Maste
60f3fbd1c0SDimitry Andric PathMappingList::~PathMappingList() = default;
61f034231aSEd Maste
Append(llvm::StringRef path,llvm::StringRef replacement,bool notify)62c0981da4SDimitry Andric void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
63c0981da4SDimitry Andric bool notify) {
647fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
65f034231aSEd Maste ++m_mod_id;
66f73363f1SDimitry Andric m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
67f034231aSEd Maste if (notify && m_callback)
68f034231aSEd Maste m_callback(*this, m_callback_baton);
69f034231aSEd Maste }
70f034231aSEd Maste
Append(const PathMappingList & rhs,bool notify)7114f1b3e8SDimitry Andric void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
727fa27ce4SDimitry Andric std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);
73f034231aSEd Maste ++m_mod_id;
7414f1b3e8SDimitry Andric if (!rhs.m_pairs.empty()) {
75f034231aSEd Maste const_iterator pos, end = rhs.m_pairs.end();
76f034231aSEd Maste for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
77f034231aSEd Maste m_pairs.push_back(*pos);
78f034231aSEd Maste if (notify && m_callback)
79f034231aSEd Maste m_callback(*this, m_callback_baton);
80f034231aSEd Maste }
81f034231aSEd Maste }
82f034231aSEd Maste
AppendUnique(llvm::StringRef path,llvm::StringRef replacement,bool notify)83e3b55780SDimitry Andric bool PathMappingList::AppendUnique(llvm::StringRef path,
84e3b55780SDimitry Andric llvm::StringRef replacement, bool notify) {
85e3b55780SDimitry Andric auto normalized_path = NormalizePath(path);
86e3b55780SDimitry Andric auto normalized_replacement = NormalizePath(replacement);
877fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
88e3b55780SDimitry Andric for (const auto &pair : m_pairs) {
89ac9a064cSDimitry Andric if (pair.first.GetStringRef() == normalized_path &&
90ac9a064cSDimitry Andric pair.second.GetStringRef() == normalized_replacement)
91e3b55780SDimitry Andric return false;
92e3b55780SDimitry Andric }
93e3b55780SDimitry Andric Append(path, replacement, notify);
94e3b55780SDimitry Andric return true;
95e3b55780SDimitry Andric }
96e3b55780SDimitry Andric
Insert(llvm::StringRef path,llvm::StringRef replacement,uint32_t index,bool notify)97c0981da4SDimitry Andric void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement,
98c0981da4SDimitry Andric uint32_t index, bool notify) {
997fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
100f034231aSEd Maste ++m_mod_id;
101f034231aSEd Maste iterator insert_iter;
102f034231aSEd Maste if (index >= m_pairs.size())
103f034231aSEd Maste insert_iter = m_pairs.end();
104f034231aSEd Maste else
105f034231aSEd Maste insert_iter = m_pairs.begin() + index;
106f73363f1SDimitry Andric m_pairs.emplace(insert_iter, pair(NormalizePath(path),
107f73363f1SDimitry Andric NormalizePath(replacement)));
108f034231aSEd Maste if (notify && m_callback)
109f034231aSEd Maste m_callback(*this, m_callback_baton);
110f034231aSEd Maste }
111f034231aSEd Maste
Replace(llvm::StringRef path,llvm::StringRef replacement,uint32_t index,bool notify)112c0981da4SDimitry Andric bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement,
113c0981da4SDimitry Andric uint32_t index, bool notify) {
1147fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
115f034231aSEd Maste if (index >= m_pairs.size())
116f034231aSEd Maste return false;
117f034231aSEd Maste ++m_mod_id;
118f73363f1SDimitry Andric m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
119f034231aSEd Maste if (notify && m_callback)
120f034231aSEd Maste m_callback(*this, m_callback_baton);
121f034231aSEd Maste return true;
122f034231aSEd Maste }
123f034231aSEd Maste
Remove(size_t index,bool notify)12414f1b3e8SDimitry Andric bool PathMappingList::Remove(size_t index, bool notify) {
1257fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
126f034231aSEd Maste if (index >= m_pairs.size())
127f034231aSEd Maste return false;
128f034231aSEd Maste
129f034231aSEd Maste ++m_mod_id;
130f034231aSEd Maste iterator iter = m_pairs.begin() + index;
131f034231aSEd Maste m_pairs.erase(iter);
132f034231aSEd Maste if (notify && m_callback)
133f034231aSEd Maste m_callback(*this, m_callback_baton);
134f034231aSEd Maste return true;
135f034231aSEd Maste }
136f034231aSEd Maste
137f034231aSEd Maste // For clients which do not need the pair index dumped, pass a pair_index >= 0
138f034231aSEd Maste // to only dump the indicated pair.
Dump(Stream * s,int pair_index)13914f1b3e8SDimitry Andric void PathMappingList::Dump(Stream *s, int pair_index) {
1407fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
141f034231aSEd Maste unsigned int numPairs = m_pairs.size();
142f034231aSEd Maste
14314f1b3e8SDimitry Andric if (pair_index < 0) {
144f034231aSEd Maste unsigned int index;
145f034231aSEd Maste for (index = 0; index < numPairs; ++index)
14614f1b3e8SDimitry Andric s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
14714f1b3e8SDimitry Andric m_pairs[index].first.GetCString(),
14814f1b3e8SDimitry Andric m_pairs[index].second.GetCString());
14914f1b3e8SDimitry Andric } else {
1500cac4ca3SEd Maste if (static_cast<unsigned int>(pair_index) < numPairs)
15114f1b3e8SDimitry Andric s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
15214f1b3e8SDimitry Andric m_pairs[pair_index].second.GetCString());
153f034231aSEd Maste }
154f034231aSEd Maste }
155f034231aSEd Maste
ToJSON()156e3b55780SDimitry Andric llvm::json::Value PathMappingList::ToJSON() {
157e3b55780SDimitry Andric llvm::json::Array entries;
1587fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
159e3b55780SDimitry Andric for (const auto &pair : m_pairs) {
160e3b55780SDimitry Andric llvm::json::Array entry{pair.first.GetStringRef().str(),
161e3b55780SDimitry Andric pair.second.GetStringRef().str()};
162e3b55780SDimitry Andric entries.emplace_back(std::move(entry));
163e3b55780SDimitry Andric }
164e3b55780SDimitry Andric return entries;
165e3b55780SDimitry Andric }
166e3b55780SDimitry Andric
Clear(bool notify)16714f1b3e8SDimitry Andric void PathMappingList::Clear(bool notify) {
1687fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
169f034231aSEd Maste if (!m_pairs.empty())
170f034231aSEd Maste ++m_mod_id;
171f034231aSEd Maste m_pairs.clear();
172f034231aSEd Maste if (notify && m_callback)
173f034231aSEd Maste m_callback(*this, m_callback_baton);
174f034231aSEd Maste }
175f034231aSEd Maste
RemapPath(ConstString path,ConstString & new_path) const1765f29bb8aSDimitry Andric bool PathMappingList::RemapPath(ConstString path,
17714f1b3e8SDimitry Andric ConstString &new_path) const {
178e3b55780SDimitry Andric if (std::optional<FileSpec> remapped = RemapPath(path.GetStringRef())) {
179344a3780SDimitry Andric new_path.SetString(remapped->GetPath());
180f034231aSEd Maste return true;
181f034231aSEd Maste }
182f034231aSEd Maste return false;
183f034231aSEd Maste }
184f034231aSEd Maste
185344a3780SDimitry Andric /// Append components to path, applying style.
AppendPathComponents(FileSpec & path,llvm::StringRef components,llvm::sys::path::Style style)186344a3780SDimitry Andric static void AppendPathComponents(FileSpec &path, llvm::StringRef components,
187344a3780SDimitry Andric llvm::sys::path::Style style) {
188344a3780SDimitry Andric auto component = llvm::sys::path::begin(components, style);
189344a3780SDimitry Andric auto e = llvm::sys::path::end(components);
190344a3780SDimitry Andric while (component != e &&
191344a3780SDimitry Andric llvm::sys::path::is_separator(*component->data(), style))
192344a3780SDimitry Andric ++component;
193344a3780SDimitry Andric for (; component != e; ++component)
194344a3780SDimitry Andric path.AppendPathComponent(*component);
195344a3780SDimitry Andric }
196344a3780SDimitry Andric
RemapPath(llvm::StringRef mapping_path,bool only_if_exists) const197e3b55780SDimitry Andric std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path,
198344a3780SDimitry Andric bool only_if_exists) const {
1997fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
200344a3780SDimitry Andric if (m_pairs.empty() || mapping_path.empty())
201344a3780SDimitry Andric return {};
202f73363f1SDimitry Andric LazyBool path_is_relative = eLazyBoolCalculate;
203344a3780SDimitry Andric
20414f1b3e8SDimitry Andric for (const auto &it : m_pairs) {
205344a3780SDimitry Andric llvm::StringRef prefix = it.first.GetStringRef();
206344a3780SDimitry Andric // We create a copy of mapping_path because StringRef::consume_from
207344a3780SDimitry Andric // effectively modifies the instance itself.
208344a3780SDimitry Andric llvm::StringRef path = mapping_path;
209f73363f1SDimitry Andric if (!path.consume_front(prefix)) {
210f73363f1SDimitry Andric // Relative paths won't have a leading "./" in them unless "." is the
211f73363f1SDimitry Andric // only thing in the relative path so we need to work around "."
212f73363f1SDimitry Andric // carefully.
213f73363f1SDimitry Andric if (prefix != ".")
214f73363f1SDimitry Andric continue;
215f73363f1SDimitry Andric // We need to figure out if the "path" argument is relative. If it is,
216f73363f1SDimitry Andric // then we should remap, else skip this entry.
217f73363f1SDimitry Andric if (path_is_relative == eLazyBoolCalculate) {
21894994d37SDimitry Andric path_is_relative =
21994994d37SDimitry Andric FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo;
220f73363f1SDimitry Andric }
221f73363f1SDimitry Andric if (!path_is_relative)
222f73363f1SDimitry Andric continue;
223f73363f1SDimitry Andric }
22494994d37SDimitry Andric FileSpec remapped(it.second.GetStringRef());
225145449b1SDimitry Andric auto orig_style = FileSpec::GuessPathStyle(prefix).value_or(
226344a3780SDimitry Andric llvm::sys::path::Style::native);
227344a3780SDimitry Andric AppendPathComponents(remapped, path, orig_style);
228344a3780SDimitry Andric if (!only_if_exists || FileSystem::Instance().Exists(remapped))
229344a3780SDimitry Andric return remapped;
230f3fbd1c0SDimitry Andric }
231344a3780SDimitry Andric return {};
232f73363f1SDimitry Andric }
233f73363f1SDimitry Andric
234e3b55780SDimitry Andric std::optional<llvm::StringRef>
ReverseRemapPath(const FileSpec & file,FileSpec & fixed) const235e3b55780SDimitry Andric PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
236f73363f1SDimitry Andric std::string path = file.GetPath();
237f73363f1SDimitry Andric llvm::StringRef path_ref(path);
2387fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
239f73363f1SDimitry Andric for (const auto &it : m_pairs) {
240e3b55780SDimitry Andric llvm::StringRef removed_prefix = it.second.GetStringRef();
241f73363f1SDimitry Andric if (!path_ref.consume_front(it.second.GetStringRef()))
242f73363f1SDimitry Andric continue;
243344a3780SDimitry Andric auto orig_file = it.first.GetStringRef();
244145449b1SDimitry Andric auto orig_style = FileSpec::GuessPathStyle(orig_file).value_or(
245344a3780SDimitry Andric llvm::sys::path::Style::native);
246344a3780SDimitry Andric fixed.SetFile(orig_file, orig_style);
247344a3780SDimitry Andric AppendPathComponents(fixed, path_ref, orig_style);
248e3b55780SDimitry Andric return removed_prefix;
249f3fbd1c0SDimitry Andric }
250e3b55780SDimitry Andric return std::nullopt;
251f3fbd1c0SDimitry Andric }
252f3fbd1c0SDimitry Andric
253e3b55780SDimitry Andric std::optional<FileSpec>
FindFile(const FileSpec & orig_spec) const254e3b55780SDimitry Andric PathMappingList::FindFile(const FileSpec &orig_spec) const {
255c0981da4SDimitry Andric // We must normalize the orig_spec again using the host's path style,
256c0981da4SDimitry Andric // otherwise there will be mismatch between the host and remote platform
257c0981da4SDimitry Andric // if they use different path styles.
258c0981da4SDimitry Andric if (auto remapped = RemapPath(NormalizePath(orig_spec.GetPath()),
259c0981da4SDimitry Andric /*only_if_exists=*/true))
260344a3780SDimitry Andric return remapped;
261f034231aSEd Maste
262344a3780SDimitry Andric return {};
263f034231aSEd Maste }
264f034231aSEd Maste
Replace(llvm::StringRef path,llvm::StringRef new_path,bool notify)265c0981da4SDimitry Andric bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path,
266c0981da4SDimitry Andric bool notify) {
2677fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
268f034231aSEd Maste uint32_t idx = FindIndexForPath(path);
26914f1b3e8SDimitry Andric if (idx < m_pairs.size()) {
270f034231aSEd Maste ++m_mod_id;
271c0981da4SDimitry Andric m_pairs[idx].second = ConstString(new_path);
272f034231aSEd Maste if (notify && m_callback)
273f034231aSEd Maste m_callback(*this, m_callback_baton);
274f034231aSEd Maste return true;
275f034231aSEd Maste }
276f034231aSEd Maste return false;
277f034231aSEd Maste }
278f034231aSEd Maste
Remove(ConstString path,bool notify)2795f29bb8aSDimitry Andric bool PathMappingList::Remove(ConstString path, bool notify) {
2807fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
281f034231aSEd Maste iterator pos = FindIteratorForPath(path);
28214f1b3e8SDimitry Andric if (pos != m_pairs.end()) {
283f034231aSEd Maste ++m_mod_id;
284f034231aSEd Maste m_pairs.erase(pos);
285f034231aSEd Maste if (notify && m_callback)
286f034231aSEd Maste m_callback(*this, m_callback_baton);
287f034231aSEd Maste return true;
288f034231aSEd Maste }
289f034231aSEd Maste return false;
290f034231aSEd Maste }
291f034231aSEd Maste
292f034231aSEd Maste PathMappingList::const_iterator
FindIteratorForPath(ConstString path) const2935f29bb8aSDimitry Andric PathMappingList::FindIteratorForPath(ConstString path) const {
2947fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
295f034231aSEd Maste const_iterator pos;
296f034231aSEd Maste const_iterator begin = m_pairs.begin();
297f034231aSEd Maste const_iterator end = m_pairs.end();
298f034231aSEd Maste
29914f1b3e8SDimitry Andric for (pos = begin; pos != end; ++pos) {
300f034231aSEd Maste if (pos->first == path)
301f034231aSEd Maste break;
302f034231aSEd Maste }
303f034231aSEd Maste return pos;
304f034231aSEd Maste }
305f034231aSEd Maste
306f034231aSEd Maste PathMappingList::iterator
FindIteratorForPath(ConstString path)3075f29bb8aSDimitry Andric PathMappingList::FindIteratorForPath(ConstString path) {
3087fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
309f034231aSEd Maste iterator pos;
310f034231aSEd Maste iterator begin = m_pairs.begin();
311f034231aSEd Maste iterator end = m_pairs.end();
312f034231aSEd Maste
31314f1b3e8SDimitry Andric for (pos = begin; pos != end; ++pos) {
314f034231aSEd Maste if (pos->first == path)
315f034231aSEd Maste break;
316f034231aSEd Maste }
317f034231aSEd Maste return pos;
318f034231aSEd Maste }
319f034231aSEd Maste
GetPathsAtIndex(uint32_t idx,ConstString & path,ConstString & new_path) const32014f1b3e8SDimitry Andric bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
32114f1b3e8SDimitry Andric ConstString &new_path) const {
3227fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
32314f1b3e8SDimitry Andric if (idx < m_pairs.size()) {
324f034231aSEd Maste path = m_pairs[idx].first;
325f034231aSEd Maste new_path = m_pairs[idx].second;
326f034231aSEd Maste return true;
327f034231aSEd Maste }
328f034231aSEd Maste return false;
329f034231aSEd Maste }
330f034231aSEd Maste
FindIndexForPath(llvm::StringRef orig_path) const331c0981da4SDimitry Andric uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const {
332c0981da4SDimitry Andric const ConstString path = ConstString(NormalizePath(orig_path));
3337fa27ce4SDimitry Andric std::lock_guard<std::recursive_mutex> lock(m_mutex);
334f034231aSEd Maste const_iterator pos;
335f034231aSEd Maste const_iterator begin = m_pairs.begin();
336f034231aSEd Maste const_iterator end = m_pairs.end();
337f034231aSEd Maste
33814f1b3e8SDimitry Andric for (pos = begin; pos != end; ++pos) {
339f034231aSEd Maste if (pos->first == path)
340f034231aSEd Maste return std::distance(begin, pos);
341f034231aSEd Maste }
342f034231aSEd Maste return UINT32_MAX;
343f034231aSEd Maste }
344