Index: include/lldb/Core/PluginManager.h =================================================================== --- include/lldb/Core/PluginManager.h +++ include/lldb/Core/PluginManager.h @@ -301,7 +301,8 @@ static bool RegisterPlugin (const ConstString &name, const char *description, - SymbolFileCreateInstance create_callback); + SymbolFileCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); static bool UnregisterPlugin (SymbolFileCreateInstance create_callback); @@ -419,13 +420,22 @@ static lldb::OptionValuePropertiesSP GetSettingForProcessPlugin (Debugger &debugger, const ConstString &setting_name); - + static bool CreateSettingForProcessPlugin (Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, const ConstString &description, bool is_global_property); + static lldb::OptionValuePropertiesSP + GetSettingForSymbolFilePlugin (Debugger &debugger, + const ConstString &setting_name); + + static bool + CreateSettingForSymbolFilePlugin (Debugger &debugger, + const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, + bool is_global_property); }; Index: source/Core/PluginManager.cpp =================================================================== --- source/Core/PluginManager.cpp +++ source/Core/PluginManager.cpp @@ -1771,13 +1771,15 @@ SymbolFileInstance() : name(), description(), - create_callback(NULL) + create_callback(nullptr), + debugger_init_callback(nullptr) { } ConstString name; std::string description; SymbolFileCreateInstance create_callback; + DebuggerInitializeCallback debugger_init_callback; }; typedef std::vector SymbolFileInstances; @@ -1802,7 +1804,8 @@ ( const ConstString &name, const char *description, - SymbolFileCreateInstance create_callback + SymbolFileCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback ) { if (create_callback) @@ -1813,6 +1816,7 @@ if (description && description[0]) instance.description = description; instance.create_callback = create_callback; + instance.debugger_init_callback = debugger_init_callback; Mutex::Locker locker (GetSymbolFileMutex ()); GetSymbolFileInstances ().push_back (instance); } @@ -2343,7 +2347,7 @@ pos->debugger_init_callback (debugger); } } - + // Initialize the Process plugins { Mutex::Locker locker (GetProcessMutex()); @@ -2357,6 +2361,15 @@ } } + // Initialize the SymbolFile plugins + { + Mutex::Locker locker (GetSymbolFileMutex()); + for (auto& sym_file: GetSymbolFileInstances()) + { + if (sym_file.debugger_init_callback) + sym_file.debugger_init_callback (debugger); + } + } } // This is the preferred new way to register plugin specific settings. e.g. @@ -2553,3 +2566,43 @@ return false; } + +static const char* kSymbolFilePluginName("symbol-file"); + +lldb::OptionValuePropertiesSP +PluginManager::GetSettingForSymbolFilePlugin (Debugger &debugger, + const ConstString &setting_name) +{ + lldb::OptionValuePropertiesSP properties_sp; + lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, + ConstString(kSymbolFilePluginName), + ConstString(), // not creating to so we don't need the description + false)); + if (plugin_type_properties_sp) + properties_sp = plugin_type_properties_sp->GetSubProperty (nullptr, setting_name); + return properties_sp; +} + +bool +PluginManager::CreateSettingForSymbolFilePlugin (Debugger &debugger, + const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, + bool is_global_property) +{ + if (properties_sp) + { + lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger, + ConstString(kSymbolFilePluginName), + ConstString("Settings for symbol file plug-ins"), + true)); + if (plugin_type_properties_sp) + { + plugin_type_properties_sp->AppendProperty (properties_sp->GetName(), + description, + is_global_property, + properties_sp); + return true; + } + } + return false; +} Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -76,6 +76,9 @@ static void Terminate(); + static void + DebuggerInitialize(lldb_private::Debugger &debugger); + static lldb_private::ConstString GetPluginNameStatic(); Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -44,6 +44,9 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Interpreter/OptionValueFileSpecList.h" +#include "lldb/Interpreter/OptionValueProperties.h" + #include "lldb/Symbol/Block.h" #include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" #include "lldb/Symbol/CompileUnit.h" @@ -106,6 +109,59 @@ // return false; //} // + +namespace { + + PropertyDefinition + g_properties[] = + { + { "comp-dir-symlink-paths" , OptionValue::eTypeFileSpecList, true, 0 , nullptr, nullptr, "If the DW_AT_comp_dir matches any of these paths the symbolic links will be resolved at DWARF parse time." }, + { nullptr , OptionValue::eTypeInvalid , false, 0, nullptr, nullptr, nullptr } + }; + + enum + { + ePropertySymLinkPaths + }; + + + class PluginProperties : public Properties + { + public: + static ConstString + GetSettingName() + { + return SymbolFileDWARF::GetPluginNameStatic(); + } + + PluginProperties() + { + m_collection_sp.reset (new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + FileSpecList& + GetSymLinkPaths() + { + OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, true, ePropertySymLinkPaths); + assert(option_value); + return option_value->GetCurrentValue(); + } + + }; + + typedef std::shared_ptr SymbolFileDWARFPropertiesSP; + + static const SymbolFileDWARFPropertiesSP& + GetGlobalPluginProperties() + { + static const auto g_settings_sp(std::make_shared()); + return g_settings_sp; + } + +} // anonymous namespace end + + static AccessType DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility) { @@ -153,11 +209,6 @@ return colon_pos + 1; } -// DW_AT_comp_dir can be overridden by setting compiler's PWD environment -// variable - for example, set to "/proc/self/cwd" in order to cope with -// distributed builds. -static const char* comp_dir_symlinks[] = {"/proc/self/cwd"}; - static const char* resolveCompDir(const char* path_from_dwarf) { @@ -171,13 +222,14 @@ return nullptr; bool is_symlink = false; - for (unsigned long i = 0; i < sizeof(comp_dir_symlinks)/sizeof(comp_dir_symlinks[0]) && !is_symlink; ++i) - is_symlink = !strcmp(comp_dir_symlinks[i], local_path); + FileSpec local_path_spec(local_path, false); + const auto& file_specs = GetGlobalPluginProperties()->GetSymLinkPaths(); + for (size_t i = 0; i < file_specs.GetSize() && !is_symlink; ++i) + is_symlink = FileSpec::Equal(file_specs.GetFileSpecAtIndex(i), local_path_spec, true); if (!is_symlink) return local_path; - const FileSpec local_path_spec(local_path, true); if (!local_path_spec.IsSymbolicLink()) return local_path; @@ -276,7 +328,21 @@ LogChannelDWARF::Initialize(); PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), - CreateInstance); + CreateInstance, + DebuggerInitialize); +} + +void +SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) +{ + if (!PluginManager::GetSettingForSymbolFilePlugin(debugger, PluginProperties::GetSettingName())) + { + const bool is_global_setting = true; + PluginManager::CreateSettingForSymbolFilePlugin(debugger, + GetGlobalPluginProperties()->GetValueProperties(), + ConstString ("Properties for the dwarf symbol-file plug-in."), + is_global_setting); + } } void Index: test/functionalities/breakpoint/comp_dir_symlink/Makefile =================================================================== --- /dev/null +++ test/functionalities/breakpoint/comp_dir_symlink/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +EXE := CompDirSymLink + +include $(LEVEL)/Makefile.rules Index: test/functionalities/breakpoint/comp_dir_symlink/TestCompDirSymLink.py =================================================================== --- /dev/null +++ test/functionalities/breakpoint/comp_dir_symlink/TestCompDirSymLink.py @@ -0,0 +1,68 @@ +""" +Test breakpoint command with AT_comp_dir set to symbolic link. +""" +import os +import unittest2 +import lldb +from lldbtest import * +import lldbutil +import shutil + + +_EXE_NAME = 'CompDirSymLink' # Must match Makefile +_SRC_FILE = 'main.cpp' +_COMP_DIR_SYM_LINK_PROP = 'plugin.symbol-file.dwarf.comp-dir-symlink-paths' + +class CompDirSymLinkTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break inside main(). + self.line = line_number(_SRC_FILE, '// Set break point at this line.') + self.src_path = os.path.join(os.getcwd(), _SRC_FILE) + + @dwarf_test + @skipIfHostWindows + def test_symlink_paths_set(self): + pwd_symlink = self.create_src_symlink() + self.build(pwd_symlink) + self.runCmd("settings set %s %s" % (_COMP_DIR_SYM_LINK_PROP, pwd_symlink)) + lldbutil.run_break_set_by_file_and_line(self, self.src_path, self.line) + + @dwarf_test + @skipUnlessHostLinux + def test_symlink_paths_set_procselfcwd(self): + pwd_symlink = '/proc/self/cwd' + self.build(pwd_symlink) + self.runCmd("settings set %s %s" % (_COMP_DIR_SYM_LINK_PROP, pwd_symlink)) + lldbutil.run_break_set_by_file_and_line(self, self.src_path, self.line) + + @dwarf_test + @skipIfHostWindows + def test_symlink_paths_unset(self): + pwd_symlink = self.create_src_symlink() + self.build(pwd_symlink) + self.runCmd('settings clear ' + _COMP_DIR_SYM_LINK_PROP) + self.assertRaises(AssertionError, lldbutil.run_break_set_by_file_and_line, self, self.src_path, self.line) + + def create_src_symlink(self): + pwd_symlink = os.path.join(os.getcwd(), 'pwd_symlink') + os.symlink(os.getcwd(), pwd_symlink) + self.addTearDownHook(lambda: os.remove(pwd_symlink)) + return pwd_symlink + + def build(self, pwd_symlink): + self.buildDwarf(None, None, {'PWD': pwd_symlink}, True) + + exe = os.path.join(os.getcwd(), _EXE_NAME) + self.runCmd('file ' + exe, CURRENT_EXECUTABLE_SET) + + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/functionalities/breakpoint/comp_dir_symlink/main.cpp =================================================================== --- /dev/null +++ test/functionalities/breakpoint/comp_dir_symlink/main.cpp @@ -0,0 +1,13 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main (int argc, char const *argv[]) +{ + return 0; // Set break point at this line. +} Index: test/lldbtest.py =================================================================== --- test/lldbtest.py +++ test/lldbtest.py @@ -869,6 +869,10 @@ """Decorate the item to skip tests that should be skipped on Linux.""" return skipIfPlatform(["linux"])(func) +def skipUnlessHostLinux(func): + """Decorate the item to skip tests that should be skipped on any non Linux host.""" + return skipUnlessHostPlatform(["linux"])(func) + def skipIfWindows(func): """Decorate the item to skip tests that should be skipped on Windows.""" return skipIfPlatform(["windows"])(func)