Files
clang-p2996/lldb/source/Target/PathMappingList.cpp
Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

301 lines
9.5 KiB
C++

//===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <climits>
#include <cstring>
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Target/PathMappingList.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-private-enumerations.h"
using namespace lldb;
using namespace lldb_private;
namespace {
// We must normalize our path pairs that we store because if we don't then
// things won't always work. We found a case where if we did:
// (lldb) settings set target.source-map . /tmp
// We would store a path pairs of "." and "/tmp" as raw strings. If the debug
// info contains "./foo/bar.c", the path will get normalized to "foo/bar.c".
// When PathMappingList::RemapPath() is called, it expects the path to start
// with the raw path pair, which doesn't work anymore because the paths have
// been normalized when the debug info was loaded. So we need to store
// nomalized path pairs to ensure things match up.
ConstString NormalizePath(const ConstString &path) {
// If we use "path" to construct a FileSpec, it will normalize the path for
// us. We then grab the string and turn it back into a ConstString.
return ConstString(FileSpec(path.GetStringRef()).GetPath());
}
}
//----------------------------------------------------------------------
// PathMappingList constructor
//----------------------------------------------------------------------
PathMappingList::PathMappingList()
: m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {}
PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
: m_pairs(), m_callback(callback), m_callback_baton(callback_baton),
m_mod_id(0) {}
PathMappingList::PathMappingList(const PathMappingList &rhs)
: m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr),
m_mod_id(0) {}
const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
if (this != &rhs) {
m_pairs = rhs.m_pairs;
m_callback = nullptr;
m_callback_baton = nullptr;
m_mod_id = rhs.m_mod_id;
}
return *this;
}
PathMappingList::~PathMappingList() = default;
void PathMappingList::Append(const ConstString &path,
const ConstString &replacement, bool notify) {
++m_mod_id;
m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
++m_mod_id;
if (!rhs.m_pairs.empty()) {
const_iterator pos, end = rhs.m_pairs.end();
for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
m_pairs.push_back(*pos);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
}
void PathMappingList::Insert(const ConstString &path,
const ConstString &replacement, uint32_t index,
bool notify) {
++m_mod_id;
iterator insert_iter;
if (index >= m_pairs.size())
insert_iter = m_pairs.end();
else
insert_iter = m_pairs.begin() + index;
m_pairs.emplace(insert_iter, pair(NormalizePath(path),
NormalizePath(replacement)));
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
bool PathMappingList::Replace(const ConstString &path,
const ConstString &replacement, uint32_t index,
bool notify) {
if (index >= m_pairs.size())
return false;
++m_mod_id;
m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
bool PathMappingList::Remove(size_t index, bool notify) {
if (index >= m_pairs.size())
return false;
++m_mod_id;
iterator iter = m_pairs.begin() + index;
m_pairs.erase(iter);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
// For clients which do not need the pair index dumped, pass a pair_index >= 0
// to only dump the indicated pair.
void PathMappingList::Dump(Stream *s, int pair_index) {
unsigned int numPairs = m_pairs.size();
if (pair_index < 0) {
unsigned int index;
for (index = 0; index < numPairs; ++index)
s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
m_pairs[index].first.GetCString(),
m_pairs[index].second.GetCString());
} else {
if (static_cast<unsigned int>(pair_index) < numPairs)
s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
m_pairs[pair_index].second.GetCString());
}
}
void PathMappingList::Clear(bool notify) {
if (!m_pairs.empty())
++m_mod_id;
m_pairs.clear();
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
bool PathMappingList::RemapPath(const ConstString &path,
ConstString &new_path) const {
std::string remapped;
if (RemapPath(path.GetStringRef(), remapped)) {
new_path.SetString(remapped);
return true;
}
return false;
}
bool PathMappingList::RemapPath(llvm::StringRef path,
std::string &new_path) const {
if (m_pairs.empty() || path.empty())
return false;
LazyBool path_is_relative = eLazyBoolCalculate;
for (const auto &it : m_pairs) {
auto prefix = it.first.GetStringRef();
if (!path.consume_front(prefix)) {
// Relative paths won't have a leading "./" in them unless "." is the
// only thing in the relative path so we need to work around "."
// carefully.
if (prefix != ".")
continue;
// We need to figure out if the "path" argument is relative. If it is,
// then we should remap, else skip this entry.
if (path_is_relative == eLazyBoolCalculate) {
path_is_relative =
FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo;
}
if (!path_is_relative)
continue;
}
FileSpec remapped(it.second.GetStringRef());
remapped.AppendPathComponent(path);
new_path = remapped.GetPath();
return true;
}
return false;
}
bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
std::string path = file.GetPath();
llvm::StringRef path_ref(path);
for (const auto &it : m_pairs) {
if (!path_ref.consume_front(it.second.GetStringRef()))
continue;
fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native);
fixed.AppendPathComponent(path_ref);
return true;
}
return false;
}
bool PathMappingList::FindFile(const FileSpec &orig_spec,
FileSpec &new_spec) const {
if (!m_pairs.empty()) {
char orig_path[PATH_MAX];
const size_t orig_path_len =
orig_spec.GetPath(orig_path, sizeof(orig_path));
if (orig_path_len > 0) {
const_iterator pos, end = m_pairs.end();
for (pos = m_pairs.begin(); pos != end; ++pos) {
const size_t prefix_len = pos->first.GetLength();
if (orig_path_len >= prefix_len) {
if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) {
new_spec.SetFile(pos->second.GetCString(), FileSpec::Style::native);
new_spec.AppendPathComponent(orig_path + prefix_len);
if (FileSystem::Instance().Exists(new_spec))
return true;
}
}
}
}
}
new_spec.Clear();
return false;
}
bool PathMappingList::Replace(const ConstString &path,
const ConstString &new_path, bool notify) {
uint32_t idx = FindIndexForPath(path);
if (idx < m_pairs.size()) {
++m_mod_id;
m_pairs[idx].second = new_path;
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
return false;
}
bool PathMappingList::Remove(const ConstString &path, bool notify) {
iterator pos = FindIteratorForPath(path);
if (pos != m_pairs.end()) {
++m_mod_id;
m_pairs.erase(pos);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
return false;
}
PathMappingList::const_iterator
PathMappingList::FindIteratorForPath(const ConstString &path) const {
const_iterator pos;
const_iterator begin = m_pairs.begin();
const_iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
break;
}
return pos;
}
PathMappingList::iterator
PathMappingList::FindIteratorForPath(const ConstString &path) {
iterator pos;
iterator begin = m_pairs.begin();
iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
break;
}
return pos;
}
bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
ConstString &new_path) const {
if (idx < m_pairs.size()) {
path = m_pairs[idx].first;
new_path = m_pairs[idx].second;
return true;
}
return false;
}
uint32_t PathMappingList::FindIndexForPath(const ConstString &orig_path) const {
const ConstString path = NormalizePath(orig_path);
const_iterator pos;
const_iterator begin = m_pairs.begin();
const_iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
return std::distance(begin, pos);
}
return UINT32_MAX;
}