forked from OSchip/llvm-project
Second part of indicating when the user is stopped in optimized code.
The first part was in r243508 -- the extent of the UI changes in that patchset was to add "[opt]" to the frame-format when a stack frame was built with optimized code. In this change, when a stack frame built with optimization is selected, a message will be printed to the async output channel -- opt1.c was compiled with optimization - stepping may behave oddly; variables may not be available. The warning will be only be printed once per source file in a debug session. These warnings may be disabled by settings set target.process.optimization-warnings false Internally, a new Process::PrintWarning() method has been added for warnings that we want to print only once to the user. It takes a type of warning (currently only eWarningsOptimization) and an object pointer (CompileUnit*) - the warning will only be printed once for a given object pointer value. This is a bit of a prototype of this change - I think we will be tweaking it more in the future. But I wanted to land this and see how it goes. Advanced users will find these warnings unnecessary noise and will quickly disable them - but anyone who maintains a debugger knows that debugging optimized code, without realizing it, is a constant source of confusion and frustation for more typical debugger users. I imagine there will be more of these "warn once per whatever" style warnings that we will want to add in the future and we'll need to come up with a better way for enabling/disabling them. But I'm not srue what form that warning settings should take and I didn't want to code up something that we regret later, so for now I just added another process setting for this one warning. <rdar://problem/19281172> llvm-svn: 244190
This commit is contained in:
parent
50fee93926
commit
ef7d641617
|
@ -19,6 +19,7 @@
|
|||
#include <list>
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
|
@ -103,6 +104,9 @@ public:
|
|||
void
|
||||
SetDetachKeepsStopped (bool keep_stopped);
|
||||
|
||||
bool
|
||||
GetWarningsOptimization () const;
|
||||
|
||||
protected:
|
||||
|
||||
static void
|
||||
|
@ -766,6 +770,14 @@ public:
|
|||
eBroadcastInternalStateControlPause = (1<<1),
|
||||
eBroadcastInternalStateControlResume = (1<<2)
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Process warning types.
|
||||
//------------------------------------------------------------------
|
||||
enum Warnings
|
||||
{
|
||||
eWarningsOptimization = 1
|
||||
};
|
||||
|
||||
typedef Range<lldb::addr_t, lldb::addr_t> LoadRange;
|
||||
// We use a read/write lock to allow on or more clients to
|
||||
|
@ -1939,6 +1951,33 @@ public:
|
|||
return StructuredData::ObjectSP();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Print a user-visible warning one time per Process
|
||||
///
|
||||
/// A facility for printing a warning to the user once per repeat_key.
|
||||
///
|
||||
/// warning_type is from the Process::Warnings enums.
|
||||
/// repeat_key is a pointer value that will be used to ensure that the
|
||||
/// warning message is not printed multiple times. For instance, with a
|
||||
/// warning about a function being optimized, you can pass the CompileUnit
|
||||
/// pointer to have the warning issued for only the first function in a
|
||||
/// CU, or the Function pointer to have it issued once for every function,
|
||||
/// or a Module pointer to have it issued once per Module.
|
||||
///
|
||||
/// @param [in] warning_type
|
||||
/// One of the types defined in Process::Warnings.
|
||||
///
|
||||
/// @param [in] repeat_key
|
||||
/// A pointer value used to ensure that the warning is only printed once.
|
||||
/// May be nullptr, indicating that the warning is printed unconditionally
|
||||
/// every time.
|
||||
///
|
||||
/// @param [in] fmt
|
||||
/// printf style format string
|
||||
//------------------------------------------------------------------
|
||||
void
|
||||
PrintWarning (uint64_t warning_type, void *repeat_key, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
|
||||
|
||||
protected:
|
||||
|
||||
void
|
||||
|
@ -3243,6 +3282,8 @@ protected:
|
|||
// Type definitions
|
||||
//------------------------------------------------------------------
|
||||
typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> LanguageRuntimeCollection;
|
||||
typedef std::unordered_set<void *> WarningsPointerSet;
|
||||
typedef std::map<uint64_t, WarningsPointerSet> WarningsCollection;
|
||||
|
||||
struct PreResumeCallbackAndBaton
|
||||
{
|
||||
|
@ -3322,6 +3363,7 @@ protected:
|
|||
std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses;
|
||||
bool m_destroy_in_process;
|
||||
bool m_can_interpret_function_calls; // Some targets, e.g the OSX kernel, don't support the ability to modify the stack.
|
||||
WarningsCollection m_warnings_issued; // A set of object pointers which have already had warnings printed
|
||||
|
||||
enum {
|
||||
eCanJITDontKnow= 0,
|
||||
|
|
|
@ -495,11 +495,7 @@ public:
|
|||
}
|
||||
|
||||
lldb::StackFrameSP
|
||||
GetSelectedFrame ()
|
||||
{
|
||||
lldb::StackFrameListSP stack_frame_list_sp(GetStackFrameList());
|
||||
return stack_frame_list_sp->GetFrameAtIndex (stack_frame_list_sp->GetSelectedFrameIndex());
|
||||
}
|
||||
GetSelectedFrame ();
|
||||
|
||||
uint32_t
|
||||
SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast = false);
|
||||
|
@ -1328,6 +1324,9 @@ protected:
|
|||
GetStackFrameList ();
|
||||
|
||||
|
||||
void
|
||||
FunctionOptimizationWarning (lldb_private::StackFrame *frame);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from Process can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -115,6 +115,7 @@ g_properties[] =
|
|||
{ "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, stop when a shared library is loaded or unloaded." },
|
||||
{ "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, detach will attempt to keep the process stopped." },
|
||||
{ "memory-cache-line-size" , OptionValue::eTypeUInt64, false, 512, NULL, NULL, "The memory cache line size" },
|
||||
{ "optimization-warnings" , OptionValue::eTypeBoolean, false, true, NULL, NULL, "If true, warn when stopped in code that is optimized where stepping and variable availability may not behave as expected." },
|
||||
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -126,7 +127,8 @@ enum {
|
|||
ePropertyPythonOSPluginPath,
|
||||
ePropertyStopOnSharedLibraryEvents,
|
||||
ePropertyDetachKeepsStopped,
|
||||
ePropertyMemCacheLineSize
|
||||
ePropertyMemCacheLineSize,
|
||||
ePropertyWarningOptimization
|
||||
};
|
||||
|
||||
ProcessProperties::ProcessProperties (lldb_private::Process *process) :
|
||||
|
@ -263,6 +265,13 @@ ProcessProperties::SetDetachKeepsStopped (bool stop)
|
|||
m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, stop);
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessProperties::GetWarningsOptimization () const
|
||||
{
|
||||
const uint32_t idx = ePropertyWarningOptimization;
|
||||
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
|
||||
}
|
||||
|
||||
void
|
||||
ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
|
||||
{
|
||||
|
@ -755,6 +764,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
|
|||
m_last_broadcast_state (eStateInvalid),
|
||||
m_destroy_in_process (false),
|
||||
m_can_interpret_function_calls(false),
|
||||
m_warnings_issued (),
|
||||
m_can_jit(eCanJITDontKnow)
|
||||
{
|
||||
CheckInWithManager ();
|
||||
|
@ -6542,6 +6552,50 @@ Process::ModulesDidLoad (ModuleList &module_list)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Process::PrintWarning (uint64_t warning_type, void *repeat_key, const char *fmt, ...)
|
||||
{
|
||||
bool print_warning = true;
|
||||
|
||||
StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
|
||||
if (stream_sp.get() == nullptr)
|
||||
return;
|
||||
if (warning_type == eWarningsOptimization
|
||||
&& GetWarningsOptimization() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (repeat_key != nullptr)
|
||||
{
|
||||
WarningsCollection::iterator it = m_warnings_issued.find (warning_type);
|
||||
if (it == m_warnings_issued.end())
|
||||
{
|
||||
m_warnings_issued[warning_type] = WarningsPointerSet();
|
||||
m_warnings_issued[warning_type].insert (repeat_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (it->second.find (repeat_key) != it->second.end())
|
||||
{
|
||||
print_warning = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.insert (repeat_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print_warning)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
stream_sp->PrintfVarArg (fmt, args);
|
||||
va_end (args);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadCollectionSP
|
||||
Process::GetHistoryThreads(lldb::addr_t addr)
|
||||
{
|
||||
|
|
|
@ -360,12 +360,22 @@ Thread::BroadcastSelectedFrameChange(StackID &new_frame_id)
|
|||
BroadcastEvent(eBroadcastBitSelectedFrameChanged, new ThreadEventData (this->shared_from_this(), new_frame_id));
|
||||
}
|
||||
|
||||
lldb::StackFrameSP
|
||||
Thread::GetSelectedFrame()
|
||||
{
|
||||
StackFrameListSP stack_frame_list_sp(GetStackFrameList());
|
||||
StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex (stack_frame_list_sp->GetSelectedFrameIndex());
|
||||
FunctionOptimizationWarning (frame_sp.get());
|
||||
return frame_sp;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Thread::SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast)
|
||||
{
|
||||
uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame);
|
||||
if (broadcast)
|
||||
BroadcastSelectedFrameChange(frame->GetStackID());
|
||||
FunctionOptimizationWarning (frame);
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
@ -378,6 +388,7 @@ Thread::SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast)
|
|||
GetStackFrameList()->SetSelectedFrame(frame_sp.get());
|
||||
if (broadcast)
|
||||
BroadcastSelectedFrameChange(frame_sp->GetStackID());
|
||||
FunctionOptimizationWarning (frame_sp.get());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -403,6 +414,7 @@ Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_strea
|
|||
|
||||
bool show_frame_info = true;
|
||||
bool show_source = !already_shown;
|
||||
FunctionOptimizationWarning (frame_sp.get());
|
||||
return frame_sp->GetStatus (output_stream, show_frame_info, show_source);
|
||||
}
|
||||
return false;
|
||||
|
@ -411,6 +423,22 @@ Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_strea
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Thread::FunctionOptimizationWarning (StackFrame *frame)
|
||||
{
|
||||
if (frame && frame->HasDebugInformation())
|
||||
{
|
||||
SymbolContext sc = frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextCompUnit);
|
||||
if (sc.function && sc.function->GetIsOptimized() == true && sc.comp_unit)
|
||||
{
|
||||
if (sc.line_entry.file.GetFilename().IsEmpty() == false)
|
||||
{
|
||||
GetProcess()->PrintWarning (Process::Warnings::eWarningsOptimization, sc.comp_unit, "%s was compiled with optimization - stepping may behave oddly; variables may not be available.\n", sc.line_entry.file.GetFilename().GetCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lldb::StopInfoSP
|
||||
Thread::GetStopInfo ()
|
||||
|
|
Loading…
Reference in New Issue