blob: d395f8da78cdcca6323dadd15217f1934e2ac34c [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8
Eugene Zelenko9394d7722016-02-18 00:10:17 +00009#include <climits>
10#include <cstring>
11
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +000012#include "lldb/Host/FileSystem.h"
Zachary Turnerf343968f2016-08-09 23:06:08 +000013#include "lldb/Host/PosixApi.h"
Eli Friedman48862d42010-06-09 09:32:42 +000014#include "lldb/Target/PathMappingList.h"
Zachary Turner5713a052017-03-22 18:40:07 +000015#include "lldb/Utility/FileSpec.h"
Zachary Turner97206d52017-05-12 04:51:55 +000016#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000017#include "lldb/Utility/Stream.h"
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +000018#include "lldb/lldb-private-enumerations.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000019
20using namespace lldb;
21using namespace lldb_private;
22
Greg Clayton86188d82018-05-21 14:14:36 +000023namespace {
24 // We must normalize our path pairs that we store because if we don't then
25 // things won't always work. We found a case where if we did:
26 // (lldb) settings set target.source-map . /tmp
27 // We would store a path pairs of "." and "/tmp" as raw strings. If the debug
28 // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c".
29 // When PathMappingList::RemapPath() is called, it expects the path to start
30 // with the raw path pair, which doesn't work anymore because the paths have
31 // been normalized when the debug info was loaded. So we need to store
32 // nomalized path pairs to ensure things match up.
33 ConstString NormalizePath(const ConstString &path) {
34 // If we use "path" to construct a FileSpec, it will normalize the path for
35 // us. We then grab the string and turn it back into a ConstString.
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +000036 return ConstString(FileSpec(path.GetStringRef()).GetPath());
Greg Clayton86188d82018-05-21 14:14:36 +000037 }
38}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000039//----------------------------------------------------------------------
40// PathMappingList constructor
41//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000042PathMappingList::PathMappingList()
43 : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {}
Greg Claytond804d282012-03-15 21:01:31 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
46 : m_pairs(), m_callback(callback), m_callback_baton(callback_baton),
47 m_mod_id(0) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049PathMappingList::PathMappingList(const PathMappingList &rhs)
50 : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr),
51 m_mod_id(0) {}
Greg Clayton7e14f912011-04-23 02:04:55 +000052
Kate Stoneb9c1b512016-09-06 20:57:50 +000053const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
54 if (this != &rhs) {
55 m_pairs = rhs.m_pairs;
56 m_callback = nullptr;
57 m_callback_baton = nullptr;
58 m_mod_id = rhs.m_mod_id;
59 }
60 return *this;
Greg Clayton7e14f912011-04-23 02:04:55 +000061}
62
Eugene Zelenko9394d7722016-02-18 00:10:17 +000063PathMappingList::~PathMappingList() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065void PathMappingList::Append(const ConstString &path,
66 const ConstString &replacement, bool notify) {
67 ++m_mod_id;
Greg Clayton86188d82018-05-21 14:14:36 +000068 m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 if (notify && m_callback)
70 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000071}
72
Kate Stoneb9c1b512016-09-06 20:57:50 +000073void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
74 ++m_mod_id;
75 if (!rhs.m_pairs.empty()) {
76 const_iterator pos, end = rhs.m_pairs.end();
77 for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
78 m_pairs.push_back(*pos);
79 if (notify && m_callback)
80 m_callback(*this, m_callback_baton);
81 }
Greg Claytond804d282012-03-15 21:01:31 +000082}
83
Kate Stoneb9c1b512016-09-06 20:57:50 +000084void PathMappingList::Insert(const ConstString &path,
85 const ConstString &replacement, uint32_t index,
86 bool notify) {
87 ++m_mod_id;
88 iterator insert_iter;
89 if (index >= m_pairs.size())
90 insert_iter = m_pairs.end();
91 else
92 insert_iter = m_pairs.begin() + index;
Greg Clayton86188d82018-05-21 14:14:36 +000093 m_pairs.emplace(insert_iter, pair(NormalizePath(path),
94 NormalizePath(replacement)));
Kate Stoneb9c1b512016-09-06 20:57:50 +000095 if (notify && m_callback)
96 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000097}
98
Kate Stoneb9c1b512016-09-06 20:57:50 +000099bool PathMappingList::Replace(const ConstString &path,
100 const ConstString &replacement, uint32_t index,
101 bool notify) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 if (index >= m_pairs.size())
103 return false;
104 ++m_mod_id;
Greg Clayton86188d82018-05-21 14:14:36 +0000105 m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106 if (notify && m_callback)
107 m_callback(*this, m_callback_baton);
108 return true;
Greg Clayton67cc0632012-08-22 17:17:09 +0000109}
110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111bool PathMappingList::Remove(size_t index, bool notify) {
112 if (index >= m_pairs.size())
113 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115 ++m_mod_id;
116 iterator iter = m_pairs.begin() + index;
117 m_pairs.erase(iter);
118 if (notify && m_callback)
119 m_callback(*this, m_callback_baton);
120 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000121}
122
Johnny Chen64bab482011-12-12 21:59:28 +0000123// For clients which do not need the pair index dumped, pass a pair_index >= 0
124// to only dump the indicated pair.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125void PathMappingList::Dump(Stream *s, int pair_index) {
126 unsigned int numPairs = m_pairs.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 if (pair_index < 0) {
129 unsigned int index;
130 for (index = 0; index < numPairs; ++index)
131 s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
132 m_pairs[index].first.GetCString(),
133 m_pairs[index].second.GetCString());
134 } else {
135 if (static_cast<unsigned int>(pair_index) < numPairs)
136 s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
137 m_pairs[pair_index].second.GetCString());
138 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000139}
140
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141void PathMappingList::Clear(bool notify) {
142 if (!m_pairs.empty())
143 ++m_mod_id;
144 m_pairs.clear();
145 if (notify && m_callback)
146 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000147}
148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149bool PathMappingList::RemapPath(const ConstString &path,
150 ConstString &new_path) const {
Greg Clayton86188d82018-05-21 14:14:36 +0000151 std::string remapped;
152 if (RemapPath(path.GetStringRef(), remapped)) {
153 new_path.SetString(remapped);
154 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155 }
156 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000157}
Greg Clayton7e14f912011-04-23 02:04:55 +0000158
Zachary Turnera498f0e2016-09-23 18:42:38 +0000159bool PathMappingList::RemapPath(llvm::StringRef path,
160 std::string &new_path) const {
161 if (m_pairs.empty() || path.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000162 return false;
Greg Clayton86188d82018-05-21 14:14:36 +0000163 LazyBool path_is_relative = eLazyBoolCalculate;
164 for (const auto &it : m_pairs) {
165 auto prefix = it.first.GetStringRef();
166 if (!path.consume_front(prefix)) {
167 // Relative paths won't have a leading "./" in them unless "." is the
168 // only thing in the relative path so we need to work around "."
169 // carefully.
170 if (prefix != ".")
171 continue;
172 // We need to figure out if the "path" argument is relative. If it is,
173 // then we should remap, else skip this entry.
174 if (path_is_relative == eLazyBoolCalculate) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000175 path_is_relative =
176 FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo;
Greg Clayton86188d82018-05-21 14:14:36 +0000177 }
178 if (!path_is_relative)
179 continue;
180 }
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000181 FileSpec remapped(it.second.GetStringRef());
Greg Clayton86188d82018-05-21 14:14:36 +0000182 remapped.AppendPathComponent(path);
183 new_path = remapped.GetPath();
Zachary Turnera498f0e2016-09-23 18:42:38 +0000184 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000185 }
186 return false;
187}
188
Greg Clayton86188d82018-05-21 14:14:36 +0000189bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
190 std::string path = file.GetPath();
191 llvm::StringRef path_ref(path);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000192 for (const auto &it : m_pairs) {
Greg Clayton86188d82018-05-21 14:14:36 +0000193 if (!path_ref.consume_front(it.second.GetStringRef()))
194 continue;
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000195 fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native);
Greg Clayton86188d82018-05-21 14:14:36 +0000196 fixed.AppendPathComponent(path_ref);
197 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000198 }
199 return false;
200}
201
202bool PathMappingList::FindFile(const FileSpec &orig_spec,
203 FileSpec &new_spec) const {
204 if (!m_pairs.empty()) {
205 char orig_path[PATH_MAX];
206 const size_t orig_path_len =
207 orig_spec.GetPath(orig_path, sizeof(orig_path));
208 if (orig_path_len > 0) {
209 const_iterator pos, end = m_pairs.end();
210 for (pos = m_pairs.begin(); pos != end; ++pos) {
Greg Claytonf9be6932012-03-19 22:22:41 +0000211 const size_t prefix_len = pos->first.GetLength();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212
213 if (orig_path_len >= prefix_len) {
214 if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +0000215 new_spec.SetFile(pos->second.GetCString(), FileSpec::Style::native);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000216 new_spec.AppendPathComponent(orig_path + prefix_len);
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +0000217 if (FileSystem::Instance().Exists(new_spec))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 return true;
219 }
Greg Claytonf9be6932012-03-19 22:22:41 +0000220 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000221 }
Greg Claytonf9be6932012-03-19 22:22:41 +0000222 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 }
224 new_spec.Clear();
225 return false;
Greg Claytonf9be6932012-03-19 22:22:41 +0000226}
227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228bool PathMappingList::Replace(const ConstString &path,
229 const ConstString &new_path, bool notify) {
230 uint32_t idx = FindIndexForPath(path);
231 if (idx < m_pairs.size()) {
232 ++m_mod_id;
233 m_pairs[idx].second = new_path;
234 if (notify && m_callback)
235 m_callback(*this, m_callback_baton);
236 return true;
237 }
238 return false;
Tamas Berghammerb0b1ea32016-03-04 11:26:44 +0000239}
240
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241bool PathMappingList::Remove(const ConstString &path, bool notify) {
242 iterator pos = FindIteratorForPath(path);
243 if (pos != m_pairs.end()) {
244 ++m_mod_id;
245 m_pairs.erase(pos);
246 if (notify && m_callback)
247 m_callback(*this, m_callback_baton);
248 return true;
249 }
250 return false;
Greg Clayton7e14f912011-04-23 02:04:55 +0000251}
252
253PathMappingList::const_iterator
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254PathMappingList::FindIteratorForPath(const ConstString &path) const {
255 const_iterator pos;
256 const_iterator begin = m_pairs.begin();
257 const_iterator end = m_pairs.end();
258
259 for (pos = begin; pos != end; ++pos) {
260 if (pos->first == path)
261 break;
262 }
263 return pos;
Greg Clayton7e14f912011-04-23 02:04:55 +0000264}
265
266PathMappingList::iterator
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267PathMappingList::FindIteratorForPath(const ConstString &path) {
268 iterator pos;
269 iterator begin = m_pairs.begin();
270 iterator end = m_pairs.end();
271
272 for (pos = begin; pos != end; ++pos) {
273 if (pos->first == path)
274 break;
275 }
276 return pos;
Greg Clayton7e14f912011-04-23 02:04:55 +0000277}
278
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
280 ConstString &new_path) const {
281 if (idx < m_pairs.size()) {
282 path = m_pairs[idx].first;
283 new_path = m_pairs[idx].second;
284 return true;
285 }
286 return false;
Greg Clayton7e14f912011-04-23 02:04:55 +0000287}
288
Greg Clayton86188d82018-05-21 14:14:36 +0000289uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const {
290 const ConstString path = NormalizePath(orig_path);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291 const_iterator pos;
292 const_iterator begin = m_pairs.begin();
293 const_iterator end = m_pairs.end();
294
295 for (pos = begin; pos != end; ++pos) {
296 if (pos->first == path)
297 return std::distance(begin, pos);
298 }
299 return UINT32_MAX;
Greg Clayton7e14f912011-04-23 02:04:55 +0000300}