486 changes: 486 additions & 0 deletions lldb/include/lldb/Core/StructuredData.h

Large diffs are not rendered by default.

111 changes: 4 additions & 107 deletions lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "lldb/DataFormatters/FormatClasses.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"

#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -139,6 +140,9 @@ namespace lldb_private {
bool
NSStringSummaryProvider (ValueObject& valobj, Stream& stream);

bool
NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream);

bool
NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream);

Expand Down Expand Up @@ -176,113 +180,6 @@ namespace lldb_private {
extern template bool
ObjCSELSummaryProvider<false> (ValueObject&, Stream&);

class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
private:
struct DataDescriptor_32
{
uint32_t _used;
uint32_t _priv1 : 2 ;
uint32_t _size : 30;
uint32_t _priv2 : 2;
uint32_t offset : 30;
uint32_t _priv3;
uint32_t _data;
};
struct DataDescriptor_64
{
uint64_t _used;
uint64_t _priv1 : 2 ;
uint64_t _size : 62;
uint64_t _priv2 : 2;
uint64_t offset : 62;
uint32_t _priv3;
uint64_t _data;
};
public:
NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

virtual size_t
CalculateNumChildren ();

virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);

virtual bool
Update();

virtual bool
MightHaveChildren ();

virtual size_t
GetIndexOfChildWithName (const ConstString &name);

virtual
~NSArrayMSyntheticFrontEnd ();
private:
ExecutionContextRef m_exe_ctx_ref;
uint8_t m_ptr_size;
DataDescriptor_32 *m_data_32;
DataDescriptor_64 *m_data_64;
ClangASTType m_id_type;
std::vector<lldb::ValueObjectSP> m_children;
};

class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

virtual size_t
CalculateNumChildren ();

virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);

virtual bool
Update();

virtual bool
MightHaveChildren ();

virtual size_t
GetIndexOfChildWithName (const ConstString &name);

virtual
~NSArrayISyntheticFrontEnd ();
private:
ExecutionContextRef m_exe_ctx_ref;
uint8_t m_ptr_size;
uint64_t m_items;
lldb::addr_t m_data_ptr;
ClangASTType m_id_type;
std::vector<lldb::ValueObjectSP> m_children;
};

class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);

virtual size_t
CalculateNumChildren ();

virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx);

virtual bool
Update();

virtual bool
MightHaveChildren ();

virtual size_t
GetIndexOfChildWithName (const ConstString &name);

virtual
~NSArrayCodeRunningSyntheticFrontEnd ();
};

SyntheticChildrenFrontEnd* NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);

class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
Expand Down
15 changes: 15 additions & 0 deletions lldb/include/lldb/Target/SystemRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "lldb/Core/ConstString.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/QueueList.h"
#include "lldb/Target/QueueItem.h"
#include "lldb/lldb-private.h"
Expand Down Expand Up @@ -310,6 +311,20 @@ class SystemRuntime :
}

//------------------------------------------------------------------
/// Add key-value pairs to the StructuredData dictionary object with
/// information debugserver may need when constructing the jThreadExtendedInfo
/// packet.
///
/// @param [out] dict
/// Dictionary to which key-value pairs should be added; they will
/// be sent to the remote gdb server stub as arguments in the
/// jThreadExtendedInfo request.
//------------------------------------------------------------------
virtual void
AddThreadExtendedInfoPacketHints (lldb_private::StructuredData::ObjectSP dict)
{
}

/// Determine whether it is safe to run an expression on a given thread
///
/// If a system must not run functions on a thread in some particular state,
Expand Down
35 changes: 35 additions & 0 deletions lldb/include/lldb/Target/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "lldb/Host/Mutex.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Target/ExecutionContextScope.h"
Expand Down Expand Up @@ -306,6 +307,28 @@ class Thread :
return NULL;
}

//------------------------------------------------------------------
/// Retrieve a dictionary of information about this thread
///
/// On Mac OS X systems there may be voucher information.
/// The top level dictionary returned will have an "activity" key and the
/// value of the activity is a dictionary. Keys in that dictionary will
/// be "name" and "id", among others.
/// There may also be "trace_messages" (an array) with each entry in that array
/// being a dictionary (keys include "message" with the text of the trace
/// message).
//------------------------------------------------------------------
StructuredData::ObjectSP
GetExtendedInfo ()
{
if (m_extended_info_fetched == false)
{
m_extended_info = FetchThreadExtendedInfo ();
m_extended_info_fetched = true;
}
return m_extended_info;
}

virtual const char *
GetName ()
{
Expand Down Expand Up @@ -511,6 +534,9 @@ class Thread :
void
DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx);

bool
GetDescription (Stream &s, lldb::DescriptionLevel level, bool json_output);

//------------------------------------------------------------------
/// Default implementation for stepping into.
///
Expand Down Expand Up @@ -1238,6 +1264,13 @@ class Thread :
return false;
}

// Subclasses that have a way to get an extended info dictionary for this thread should
// fill
virtual lldb_private::StructuredData::ObjectSP
FetchThreadExtendedInfo ()
{
return StructuredData::ObjectSP();
}

lldb::StackFrameListSP
GetStackFrameList ();
Expand Down Expand Up @@ -1268,6 +1301,8 @@ class Thread :
bool m_destroy_called; // This is used internally to make sure derived Thread classes call DestroyThread.
LazyBool m_override_should_notify;
private:
bool m_extended_info_fetched; // Have we tried to retrieve the m_extended_info for this thread?
StructuredData::ObjectSP m_extended_info; // The extended info for this thread
//------------------------------------------------------------------
// For Thread only
//------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions lldb/lldb.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@
AF9107EF168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9107EC168570D200DBCD3C /* RegisterContextDarwin_arm64.cpp */; };
AF9B8F33182DB52900DA866F /* SystemRuntimeMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF9B8F31182DB52900DA866F /* SystemRuntimeMacOSX.cpp */; };
AF9B8F34182DB52900DA866F /* SystemRuntimeMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = AF9B8F32182DB52900DA866F /* SystemRuntimeMacOSX.h */; };
AFEC3362194A8ABA00FF05C6 /* StructuredData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */; };
AFF87C87150FF669000E1742 /* com.apple.debugserver.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C86150FF669000E1742 /* com.apple.debugserver.plist */; };
AFF87C89150FF672000E1742 /* com.apple.debugserver-secure.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C88150FF672000E1742 /* com.apple.debugserver-secure.plist */; };
AFF87C8F150FF688000E1742 /* com.apple.debugserver.applist.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = AFF87C8E150FF688000E1742 /* com.apple.debugserver.applist.plist */; };
Expand Down Expand Up @@ -1965,6 +1966,7 @@
AF94005711C03F6500085DB9 /* SymbolVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolVendor.cpp; path = source/Symbol/SymbolVendor.cpp; sourceTree = "<group>"; };
AF9B8F31182DB52900DA866F /* SystemRuntimeMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemRuntimeMacOSX.cpp; sourceTree = "<group>"; };
AF9B8F32182DB52900DA866F /* SystemRuntimeMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemRuntimeMacOSX.h; sourceTree = "<group>"; };
AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StructuredData.cpp; path = source/Core/StructuredData.cpp; sourceTree = "<group>"; };
AFF87C86150FF669000E1742 /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.debugserver.plist; path = tools/debugserver/source/com.apple.debugserver.plist; sourceTree = "<group>"; };
AFF87C88150FF672000E1742 /* com.apple.debugserver-secure.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "com.apple.debugserver-secure.plist"; path = "tools/debugserver/source/com.apple.debugserver-secure.plist"; sourceTree = "<group>"; };
AFF87C8A150FF677000E1742 /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.debugserver.applist.plist; path = tools/debugserver/source/com.apple.debugserver.applist.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3028,6 +3030,7 @@
4C626533130F1B0A00C889F6 /* StreamTee.h */,
9A35765E116E76A700E8ED2F /* StringList.h */,
9A35765F116E76B900E8ED2F /* StringList.cpp */,
AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */,
26B167A41123BF5500DC7B4F /* ThreadSafeValue.h */,
263FEDA5112CC1DA00E4C208 /* ThreadSafeSTLMap.h */,
26BC7D7E10F1B77400F91463 /* Timer.h */,
Expand Down Expand Up @@ -4524,6 +4527,7 @@
2689001413353DDE00698AC0 /* CommandObjectBreakpoint.cpp in Sources */,
2689001513353DDE00698AC0 /* CommandObjectBreakpointCommand.cpp in Sources */,
2689001613353DDE00698AC0 /* CommandObjectCommands.cpp in Sources */,
AFEC3362194A8ABA00FF05C6 /* StructuredData.cpp in Sources */,
26474CAC18D0CB070073DEBA /* RegisterContextFreeBSD_x86_64.cpp in Sources */,
2689001713353DDE00698AC0 /* CommandObjectDisassemble.cpp in Sources */,
2689001813353DDE00698AC0 /* CommandObjectExpression.cpp in Sources */,
Expand Down
4 changes: 4 additions & 0 deletions lldb/scripts/Python/interface/SBExpressionOptions.i
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ public:
void
SetTrapExceptions (bool trap_exceptions = true);

%feature ("docstring", "Sets the language that LLDB should assume the expression is written in") SetLanguage;
void
SetLanguage (lldb::LanguageType language);

protected:

SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);
Expand Down
11 changes: 11 additions & 0 deletions lldb/scripts/Python/interface/SBThread.i
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,17 @@ public:
lldb::queue_id_t
GetQueueID() const;

%feature("autodoc", "
Takes a path string and a SBStream reference as parameters, returns a bool.
Collects the thread's 'info' dictionary from the remote system, uses the path
argument to descend into the dictionary to an item of interest, and prints
it into the SBStream in a natural format. Return bool is to indicate if
anything was printed into the stream (true) or not (false).
") GetInfoItemByPathAsString;

bool
GetInfoItemByPathAsString (const char *path, lldb::SBStream &strm);

%feature("autodoc", "
Return the SBQueue for this thread. If this thread is not currently associated
with a libdispatch queue, the SBQueue object's IsValid() method will return false.
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/API/SBExpressionOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ SBExpressionOptions::SetTrapExceptions (bool trap_exceptions)
m_opaque_ap->SetTrapExceptions (trap_exceptions);
}

void
SBExpressionOptions::SetLanguage (lldb::LanguageType language)
{
m_opaque_ap->SetLanguage(language);
}

void
SBExpressionOptions::SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton)
{
Expand Down
69 changes: 69 additions & 0 deletions lldb/source/API/SBThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Thread.h"
Expand Down Expand Up @@ -589,6 +590,74 @@ SBThread::GetQueueID () const
return id;
}

bool
SBThread::GetInfoItemByPathAsString (const char *path, SBStream &strm)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
bool success = false;
Mutex::Locker api_locker;
ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);

if (exe_ctx.HasThreadScope())
{
Process::StopLocker stop_locker;
if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
{
Thread *thread = exe_ctx.GetThreadPtr();
StructuredData::ObjectSP info_root_sp = thread->GetExtendedInfo();
if (info_root_sp)
{
StructuredData::ObjectSP node = info_root_sp->GetObjectForDotSeparatedPath (path);
if (node)
{
if (node->GetType() == StructuredData::Type::eTypeString)
{
strm.Printf ("%s", node->GetAsString()->GetValue().c_str());
success = true;
}
if (node->GetType() == StructuredData::Type::eTypeInteger)
{
strm.Printf ("0x%" PRIx64, node->GetAsInteger()->GetValue());
success = true;
}
if (node->GetType() == StructuredData::Type::eTypeFloat)
{
strm.Printf ("0x%f", node->GetAsFloat()->GetValue());
success = true;
}
if (node->GetType() == StructuredData::Type::eTypeBoolean)
{
if (node->GetAsBoolean()->GetValue() == true)
strm.Printf ("true");
else
strm.Printf ("false");
success = true;
}
if (node->GetType() == StructuredData::Type::eTypeNull)
{
strm.Printf ("null");
success = true;
}
}
}
}
else
{
if (log)
log->Printf ("SBThread(%p)::GetInfoItemByPathAsString() => error: process is running",
static_cast<void*>(exe_ctx.GetThreadPtr()));
}
}

if (log)
log->Printf ("SBThread(%p)::GetInfoItemByPathAsString () => %s",
static_cast<void*>(exe_ctx.GetThreadPtr()),
strm.GetData());

return success;
}


SBError
SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan)
{
Expand Down
188 changes: 188 additions & 0 deletions lldb/source/Commands/CommandObjectThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,193 @@ class CommandObjectThreadList : public CommandObjectParsed
}
};

//-------------------------------------------------------------------------
// CommandObjectThreadInfo
//-------------------------------------------------------------------------

class CommandObjectThreadInfo : public CommandObjectParsed
{
public:

CommandObjectThreadInfo (CommandInterpreter &interpreter) :
CommandObjectParsed (interpreter,
"thread info",
"Show an extended summary of information about thread(s) in a process.",
"thread info",
eFlagRequiresProcess |
eFlagTryTargetAPILock |
eFlagProcessMustBeLaunched |
eFlagProcessMustBePaused),
m_options (interpreter)
{
CommandArgumentEntry arg;
CommandArgumentData thread_idx_arg;

thread_idx_arg.arg_type = eArgTypeThreadIndex;
thread_idx_arg.arg_repetition = eArgRepeatStar;

// There is only one variant this argument could be; put it into the argument entry.
arg.push_back (thread_idx_arg);

// Push the data for the first argument into the m_arguments vector.
m_arguments.push_back (arg);
}

class CommandOptions : public Options
{
public:

CommandOptions (CommandInterpreter &interpreter) :
Options (interpreter)
{
OptionParsingStarting ();
}

void
OptionParsingStarting ()
{
m_json = false;
}

virtual
~CommandOptions ()
{
}

virtual Error
SetOptionValue (uint32_t option_idx, const char *option_arg)
{
const int short_option = m_getopt_table[option_idx].val;
Error error;

switch (short_option)
{
case 'j':
m_json = true;
break;

default:
return Error("invalid short option character '%c'", short_option);

}
return error;
}

const OptionDefinition*
GetDefinitions ()
{
return g_option_table;
}

bool m_json;

static OptionDefinition g_option_table[];
};

virtual
Options *
GetOptions ()
{
return &m_options;
}


virtual
~CommandObjectThreadInfo ()
{
}

virtual bool
DoExecute (Args& command, CommandReturnObject &result)
{
result.SetStatus (eReturnStatusSuccessFinishResult);
Stream &strm = result.GetOutputStream();

if (command.GetArgumentCount() == 0)
{
Thread *thread = m_exe_ctx.GetThreadPtr();
if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
{
result.SetStatus (eReturnStatusSuccessFinishResult);
}
}
else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
{
Process *process = m_exe_ctx.GetProcessPtr();
uint32_t idx = 0;
for (ThreadSP thread_sp : process->Threads())
{
if (idx != 0)
result.AppendMessage("");
if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
{
result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx);
result.SetStatus (eReturnStatusFailed);
return false;
}
++idx;
}
}
else
{
const size_t num_args = command.GetArgumentCount();
Process *process = m_exe_ctx.GetProcessPtr();
Mutex::Locker locker (process->GetThreadList().GetMutex());
std::vector<ThreadSP> thread_sps;

for (size_t i = 0; i < num_args; i++)
{
bool success;

uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
if (!success)
{
result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
result.SetStatus (eReturnStatusFailed);
return false;
}

thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));

if (!thread_sps[i])
{
result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
result.SetStatus (eReturnStatusFailed);
return false;
}

}

for (uint32_t i = 0; i < num_args; i++)
{
if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json))
{
result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i));
result.SetStatus (eReturnStatusFailed);
return false;
}

if (i < num_args - 1)
result.AppendMessage("");
}

}
return result.Succeeded();
}

CommandOptions m_options;

};

OptionDefinition
CommandObjectThreadInfo::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."},

{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};


//-------------------------------------------------------------------------
// CommandObjectThreadReturn
//-------------------------------------------------------------------------
Expand Down Expand Up @@ -1764,6 +1951,7 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &
LoadSubCommand ("jump", CommandObjectSP (new CommandObjectThreadJump (interpreter)));
LoadSubCommand ("select", CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
LoadSubCommand ("until", CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
LoadSubCommand ("info", CommandObjectSP (new CommandObjectThreadInfo (interpreter)));
LoadSubCommand ("step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
interpreter,
"thread step-in",
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ add_lldb_library(lldbCore
StreamGDBRemote.cpp
StreamString.cpp
StringList.cpp
StructuredData.cpp
Timer.cpp
UserID.cpp
UserSettingsController.cpp
Expand Down
103 changes: 103 additions & 0 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/StringRef.h"

#include "lldb/lldb-private.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
Expand All @@ -26,6 +27,7 @@
#include "lldb/Core/StreamCallback.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectVariable.h"
Expand Down Expand Up @@ -105,6 +107,8 @@ g_language_enumerators[] =
FILE_AND_LINE\
"{, name = '${thread.name}'}"\
"{, queue = '${thread.queue}'}"\
"{, activity = '${thread.info.activity.name}'}" \
"{, ${thread.info.trace_messages} messages}" \
"{, stop reason = ${thread.stop-reason}}"\
"{\\nReturn value: ${thread.return-value}}"\
"\\n"
Expand Down Expand Up @@ -1430,6 +1434,96 @@ IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &form
return false;
}

// Find information for the "thread.info.*" specifiers in a format string
static bool
FormatThreadExtendedInfoRecurse
(
const char *var_name_begin,
StructuredData::ObjectSP thread_info_dictionary,
const SymbolContext *sc,
const ExecutionContext *exe_ctx,
Stream &s
)
{
bool var_success = false;
std::string token_format;

llvm::StringRef var_name(var_name_begin);
size_t percent_idx = var_name.find('%');
size_t close_curly_idx = var_name.find('}');
llvm::StringRef path = var_name;
llvm::StringRef formatter = var_name;

// 'path' will be the dot separated list of objects to transverse up until we hit
// a close curly brace, a percent sign, or an end of string.
if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos)
{
if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos)
{
if (percent_idx < close_curly_idx)
{
path = var_name.slice(0, percent_idx);
formatter = var_name.substr (percent_idx);
}
else
{
path = var_name.slice(0, close_curly_idx);
formatter = var_name.substr (close_curly_idx);
}
}
else if (percent_idx != llvm::StringRef::npos)
{
path = var_name.slice(0, percent_idx);
formatter = var_name.substr (percent_idx);
}
else if (close_curly_idx != llvm::StringRef::npos)
{
path = var_name.slice(0, close_curly_idx);
formatter = var_name.substr (close_curly_idx);
}
}

StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path);

if (value.get())
{
if (value->GetType() == StructuredData::Type::eTypeInteger)
{
if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
{
s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue());
var_success = true;
}
}
else if (value->GetType() == StructuredData::Type::eTypeFloat)
{
s.Printf ("%f", value->GetAsFloat()->GetValue());
var_success = true;
}
else if (value->GetType() == StructuredData::Type::eTypeString)
{
s.Printf("%s", value->GetAsString()->GetValue().c_str());
var_success = true;
}
else if (value->GetType() == StructuredData::Type::eTypeArray)
{
if (value->GetAsArray()->GetSize() > 0)
{
s.Printf ("%zu", value->GetAsArray()->GetSize());
var_success = true;
}
}
else if (value->GetType() == StructuredData::Type::eTypeDictionary)
{
s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize());
var_success = true;
}
}

return var_success;
}


static bool
FormatPromptRecurse
(
Expand Down Expand Up @@ -1969,6 +2063,15 @@ FormatPromptRecurse
if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name))
var_success = true;
}
else if (IsToken (var_name_begin, "info."))
{
var_name_begin += ::strlen("info.");
StructuredData::ObjectSP object_sp = thread->GetExtendedInfo();
if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary)
{
var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s);
}
}
}
}
}
Expand Down
427 changes: 427 additions & 0 deletions lldb/source/Core/StructuredData.cpp

Large diffs are not rendered by default.

62 changes: 61 additions & 1 deletion lldb/source/DataFormatters/CXXFormatterFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"

#include <algorithm>
Expand Down Expand Up @@ -965,6 +964,61 @@ ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
return true;
}

bool
lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream)
{
if (!descriptor)
return false;
uint64_t len_bits = 0, data_bits = 0;
if (!descriptor->GetTaggedPointerInfo(&len_bits,&data_bits,nullptr))
return false;

static const int g_MaxNonBitmaskedLen = 7; //TAGGED_STRING_UNPACKED_MAXLEN
static const int g_SixbitMaxLen = 9;
static const int g_fiveBitMaxLen = 11;

static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013" "bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";

if (len_bits > g_fiveBitMaxLen)
return false;

// this is a fairly ugly trick - pretend that the numeric value is actually a char*
// this works under a few assumptions:
// little endian architecture
// sizeof(uint64_t) > g_MaxNonBitmaskedLen
if (len_bits <= g_MaxNonBitmaskedLen)
{
stream.Printf("@\"%s\"",(const char*)&data_bits);
return true;
}

// if the data is bitmasked, we need to actually process the bytes
uint8_t bitmask = 0;
uint8_t shift_offset = 0;

if (len_bits <= g_SixbitMaxLen)
{
bitmask = 0x03f;
shift_offset = 6;
}
else
{
bitmask = 0x01f;
shift_offset = 5;
}

std::vector<uint8_t> bytes;
bytes.resize(len_bits);
for (; len_bits > 0; data_bits >>= shift_offset, --len_bits)
{
uint8_t packed = data_bits & bitmask;
bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
}

stream.Printf("@\"%s\"",&bytes[0]);
return true;
}

bool
lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
{
Expand Down Expand Up @@ -994,6 +1048,12 @@ lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream&
if (!class_name || !*class_name)
return false;

bool is_tagged_ptr = (0 == strcmp(class_name,"NSTaggedPointerString")) && descriptor->GetTaggedPointerInfo();
// for a tagged pointer, the descriptor has everything we need
if (is_tagged_ptr)
return NSTaggedString_SummaryProvider(descriptor, stream);

// if not a tagged pointer that we know about, try the normal route
uint64_t info_bits_location = valobj_addr + ptr_size;
if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
info_bits_location += 3;
Expand Down
378 changes: 356 additions & 22 deletions lldb/source/DataFormatters/NSArray.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_supports_qXfer_libraries_read (eLazyBoolCalculate),
m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate),
m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),
m_supports_jThreadExtendedInfo (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
Expand Down Expand Up @@ -495,6 +496,24 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)
return m_supports_p;
}

bool
GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
{
if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate)
{
StringExtractorGDBRemote response;
m_supports_jThreadExtendedInfo = eLazyBoolNo;
if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success)
{
if (response.IsOKResponse())
{
m_supports_jThreadExtendedInfo = eLazyBoolYes;
}
}
}
return m_supports_jThreadExtendedInfo;
}

bool
GDBRemoteCommunicationClient::GetxPacketSupported ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteCommunication
bool
AvoidGPackets(ProcessGDBRemote *process);

bool
GetThreadExtendedInfoSupported();

protected:

PacketResult
Expand Down Expand Up @@ -555,6 +558,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteCommunication
lldb_private::LazyBool m_supports_qXfer_libraries_read;
lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read;
lldb_private::LazyBool m_supports_augmented_libraries_svr4_read;
lldb_private::LazyBool m_supports_jThreadExtendedInfo;

bool
m_supports_qProcessInfoPID:1,
Expand Down
45 changes: 45 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Utility/PseudoTerminal.h"

// Project includes
Expand Down Expand Up @@ -3149,6 +3150,50 @@ ProcessGDBRemote::GetAuxvData()
return buf;
}

StructuredData::ObjectSP
ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid)
{
StructuredData::ObjectSP object_sp;

if (m_gdb_comm.GetThreadExtendedInfoSupported())
{
StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
SystemRuntime *runtime = GetSystemRuntime();
if (runtime)
{
runtime->AddThreadExtendedInfoPacketHints (args_dict);
}
args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid);

StreamString packet;
packet << "jThreadExtendedInfo:";
args_dict->Dump (packet);

// FIXME the final character of a JSON dictionary, '}', is the escape
// character in gdb-remote binary mode. lldb currently doesn't escape
// these characters in its packet output -- so we add the quoted version
// of the } character here manually in case we talk to a debugserver which
// un-escapes the chracters at packet read time.
packet << (char) (0x7d ^ 0x20);

StringExtractorGDBRemote response;
if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success)
{
StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse)
{
if (!response.Empty())
{
// The packet has already had the 0x7d xor quoting stripped out at the
// GDBRemoteCommunication packet receive level.
object_sp = StructuredData::ParseJSON (response.GetStringRef());
}
}
}
}
return object_sp;
}

// Establish the largest memory read/write payloads we should use.
// If the remote stub has a max packet size, stay under that size.
//
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "lldb/Core/Error.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/StringList.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
Expand Down Expand Up @@ -307,6 +308,9 @@ class ProcessGDBRemote : public lldb_private::Process
virtual const lldb::DataBufferSP
GetAuxvData();

lldb_private::StructuredData::ObjectSP
GetExtendedInfoForThread (lldb::tid_t tid);

void
GetMaxMemorySize();

Expand Down
17 changes: 17 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,23 @@ ThreadGDBRemote::GetQueueLibdispatchQueueAddress ()
return dispatch_queue_t_addr;
}

StructuredData::ObjectSP
ThreadGDBRemote::FetchThreadExtendedInfo ()
{
StructuredData::ObjectSP object_sp;
const lldb::user_id_t tid = GetProtocolID();
Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
if (log)
log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid);
ProcessSP process_sp (GetProcess());
if (process_sp)
{
ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
object_sp = gdb_process->GetExtendedInfoForThread (tid);
}
return object_sp;
}

void
ThreadGDBRemote::WillResume (StateType resume_state)
{
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include <string>

#include "lldb/Core/StructuredData.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"

Expand Down Expand Up @@ -86,6 +87,9 @@ class ThreadGDBRemote : public lldb_private::Thread
m_thread_dispatch_qaddr = thread_dispatch_qaddr;
}

lldb_private::StructuredData::ObjectSP
FetchThreadExtendedInfo ();

protected:

friend class ProcessGDBRemote;
Expand Down
180 changes: 178 additions & 2 deletions lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Expression/ClangFunction.h"
#include "lldb/Expression/ClangUtilityFunction.h"
#include "lldb/Host/FileSpec.h"
Expand All @@ -28,7 +29,6 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/Process.h"


#include "SystemRuntimeMacOSX.h"

using namespace lldb;
Expand Down Expand Up @@ -93,7 +93,13 @@ SystemRuntimeMacOSX::SystemRuntimeMacOSX (Process* process) :
m_page_to_free_size(0),
m_lib_backtrace_recording_info(),
m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
m_libdispatch_offsets()
m_libdispatch_offsets(),
m_libpthread_layout_offsets_addr (LLDB_INVALID_ADDRESS),
m_libpthread_offsets(),
m_dispatch_tsd_indexes_addr (LLDB_INVALID_ADDRESS),
m_libdispatch_tsd_indexes(),
m_dispatch_voucher_offsets_addr (LLDB_INVALID_ADDRESS),
m_libdispatch_voucher_offsets()
{
}

Expand Down Expand Up @@ -214,6 +220,30 @@ SystemRuntimeMacOSX::GetQueueKind (addr_t dispatch_queue_addr)
return kind;
}

void
SystemRuntimeMacOSX::AddThreadExtendedInfoPacketHints (lldb_private::StructuredData::ObjectSP dict_sp)
{
StructuredData::Dictionary *dict = dict_sp->GetAsDictionary();
if (dict)
{
ReadLibpthreadOffsets();
if (m_libpthread_offsets.IsValid())
{
dict->AddIntegerItem ("plo_pthread_tsd_base_offset", m_libpthread_offsets.plo_pthread_tsd_base_offset);
dict->AddIntegerItem ("plo_pthread_tsd_base_address_offset", m_libpthread_offsets.plo_pthread_tsd_base_address_offset);
dict->AddIntegerItem ("plo_pthread_tsd_entry_size", m_libpthread_offsets.plo_pthread_tsd_entry_size);
}

ReadLibdispatchTSDIndexes ();
if (m_libdispatch_tsd_indexes.IsValid())
{
dict->AddIntegerItem ("dti_queue_index", m_libdispatch_tsd_indexes.dti_queue_index);
dict->AddIntegerItem ("dti_voucher_index", m_libdispatch_tsd_indexes.dti_voucher_index);
dict->AddIntegerItem ("dti_qos_class_index", m_libdispatch_tsd_indexes.dti_qos_class_index);
}
}
}

bool
SystemRuntimeMacOSX::SafeToCallFunctionsOnThisThread (ThreadSP thread_sp)
{
Expand Down Expand Up @@ -312,6 +342,152 @@ SystemRuntimeMacOSX::ReadLibdispatchOffsets ()
}
}

void
SystemRuntimeMacOSX::ReadLibpthreadOffsetsAddress ()
{
if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS)
return;

static ConstString g_libpthread_layout_offsets_symbol_name ("pthread_layout_offsets");
const Symbol *libpthread_layout_offsets_symbol = NULL;

ModuleSpec libpthread_module_spec (FileSpec("libsystem_pthread.dylib", false));
ModuleSP module_sp (m_process->GetTarget().GetImages().FindFirstModule (libpthread_module_spec));
if (module_sp)
{
libpthread_layout_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType
(g_libpthread_layout_offsets_symbol_name, eSymbolTypeData);
if (libpthread_layout_offsets_symbol)
{
m_libpthread_layout_offsets_addr = libpthread_layout_offsets_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
}
}
}

void
SystemRuntimeMacOSX::ReadLibpthreadOffsets ()
{
if (m_libpthread_offsets.IsValid())
return;

ReadLibpthreadOffsetsAddress ();

if (m_libpthread_layout_offsets_addr != LLDB_INVALID_ADDRESS)
{
uint8_t memory_buffer[sizeof (struct LibpthreadOffsets)];
DataExtractor data (memory_buffer,
sizeof(memory_buffer),
m_process->GetByteOrder(),
m_process->GetAddressByteSize());
Error error;
if (m_process->ReadMemory (m_libpthread_layout_offsets_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
{
lldb::offset_t data_offset = 0;

// The struct LibpthreadOffsets is a series of uint16_t's - extract them all
// in one big go.
data.GetU16 (&data_offset, &m_libpthread_offsets.plo_version, sizeof (struct LibpthreadOffsets) / sizeof (uint16_t));
}
}
}

void
SystemRuntimeMacOSX::ReadLibdispatchTSDIndexesAddress ()
{
if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS)
return;

static ConstString g_libdispatch_tsd_indexes_symbol_name ("dispatch_tsd_indexes");
const Symbol *libdispatch_tsd_indexes_symbol = NULL;

ModuleSpec libpthread_module_spec (FileSpec("libdispatch.dylib", false));
ModuleSP module_sp (m_process->GetTarget().GetImages().FindFirstModule (libpthread_module_spec));
if (module_sp)
{
libdispatch_tsd_indexes_symbol = module_sp->FindFirstSymbolWithNameAndType
(g_libdispatch_tsd_indexes_symbol_name, eSymbolTypeData);
if (libdispatch_tsd_indexes_symbol)
{
m_dispatch_tsd_indexes_addr = libdispatch_tsd_indexes_symbol->GetAddress().GetLoadAddress(&m_process->GetTarget());
}
}
}

void
SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes ()
{
if (m_libdispatch_tsd_indexes.IsValid())
return;

ReadLibdispatchTSDIndexesAddress ();

if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS)
{
size_t maximum_tsd_indexes_struct_size;
Address dti_struct_addr;
uint16_t dti_version = 2;
if (m_process->GetTarget().ResolveLoadAddress(m_dispatch_tsd_indexes_addr, dti_struct_addr))
{
Error error;
uint16_t version = m_process->GetTarget().ReadUnsignedIntegerFromMemory (dti_struct_addr, false, 2, UINT16_MAX, error);
if (error.Success() && dti_version != UINT16_MAX)
{
dti_version = version;
}
}
if (dti_version == 1)
{
if (m_process->GetAddressByteSize() == 4)
{
maximum_tsd_indexes_struct_size = 4 + 4 + 4 + 4;
}
else
{
maximum_tsd_indexes_struct_size = 8 + 8 + 8 + 8;
}
}
else
{
maximum_tsd_indexes_struct_size = 2 + 2 + 2 + 2;
}

uint8_t memory_buffer[maximum_tsd_indexes_struct_size];
DataExtractor data (memory_buffer,
sizeof(memory_buffer),
m_process->GetByteOrder(),
m_process->GetAddressByteSize());
Error error;
if (m_process->ReadMemory (m_dispatch_tsd_indexes_addr, memory_buffer, sizeof(memory_buffer), error) == sizeof(memory_buffer))
{
lldb::offset_t offset = 0;

if (dti_version == 1)
{
m_libdispatch_tsd_indexes.dti_version = data.GetU16 (&offset);
// word alignment to next item
if (m_process->GetAddressByteSize() == 4)
{
offset += 2;
}
else
{
offset += 6;
}
m_libdispatch_tsd_indexes.dti_queue_index = data.GetPointer (&offset);
m_libdispatch_tsd_indexes.dti_voucher_index = data.GetPointer (&offset);
m_libdispatch_tsd_indexes.dti_qos_class_index = data.GetPointer (&offset);
}
else
{
m_libdispatch_tsd_indexes.dti_version = data.GetU16 (&offset);
m_libdispatch_tsd_indexes.dti_queue_index = data.GetU16 (&offset);
m_libdispatch_tsd_indexes.dti_voucher_index = data.GetU16 (&offset);
m_libdispatch_tsd_indexes.dti_qos_class_index = data.GetU16 (&offset);
}
}
}
}


ThreadSP
SystemRuntimeMacOSX::GetExtendedBacktraceThread (ThreadSP real_thread, ConstString type)
Expand Down
95 changes: 94 additions & 1 deletion lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
// Other libraries and framework includes

#include "lldb/Target/SystemRuntime.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/UUID.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/QueueItem.h"
Expand Down Expand Up @@ -108,6 +109,9 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
virtual lldb::QueueKind
GetQueueKind (lldb::addr_t dispatch_queue_addr);

virtual void
AddThreadExtendedInfoPacketHints (lldb_private::StructuredData::ObjectSP dict);

virtual bool
SafeToCallFunctionsOnThisThread (lldb::ThreadSP thread_sp);

Expand Down Expand Up @@ -176,6 +180,13 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
uint16_t dqo_running;
uint16_t dqo_running_size;

uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X 10.10/iOS 8
uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X 10.10/iOS 8
uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8
uint16_t dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8
uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8

LibdispatchOffsets ()
{
dqo_version = UINT16_MAX;
Expand All @@ -184,6 +195,10 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
dqo_label = UINT16_MAX;
dqo_width = UINT16_MAX;
dqo_running = UINT16_MAX;
dqo_suspend_cnt = UINT16_MAX;
dqo_target_queue = UINT16_MAX;
dqo_target_queue = UINT16_MAX;
dqo_priority = UINT16_MAX;
};

bool
Expand All @@ -199,6 +214,62 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
}
};

struct LibdispatchVoucherOffsets
{
uint16_t vo_version;
uint16_t vo_activity_ids_count;
uint16_t vo_activity_ids_count_size;
uint16_t vo_activity_ids_array;
uint16_t vo_activity_ids_array_entry_size;

LibdispatchVoucherOffsets () :
vo_version (UINT16_MAX),
vo_activity_ids_count (UINT16_MAX),
vo_activity_ids_count_size (UINT16_MAX),
vo_activity_ids_array (UINT16_MAX),
vo_activity_ids_array_entry_size (UINT16_MAX)
{ }

bool IsValid () { return vo_version != UINT16_MAX; }
};

struct LibdispatchTSDIndexes
{
uint16_t dti_version;
uint64_t dti_queue_index;
uint64_t dti_voucher_index;
uint64_t dti_qos_class_index;

LibdispatchTSDIndexes () :
dti_version (UINT16_MAX),
dti_queue_index (UINT64_MAX),
dti_voucher_index (UINT64_MAX),
dti_qos_class_index (UINT64_MAX)
{ }

bool IsValid () { return dti_version != UINT16_MAX; }
};

struct LibpthreadOffsets
{
uint16_t plo_version;
uint16_t plo_pthread_tsd_base_offset;
uint16_t plo_pthread_tsd_base_address_offset;
uint16_t plo_pthread_tsd_entry_size;

LibpthreadOffsets () :
plo_version (UINT16_MAX),
plo_pthread_tsd_base_offset (UINT16_MAX),
plo_pthread_tsd_base_address_offset (UINT16_MAX),
plo_pthread_tsd_entry_size (UINT16_MAX)
{
}

bool IsValid ()
{
return plo_version != UINT16_MAX;
}
};

// The libBacktraceRecording function __introspection_dispatch_queue_get_pending_items has
// two forms. It can either return a simple array of item_refs (void *) size or it can return
Expand All @@ -225,6 +296,18 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
void
ReadLibdispatchOffsets ();

void
ReadLibpthreadOffsetsAddress();

void
ReadLibpthreadOffsets ();

void
ReadLibdispatchTSDIndexesAddress ();

void
ReadLibdispatchTSDIndexes ();

PendingItemsForQueue
GetPendingItemRefsForQueue (lldb::addr_t queue);

Expand All @@ -239,9 +322,19 @@ class SystemRuntimeMacOSX : public lldb_private::SystemRuntime
lldb::addr_t m_page_to_free;
uint64_t m_page_to_free_size;
libBacktraceRecording_info m_lib_backtrace_recording_info;

lldb::addr_t m_dispatch_queue_offsets_addr;
struct LibdispatchOffsets m_libdispatch_offsets;

lldb::addr_t m_libpthread_layout_offsets_addr;
struct LibpthreadOffsets m_libpthread_offsets;

lldb::addr_t m_dispatch_tsd_indexes_addr;
struct LibdispatchTSDIndexes m_libdispatch_tsd_indexes;

lldb::addr_t m_dispatch_voucher_offsets_addr;
struct LibdispatchVoucherOffsets m_libdispatch_voucher_offsets;

DISALLOW_COPY_AND_ASSIGN (SystemRuntimeMacOSX);
};

Expand Down
83 changes: 82 additions & 1 deletion lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,9 @@ Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :
m_temporary_resume_state (eStateRunning),
m_unwinder_ap (),
m_destroy_called (false),
m_override_should_notify (eLazyBoolCalculate)
m_override_should_notify (eLazyBoolCalculate),
m_extended_info_fetched (false),
m_extended_info ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
Expand Down Expand Up @@ -1709,6 +1711,9 @@ Thread::ClearStackFrames ()
if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched())
m_prev_frames_sp.swap (m_curr_frames_sp);
m_curr_frames_sp.reset();

m_extended_info.reset();
m_extended_info_fetched = false;
}

lldb::StackFrameSP
Expand Down Expand Up @@ -2068,6 +2073,82 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint
return num_frames_shown;
}

bool
Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json)
{
DumpUsingSettingsFormat (strm, 0);
strm.Printf("\n");

StructuredData::ObjectSP thread_info = GetExtendedInfo();

if (thread_info && print_json)
{
thread_info->Dump (strm);
strm.Printf("\n");
return true;
}

if (thread_info)
{
StructuredData::ObjectSP activity = thread_info->GetObjectForDotSeparatedPath("activity");
StructuredData::ObjectSP breadcrumb = thread_info->GetObjectForDotSeparatedPath("breadcrumb");
StructuredData::ObjectSP messages = thread_info->GetObjectForDotSeparatedPath("trace_messages");

bool printed_activity = false;
if (activity && activity->GetType() == StructuredData::Type::eTypeDictionary)
{
StructuredData::Dictionary *activity_dict = activity->GetAsDictionary();
StructuredData::ObjectSP id = activity_dict->GetValueForKey("id");
StructuredData::ObjectSP name = activity_dict->GetValueForKey("name");
if (name && name->GetType() == StructuredData::Type::eTypeString
&& id && id->GetType() == StructuredData::Type::eTypeInteger)
{
strm.Printf(" Activity '%s', 0x%" PRIx64 "\n", name->GetAsString()->GetValue().c_str(), id->GetAsInteger()->GetValue());
}
printed_activity = true;
}
bool printed_breadcrumb = false;
if (breadcrumb && breadcrumb->GetType() == StructuredData::Type::eTypeDictionary)
{
if (printed_activity)
strm.Printf ("\n");
StructuredData::Dictionary *breadcrumb_dict = breadcrumb->GetAsDictionary();
StructuredData::ObjectSP breadcrumb_text = breadcrumb_dict->GetValueForKey ("name");
if (breadcrumb_text && breadcrumb_text->GetType() == StructuredData::Type::eTypeString)
{
strm.Printf (" Current Breadcrumb: %s\n", breadcrumb_text->GetAsString()->GetValue().c_str());
}
printed_breadcrumb = true;
}
if (messages && messages->GetType() == StructuredData::Type::eTypeArray)
{
if (printed_breadcrumb)
strm.Printf("\n");
StructuredData::Array *messages_array = messages->GetAsArray();
const size_t msg_count = messages_array->GetSize();
if (msg_count > 0)
{
strm.Printf (" %zu trace messages:\n", msg_count);
for (size_t i = 0; i < msg_count; i++)
{
StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i);
if (message && message->GetType() == StructuredData::Type::eTypeDictionary)
{
StructuredData::Dictionary *message_dict = message->GetAsDictionary();
StructuredData::ObjectSP message_text = message_dict->GetValueForKey ("message");
if (message_text && message_text->GetType() == StructuredData::Type::eTypeString)
{
strm.Printf (" %s\n", message_text->GetAsString()->GetValue().c_str());
}
}
}
}
}
}

return true;
}

size_t
Thread::GetStackFrameStatus (Stream& strm,
uint32_t first_frame,
Expand Down
113 changes: 84 additions & 29 deletions lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@
26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; };
26CE05C4115C36590022F371 /* CFData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DE2E0D3EE55B007E4CA2 /* CFData.cpp */; };
26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; };
26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; };
26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; };
26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; };
4971AE7213D10F4F00649E37 /* HasAVX.s in Sources */ = {isa = PBXBuildFile; fileRef = 4971AE7113D10F4F00649E37 /* HasAVX.s */; };
AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -131,9 +132,15 @@
49F530111331519C008956F6 /* MachRegisterStatesI386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesI386.h; sourceTree = "<group>"; };
49F5301213316D7F008956F6 /* MachRegisterStatesX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesX86_64.h; sourceTree = "<group>"; };
9457ECF61419864100DFE7D8 /* stack_logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stack_logging.h; sourceTree = "<group>"; };
AF0934BA18E12B92005A11FD /* Genealogy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Genealogy.h; sourceTree = "<group>"; };
AF0934BB18E12B92005A11FD /* GenealogySPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenealogySPI.h; sourceTree = "<group>"; };
AF5B2E72150EB6020075D7FD /* com.apple.debugserver-secure.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "com.apple.debugserver-secure.plist"; sourceTree = "<group>"; };
AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "debugserver-macosx-entitlements.plist"; sourceTree = "<group>"; };
AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = "<group>"; };
AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = "<group>"; };
AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = "<group>"; };
ED128B7918E1F163003F6A7B /* libpmenergy.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmenergy.dylib; path = usr/lib/libpmenergy.dylib; sourceTree = SDKROOT; };
ED128B7A18E1F163003F6A7B /* libpmsample.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpmsample.dylib; path = usr/lib/libpmsample.dylib; sourceTree = SDKROOT; };
EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = "<group>"; };
EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = "<group>"; };
EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -196,6 +203,7 @@
26203D1D1641EFB200A662F7 /* com.apple.debugserver.internal.plist */,
260FC7320E5B290400043FC9 /* debugnub-exports */,
26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */,
AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */,
26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */,
AF5B2E72150EB6020075D7FD /* com.apple.debugserver-secure.plist */,
EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */,
Expand Down Expand Up @@ -244,6 +252,8 @@
26ACA3330D3E94F200A2120B /* Framework */ = {
isa = PBXGroup;
children = (
ED128B7918E1F163003F6A7B /* libpmenergy.dylib */,
ED128B7A18E1F163003F6A7B /* libpmsample.dylib */,
26ACA3340D3E956300A2120B /* CoreFoundation.framework */,
);
name = Framework;
Expand Down Expand Up @@ -273,6 +283,8 @@
26C637E60C71334A0024798E /* MacOSX */ = {
isa = PBXGroup;
children = (
AF0934BA18E12B92005A11FD /* Genealogy.h */,
AF0934BB18E12B92005A11FD /* GenealogySPI.h */,
2695DD920D3EBFF6007E4CA2 /* CFBundle.h */,
2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */,
2695DE2D0D3EE55B007E4CA2 /* CFData.h */,
Expand All @@ -288,6 +300,7 @@
4971AE7013D10F4F00649E37 /* HasAVX.h */,
4971AE7113D10F4F00649E37 /* HasAVX.s */,
26C637E80C71334A0024798E /* dbgnub-mig.defs */,
AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */,
26C637EF0C71334A0024798E /* MachException.h */,
26C637EE0C71334A0024798E /* MachException.cpp */,
26C637F10C71334A0024798E /* MachProcess.h */,
Expand Down Expand Up @@ -457,6 +470,7 @@
26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */,
26CE05B6115C36390022F371 /* MachTask.mm in Sources */,
26CE05B7115C363B0022F371 /* DNB.cpp in Sources */,
AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */,
26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */,
26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */,
26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */,
Expand Down Expand Up @@ -579,6 +593,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist";
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 320.99.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
Expand All @@ -595,20 +610,22 @@
INSTALL_PATH = /usr/bin;
"INSTALL_PATH[sdk=iphoneos*]" = /Developer/usr/bin/;
LLDB_DEBUGSERVER = 1;
OTHER_CFLAGS = "-Wparentheses";
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=macosx10.10internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LFLAGS = "";
"LLDB_ENERGY_LFLAGS[sdk=macosx10.10internal]" = "-weak-lpmenergy -weak-lpmsample";
MACOSX_DEPLOYMENT_TARGET = 10.9;
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
"-Wparentheses",
"-DWITH_LOCKDOWN",
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
);
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-framework",
SpringBoardServices,
Expand All @@ -618,6 +635,13 @@
Foundation,
"-llockdown",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
SKIP_INSTALL = YES;
Expand All @@ -634,6 +658,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
COPY_PHASE_STRIP = YES;
Expand All @@ -651,20 +676,23 @@
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
LLDB_DEBUGSERVER = 1;
OTHER_CFLAGS = "-Wparentheses";
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=macosx10.10internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LFLAGS = "";
"LLDB_ENERGY_LFLAGS[sdk=macosx10.10internal]" = "-weak-lpmenergy -weak-lpmsample";
MACOSX_DEPLOYMENT_TARGET = 10.9;
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
"-Wparentheses",
"-DWITH_LOCKDOWN",
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
);
OTHER_LDFLAGS = "";
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-framework",
SpringBoardServices,
Expand All @@ -674,6 +702,13 @@
Foundation,
"-llockdown",
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "";
Expand All @@ -690,6 +725,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
COPY_PHASE_STRIP = YES;
Expand All @@ -707,20 +743,22 @@
HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
INSTALL_PATH = /usr/bin;
LLDB_DEBUGSERVER = 1;
OTHER_CFLAGS = "-Wparentheses";
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=macosx10.10internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LFLAGS = "";
"LLDB_ENERGY_LFLAGS[sdk=macosx10.10internal]" = "-weak-lpmenergy -weak-lpmsample";
MACOSX_DEPLOYMENT_TARGET = 10.9;
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
"-Wparentheses",
"-DWITH_LOCKDOWN",
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
);
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-framework",
SpringBoardServices,
Expand All @@ -730,6 +768,13 @@
"-framework",
Foundation,
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "";
Expand Down Expand Up @@ -778,6 +823,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LIBRARY = "libc++";
"CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist";
"CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
COPY_PHASE_STRIP = YES;
Expand All @@ -795,20 +841,22 @@
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
INSTALL_PATH = /usr/bin;
LLDB_DEBUGSERVER = 1;
OTHER_CFLAGS = "-Wparentheses";
LLDB_ENERGY_CFLAGS = "";
"LLDB_ENERGY_CFLAGS[sdk=macosx10.10internal]" = "-DLLDB_ENERGY";
LLDB_ENERGY_LFLAGS = "";
"LLDB_ENERGY_LFLAGS[sdk=macosx10.10internal]" = "-weak-lpmenergy -weak-lpmsample";
MACOSX_DEPLOYMENT_TARGET = 10.9;
OTHER_CFLAGS = (
"-Wparentheses",
"$(LLDB_ENERGY_CFLAGS)",
);
"OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
"-Wparentheses",
"-DWITH_LOCKDOWN",
"-DWITH_BKS",
"-DOS_OBJECT_USE_OBJC=0",
);
"OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)";
OTHER_LDFLAGS = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
);
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-framework",
SpringBoardServices,
Expand All @@ -818,6 +866,13 @@
"-framework",
Foundation,
);
"OTHER_LDFLAGS[sdk=macosx*]" = (
"-sectcreate",
__TEXT,
__info_plist,
"$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist",
"$(LLDB_ENERGY_LFLAGS)",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
PRODUCT_NAME = debugserver;
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "";
Expand Down
69 changes: 69 additions & 0 deletions lldb/tools/debugserver/source/DNB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

#include "MacOSX/MachProcess.h"
#include "MacOSX/MachTask.h"
#include "MacOSX/Genealogy.h"
#include "MacOSX/ThreadInfo.h"
#include "CFString.h"
#include "DNBLog.h"
#include "DNBDataRef.h"
Expand Down Expand Up @@ -977,6 +979,73 @@ DNBStateAsString(nub_state_t state)
return "nub_state_t ???";
}

Genealogy::ThreadActivitySP
DNBGetGenealogyInfoForThread (nub_process_t pid, nub_thread_t tid, bool &timed_out)
{
Genealogy::ThreadActivitySP thread_activity_sp;
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
thread_activity_sp = procSP->GetGenealogyInfoForThread (tid, timed_out);
return thread_activity_sp;
}

Genealogy::ProcessExecutableInfoSP
DNBGetGenealogyImageInfo (nub_process_t pid, size_t idx)
{
Genealogy::ProcessExecutableInfoSP image_info_sp;
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
image_info_sp = procSP->GetGenealogyImageInfo (idx);
}
return image_info_sp;
}

ThreadInfo::QoS
DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index)
{
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
return procSP->GetRequestedQoS (tid, tsd, dti_qos_class_index);
}
return ThreadInfo::QoS();
}

nub_addr_t
DNBGetPThreadT (nub_process_t pid, nub_thread_t tid)
{
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
return procSP->GetPThreadT (tid);
}
return INVALID_NUB_ADDRESS;
}

nub_addr_t
DNBGetDispatchQueueT (nub_process_t pid, nub_thread_t tid)
{
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
return procSP->GetDispatchQueueT (tid);
}
return INVALID_NUB_ADDRESS;
}

nub_addr_t
DNBGetTSDAddressForThread (nub_process_t pid, nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
{
MachProcessSP procSP;
if (GetProcessSP (pid, procSP))
{
return procSP->GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
}
return INVALID_NUB_ADDRESS;
}


const char *
DNBProcessGetExecutablePath (nub_process_t pid)
{
Expand Down
9 changes: 9 additions & 0 deletions lldb/tools/debugserver/source/DNB.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#ifndef __DNB_h__
#define __DNB_h__

#include "MacOSX/Genealogy.h"
#include "MacOSX/ThreadInfo.h"
#include "DNBDefs.h"
#include <mach/thread_info.h>
#include <string>
Expand Down Expand Up @@ -129,6 +131,13 @@ nub_bool_t DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t
nub_bool_t DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value);
nub_bool_t DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info);
const char * DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid);
Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread (nub_process_t pid, nub_thread_t tid, bool &timed_out);
Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo (nub_process_t pid, size_t idx);
ThreadInfo::QoS DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index);
nub_addr_t DNBGetPThreadT (nub_process_t pid, nub_thread_t tid);
nub_addr_t DNBGetDispatchQueueT (nub_process_t pid, nub_thread_t tid);
nub_addr_t DNBGetTSDAddressForThread (nub_process_t pid, nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);
//
//----------------------------------------------------------------------
// Breakpoint functions
//----------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions lldb/tools/debugserver/source/DNBDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ enum DNBProfileDataScanType
eProfileMemoryDirtyPage = (1 << 7), // Assume eProfileMemory, get Dirty Page size as well.
eProfileMemoryAnonymous = (1 << 8), // Assume eProfileMemory, get Anonymous memory as well.

eProfileEnergy = (1 << 9),

eProfileAll = 0xffffffff
};

Expand Down
1 change: 1 addition & 0 deletions lldb/tools/debugserver/source/MacOSX/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ add_lldb_executable(debugserver
CFBundle.cpp
CFData.cpp
CFString.cpp
Genealogy.cpp
MachException.cpp
MachProcess.mm
MachTask.mm
Expand Down
302 changes: 302 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/Genealogy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
///===-- Activity.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <Availability.h>
#include <string>
#include <dlfcn.h>
#include <uuid/uuid.h>

#include "DNBDefs.h"
#include "Genealogy.h"
#include "GenealogySPI.h"
#include "MachThreadList.h"

//---------------------------
/// Constructor
//---------------------------

Genealogy::Genealogy () :
m_os_activity_diagnostic_for_pid (nullptr),
m_os_activity_iterate_processes (nullptr),
m_os_activity_iterate_breadcrumbs (nullptr),
m_os_activity_iterate_messages (nullptr),
m_os_activity_iterate_activities (nullptr),
m_os_trace_get_type (nullptr),
m_os_trace_copy_formatted_message (nullptr),
m_os_activity_for_thread (nullptr),
m_os_activity_for_task_thread (nullptr),
m_thread_activities(),
m_process_executable_infos(),
m_diagnosticd_call_timed_out(false)
{
m_os_activity_diagnostic_for_pid = (bool (*)(pid_t, os_activity_t, uint32_t, os_diagnostic_block_t))dlsym (RTLD_DEFAULT, "os_activity_diagnostic_for_pid");
m_os_activity_iterate_processes = (void (*)(os_activity_process_list_t, bool (^)(os_activity_process_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_processes");
m_os_activity_iterate_breadcrumbs = (void (*)(os_activity_process_t, bool (^)(os_activity_breadcrumb_t))) dlsym (RTLD_DEFAULT, "os_activity_iterate_breadcrumbs");
m_os_activity_iterate_messages = (void (*)(os_trace_message_list_t, os_activity_process_t, bool (^)(os_trace_message_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_messages");
m_os_activity_iterate_activities = (void (*)(os_activity_list_t, os_activity_process_t, bool (^)(os_activity_entry_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_activities");
m_os_trace_get_type = (uint8_t (*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_get_type");
m_os_trace_copy_formatted_message = (char *(*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_copy_formatted_message");
m_os_activity_for_thread = (os_activity_t (*)(os_activity_process_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_thread");
m_os_activity_for_task_thread = (os_activity_t (*)(task_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_task_thread");
m_os_activity_messages_for_thread = (os_trace_message_list_t (*) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id)) dlsym (RTLD_DEFAULT, "os_activity_messages_for_thread");
}

Genealogy::ThreadActivitySP
Genealogy::GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out)
{
ThreadActivitySP activity;
//
// if we've timed out trying to get the activities, don't try again at this process stop.
// (else we'll need to hit the timeout for every thread we're asked about.)
// We'll try again at the next public stop.

if (m_thread_activities.size() == 0 && m_diagnosticd_call_timed_out == false)
{
GetActivities(pid, thread_list, task);
}
std::map<nub_thread_t, ThreadActivitySP>::const_iterator search;
search = m_thread_activities.find(tid);
if (search != m_thread_activities.end())
{
activity = search->second;
}
timed_out = m_diagnosticd_call_timed_out;
return activity;
}

void
Genealogy::Clear()
{
m_thread_activities.clear();
m_diagnosticd_call_timed_out = false;
}

void
Genealogy::GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task)
{
if (m_os_activity_diagnostic_for_pid != nullptr
&& m_os_activity_iterate_processes != nullptr
&& m_os_activity_iterate_breadcrumbs != nullptr
&& m_os_activity_iterate_messages != nullptr
&& m_os_activity_iterate_activities != nullptr
&& m_os_trace_get_type != nullptr
&& m_os_trace_copy_formatted_message != nullptr
&& (m_os_activity_for_thread != nullptr || m_os_activity_for_task_thread != nullptr)
)
{
__block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block BreadcrumbList breadcrumbs;
__block ActivityList activities;
__block MessageList messages;
__block std::map<nub_thread_t, uint64_t> thread_activity_mapping;

os_activity_diagnostic_flag_t flags = OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES | OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY;
if (m_os_activity_diagnostic_for_pid (pid, 0, flags, ^(os_activity_process_list_t processes, int error)
{
if (error == 0)
{
m_os_activity_iterate_processes (processes, ^bool(os_activity_process_t process_info)
{
if (pid == process_info->pid)
{
// Collect all the Breadcrumbs
m_os_activity_iterate_breadcrumbs (process_info, ^bool(os_activity_breadcrumb_t breadcrumb)
{
Breadcrumb bc;
bc.breadcrumb_id = breadcrumb->breadcrumb_id;
bc.activity_id = breadcrumb->activity_id;
bc.timestamp = breadcrumb->timestamp;
if (breadcrumb->name)
bc.name = breadcrumb->name;
breadcrumbs.push_back (bc);
return true;
});

// Collect all the Activites
m_os_activity_iterate_activities (process_info->activities, process_info, ^bool(os_activity_entry_t activity)
{
Activity ac;
ac.activity_start = activity->activity_start;
ac.activity_id = activity->activity_id;
ac.parent_id = activity->parent_id;
if (activity->activity_name)
ac.activity_name = activity->activity_name;
if (activity->reason)
ac.reason = activity->reason;
activities.push_back (ac);
return true;
});


// Collect all the Messages -- messages not associated with any thread
m_os_activity_iterate_messages (process_info->messages, process_info, ^bool(os_trace_message_t trace_msg)
{
Message msg;
msg.timestamp = trace_msg->timestamp;
msg.trace_id = trace_msg->trace_id;
msg.thread = trace_msg->thread;
msg.type = m_os_trace_get_type (trace_msg);
msg.activity_id = 0;
if (trace_msg->image_uuid && trace_msg->image_path)
{
ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo());
uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid);
process_info_sp->image_path = trace_msg->image_path;
msg.process_info_index = AddProcessExecutableInfo (process_info_sp);
}
const char *message_text = m_os_trace_copy_formatted_message (trace_msg);
if (message_text)
msg.message = message_text;
messages.push_back (msg);
return true;
});

// Discover which activities are said to be running on threads currently
const nub_size_t num_threads = thread_list.NumThreads();
for (nub_size_t i = 0; i < num_threads; ++i)
{
nub_thread_t thread_id = thread_list.ThreadIDAtIndex(i);
os_activity_t act = 0;
if (m_os_activity_for_task_thread != nullptr)
{
act = m_os_activity_for_task_thread (task, thread_id);
}
else if (m_os_activity_for_thread != nullptr)
{
act = m_os_activity_for_thread (process_info, thread_id);
}
if (act != 0)
thread_activity_mapping[thread_id] = act;
}

// Collect all Messages -- messages associated with a thread

// When there's no genealogy information, an early version of os_activity_messages_for_thread
// can crash in rare circumstances. Check to see if this process has any activities before
// making the call to get messages.
if (process_info->activities != nullptr && thread_activity_mapping.size() > 0)
{
std::map<nub_thread_t, uint64_t>::const_iterator iter;
for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter)
{
nub_thread_t thread_id = iter->first;
os_activity_t act = iter->second;
os_trace_message_list_t this_thread_messages = m_os_activity_messages_for_thread (process_info, act, thread_id);
m_os_activity_iterate_messages (this_thread_messages, process_info, ^bool(os_trace_message_t trace_msg)
{
Message msg;
msg.timestamp = trace_msg->timestamp;
msg.trace_id = trace_msg->trace_id;
msg.thread = trace_msg->thread;
msg.type = m_os_trace_get_type (trace_msg);
msg.activity_id = act;
if (trace_msg->image_uuid && trace_msg->image_path)
{
ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo());
uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid);
process_info_sp->image_path = trace_msg->image_path;
msg.process_info_index = AddProcessExecutableInfo (process_info_sp);
}
const char *message_text = m_os_trace_copy_formatted_message (trace_msg);
if (message_text)
msg.message = message_text;
messages.push_back (msg);
return true;
});
}
}
}
return true;
});
}
dispatch_semaphore_signal(semaphore);
}) == true)
{
// Wait for the diagnosticd xpc calls to all finish up -- or half a second to elapse.
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2);
bool success = dispatch_semaphore_wait(semaphore, timeout) == 0;
if (!success)
{
m_diagnosticd_call_timed_out = true;
return;
}
}

// breadcrumbs, activities, and messages have all now been filled in.

std::map<nub_thread_t, uint64_t>::const_iterator iter;
for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter)
{
nub_thread_t thread_id = iter->first;
uint64_t activity_id = iter->second;
ActivityList::const_iterator activity_search;
bool found_activity_for_this_thread = false;
for (activity_search = activities.begin(); activity_search != activities.end(); ++activity_search)
{
if (activity_search->activity_id == activity_id)
{
found_activity_for_this_thread = true;
ThreadActivitySP thread_activity_sp (new ThreadActivity());
thread_activity_sp->current_activity = *activity_search;

BreadcrumbList::const_iterator breadcrumb_search;
for (breadcrumb_search = breadcrumbs.begin(); breadcrumb_search != breadcrumbs.end(); ++breadcrumb_search)
{
if (breadcrumb_search->activity_id == activity_id)
{
thread_activity_sp->breadcrumbs.push_back (*breadcrumb_search);
}
}
MessageList::const_iterator message_search;
for (message_search = messages.begin(); message_search != messages.end(); ++message_search)
{
if (message_search->thread == thread_id)
{
thread_activity_sp->messages.push_back (*message_search);
}
}

m_thread_activities[thread_id] = thread_activity_sp;
break;
}
}
}
}
}

uint32_t
Genealogy::AddProcessExecutableInfo (ProcessExecutableInfoSP process_exe_info)
{
const uint32_t info_size = m_process_executable_infos.size();
for (uint32_t idx = 0; idx < info_size; ++idx)
{
if (uuid_compare (m_process_executable_infos[idx]->image_uuid, process_exe_info->image_uuid) == 0)
{
return idx + 1;
}
}
m_process_executable_infos.push_back (process_exe_info);
return info_size + 1;
}

Genealogy::ProcessExecutableInfoSP
Genealogy::GetProcessExecutableInfosAtIndex(uint32_t idx)
{
ProcessExecutableInfoSP info_sp;
if (idx > 0)
{
idx--;
if (idx <= m_process_executable_infos.size())
{
info_sp = m_process_executable_infos[idx];
}
}
return info_sp;
}

116 changes: 116 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/Genealogy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//===-- Activity.h -----------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef __Genealogy_h__
#define __Genealogy_h__

#include <string>
#include <vector>
#include <map>
#include <pthread.h>
#include <mach/task.h>

#include "GenealogySPI.h"
#include "MachThreadList.h"

class Genealogy
{
public:

Genealogy ();

~Genealogy ()
{
}

void
Clear();

struct Breadcrumb
{
uint32_t breadcrumb_id;
uint64_t activity_id;
uint64_t timestamp;
std::string name;
};

struct Activity
{
uint64_t activity_start;
uint64_t activity_id;
uint64_t parent_id;
std::string activity_name;
std::string reason;
};

struct Message
{
uint64_t timestamp;
uint64_t activity_id;
uint64_t trace_id;
uint64_t thread;
uint8_t type; // OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_DEBUG, OS_TRACE_TYPE_ERROR, OS_TRACE_TYPE_FAULT
uint32_t process_info_index; // index # of the image uuid/file path, 0 means unknown
std::string message;
};

typedef std::vector<Message> MessageList;
typedef std::vector<Breadcrumb> BreadcrumbList;
typedef std::vector<Activity> ActivityList;

struct ThreadActivity
{
Activity current_activity;
MessageList messages;
BreadcrumbList breadcrumbs; // should be 0 or 1 breadcrumbs; no more than 1 BC for any given activity
};

typedef std::shared_ptr<ThreadActivity> ThreadActivitySP;

ThreadActivitySP
GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out);

struct ProcessExecutableInfo
{
std::string image_path;
uuid_t image_uuid;
};

typedef std::shared_ptr<ProcessExecutableInfo> ProcessExecutableInfoSP;

ProcessExecutableInfoSP
GetProcessExecutableInfosAtIndex(uint32_t idx);

uint32_t
AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info);

private:

void
GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task);

// the spi we need to call into libtrace - look them up via dlsym at runtime
bool (*m_os_activity_diagnostic_for_pid) (pid_t pid, os_activity_t activity, uint32_t flags, os_diagnostic_block_t block);
void (*m_os_activity_iterate_processes) (os_activity_process_list_t processes, bool (^iterator)(os_activity_process_t process_info));
void (*m_os_activity_iterate_breadcrumbs) (os_activity_process_t process_info, bool (^iterator)(os_activity_breadcrumb_t breadcrumb));
void (*m_os_activity_iterate_messages) (os_trace_message_list_t messages, os_activity_process_t process_info, bool (^iterator)(os_trace_message_t tracemsg));
void (*m_os_activity_iterate_activities) (os_activity_list_t activities, os_activity_process_t process_info, bool (^iterator)(os_activity_entry_t activity));
uint8_t (*m_os_trace_get_type) (os_trace_message_t trace_msg);
char * (*m_os_trace_copy_formatted_message) (os_trace_message_t trace_msg);
os_activity_t (*m_os_activity_for_thread) (os_activity_process_t process, uint64_t thread_id);
os_activity_t (*m_os_activity_for_task_thread) (task_t target, uint64_t thread_id);
os_trace_message_list_t (*m_os_activity_messages_for_thread) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id);


std::map<nub_thread_t, ThreadActivitySP> m_thread_activities;
std::vector<ProcessExecutableInfoSP> m_process_executable_infos;
bool m_diagnosticd_call_timed_out;
};

#endif // __Genealogy_h__
96 changes: 96 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/GenealogySPI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//===-- ActivitySPI.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===//

#ifndef __GenealogySPI_h__
#define __GenealogySPI_h__

#include <xpc/xpc.h>

typedef void *os_activity_process_list_t;
typedef void *os_activity_list_t;
typedef void *os_trace_message_list_t;
typedef struct os_activity_watch_s *os_activity_watch_t;
typedef uint64_t os_activity_t;

struct os_activity_breadcrumb_s {
uint32_t breadcrumb_id;
uint64_t activity_id;
uint64_t timestamp;
const char *name;
};

typedef struct os_activity_breadcrumb_s *os_activity_breadcrumb_t;

typedef struct os_trace_message_s {
uint64_t trace_id;
uint64_t thread;
uint64_t timestamp;
uint32_t offset;
xpc_object_t __unsafe_unretained payload;
const uint8_t *image_uuid;
const char *image_path;
const char *format;
const void *buffer;
size_t bufferLen;
} *os_trace_message_t;

typedef struct os_activity_process_s {
os_activity_process_list_t child_procs;
os_trace_message_list_t messages;
os_activity_list_t activities;
void *breadcrumbs;
uint64_t proc_id;
const uint8_t *image_uuid;
const char *image_path;
pid_t pid;
} *os_activity_process_t;

typedef struct os_activity_entry_s {
uint64_t activity_start;
os_activity_t activity_id;
os_activity_t parent_id;
const char *activity_name;
const char *reason;
os_trace_message_list_t messages;
} *os_activity_entry_t;

enum
{
OS_ACTIVITY_DIAGNOSTIC_DEFAULT = 0x00000000,
OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY = 0x00000001,
OS_ACTIVITY_DIAGNOSTIC_SKIP_DECODE = 0x00000002,
OS_ACTIVITY_DIAGNOSTIC_FLATTENED = 0x00000004,
OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES = 0x00000008,
OS_ACTIVITY_DIAGNOSTIC_MAX = 0x0000000f
};
typedef uint32_t os_activity_diagnostic_flag_t;

enum
{
OS_ACTIVITY_WATCH_DEFAULT = 0x00000000,
OS_ACTIVITY_WATCH_PROCESS_ONLY = 0x00000001,
OS_ACTIVITY_WATCH_SKIP_DECODE = 0x00000002,
OS_ACTIVITY_WATCH_PAYLOAD = 0x00000004,
OS_ACTIVITY_WATCH_ERRORS = 0x00000008,
OS_ACTIVITY_WATCH_FAULTS = 0x00000010,
OS_ACTIVITY_WATCH_MAX = 0x0000001f
};
typedef uint32_t os_activity_watch_flag_t;

// Return values from os_trace_get_type()
#define OS_TRACE_TYPE_RELEASE (1u << 0)
#define OS_TRACE_TYPE_DEBUG (1u << 1)
#define OS_TRACE_TYPE_ERROR ((1u << 6) | (1u << 0))
#define OS_TRACE_TYPE_FAULT ((1u << 7) | (1u << 6) | (1u << 0))


typedef void (^os_activity_watch_block_t)(os_activity_watch_t watch, os_activity_process_t process_info, bool canceled);
typedef void (^os_diagnostic_block_t)(os_activity_process_list_t processes, int error);

#endif

12 changes: 12 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/MachProcess.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include "PThreadCondition.h"
#include "PThreadEvent.h"
#include "PThreadMutex.h"
#include "Genealogy.h"
#include "ThreadInfo.h"

#include <mach/mach.h>
#include <sys/signal.h>
Expand Down Expand Up @@ -179,6 +181,11 @@ class MachProcess
nub_bool_t SyncThreadState (nub_thread_t tid);
const char * ThreadGetName (nub_thread_t tid);
nub_state_t ThreadGetState (nub_thread_t tid);
ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index);
nub_addr_t GetPThreadT (nub_thread_t tid);
nub_addr_t GetDispatchQueueT (nub_thread_t tid);
nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size);

nub_size_t GetNumThreads () const;
nub_thread_t GetThreadAtIndex (nub_size_t thread_idx) const;
nub_thread_t GetCurrentThread ();
Expand Down Expand Up @@ -265,6 +272,10 @@ class MachProcess
bool ProcessUsingSpringBoard() const { return (m_flags & eMachProcessFlagsUsingSBS) != 0; }
bool ProcessUsingBackBoard() const { return (m_flags & eMachProcessFlagsUsingBKS) != 0; }

Genealogy::ThreadActivitySP GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out);

Genealogy::ProcessExecutableInfoSP GetGenealogyImageInfo (size_t idx);

DNBProfileDataScanType GetProfileScanType () { return m_profile_scan_type; }

private:
Expand Down Expand Up @@ -311,6 +322,7 @@ class MachProcess
PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages

MachThreadList m_thread_list; // A list of threads that is maintained/updated after each stop
Genealogy m_activities; // A list of activities that is updated after every stop lazily
nub_state_t m_state; // The state of our process
PThreadMutex m_state_mutex; // Multithreaded protection for m_state
PThreadEvent m_events; // Process related events in the child processes lifetime can be waited upon
Expand Down
41 changes: 41 additions & 0 deletions lldb/tools/debugserver/source/MacOSX/MachProcess.mm
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE),
m_profile_data (),
m_thread_list (),
m_activities (),
m_exception_messages (),
m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE),
m_state (eStateUnloaded),
Expand Down Expand Up @@ -219,6 +220,30 @@

}

ThreadInfo::QoS
MachProcess::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index)
{
return m_thread_list.GetRequestedQoS (tid, tsd, dti_qos_class_index);
}

nub_addr_t
MachProcess::GetPThreadT (nub_thread_t tid)
{
return m_thread_list.GetPThreadT (tid);
}

nub_addr_t
MachProcess::GetDispatchQueueT (nub_thread_t tid)
{
return m_thread_list.GetDispatchQueueT (tid);
}

nub_addr_t
MachProcess::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size)
{
return m_thread_list.GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size);
}

nub_thread_t
MachProcess::GetCurrentThread ()
{
Expand Down Expand Up @@ -365,6 +390,7 @@
PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex);
m_exception_messages.clear();
}
m_activities.Clear();
if (m_profile_thread)
{
pthread_join(m_profile_thread, NULL);
Expand Down Expand Up @@ -605,6 +631,7 @@

{
m_thread_actions.Clear();
m_activities.Clear();
DNBThreadResumeAction thread_action;
thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx);
thread_action.state = eStateRunning;
Expand Down Expand Up @@ -1250,6 +1277,7 @@
DNBArchProtocol::SetArchitecture (process_cpu_type);
}
m_thread_list.Clear();
m_activities.Clear();
m_breakpoints.DisableAll();
}

Expand Down Expand Up @@ -1288,6 +1316,7 @@
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
m_thread_list.ProcessDidStop(this);
m_activities.Clear();

// Let each thread know of any exceptions
for (i=0; i<m_exception_messages.size(); ++i)
Expand Down Expand Up @@ -1666,6 +1695,18 @@
return INVALID_NUB_PROCESS;
}

Genealogy::ThreadActivitySP
MachProcess::GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out)
{
return m_activities.GetGenealogyInfoForThread (m_pid, tid, m_thread_list, m_task.TaskPort(), timed_out);
}

Genealogy::ProcessExecutableInfoSP
MachProcess::GetGenealogyImageInfo (size_t idx)
{
return m_activities.GetProcessExecutableInfosAtIndex (idx);
}

// Do the process specific setup for attach. If this returns NULL, then there's no
// platform specific stuff to be done to wait for the attach. If you get non-null,
// pass that token to the CheckForProcess method, and then to CleanupAfterAttach.
Expand Down
Loading