From 220c17ffd4e1b127bcc02b25980b7934184ee1da Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 21 May 2020 17:42:24 -0700 Subject: [PATCH] Print a warning when stopped in a frame LLDB has no plugin for. This patchs adds an optional warning that is printed when stopped at a frame that was compiled in a source language that LLDB has no plugin for. The motivational use-case is debugging Swift code on Linux. When the user accidentally invokes the system LLDB that was built without the Swift plugin, it is very much non-obvious why debugging doesnt work. This warning makes it easy to figure out what went wrong. --- lldb/include/lldb/Target/Process.h | 9 ++++- lldb/source/Target/Process.cpp | 35 ++++++++++++++++--- lldb/source/Target/TargetProperties.td | 3 ++ lldb/source/Target/Thread.cpp | 5 ++- lldb/test/Shell/Process/Inputs/true.c | 3 ++ lldb/test/Shell/Process/Optimization.test | 6 ++++ .../Shell/Process/UnsupportedLanguage.test | 8 +++++ 7 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 lldb/test/Shell/Process/Inputs/true.c create mode 100644 lldb/test/Shell/Process/Optimization.test create mode 100644 lldb/test/Shell/Process/UnsupportedLanguage.test diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index fe811deb7caa..6f31741b4ce6 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -86,6 +86,7 @@ public: bool GetDetachKeepsStopped() const; void SetDetachKeepsStopped(bool keep_stopped); bool GetWarningsOptimization() const; + bool GetWarningsUnsupportedLanguage() const; bool GetStopOnExec() const; std::chrono::seconds GetUtilityExpressionTimeout() const; bool GetOSPluginReportsAllThreads() const; @@ -390,7 +391,7 @@ public: }; /// Process warning types. - enum Warnings { eWarningsOptimization = 1 }; + enum Warnings { eWarningsOptimization = 1, eWarningsUnsupportedLanguage = 2 }; typedef Range LoadRange; // We use a read/write lock to allow on or more clients to access the process @@ -1319,6 +1320,12 @@ public: /// pre-computed. void PrintWarningOptimization(const SymbolContext &sc); + /// Print a user-visible warning about a function written in a + /// language that this version of LLDB doesn't support. + /// + /// \see PrintWarningOptimization + void PrintWarningUnsupportedLanguage(const SymbolContext &sc); + virtual bool GetProcessInfo(ProcessInstanceInfo &info); public: diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 0eb9866e4a4b..25a940b66430 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -258,6 +258,12 @@ bool ProcessProperties::GetWarningsOptimization() const { nullptr, idx, g_process_properties[idx].default_uint_value != 0); } +bool ProcessProperties::GetWarningsUnsupportedLanguage() const { + const uint32_t idx = ePropertyWarningUnsupportedLanguage; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_process_properties[idx].default_uint_value != 0); +} + bool ProcessProperties::GetStopOnExec() const { const uint32_t idx = ePropertyStopOnExec; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -5779,9 +5785,6 @@ void Process::PrintWarning(uint64_t warning_type, const void *repeat_key, StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); if (!stream_sp) return; - if (warning_type == eWarningsOptimization && !GetWarningsOptimization()) { - return; - } if (repeat_key != nullptr) { WarningsCollection::iterator it = m_warnings_issued.find(warning_type); @@ -5806,8 +5809,11 @@ void Process::PrintWarning(uint64_t warning_type, const void *repeat_key, } void Process::PrintWarningOptimization(const SymbolContext &sc) { - if (GetWarningsOptimization() && sc.module_sp && - !sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function && + if (!GetWarningsOptimization()) + return; + if (!sc.module_sp) + return; + if (!sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function && sc.function->GetIsOptimized()) { PrintWarning(Process::Warnings::eWarningsOptimization, sc.module_sp.get(), "%s was compiled with optimization - stepping may behave " @@ -5816,6 +5822,25 @@ void Process::PrintWarningOptimization(const SymbolContext &sc) { } } +void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { + if (!GetWarningsUnsupportedLanguage()) + return; + if (!sc.module_sp) + return; + LanguageType language = sc.GetLanguage(); + if (language == eLanguageTypeUnknown) + return; + auto type_system_or_err = sc.module_sp->GetTypeSystemForLanguage(language); + if (auto err = type_system_or_err.takeError()) { + llvm::consumeError(std::move(err)); + PrintWarning(Process::Warnings::eWarningsUnsupportedLanguage, + sc.module_sp.get(), + "This version of LLDB has no plugin for the %s language. " + "Inspection of frame variables will be limited.\n", + Language::GetNameForLanguageType(language)); + } +} + bool Process::GetProcessInfo(ProcessInstanceInfo &info) { info.Clear(); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 8f3a6b04bb69..ae3abe354856 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -204,6 +204,9 @@ let Definition = "process" in { def WarningOptimization: Property<"optimization-warnings", "Boolean">, DefaultTrue, Desc<"If true, warn when stopped in code that is optimized where stepping and variable availability may not behave as expected.">; + def WarningUnsupportedLanguage: Property<"unsupported-language-warnings", "Boolean">, + DefaultTrue, + Desc<"If true, warn when stopped in code that is written in a source language that LLDB does not support.">; def StopOnExec: Property<"stop-on-exec", "Boolean">, Global, DefaultTrue, diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index e24024c37a47..35cde4015986 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -326,10 +326,13 @@ void Thread::FrameSelectedCallback(StackFrame *frame) { if (!frame) return; - if (frame->HasDebugInformation() && GetProcess()->GetWarningsOptimization()) { + if (frame->HasDebugInformation() && + (GetProcess()->GetWarningsOptimization() || + GetProcess()->GetWarningsUnsupportedLanguage())) { SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextModule); GetProcess()->PrintWarningOptimization(sc); + GetProcess()->PrintWarningUnsupportedLanguage(sc); } } diff --git a/lldb/test/Shell/Process/Inputs/true.c b/lldb/test/Shell/Process/Inputs/true.c new file mode 100644 index 000000000000..5c2fa9bb6a78 --- /dev/null +++ b/lldb/test/Shell/Process/Inputs/true.c @@ -0,0 +1,3 @@ +int main(int argc, char **argv) { + return 0; +} diff --git a/lldb/test/Shell/Process/Optimization.test b/lldb/test/Shell/Process/Optimization.test new file mode 100644 index 000000000000..10d241f698c0 --- /dev/null +++ b/lldb/test/Shell/Process/Optimization.test @@ -0,0 +1,6 @@ +Test warnings. +REQUIRES: shell +RUN: %clang_host -O3 %S/Inputs/true.c -std=c99 -g -o %t.exe +RUN: %lldb -o "b main" -o r -o q -b %t.exe | FileCheck %s + +CHECK: compiled with optimization diff --git a/lldb/test/Shell/Process/UnsupportedLanguage.test b/lldb/test/Shell/Process/UnsupportedLanguage.test new file mode 100644 index 000000000000..28726abd6a1e --- /dev/null +++ b/lldb/test/Shell/Process/UnsupportedLanguage.test @@ -0,0 +1,8 @@ +Test warnings. +REQUIRES: shell +RUN: %clang_host %S/Inputs/true.c -std=c99 -g -c -S -emit-llvm -o - \ +RUN: | sed -e 's/DW_LANG_C99/DW_LANG_PLI/g' >%t.ll +RUN: %clang_host %t.ll -g -o %t.exe +RUN: %lldb -o "b main" -o r -o q -b %t.exe | FileCheck %s + +CHECK: This version of LLDB has no plugin for the pli language