Path: blob/main/contrib/llvm-project/lldb/source/Target/PathMappingList.cpp
39587 views
//===-- PathMappingList.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <climits>9#include <cstring>10#include <optional>1112#include "lldb/Host/FileSystem.h"13#include "lldb/Host/PosixApi.h"14#include "lldb/Target/PathMappingList.h"15#include "lldb/Utility/FileSpec.h"16#include "lldb/Utility/Status.h"17#include "lldb/Utility/Stream.h"18#include "lldb/lldb-private-enumerations.h"1920using namespace lldb;21using namespace lldb_private;2223namespace {24// We must normalize our path pairs that we store because if we don't then25// things won't always work. We found a case where if we did:26// (lldb) settings set target.source-map . /tmp27// We would store a path pairs of "." and "/tmp" as raw strings. If the debug28// 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 start30// with the raw path pair, which doesn't work anymore because the paths have31// been normalized when the debug info was loaded. So we need to store32// nomalized path pairs to ensure things match up.33std::string NormalizePath(llvm::StringRef path) {34// If we use "path" to construct a FileSpec, it will normalize the path for35// us. We then grab the string.36return FileSpec(path).GetPath();37}38}39// PathMappingList constructor40PathMappingList::PathMappingList() : m_pairs() {}4142PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)43: m_pairs(), m_callback(callback), m_callback_baton(callback_baton) {}4445PathMappingList::PathMappingList(const PathMappingList &rhs)46: m_pairs(rhs.m_pairs) {}4748const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {49if (this != &rhs) {50std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);51m_pairs = rhs.m_pairs;52m_callback = nullptr;53m_callback_baton = nullptr;54m_mod_id = rhs.m_mod_id;55}56return *this;57}5859PathMappingList::~PathMappingList() = default;6061void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,62bool notify) {63std::lock_guard<std::recursive_mutex> lock(m_mutex);64++m_mod_id;65m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));66if (notify && m_callback)67m_callback(*this, m_callback_baton);68}6970void PathMappingList::Append(const PathMappingList &rhs, bool notify) {71std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);72++m_mod_id;73if (!rhs.m_pairs.empty()) {74const_iterator pos, end = rhs.m_pairs.end();75for (pos = rhs.m_pairs.begin(); pos != end; ++pos)76m_pairs.push_back(*pos);77if (notify && m_callback)78m_callback(*this, m_callback_baton);79}80}8182bool PathMappingList::AppendUnique(llvm::StringRef path,83llvm::StringRef replacement, bool notify) {84auto normalized_path = NormalizePath(path);85auto normalized_replacement = NormalizePath(replacement);86std::lock_guard<std::recursive_mutex> lock(m_mutex);87for (const auto &pair : m_pairs) {88if (pair.first.GetStringRef() == normalized_path &&89pair.second.GetStringRef() == normalized_replacement)90return false;91}92Append(path, replacement, notify);93return true;94}9596void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement,97uint32_t index, bool notify) {98std::lock_guard<std::recursive_mutex> lock(m_mutex);99++m_mod_id;100iterator insert_iter;101if (index >= m_pairs.size())102insert_iter = m_pairs.end();103else104insert_iter = m_pairs.begin() + index;105m_pairs.emplace(insert_iter, pair(NormalizePath(path),106NormalizePath(replacement)));107if (notify && m_callback)108m_callback(*this, m_callback_baton);109}110111bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement,112uint32_t index, bool notify) {113std::lock_guard<std::recursive_mutex> lock(m_mutex);114if (index >= m_pairs.size())115return false;116++m_mod_id;117m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));118if (notify && m_callback)119m_callback(*this, m_callback_baton);120return true;121}122123bool PathMappingList::Remove(size_t index, bool notify) {124std::lock_guard<std::recursive_mutex> lock(m_mutex);125if (index >= m_pairs.size())126return false;127128++m_mod_id;129iterator iter = m_pairs.begin() + index;130m_pairs.erase(iter);131if (notify && m_callback)132m_callback(*this, m_callback_baton);133return true;134}135136// For clients which do not need the pair index dumped, pass a pair_index >= 0137// to only dump the indicated pair.138void PathMappingList::Dump(Stream *s, int pair_index) {139std::lock_guard<std::recursive_mutex> lock(m_mutex);140unsigned int numPairs = m_pairs.size();141142if (pair_index < 0) {143unsigned int index;144for (index = 0; index < numPairs; ++index)145s->Printf("[%d] \"%s\" -> \"%s\"\n", index,146m_pairs[index].first.GetCString(),147m_pairs[index].second.GetCString());148} else {149if (static_cast<unsigned int>(pair_index) < numPairs)150s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),151m_pairs[pair_index].second.GetCString());152}153}154155llvm::json::Value PathMappingList::ToJSON() {156llvm::json::Array entries;157std::lock_guard<std::recursive_mutex> lock(m_mutex);158for (const auto &pair : m_pairs) {159llvm::json::Array entry{pair.first.GetStringRef().str(),160pair.second.GetStringRef().str()};161entries.emplace_back(std::move(entry));162}163return entries;164}165166void PathMappingList::Clear(bool notify) {167std::lock_guard<std::recursive_mutex> lock(m_mutex);168if (!m_pairs.empty())169++m_mod_id;170m_pairs.clear();171if (notify && m_callback)172m_callback(*this, m_callback_baton);173}174175bool PathMappingList::RemapPath(ConstString path,176ConstString &new_path) const {177if (std::optional<FileSpec> remapped = RemapPath(path.GetStringRef())) {178new_path.SetString(remapped->GetPath());179return true;180}181return false;182}183184/// Append components to path, applying style.185static void AppendPathComponents(FileSpec &path, llvm::StringRef components,186llvm::sys::path::Style style) {187auto component = llvm::sys::path::begin(components, style);188auto e = llvm::sys::path::end(components);189while (component != e &&190llvm::sys::path::is_separator(*component->data(), style))191++component;192for (; component != e; ++component)193path.AppendPathComponent(*component);194}195196std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path,197bool only_if_exists) const {198std::lock_guard<std::recursive_mutex> lock(m_mutex);199if (m_pairs.empty() || mapping_path.empty())200return {};201LazyBool path_is_relative = eLazyBoolCalculate;202203for (const auto &it : m_pairs) {204llvm::StringRef prefix = it.first.GetStringRef();205// We create a copy of mapping_path because StringRef::consume_from206// effectively modifies the instance itself.207llvm::StringRef path = mapping_path;208if (!path.consume_front(prefix)) {209// Relative paths won't have a leading "./" in them unless "." is the210// only thing in the relative path so we need to work around "."211// carefully.212if (prefix != ".")213continue;214// We need to figure out if the "path" argument is relative. If it is,215// then we should remap, else skip this entry.216if (path_is_relative == eLazyBoolCalculate) {217path_is_relative =218FileSpec(path).IsRelative() ? eLazyBoolYes : eLazyBoolNo;219}220if (!path_is_relative)221continue;222}223FileSpec remapped(it.second.GetStringRef());224auto orig_style = FileSpec::GuessPathStyle(prefix).value_or(225llvm::sys::path::Style::native);226AppendPathComponents(remapped, path, orig_style);227if (!only_if_exists || FileSystem::Instance().Exists(remapped))228return remapped;229}230return {};231}232233std::optional<llvm::StringRef>234PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {235std::string path = file.GetPath();236llvm::StringRef path_ref(path);237std::lock_guard<std::recursive_mutex> lock(m_mutex);238for (const auto &it : m_pairs) {239llvm::StringRef removed_prefix = it.second.GetStringRef();240if (!path_ref.consume_front(it.second.GetStringRef()))241continue;242auto orig_file = it.first.GetStringRef();243auto orig_style = FileSpec::GuessPathStyle(orig_file).value_or(244llvm::sys::path::Style::native);245fixed.SetFile(orig_file, orig_style);246AppendPathComponents(fixed, path_ref, orig_style);247return removed_prefix;248}249return std::nullopt;250}251252std::optional<FileSpec>253PathMappingList::FindFile(const FileSpec &orig_spec) const {254// We must normalize the orig_spec again using the host's path style,255// otherwise there will be mismatch between the host and remote platform256// if they use different path styles.257if (auto remapped = RemapPath(NormalizePath(orig_spec.GetPath()),258/*only_if_exists=*/true))259return remapped;260261return {};262}263264bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path,265bool notify) {266std::lock_guard<std::recursive_mutex> lock(m_mutex);267uint32_t idx = FindIndexForPath(path);268if (idx < m_pairs.size()) {269++m_mod_id;270m_pairs[idx].second = ConstString(new_path);271if (notify && m_callback)272m_callback(*this, m_callback_baton);273return true;274}275return false;276}277278bool PathMappingList::Remove(ConstString path, bool notify) {279std::lock_guard<std::recursive_mutex> lock(m_mutex);280iterator pos = FindIteratorForPath(path);281if (pos != m_pairs.end()) {282++m_mod_id;283m_pairs.erase(pos);284if (notify && m_callback)285m_callback(*this, m_callback_baton);286return true;287}288return false;289}290291PathMappingList::const_iterator292PathMappingList::FindIteratorForPath(ConstString path) const {293std::lock_guard<std::recursive_mutex> lock(m_mutex);294const_iterator pos;295const_iterator begin = m_pairs.begin();296const_iterator end = m_pairs.end();297298for (pos = begin; pos != end; ++pos) {299if (pos->first == path)300break;301}302return pos;303}304305PathMappingList::iterator306PathMappingList::FindIteratorForPath(ConstString path) {307std::lock_guard<std::recursive_mutex> lock(m_mutex);308iterator pos;309iterator begin = m_pairs.begin();310iterator end = m_pairs.end();311312for (pos = begin; pos != end; ++pos) {313if (pos->first == path)314break;315}316return pos;317}318319bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,320ConstString &new_path) const {321std::lock_guard<std::recursive_mutex> lock(m_mutex);322if (idx < m_pairs.size()) {323path = m_pairs[idx].first;324new_path = m_pairs[idx].second;325return true;326}327return false;328}329330uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const {331const ConstString path = ConstString(NormalizePath(orig_path));332std::lock_guard<std::recursive_mutex> lock(m_mutex);333const_iterator pos;334const_iterator begin = m_pairs.begin();335const_iterator end = m_pairs.end();336337for (pos = begin; pos != end; ++pos) {338if (pos->first == path)339return std::distance(begin, pos);340}341return UINT32_MAX;342}343344345