From 6ab659a922bf919764dc5dd7a6c47e61b35bbde5 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 29 Jul 2015 00:42:47 +0000 Subject: [PATCH] First part of an attempt to indicate to the user when they are 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. llvm-svn: 243508 --- lldb/include/lldb/API/SBFunction.h | 3 +++ lldb/include/lldb/Core/FormatEntity.h | 1 + lldb/include/lldb/Symbol/CompileUnit.h | 27 +++++++++++++++++-- lldb/include/lldb/Symbol/Function.h | 18 +++++++++++++ lldb/scripts/interface/SBFunction.i | 10 +++++++ lldb/source/API/SBFunction.cpp | 11 +++++++- lldb/source/Core/Debugger.cpp | 2 ++ lldb/source/Core/FormatEntity.cpp | 14 +++++++++- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 8 +++++- .../DWARF/SymbolFileDWARFDebugMap.cpp | 3 ++- .../SymbolFile/Symtab/SymbolFileSymtab.cpp | 2 +- lldb/source/Symbol/CompileUnit.cpp | 16 ++++++++--- lldb/source/Symbol/Function.cpp | 15 +++++++++++ 13 files changed, 119 insertions(+), 11 deletions(-) diff --git a/lldb/include/lldb/API/SBFunction.h b/lldb/include/lldb/API/SBFunction.h index 86cfeb49bb58..8fb24c453b19 100644 --- a/lldb/include/lldb/API/SBFunction.h +++ b/lldb/include/lldb/API/SBFunction.h @@ -65,6 +65,9 @@ public: lldb::LanguageType GetLanguage (); + bool + GetIsOptimized (); + bool operator == (const lldb::SBFunction &rhs) const; diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h index db4f59132832..d3a0b0c5d4a8 100644 --- a/lldb/include/lldb/Core/FormatEntity.h +++ b/lldb/include/lldb/Core/FormatEntity.h @@ -81,6 +81,7 @@ namespace lldb_private FunctionPCOffset, FunctionInitial, FunctionChanged, + FunctionIsOptimized, LineEntryFile, LineEntryLineNumber, LineEntryStartAddress, diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h index e0c069352bf4..85f446ddd008 100644 --- a/lldb/include/lldb/Symbol/CompileUnit.h +++ b/lldb/include/lldb/Symbol/CompileUnit.h @@ -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 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 diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 30c8f168e5f1..7b7c5411730e 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -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, diff --git a/lldb/scripts/interface/SBFunction.i b/lldb/scripts/interface/SBFunction.i index 346237583e80..df8fb8836d57 100644 --- a/lldb/scripts/interface/SBFunction.i +++ b/lldb/scripts/interface/SBFunction.i @@ -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); diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp index 2ec6072b51eb..795a726a183c 100644 --- a/lldb/source/API/SBFunction.cpp +++ b/lldb/source/API/SBFunction.cpp @@ -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; +} diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index cd41e5d65103..55324f15c5e7 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -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: diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index b960007251fb..19889ce47755 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -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; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index b18628f7b19f..564b2dd2853b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -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 diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index de972acd7ed7..1e973b0ac685 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -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) { diff --git a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index 09b919782608..d535078c1897 100644 --- a/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -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; } diff --git a/lldb/source/Symbol/CompileUnit.cpp b/lldb/source/Symbol/CompileUnit.cpp index d43ef44a1376..29ee99522059 100644 --- a/lldb/source/Symbol/CompileUnit.cpp +++ b/lldb/source/Symbol/CompileUnit.cpp @@ -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) { diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index 77448d4f2a22..be51925fc30e 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -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 {