LLDB  mainline
PathMappingList.cpp
Go to the documentation of this file.
1 //===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <climits>
10 #include <cstring>
11 
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Host/PosixApi.h"
15 #include "lldb/Utility/FileSpec.h"
16 #include "lldb/Utility/Status.h"
17 #include "lldb/Utility/Stream.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 namespace {
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(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.
36  return ConstString(FileSpec(path.GetStringRef()).GetPath());
37  }
38 }
39 // PathMappingList constructor
40 PathMappingList::PathMappingList()
41  : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {}
42 
43 PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
44  : m_pairs(), m_callback(callback), m_callback_baton(callback_baton),
45  m_mod_id(0) {}
46 
48  : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr),
49  m_mod_id(0) {}
50 
52  if (this != &rhs) {
53  m_pairs = rhs.m_pairs;
54  m_callback = nullptr;
55  m_callback_baton = nullptr;
56  m_mod_id = rhs.m_mod_id;
57  }
58  return *this;
59 }
60 
62 
64  ConstString replacement, bool notify) {
65  ++m_mod_id;
66  m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
67  if (notify && m_callback)
69 }
70 
71 void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
72  ++m_mod_id;
73  if (!rhs.m_pairs.empty()) {
74  const_iterator pos, end = rhs.m_pairs.end();
75  for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
76  m_pairs.push_back(*pos);
77  if (notify && m_callback)
79  }
80 }
81 
83  ConstString replacement, uint32_t index,
84  bool notify) {
85  ++m_mod_id;
86  iterator insert_iter;
87  if (index >= m_pairs.size())
88  insert_iter = m_pairs.end();
89  else
90  insert_iter = m_pairs.begin() + index;
91  m_pairs.emplace(insert_iter, pair(NormalizePath(path),
92  NormalizePath(replacement)));
93  if (notify && m_callback)
95 }
96 
98  ConstString replacement, uint32_t index,
99  bool notify) {
100  if (index >= m_pairs.size())
101  return false;
102  ++m_mod_id;
103  m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
104  if (notify && m_callback)
106  return true;
107 }
108 
109 bool PathMappingList::Remove(size_t index, bool notify) {
110  if (index >= m_pairs.size())
111  return false;
112 
113  ++m_mod_id;
114  iterator iter = m_pairs.begin() + index;
115  m_pairs.erase(iter);
116  if (notify && m_callback)
118  return true;
119 }
120 
121 // For clients which do not need the pair index dumped, pass a pair_index >= 0
122 // to only dump the indicated pair.
123 void PathMappingList::Dump(Stream *s, int pair_index) {
124  unsigned int numPairs = m_pairs.size();
125 
126  if (pair_index < 0) {
127  unsigned int index;
128  for (index = 0; index < numPairs; ++index)
129  s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
130  m_pairs[index].first.GetCString(),
131  m_pairs[index].second.GetCString());
132  } else {
133  if (static_cast<unsigned int>(pair_index) < numPairs)
134  s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
135  m_pairs[pair_index].second.GetCString());
136  }
137 }
138 
139 void PathMappingList::Clear(bool notify) {
140  if (!m_pairs.empty())
141  ++m_mod_id;
142  m_pairs.clear();
143  if (notify && m_callback)
145 }
146 
148  ConstString &new_path) const {
149  std::string remapped;
150  if (RemapPath(path.GetStringRef(), remapped)) {
151  new_path.SetString(remapped);
152  return true;
153  }
154  return false;
155 }
156 
157 bool PathMappingList::RemapPath(llvm::StringRef path,
158  std::string &new_path) const {
159  if (m_pairs.empty() || path.empty())
160  return false;
161  LazyBool path_is_relative = eLazyBoolCalculate;
162  for (const auto &it : m_pairs) {
163  auto prefix = it.first.GetStringRef();
164  if (!path.consume_front(prefix)) {
165  // Relative paths won't have a leading "./" in them unless "." is the
166  // only thing in the relative path so we need to work around "."
167  // carefully.
168  if (prefix != ".")
169  continue;
170  // We need to figure out if the "path" argument is relative. If it is,
171  // then we should remap, else skip this entry.
172  if (path_is_relative == eLazyBoolCalculate) {
173  path_is_relative =
175  }
176  if (!path_is_relative)
177  continue;
178  }
179  FileSpec remapped(it.second.GetStringRef());
180  remapped.AppendPathComponent(path);
181  new_path = remapped.GetPath();
182  return true;
183  }
184  return false;
185 }
186 
187 bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
188  std::string path = file.GetPath();
189  llvm::StringRef path_ref(path);
190  for (const auto &it : m_pairs) {
191  if (!path_ref.consume_front(it.second.GetStringRef()))
192  continue;
193  fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native);
194  fixed.AppendPathComponent(path_ref);
195  return true;
196  }
197  return false;
198 }
199 
200 bool PathMappingList::FindFile(const FileSpec &orig_spec,
201  FileSpec &new_spec) const {
202  if (m_pairs.empty())
203  return false;
204 
205  std::string orig_path = orig_spec.GetPath();
206 
207  if (orig_path.empty())
208  return false;
209 
210  bool orig_is_relative = orig_spec.IsRelative();
211 
212  for (auto entry : m_pairs) {
213  llvm::StringRef orig_ref(orig_path);
214  llvm::StringRef prefix_ref = entry.first.GetStringRef();
215  if (orig_ref.size() < prefix_ref.size())
216  continue;
217  // We consider a relative prefix or one of just "." to
218  // mean "only apply to relative paths".
219  bool prefix_is_relative = false;
220 
221  if (prefix_ref == ".") {
222  prefix_is_relative = true;
223  // Remove the "." since it will have been removed from the
224  // FileSpec paths already.
225  prefix_ref = prefix_ref.drop_front();
226  } else {
227  FileSpec prefix_spec(prefix_ref, FileSpec::Style::native);
228  prefix_is_relative = prefix_spec.IsRelative();
229  }
230  if (prefix_is_relative != orig_is_relative)
231  continue;
232 
233  if (orig_ref.consume_front(prefix_ref)) {
234  new_spec.SetFile(entry.second.GetCString(), FileSpec::Style::native);
235  new_spec.AppendPathComponent(orig_ref);
236  if (FileSystem::Instance().Exists(new_spec))
237  return true;
238  }
239  }
240 
241  new_spec.Clear();
242  return false;
243 }
244 
246  ConstString new_path, bool notify) {
247  uint32_t idx = FindIndexForPath(path);
248  if (idx < m_pairs.size()) {
249  ++m_mod_id;
250  m_pairs[idx].second = new_path;
251  if (notify && m_callback)
253  return true;
254  }
255  return false;
256 }
257 
258 bool PathMappingList::Remove(ConstString path, bool notify) {
259  iterator pos = FindIteratorForPath(path);
260  if (pos != m_pairs.end()) {
261  ++m_mod_id;
262  m_pairs.erase(pos);
263  if (notify && m_callback)
265  return true;
266  }
267  return false;
268 }
269 
272  const_iterator pos;
273  const_iterator begin = m_pairs.begin();
274  const_iterator end = m_pairs.end();
275 
276  for (pos = begin; pos != end; ++pos) {
277  if (pos->first == path)
278  break;
279  }
280  return pos;
281 }
282 
285  iterator pos;
286  iterator begin = m_pairs.begin();
287  iterator end = m_pairs.end();
288 
289  for (pos = begin; pos != end; ++pos) {
290  if (pos->first == path)
291  break;
292  }
293  return pos;
294 }
295 
297  ConstString &new_path) const {
298  if (idx < m_pairs.size()) {
299  path = m_pairs[idx].first;
300  new_path = m_pairs[idx].second;
301  return true;
302  }
303  return false;
304 }
305 
307  const ConstString path = NormalizePath(orig_path);
308  const_iterator pos;
309  const_iterator begin = m_pairs.begin();
310  const_iterator end = m_pairs.end();
311 
312  for (pos = begin; pos != end; ++pos) {
313  if (pos->first == path)
314  return std::distance(begin, pos);
315  }
316  return UINT32_MAX;
317 }
collection::iterator iterator
void Dump(Stream *s, int pair_index=-1)
void SetString(const llvm::StringRef &s)
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
bool FindFile(const FileSpec &orig_spec, FileSpec &new_spec) const
Finds a source file given a file spec using the path remappings.
const PathMappingList & operator=(const PathMappingList &rhs)
A file utility class.
Definition: FileSpec.h:55
void Clear()
Clears the object state.
Definition: FileSpec.cpp:285
iterator FindIteratorForPath(ConstString path)
static FileSystem & Instance()
void(* ChangedCallback)(const PathMappingList &path_list, void *baton)
collection::const_iterator const_iterator
#define UINT32_MAX
Definition: lldb-defines.h:31
void AppendPathComponent(llvm::StringRef component)
Definition: FileSpec.cpp:463
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:233
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
void Append(ConstString path, ConstString replacement, bool notify)
bool RemapPath(ConstString path, ConstString &new_path) const
std::pair< ConstString, ConstString > pair
bool Replace(ConstString path, ConstString replacement, bool notify)
void Insert(ConstString path, ConstString replacement, uint32_t insert_idx, bool notify)
uint32_t FindIndexForPath(ConstString path) const
bool Remove(size_t index, bool notify)
A uniqued constant string class.
Definition: ConstString.h:38
bool ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const
Definition: SBAddress.h:15
bool IsRelative() const
Returns true if the filespec represents a relative path.
Definition: FileSpec.cpp:503
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:198
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
bool GetPathsAtIndex(uint32_t idx, ConstString &path, ConstString &new_path) const