Files
llvm/lldb/source/Target/PathMappingList.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

369 lines
12 KiB
C++
Raw Normal View History

//===-- PathMappingList.cpp -----------------------------------------------===//
//
// 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 <optional>
#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.
std::string NormalizePath(llvm::StringRef path) {
// If we use "path" to construct a FileSpec, it will normalize the path for
// us. We then grab the string.
return FileSpec(path).GetPath();
}
}
// PathMappingList constructor
PathMappingList::PathMappingList() : m_pairs() {}
PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
: m_pairs(), m_callback(callback), m_callback_baton(callback_baton) {}
PathMappingList::PathMappingList(const PathMappingList &rhs)
: m_pairs(rhs.m_pairs) {}
const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
if (this != &rhs) {
std::scoped_lock<std::mutex, std::mutex> callback_locks(
m_callback_mutex, rhs.m_callback_mutex);
std::scoped_lock<std::mutex, std::mutex> pairs_locks(m_pairs_mutex,
rhs.m_pairs_mutex);
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::AppendImpl(llvm::StringRef path,
llvm::StringRef replacement) {
++m_mod_id;
m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
}
void PathMappingList::Notify(bool notify) const {
std::lock_guard<std::mutex> lock(m_callback_mutex);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
AppendImpl(path, replacement);
}
Notify(notify);
}
void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
{
std::scoped_lock<std::mutex, std::mutex> locks(m_pairs_mutex,
rhs.m_pairs_mutex);
++m_mod_id;
if (rhs.m_pairs.empty())
return;
const_iterator pos, end = rhs.m_pairs.end();
for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
m_pairs.push_back(*pos);
}
Notify(notify);
}
bool PathMappingList::AppendUnique(llvm::StringRef path,
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
llvm::StringRef replacement, bool notify) {
auto normalized_path = NormalizePath(path);
auto normalized_replacement = NormalizePath(replacement);
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
for (const auto &pair : m_pairs) {
if (pair.first.GetStringRef() == normalized_path &&
pair.second.GetStringRef() == normalized_replacement)
return false;
}
AppendImpl(path, replacement);
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
}
Notify(notify);
return true;
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
}
void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement,
uint32_t index, bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
++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)));
}
Notify(notify);
}
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement,
uint32_t index, bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
if (index >= m_pairs.size())
return false;
++m_mod_id;
m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
}
Notify(notify);
return true;
}
bool PathMappingList::Remove(size_t index, bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
if (index >= m_pairs.size())
return false;
++m_mod_id;
iterator iter = m_pairs.begin() + index;
m_pairs.erase(iter);
}
Notify(notify);
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) {
std::lock_guard<std::mutex> lock(m_pairs_mutex);
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());
}
}
llvm::json::Value PathMappingList::ToJSON() {
llvm::json::Array entries;
std::lock_guard<std::mutex> lock(m_pairs_mutex);
for (const auto &pair : m_pairs) {
llvm::json::Array entry{pair.first.GetStringRef().str(),
pair.second.GetStringRef().str()};
entries.emplace_back(std::move(entry));
}
return entries;
}
void PathMappingList::Clear(bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
if (!m_pairs.empty())
++m_mod_id;
m_pairs.clear();
}
Notify(notify);
}
bool PathMappingList::RemapPath(ConstString path,
ConstString &new_path) const {
if (std::optional<FileSpec> remapped = RemapPath(path.GetStringRef())) {
new_path.SetString(remapped->GetPath());
return true;
}
return false;
}
/// Append components to path, applying style.
static void AppendPathComponents(FileSpec &path, llvm::StringRef components,
llvm::sys::path::Style style) {
auto component = llvm::sys::path::begin(components, style);
auto e = llvm::sys::path::end(components);
while (component != e &&
llvm::sys::path::is_separator(*component->data(), style))
++component;
for (; component != e; ++component)
path.AppendPathComponent(*component);
}
std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path,
bool only_if_exists) const {
std::lock_guard<std::mutex> lock(m_pairs_mutex);
if (m_pairs.empty() || mapping_path.empty())
return {};
LazyBool path_is_relative = eLazyBoolCalculate;
for (const auto &it : m_pairs) {
llvm::StringRef prefix = it.first.GetStringRef();
// We create a copy of mapping_path because StringRef::consume_from
// effectively modifies the instance itself.
llvm::StringRef path = mapping_path;
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());
auto orig_style = FileSpec::GuessPathStyle(prefix).value_or(
llvm::sys::path::Style::native);
AppendPathComponents(remapped, path, orig_style);
if (!only_if_exists || FileSystem::Instance().Exists(remapped))
return remapped;
}
return {};
}
std::optional<llvm::StringRef>
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
std::string path = file.GetPath();
llvm::StringRef path_ref(path);
std::lock_guard<std::mutex> lock(m_pairs_mutex);
for (const auto &it : m_pairs) {
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
llvm::StringRef removed_prefix = it.second.GetStringRef();
if (!path_ref.consume_front(it.second.GetStringRef()))
continue;
auto orig_file = it.first.GetStringRef();
auto orig_style = FileSpec::GuessPathStyle(orig_file).value_or(
llvm::sys::path::Style::native);
fixed.SetFile(orig_file, orig_style);
AppendPathComponents(fixed, path_ref, orig_style);
Add auto deduce source map setting This patch adds a new "target.auto-source-map-relative" setting. If enabled, this setting may auto deduce a source map entry based on requested breakpoint path and the original path stored in debug info for resolved breakpoint. As an example, if debug info contains "./a/b/c/main.cpp", user sets a source breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". The breakpoint will resolve correctly now with Greg's patch https://reviews.llvm.org/D130401. However, the resolved breakpoint will use "./a/b/c/main.cpp" to locate source file during stop event which would fail most of the time. With the new "target.auto-source-map-relative" setting enabled, a auto deduced source map entry "." => "/root/repo/x/y/z" will be added. This new mapping will help lldb to map resolved breakpoint path "./a/b/c/main.cpp" back to "/root/repo/x/y/z/a/b/c/main.cpp" and locate it on disk. If an existing source map entry is used the patch also concatenates the auto deduced entry with any stripped reverse mapping prefix (see example below). As a second example, debug info contains "./a/b/c/main.cpp" and user sets breakpoint at "/root/repo/x/y/z/a/b/c/main.cpp". Let's say there is an existing source map entry "." => "/root/repo"; this mapping would strip the prefix out of "/root/repo/x/y/z/a/b/c/main.cpp" and use "x/y/z/a/b/c/main.cpp" to resolve breakpoint. "target.auto-source-map-relative" setting would auto deduce a new potential mapping of "." => "x/y/z", then it detects that there is a stripped prefix from reverse mapping and concatenates it as the new mapping: "." => "/root/repo/x/y/z" which would correct map "./a/b/c/main.cpp" path to new path in disk. This patches depends on https://reviews.llvm.org/D130401 to use new added SBDebugger::GetSetting() API for testing. Differential Revision: https://reviews.llvm.org/D133042
2022-09-08 11:21:08 -07:00
return removed_prefix;
}
return std::nullopt;
}
std::optional<FileSpec>
PathMappingList::FindFile(const FileSpec &orig_spec) const {
// We must normalize the orig_spec again using the host's path style,
// otherwise there will be mismatch between the host and remote platform
// if they use different path styles.
if (auto remapped = RemapPath(NormalizePath(orig_spec.GetPath()),
/*only_if_exists=*/true))
return remapped;
return {};
}
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path,
bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
uint32_t idx = FindIndexForPath(path);
if (idx >= m_pairs.size())
return false;
++m_mod_id;
m_pairs[idx].second = ConstString(new_path);
}
Notify(notify);
return true;
}
bool PathMappingList::Remove(ConstString path, bool notify) {
{
std::lock_guard<std::mutex> lock(m_pairs_mutex);
iterator pos = FindIteratorForPath(path);
if (pos == m_pairs.end())
return false;
++m_mod_id;
m_pairs.erase(pos);
}
Notify(notify);
return true;
}
PathMappingList::const_iterator
PathMappingList::FindIteratorForPath(ConstString path) const {
std::lock_guard<std::mutex> lock(m_pairs_mutex);
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(ConstString path) {
std::lock_guard<std::mutex> lock(m_pairs_mutex);
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 {
std::lock_guard<std::mutex> lock(m_pairs_mutex);
if (idx < m_pairs.size()) {
path = m_pairs[idx].first;
new_path = m_pairs[idx].second;
return true;
}
return false;
}
uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const {
const ConstString path = ConstString(NormalizePath(orig_path));
std::lock_guard<std::mutex> lock(m_pairs_mutex);
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;
}