From d804d285567f7833b2fb3d14eceac8dbeaae8f87 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Thu, 15 Mar 2012 21:01:31 +0000 Subject: [PATCH] Use the metadata in the dSYM bundle Info.plist to remap source paths when they keys are available. llvm-svn: 152836 --- lldb/include/lldb/Core/Module.h | 77 +++++++++++++------ lldb/include/lldb/Core/ModuleList.h | 3 + lldb/include/lldb/Target/PathMappingList.h | 15 +++- lldb/source/Core/Module.cpp | 9 +++ lldb/source/Core/ModuleList.cpp | 15 ++++ lldb/source/Core/SourceManager.cpp | 23 +++--- lldb/source/Host/macosx/Symbols.cpp | 49 ++++++++---- .../SymbolFile/DWARF/DWARFDebugLine.cpp | 14 +++- .../Plugins/SymbolFile/DWARF/DWARFDebugLine.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 14 +++- .../MacOSX/SymbolVendorMacOSX.cpp | 7 ++ lldb/source/Target/PathMappingList.cpp | 69 ++++++++++++++--- 12 files changed, 232 insertions(+), 65 deletions(-) diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 08ac448639a1..1cf9ad4e7b31 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -21,26 +21,9 @@ #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symtab.h" #include "lldb/Symbol/TypeList.h" +#include "lldb/Target/PathMappingList.h" + -//---------------------------------------------------------------------- -/// @class Module Module.h "lldb/Core/Module.h" -/// @brief A class that describes an executable image and its associated -/// object and symbol files. -/// -/// The module is designed to be able to select a single slice of an -/// executable image as it would appear on disk and during program -/// execution. -/// -/// Modules control when and if information is parsed according to which -/// accessors are called. For example the object file (ObjectFile) -/// representation will only be parsed if the object file is requested -/// using the Module::GetObjectFile() is called. The debug symbols -/// will only be parsed if the symbol vendor (SymbolVendor) is -/// requested using the Module::GetSymbolVendor() is called. -/// -/// The module will parse more detailed information as more queries are -/// made. -//---------------------------------------------------------------------- namespace lldb_private { class ModuleSpec @@ -53,7 +36,8 @@ public: m_arch (), m_uuid (), m_object_name (), - m_object_offset (0) + m_object_offset (0), + m_source_mappings () { } @@ -64,7 +48,8 @@ public: m_arch (), m_uuid (), m_object_name (), - m_object_offset (0) + m_object_offset (0), + m_source_mappings () { } @@ -75,7 +60,8 @@ public: m_arch (arch), m_uuid (), m_object_name (), - m_object_offset (0) + m_object_offset (0), + m_source_mappings () { } @@ -86,7 +72,8 @@ public: m_arch (rhs.m_arch), m_uuid (rhs.m_uuid), m_object_name (rhs.m_object_name), - m_object_offset (rhs.m_object_offset) + m_object_offset (rhs.m_object_offset), + m_source_mappings (rhs.m_source_mappings) { } @@ -102,6 +89,7 @@ public: m_uuid = rhs.m_uuid; m_object_name = rhs.m_object_name; m_object_offset = rhs.m_object_offset; + m_source_mappings = rhs.m_source_mappings; } return *this; } @@ -270,6 +258,12 @@ public: m_object_offset = object_offset; } + PathMappingList & + GetSourceMappingList () const + { + return m_source_mappings; + } + protected: FileSpec m_file; FileSpec m_platform_file; @@ -278,8 +272,28 @@ protected: UUID m_uuid; ConstString m_object_name; uint64_t m_object_offset; + mutable PathMappingList m_source_mappings; }; +//---------------------------------------------------------------------- +/// @class Module Module.h "lldb/Core/Module.h" +/// @brief A class that describes an executable image and its associated +/// object and symbol files. +/// +/// The module is designed to be able to select a single slice of an +/// executable image as it would appear on disk and during program +/// execution. +/// +/// Modules control when and if information is parsed according to which +/// accessors are called. For example the object file (ObjectFile) +/// representation will only be parsed if the object file is requested +/// using the Module::GetObjectFile() is called. The debug symbols +/// will only be parsed if the symbol vendor (SymbolVendor) is +/// requested using the Module::GetSymbolVendor() is called. +/// +/// The module will parse more detailed information as more queries are +/// made. +//---------------------------------------------------------------------- class Module : public STD_ENABLE_SHARED_FROM_THIS(Module), public SymbolContextScope @@ -994,6 +1008,21 @@ public: return m_mutex; } + PathMappingList & + GetSourceMappingList () + { + return m_source_mappings; + } + + const PathMappingList & + GetSourceMappingList () const + { + return m_source_mappings; + } + + bool + FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const; + protected: //------------------------------------------------------------------ // Member Variables @@ -1010,6 +1039,8 @@ protected: lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file parser for this module as it may or may not be shared with the SymbolFile std::auto_ptr m_symfile_ap; ///< A pointer to the symbol vendor for this module. ClangASTContext m_ast; ///< The AST context for this module. + PathMappingList m_source_mappings; ///< Module specific source remappings for when you have debug info for a module that doesn't match where the sources currently are + bool m_did_load_objfile:1, m_did_load_symbol_vendor:1, m_did_parse_uuid:1, diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 4d637a78be57..bb6f0288112a 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -346,6 +346,9 @@ public: uint32_t max_matches, TypeList& types); + bool + FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const; + bool Remove (const lldb::ModuleSP &module_sp); diff --git a/lldb/include/lldb/Target/PathMappingList.h b/lldb/include/lldb/Target/PathMappingList.h index 38801f313393..d385322fa3cf 100644 --- a/lldb/include/lldb/Target/PathMappingList.h +++ b/lldb/include/lldb/Target/PathMappingList.h @@ -31,6 +31,8 @@ public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ + PathMappingList (); + PathMappingList (ChangedCallback callback, void *callback_baton); @@ -45,6 +47,9 @@ public: void Append (const ConstString &path, const ConstString &replacement, bool notify); + void + Append (const PathMappingList &rhs, bool notify); + void Clear (bool notify); @@ -53,7 +58,10 @@ public: Dump (Stream *s, int pair_index=-1); size_t - GetSize (); + GetSize () const + { + return m_pairs.size(); + } bool GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const; @@ -76,7 +84,10 @@ public: bool notify); bool - RemapPath (const ConstString &path, ConstString &new_path); + RemapPath (const ConstString &path, ConstString &new_path) const; + + bool + FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const; uint32_t FindIndexForPath (const ConstString &path) const; diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index f2c32c57ec99..8372b53afe39 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -127,6 +127,7 @@ Module::Module (const ModuleSpec &module_spec) : m_objfile_sp (), m_symfile_ap (), m_ast (), + m_source_mappings (), m_did_load_objfile (false), m_did_load_symbol_vendor (false), m_did_parse_uuid (false), @@ -168,6 +169,7 @@ Module::Module(const FileSpec& file_spec, m_objfile_sp (), m_symfile_ap (), m_ast (), + m_source_mappings (), m_did_load_objfile (false), m_did_load_symbol_vendor (false), m_did_parse_uuid (false), @@ -1156,3 +1158,10 @@ Module::MatchesModuleSpec (const ModuleSpec &module_ref) return true; } +bool +Module::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const +{ + Mutex::Locker locker (m_mutex); + return m_source_mappings.FindFile (orig_spec, new_spec); +} + diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 9ba911921fb1..89021f12dd1b 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -372,6 +372,21 @@ ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool ap return total_matches; } +bool +ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const +{ + Mutex::Locker locker(m_modules_mutex); + collection::const_iterator pos, end = m_modules.end(); + for (pos = m_modules.begin(); pos != end; ++pos) + { + if ((*pos)->FindSourceFile (orig_spec, new_spec)) + return true; + } + return false; +} + + + ModuleSP ModuleList::FindFirstModule (const ModuleSpec &module_spec) { diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp index 4d077b3bfe4b..849c8243e1aa 100644 --- a/lldb/source/Core/SourceManager.cpp +++ b/lldb/source/Core/SourceManager.cpp @@ -272,10 +272,10 @@ SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line) void SourceManager::FindLinesMatchingRegex (FileSpec &file_spec, - RegularExpression& regex, - uint32_t start_line, - uint32_t end_line, - std::vector &match_lines) + RegularExpression& regex, + uint32_t start_line, + uint32_t end_line, + std::vector &match_lines) { match_lines.clear(); FileSP file_sp = GetFile (file_spec); @@ -333,7 +333,7 @@ SourceManager::File::File(const FileSpec &file_spec, Target *target) : { SymbolContext sc; sc_list.GetContextAtIndex (0, sc); - m_file_spec = static_cast(sc.comp_unit); + m_file_spec = sc.comp_unit; m_mod_time = m_file_spec.GetModificationTime(); } } @@ -341,12 +341,15 @@ SourceManager::File::File(const FileSpec &file_spec, Target *target) : // Try remapping if m_file_spec does not correspond to an existing file. if (!m_file_spec.Exists()) { - ConstString new_path; - if (target->GetSourcePathMap().RemapPath(m_file_spec.GetDirectory(), new_path)) + FileSpec new_file_spec; + // Check target specific source remappings first, then fall back to + // modules objects can have individual path remappings that were detected + // when the debug info for a module was found. + // then + if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) || + target->GetImages().FindSourceFile (m_file_spec, new_file_spec)) { - char resolved_path[PATH_MAX]; - ::snprintf(resolved_path, PATH_MAX, "%s/%s", new_path.AsCString(), m_file_spec.GetFilename().AsCString()); - m_file_spec = new FileSpec(resolved_path, true); + m_file_spec = new_file_spec; m_mod_time = m_file_spec.GetModificationTime(); } } diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp index efd8fbb47ff6..1509b712907f 100644 --- a/lldb/source/Host/macosx/Symbols.cpp +++ b/lldb/source/Host/macosx/Symbols.cpp @@ -367,26 +367,45 @@ LocateMacOSXFilesUsingDebugSymbols } } + CFCReleaser dict(::DBGCopyDSYMPropertyLists (dsym_url.get())); + CFDictionaryRef uuid_dict = NULL; + if (dict.get()) + { + char uuid_cstr_buf[64]; + const char *uuid_cstr = uuid->GetAsCString (uuid_cstr_buf, sizeof(uuid_cstr_buf)); + CFCString uuid_cfstr (uuid_cstr); + CFDictionaryRef uuid_dict = static_cast(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get())); + if (uuid_dict) + { + + CFStringRef actual_src_cfpath = static_cast(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSourcePath"))); + if (actual_src_cfpath) + { + CFStringRef build_src_cfpath = static_cast(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGBuildSourcePath"))); + if (build_src_cfpath) + { + char actual_src_path[PATH_MAX]; + char build_src_path[PATH_MAX]; + ::CFStringGetFileSystemRepresentation (actual_src_cfpath, actual_src_path, sizeof(actual_src_path)); + ::CFStringGetFileSystemRepresentation (build_src_cfpath, build_src_path, sizeof(build_src_path)); + module_spec.GetSourceMappingList().Append (ConstString(build_src_path), ConstString(actual_src_path), true); + } + } + } + } + if (out_exec_fspec) { - CFCReleaser dict(::DBGCopyDSYMPropertyLists (dsym_url.get())); bool success = false; - if (dict.get()) + if (uuid_dict) { - char uuid_cstr_buf[64]; - const char *uuid_cstr = uuid->GetAsCString (uuid_cstr_buf, sizeof(uuid_cstr_buf)); - CFCString uuid_cfstr (uuid_cstr); - CFDictionaryRef uuid_dict = static_cast(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get())); - if (uuid_dict) + CFStringRef exec_cf_path = static_cast(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) { - CFStringRef exec_cf_path = static_cast(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable"))); - if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) - { - ++items_found; - out_exec_fspec->SetFile(path, path[0] == '~'); - if (out_exec_fspec->Exists()) - success = true; - } + ++items_found; + out_exec_fspec->SetFile(path, path[0] == '~'); + if (out_exec_fspec->Exists()) + success = true; } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp index dd84595b412c..d084bd26aa12 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp @@ -14,6 +14,7 @@ #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" @@ -467,7 +468,11 @@ DWARFDebugLine::ParsePrologue(const DataExtractor& debug_line_data, dw_offset_t* } bool -DWARFDebugLine::ParseSupportFiles(const DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, FileSpecList &support_files) +DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp, + const DataExtractor& debug_line_data, + const char *cu_comp_dir, + dw_offset_t stmt_list, + FileSpecList &support_files) { uint32_t offset = stmt_list + 4; // Skip the total length const char * s; @@ -537,7 +542,12 @@ DWARFDebugLine::ParseSupportFiles(const DataExtractor& debug_line_data, const ch // We don't need to realpath files in the debug_line tables. FileSpec file_spec(fullpath.c_str(), false); - support_files.Append(file_spec); + + FileSpec remapped_file_spec; + if (module_sp->FindSourceFile(file_spec, remapped_file_spec)) + support_files.Append(remapped_file_spec); + else + support_files.Append(file_spec); } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h index b10c2c4cd01f..940b1b3a3656 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h @@ -196,7 +196,7 @@ public: static bool DumpOpcodes(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET, uint32_t dump_flags = 0); // If line_offset is invalid, dump everything static bool DumpLineTableRows(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET); // If line_offset is invalid, dump everything - static bool ParseSupportFiles(const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files); + static bool ParseSupportFiles(const lldb::ModuleSP &module_sp, const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files); static bool ParsePrologue(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, Prologue* prologue); static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, dw_offset_t* offset_ptr, State::Callback callback, void* userData); static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 8b501c79bf4b..ec683363c654 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -711,6 +711,10 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* curr_cu, CompUnitSP& compil { if (curr_cu != NULL) { + ModuleSP module_sp (m_obj_file->GetModule()); + if (!module_sp) + return false; + const DWARFDebugInfoEntry * cu_die = curr_cu->GetCompileUnitDIEOnly (); if (cu_die) { @@ -736,8 +740,12 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* curr_cu, CompUnitSP& compil cu_file_spec.SetFile (fullpath.c_str(), false); } - compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(), - curr_cu, + FileSpec remapped_file_spec; + if (module_sp->FindSourceFile(cu_file_spec, remapped_file_spec)) + cu_file_spec = remapped_file_spec; + + compile_unit_sp.reset(new CompileUnit (module_sp, + curr_cu, cu_file_spec, MakeUserID(curr_cu->GetOffset()), cu_language)); @@ -926,7 +934,7 @@ SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpec // supposed to be the compile unit itself. support_files.Append (*sc.comp_unit); - return DWARFDebugLine::ParseSupportFiles(get_debug_line_data(), cu_comp_dir, stmt_list, support_files); + return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files); } return false; } diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index 23e29d75db96..8ff2cc595445 100644 --- a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -120,6 +120,9 @@ SymbolVendorMacOSX::GetPluginDescriptionStatic() SymbolVendor* SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp) { + if (!module_sp) + return NULL; + Timer scoped_timer (__PRETTY_FUNCTION__, "SymbolVendorMacOSX::CreateInstance (module = %s/%s)", module_sp->GetFileSpec().GetDirectory().AsCString(), @@ -154,6 +157,10 @@ SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp) ModuleSpec module_spec(file_spec, module_sp->GetArchitecture()); module_spec.GetUUID() = module_sp->GetUUID(); dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec); + if (module_spec.GetSourceMappingList().GetSize()) + { + module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true); + } } } diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp index 628fcc23f2f7..cbdfa12c0512 100644 --- a/lldb/source/Target/PathMappingList.cpp +++ b/lldb/source/Target/PathMappingList.cpp @@ -8,13 +8,15 @@ //===----------------------------------------------------------------------===// // C Includes +#include + // C++ Includes // Other libraries and framework includes +// Project includes #include "lldb/Core/Error.h" #include "lldb/Core/Stream.h" -// Project includes +#include "lldb/Host/FileSpec.h" #include "lldb/Target/PathMappingList.h" -#include using namespace lldb; using namespace lldb_private; @@ -22,6 +24,13 @@ using namespace lldb_private; //---------------------------------------------------------------------- // PathMappingList constructor //---------------------------------------------------------------------- +PathMappingList::PathMappingList () : + m_pairs (), + m_callback (NULL), + m_callback_baton (NULL) +{ +} + PathMappingList::PathMappingList ( ChangedCallback callback, @@ -72,6 +81,19 @@ PathMappingList::Append (const ConstString &path, m_callback (*this, m_callback_baton); } +void +PathMappingList::Append (const PathMappingList &rhs, bool notify) +{ + 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, @@ -131,14 +153,8 @@ PathMappingList::Clear (bool notify) m_callback (*this, m_callback_baton); } -size_t -PathMappingList::GetSize () -{ - return m_pairs.size(); -} - bool -PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) +PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) const { const_iterator pos, end = m_pairs.end(); for (pos = m_pairs.begin(); pos != end; ++pos) @@ -156,6 +172,41 @@ PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) return false; } +bool +PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const +{ + if (!m_pairs.empty()) + { + char orig_path[PATH_MAX]; + char new_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) + { + const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len); + if (new_path_len < sizeof(new_path)) + { + new_spec.SetFile (new_path, true); + if (new_spec.Exists()) + return true; + } + } + } + } + } + } + new_spec.Clear(); + return false; +} + bool PathMappingList::Replace (const ConstString &path, const ConstString &new_path, bool notify) {