blob: 2b9ebf305c1d12f6c5e2062d0f2c99774cc9f75c [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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// C Includes
11// C++ Includes
Eugene Zelenko9394d7722016-02-18 00:10:17 +000012#include <climits>
13#include <cstring>
14
Chris Lattner30fdc8d2010-06-08 16:52:24 +000015// Other libraries and framework includes
Greg Claytond804d282012-03-15 21:01:31 +000016// Project includes
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +000017#include "lldb/Host/FileSystem.h"
Zachary Turnerf343968f2016-08-09 23:06:08 +000018#include "lldb/Host/PosixApi.h"
Eli Friedman48862d42010-06-09 09:32:42 +000019#include "lldb/Target/PathMappingList.h"
Zachary Turner5713a052017-03-22 18:40:07 +000020#include "lldb/Utility/FileSpec.h"
Zachary Turner97206d52017-05-12 04:51:55 +000021#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000022#include "lldb/Utility/Stream.h"
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +000023#include "lldb/lldb-private-enumerations.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024
25using namespace lldb;
26using namespace lldb_private;
27
Greg Clayton86188d82018-05-21 14:14:36 +000028namespace {
29 // We must normalize our path pairs that we store because if we don't then
30 // things won't always work. We found a case where if we did:
31 // (lldb) settings set target.source-map . /tmp
32 // We would store a path pairs of "." and "/tmp" as raw strings. If the debug
33 // info contains "./foo/bar.c", the path will get normalized to "foo/bar.c".
34 // When PathMappingList::RemapPath() is called, it expects the path to start
35 // with the raw path pair, which doesn't work anymore because the paths have
36 // been normalized when the debug info was loaded. So we need to store
37 // nomalized path pairs to ensure things match up.
38 ConstString NormalizePath(const ConstString &path) {
39 // If we use "path" to construct a FileSpec, it will normalize the path for
40 // us. We then grab the string and turn it back into a ConstString.
41 return ConstString(FileSpec(path.GetStringRef(), false).GetPath());
42 }
43}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044//----------------------------------------------------------------------
45// PathMappingList constructor
46//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000047PathMappingList::PathMappingList()
48 : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {}
Greg Claytond804d282012-03-15 21:01:31 +000049
Kate Stoneb9c1b512016-09-06 20:57:50 +000050PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
51 : m_pairs(), m_callback(callback), m_callback_baton(callback_baton),
52 m_mod_id(0) {}
Chris Lattner30fdc8d2010-06-08 16:52:24 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054PathMappingList::PathMappingList(const PathMappingList &rhs)
55 : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr),
56 m_mod_id(0) {}
Greg Clayton7e14f912011-04-23 02:04:55 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
59 if (this != &rhs) {
60 m_pairs = rhs.m_pairs;
61 m_callback = nullptr;
62 m_callback_baton = nullptr;
63 m_mod_id = rhs.m_mod_id;
64 }
65 return *this;
Greg Clayton7e14f912011-04-23 02:04:55 +000066}
67
Eugene Zelenko9394d7722016-02-18 00:10:17 +000068PathMappingList::~PathMappingList() = default;
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069
Kate Stoneb9c1b512016-09-06 20:57:50 +000070void PathMappingList::Append(const ConstString &path,
71 const ConstString &replacement, bool notify) {
72 ++m_mod_id;
Greg Clayton86188d82018-05-21 14:14:36 +000073 m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 if (notify && m_callback)
75 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000076}
77
Kate Stoneb9c1b512016-09-06 20:57:50 +000078void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
79 ++m_mod_id;
80 if (!rhs.m_pairs.empty()) {
81 const_iterator pos, end = rhs.m_pairs.end();
82 for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
83 m_pairs.push_back(*pos);
84 if (notify && m_callback)
85 m_callback(*this, m_callback_baton);
86 }
Greg Claytond804d282012-03-15 21:01:31 +000087}
88
Kate Stoneb9c1b512016-09-06 20:57:50 +000089void PathMappingList::Insert(const ConstString &path,
90 const ConstString &replacement, uint32_t index,
91 bool notify) {
92 ++m_mod_id;
93 iterator insert_iter;
94 if (index >= m_pairs.size())
95 insert_iter = m_pairs.end();
96 else
97 insert_iter = m_pairs.begin() + index;
Greg Clayton86188d82018-05-21 14:14:36 +000098 m_pairs.emplace(insert_iter, pair(NormalizePath(path),
99 NormalizePath(replacement)));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100 if (notify && m_callback)
101 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000102}
103
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104bool PathMappingList::Replace(const ConstString &path,
105 const ConstString &replacement, uint32_t index,
106 bool notify) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 if (index >= m_pairs.size())
108 return false;
109 ++m_mod_id;
Greg Clayton86188d82018-05-21 14:14:36 +0000110 m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 if (notify && m_callback)
112 m_callback(*this, m_callback_baton);
113 return true;
Greg Clayton67cc0632012-08-22 17:17:09 +0000114}
115
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116bool PathMappingList::Remove(size_t index, bool notify) {
117 if (index >= m_pairs.size())
118 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000119
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 ++m_mod_id;
121 iterator iter = m_pairs.begin() + index;
122 m_pairs.erase(iter);
123 if (notify && m_callback)
124 m_callback(*this, m_callback_baton);
125 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000126}
127
Johnny Chen64bab482011-12-12 21:59:28 +0000128// For clients which do not need the pair index dumped, pass a pair_index >= 0
129// to only dump the indicated pair.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130void PathMappingList::Dump(Stream *s, int pair_index) {
131 unsigned int numPairs = m_pairs.size();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133 if (pair_index < 0) {
134 unsigned int index;
135 for (index = 0; index < numPairs; ++index)
136 s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
137 m_pairs[index].first.GetCString(),
138 m_pairs[index].second.GetCString());
139 } else {
140 if (static_cast<unsigned int>(pair_index) < numPairs)
141 s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
142 m_pairs[pair_index].second.GetCString());
143 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000144}
145
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146void PathMappingList::Clear(bool notify) {
147 if (!m_pairs.empty())
148 ++m_mod_id;
149 m_pairs.clear();
150 if (notify && m_callback)
151 m_callback(*this, m_callback_baton);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152}
153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154bool PathMappingList::RemapPath(const ConstString &path,
155 ConstString &new_path) const {
Greg Clayton86188d82018-05-21 14:14:36 +0000156 std::string remapped;
157 if (RemapPath(path.GetStringRef(), remapped)) {
158 new_path.SetString(remapped);
159 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 }
161 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000162}
Greg Clayton7e14f912011-04-23 02:04:55 +0000163
Zachary Turnera498f0e2016-09-23 18:42:38 +0000164bool PathMappingList::RemapPath(llvm::StringRef path,
165 std::string &new_path) const {
166 if (m_pairs.empty() || path.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 return false;
Greg Clayton86188d82018-05-21 14:14:36 +0000168 LazyBool path_is_relative = eLazyBoolCalculate;
169 for (const auto &it : m_pairs) {
170 auto prefix = it.first.GetStringRef();
171 if (!path.consume_front(prefix)) {
172 // Relative paths won't have a leading "./" in them unless "." is the
173 // only thing in the relative path so we need to work around "."
174 // carefully.
175 if (prefix != ".")
176 continue;
177 // We need to figure out if the "path" argument is relative. If it is,
178 // then we should remap, else skip this entry.
179 if (path_is_relative == eLazyBoolCalculate) {
180 path_is_relative = FileSpec(path, false).IsRelative() ? eLazyBoolYes :
181 eLazyBoolNo;
182 }
183 if (!path_is_relative)
184 continue;
185 }
186 FileSpec remapped(it.second.GetStringRef(), false);
187 remapped.AppendPathComponent(path);
188 new_path = remapped.GetPath();
Zachary Turnera498f0e2016-09-23 18:42:38 +0000189 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 }
191 return false;
192}
193
Greg Clayton86188d82018-05-21 14:14:36 +0000194bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
195 std::string path = file.GetPath();
196 llvm::StringRef path_ref(path);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000197 for (const auto &it : m_pairs) {
Greg Clayton86188d82018-05-21 14:14:36 +0000198 if (!path_ref.consume_front(it.second.GetStringRef()))
199 continue;
Jonas Devlieghere937348c2018-06-13 22:08:14 +0000200 fixed.SetFile(it.first.GetStringRef(), false, FileSpec::Style::native);
Greg Clayton86188d82018-05-21 14:14:36 +0000201 fixed.AppendPathComponent(path_ref);
202 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 }
204 return false;
205}
206
207bool PathMappingList::FindFile(const FileSpec &orig_spec,
208 FileSpec &new_spec) const {
209 if (!m_pairs.empty()) {
210 char orig_path[PATH_MAX];
211 const size_t orig_path_len =
212 orig_spec.GetPath(orig_path, sizeof(orig_path));
213 if (orig_path_len > 0) {
214 const_iterator pos, end = m_pairs.end();
215 for (pos = m_pairs.begin(); pos != end; ++pos) {
Greg Claytonf9be6932012-03-19 22:22:41 +0000216 const size_t prefix_len = pos->first.GetLength();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217
218 if (orig_path_len >= prefix_len) {
219 if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) {
Jonas Devlieghere937348c2018-06-13 22:08:14 +0000220 new_spec.SetFile(pos->second.GetCString(), false,
221 FileSpec::Style::native);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000222 new_spec.AppendPathComponent(orig_path + prefix_len);
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +0000223 if (FileSystem::Instance().Exists(new_spec))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 return true;
225 }
Greg Claytonf9be6932012-03-19 22:22:41 +0000226 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227 }
Greg Claytonf9be6932012-03-19 22:22:41 +0000228 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229 }
230 new_spec.Clear();
231 return false;
Greg Claytonf9be6932012-03-19 22:22:41 +0000232}
233
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234bool PathMappingList::Replace(const ConstString &path,
235 const ConstString &new_path, bool notify) {
236 uint32_t idx = FindIndexForPath(path);
237 if (idx < m_pairs.size()) {
238 ++m_mod_id;
239 m_pairs[idx].second = new_path;
240 if (notify && m_callback)
241 m_callback(*this, m_callback_baton);
242 return true;
243 }
244 return false;
Tamas Berghammerb0b1ea32016-03-04 11:26:44 +0000245}
246
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247bool PathMappingList::Remove(const ConstString &path, bool notify) {
248 iterator pos = FindIteratorForPath(path);
249 if (pos != m_pairs.end()) {
250 ++m_mod_id;
251 m_pairs.erase(pos);
252 if (notify && m_callback)
253 m_callback(*this, m_callback_baton);
254 return true;
255 }
256 return false;
Greg Clayton7e14f912011-04-23 02:04:55 +0000257}
258
259PathMappingList::const_iterator
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260PathMappingList::FindIteratorForPath(const ConstString &path) const {
261 const_iterator pos;
262 const_iterator begin = m_pairs.begin();
263 const_iterator end = m_pairs.end();
264
265 for (pos = begin; pos != end; ++pos) {
266 if (pos->first == path)
267 break;
268 }
269 return pos;
Greg Clayton7e14f912011-04-23 02:04:55 +0000270}
271
272PathMappingList::iterator
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273PathMappingList::FindIteratorForPath(const ConstString &path) {
274 iterator pos;
275 iterator begin = m_pairs.begin();
276 iterator end = m_pairs.end();
277
278 for (pos = begin; pos != end; ++pos) {
279 if (pos->first == path)
280 break;
281 }
282 return pos;
Greg Clayton7e14f912011-04-23 02:04:55 +0000283}
284
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
286 ConstString &new_path) const {
287 if (idx < m_pairs.size()) {
288 path = m_pairs[idx].first;
289 new_path = m_pairs[idx].second;
290 return true;
291 }
292 return false;
Greg Clayton7e14f912011-04-23 02:04:55 +0000293}
294
Greg Clayton86188d82018-05-21 14:14:36 +0000295uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const {
296 const ConstString path = NormalizePath(orig_path);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000297 const_iterator pos;
298 const_iterator begin = m_pairs.begin();
299 const_iterator end = m_pairs.end();
300
301 for (pos = begin; pos != end; ++pos) {
302 if (pos->first == path)
303 return std::distance(begin, pos);
304 }
305 return UINT32_MAX;
Greg Clayton7e14f912011-04-23 02:04:55 +0000306}