First part of an attempt to indicate to the user when they are
authorJason Molenda <jmolenda@apple.com>
Wed, 29 Jul 2015 00:42:47 +0000 (00:42 +0000)
committerJason Molenda <jmolenda@apple.com>
Wed, 29 Jul 2015 00:42:47 +0000 (00:42 +0000)
debugging optimized code.  Adds new methods on Function/SBFunction
to query whether a given function is optimized.  Adds a new
function.is-optimized format entity and changes the default
frame-format to append "[opt]" if the function was built with
optimization.

The only indication that a binary was built with optimization
that we have right now is the presence of the DW_AT_APPLE_optimized
attribute (DW_FORM_flag value 1) in the DW_TAG_compile_unit.
The absence of this flag may mean that the compile_unit was not
compiled with optimization, or it may mean that the producer
does not generate this attribute.

Currently this only works for dSYM debugging.  When we create
the CompileUnit with dwarf-in-.o-file debugging we don't have
the attribute value yet so it's not set.  I need to find the
flag value when we do start to read the .o file DWARF and
set the CompileUnit's status at that point - but haven't
done it yet.

I'm also going to add a mechanism for issuing warnings to users
such that they're only issued once in a debug session and
there is away for users to suppress these warnings altogether
via .lldbinit file settings.  But I want to get this changeset
committed now that it's at a useful state.

<rdar://problem/19281172>

llvm-svn: 243508

13 files changed:
lldb/include/lldb/API/SBFunction.h
lldb/include/lldb/Core/FormatEntity.h
lldb/include/lldb/Symbol/CompileUnit.h
lldb/include/lldb/Symbol/Function.h
lldb/scripts/interface/SBFunction.i
lldb/source/API/SBFunction.cpp
lldb/source/Core/Debugger.cpp
lldb/source/Core/FormatEntity.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
lldb/source/Symbol/CompileUnit.cpp
lldb/source/Symbol/Function.cpp

index 86cfeb4..8fb24c4 100644 (file)
@@ -66,6 +66,9 @@ public:
     GetLanguage ();
 
     bool
+    GetIsOptimized ();
+
+    bool
     operator == (const lldb::SBFunction &rhs) const;
 
     bool
index db4f591..d3a0b0c 100644 (file)
@@ -81,6 +81,7 @@ namespace lldb_private
                 FunctionPCOffset,
                 FunctionInitial,
                 FunctionChanged,
+                FunctionIsOptimized,
                 LineEntryFile,
                 LineEntryLineNumber,
                 LineEntryStartAddress,
index e0c0693..85f446d 100644 (file)
@@ -66,9 +66,12 @@ public:
     ///     A language enumeration type that describes the main language
     ///     of this compile unit.
     ///
+    /// @param[in] is_optimized
+    ///     true if this compile unit was compiled with optimization.
+    ///
     /// @see lldb::LanguageType
     //------------------------------------------------------------------
-    CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, lldb::user_id_t uid, lldb::LanguageType language);
+    CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, lldb::user_id_t uid, lldb::LanguageType language, bool is_optimized);
 
     //------------------------------------------------------------------
     /// Construct with a module, file spec, UID and language.
@@ -98,9 +101,12 @@ public:
     ///     A language enumeration type that describes the main language
     ///     of this compile unit.
     ///
+    /// @param[in] is_optimized
+    ///     true if this compile unit was compiled with optimization.
+    ///
     /// @see lldb::LanguageType
     //------------------------------------------------------------------
-    CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &file_spec, lldb::user_id_t uid, lldb::LanguageType language);
+    CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &file_spec, lldb::user_id_t uid, lldb::LanguageType language, bool is_optimized);
 
     //------------------------------------------------------------------
     /// Destructor
@@ -406,6 +412,22 @@ public:
                           SymbolContextList &sc_list);
 
 
+    //------------------------------------------------------------------
+    /// Get whether compiler optimizations were enabled for this compile unit
+    ///
+    /// "optimized" means that the debug experience may be difficult
+    /// for the user to understand.  Variables may not be available when
+    /// the developer would expect them, stepping through the source lines
+    /// in the function may appear strange, etc.
+    /// 
+    /// @return
+    ///     Returns 'true' if this compile unit was compiled with 
+    ///     optimization.  'false' indicates that either the optimization
+    ///     is unknown, or this compile unit was built without optimization.
+    //------------------------------------------------------------------
+    bool
+    GetIsOptimized ();
+
 protected:
     void *m_user_data; ///< User data for the SymbolFile parser to store information into.
     lldb::LanguageType m_language; ///< The programming language enumeration value.
@@ -417,6 +439,7 @@ protected:
     FileSpecList m_support_files; ///< Files associated with this compile unit's line table and declarations.
     std::unique_ptr<LineTable> m_line_table_ap; ///< Line table that will get parsed on demand.
     lldb::VariableListSP m_variables; ///< Global and static variable list that will get parsed on demand.
+    bool       m_is_optimized; /// eLazyBoolYes if this compile unit was compiled with optimization.
 
 private:
     enum
index 30c8f16..7b7c541 100644 (file)
@@ -616,6 +616,24 @@ public:
     size_t
     MemorySize () const;
 
+    //------------------------------------------------------------------
+    /// Get whether compiler optimizations were enabled for this function
+    ///
+    /// The debug information may provide information about whether this
+    /// function was compiled with optimization or not.  In this case,
+    /// "optimized" means that the debug experience may be difficult
+    /// for the user to understand.  Variables may not be available when
+    /// the developer would expect them, stepping through the source lines
+    /// in the function may appear strange, etc.
+    /// 
+    /// @return
+    ///     Returns 'true' if this function was compiled with 
+    ///     optimization.  'false' indicates that either the optimization
+    ///     is unknown, or this function was built without optimization.
+    //------------------------------------------------------------------
+    bool
+    GetIsOptimized ();
+
     lldb::DisassemblerSP
     GetInstructions (const ExecutionContext &exe_ctx,
                      const char *flavor,
index 3462375..df8fb88 100644 (file)
@@ -89,6 +89,16 @@ public:
     lldb::LanguageType
     GetLanguage ();
 
+    %feature("docstring", "
+    Returns true if the function was compiled with optimization.
+    Optimization, in this case, is meant to indicate that the debugger
+    experience may be confusing for the user -- variables optimized away,
+    stepping jumping between source lines -- and the driver may want to 
+    provide some guidance to the user about this.
+    Returns false if unoptimized, or unknown.") GetIsOptimized;
+    bool
+    GetIsOptimized();
+
     bool
     GetDescription (lldb::SBStream &description);
     
index 2ec6072..795a726 100644 (file)
@@ -258,4 +258,13 @@ SBFunction::GetLanguage ()
     return lldb::eLanguageTypeUnknown;
 }
 
-
+bool
+SBFunction::GetIsOptimized ()
+{
+    if (m_opaque_ptr)
+    {
+        if (m_opaque_ptr->GetCompileUnit())
+            return m_opaque_ptr->GetCompileUnit()->GetIsOptimized();
+    }
+    return false;
+}
index cd41e5d..55324f1 100644 (file)
@@ -105,6 +105,7 @@ g_language_enumerators[] =
 
 #define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}"
 #define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
+#define IS_OPTIMIZED "{${function.is-optimized} [opt]}"
 
 #define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\
     "{, ${frame.pc}}"\
@@ -122,6 +123,7 @@ g_language_enumerators[] =
 #define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
     MODULE_WITH_FUNC\
     FILE_AND_LINE\
+    IS_OPTIMIZED\
     "\\n"
 
 // Three parts to this disassembly format specification:
index b960007..19889ce 100644 (file)
@@ -98,7 +98,8 @@ static FormatEntity::Entry::Definition g_function_child_entries[] =
     ENTRY ("line-offset"         , FunctionLineOffset     , UInt64),
     ENTRY ("pc-offset"           , FunctionPCOffset       , UInt64),
     ENTRY ("initial-function"    , FunctionInitial        , None),
-    ENTRY ("changed"             , FunctionChanged        , None)
+    ENTRY ("changed"             , FunctionChanged        , None),
+    ENTRY ("is-optimized"        , FunctionIsOptimized    , None)
 };
 
 static FormatEntity::Entry::Definition g_line_child_entries[] =
@@ -343,6 +344,7 @@ FormatEntity::Entry::TypeToCString (Type t)
     ENUM_TO_CSTR(FunctionPCOffset);
     ENUM_TO_CSTR(FunctionInitial);
     ENUM_TO_CSTR(FunctionChanged);
+    ENUM_TO_CSTR(FunctionIsOptimized);
     ENUM_TO_CSTR(LineEntryFile);
     ENUM_TO_CSTR(LineEntryLineNumber);
     ENUM_TO_CSTR(LineEntryStartAddress);
@@ -1870,6 +1872,16 @@ FormatEntity::Format (const Entry &entry,
         case Entry::Type::FunctionChanged:
             return function_changed == true;
 
+        case Entry::Type::FunctionIsOptimized:
+            {
+                bool is_optimized = false;
+                if (sc->function && sc->function->GetIsOptimized())
+                {
+                    is_optimized = true;
+                }
+                return is_optimized;
+            }
+
         case Entry::Type::FunctionInitial:
             return initial_function == true;
 
index b18628f..564b2dd 100644 (file)
@@ -1034,11 +1034,17 @@ SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
 
                         LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0));
 
+                        bool is_optimized = false;
+                        if (cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_APPLE_optimized, 0) == 1)
+                        {
+                            is_optimized = true;
+                        }
                         cu_sp.reset(new CompileUnit (module_sp,
                                                      dwarf_cu,
                                                      cu_file_spec, 
                                                      MakeUserID(dwarf_cu->GetOffset()),
-                                                     cu_language));
+                                                     cu_language,
+                                                     is_optimized));
                         if (cu_sp)
                         {
                             // If we just created a compile unit with an invalid file spec, try and get the
index de972ac..1e973b0 100644 (file)
@@ -660,7 +660,8 @@ SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx)
                                                                                     NULL,
                                                                                     so_file_spec,
                                                                                     cu_id,
-                                                                                    eLanguageTypeUnknown));
+                                                                                    eLanguageTypeUnknown,
+                                                                                    false));
             
                 if (m_compile_unit_infos[cu_idx].compile_unit_sp)
                 {
index 09b9197..d535078 100644 (file)
@@ -161,7 +161,7 @@ SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx)
     {
         const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]);
         if (cu_symbol)
-            cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetName().AsCString(), 0, eLanguageTypeUnknown));
+            cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetName().AsCString(), 0, eLanguageTypeUnknown, false));
     }
     return cu_sp;
 }
index d43ef44..29ee995 100644 (file)
@@ -17,7 +17,7 @@
 using namespace lldb;
 using namespace lldb_private;
 
-CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
+CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, lldb::LanguageType language, bool is_optimized) :
     ModuleChild(module_sp),
     FileSpec (pathname, false),
     UserID(cu_sym_id),
@@ -27,14 +27,15 @@ CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, cons
     m_functions (),
     m_support_files (),
     m_line_table_ap (),
-    m_variables()
+    m_variables(),
+    m_is_optimized (is_optimized)
 {
     if (language != eLanguageTypeUnknown)
         m_flags.Set(flagsParsedLanguage);
     assert(module_sp);
 }
 
-CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
+CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, lldb::LanguageType language, bool is_optimized) :
     ModuleChild(module_sp),
     FileSpec (fspec),
     UserID(cu_sym_id),
@@ -44,7 +45,8 @@ CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, cons
     m_functions (),
     m_support_files (),
     m_line_table_ap (),
-    m_variables()
+    m_variables(),
+    m_is_optimized (is_optimized)
 {
     if (language != eLanguageTypeUnknown)
         m_flags.Set(flagsParsedLanguage);
@@ -430,6 +432,12 @@ CompileUnit::ResolveSymbolContext
     return sc_list.GetSize() - prev_size;
 }
 
+bool
+CompileUnit::GetIsOptimized ()
+{
+    return m_is_optimized;
+}
+
 void
 CompileUnit::SetVariableList(VariableListSP &variables)
 {
index 77448d4..be51925 100644 (file)
@@ -466,6 +466,21 @@ Function::MemorySize () const
     return mem_size;
 }
 
+bool
+Function::GetIsOptimized ()
+{
+    bool result = false;
+
+    // Currently optimization is only indicted by the
+    // vendor extension DW_AT_APPLE_optimized which
+    // is set on a compile unit level.
+    if (m_comp_unit)
+    {
+        result = m_comp_unit->GetIsOptimized();
+    }
+    return result;
+}
+
 ConstString
 Function::GetDisplayName () const
 {