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.

<rdar://problem/19281172> 

llvm-svn: 243508
This commit is contained in:
Jason Molenda 2015-07-29 00:42:47 +00:00
parent ff244c1d97
commit 6ab659a922
13 changed files with 119 additions and 11 deletions

View File

@ -65,6 +65,9 @@ public:
lldb::LanguageType
GetLanguage ();
bool
GetIsOptimized ();
bool
operator == (const lldb::SBFunction &rhs) const;

View File

@ -81,6 +81,7 @@ namespace lldb_private
FunctionPCOffset,
FunctionInitial,
FunctionChanged,
FunctionIsOptimized,
LineEntryFile,
LineEntryLineNumber,
LineEntryStartAddress,

View 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

View 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,

View 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);

View 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;
}

View 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:

View 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;

View 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

View 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)
{

View 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;
}

View 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)
{

View 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
{