2016-01-06 15:12:03 -05:00
//===-- SystemRuntimeMacOSX.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/Breakpoint/StoppointCallbackContext.h"
# include "lldb/Core/Log.h"
# include "lldb/Core/Module.h"
# include "lldb/Core/ModuleSpec.h"
# include "lldb/Core/PluginManager.h"
# include "lldb/Core/DataExtractor.h"
# include "lldb/Core/DataBufferHeap.h"
# include "lldb/Core/Section.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Host/FileSpec.h"
# include "lldb/Symbol/ClangASTContext.h"
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Symbol/SymbolContext.h"
# include "Plugins/Process/Utility/HistoryThread.h"
# include "lldb/Target/Queue.h"
# include "lldb/Target/QueueList.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/Process.h"
# include "lldb/Utility/ProcessStructReader.h"
# include "SystemRuntimeMacOSX.h"
using namespace lldb ;
using namespace lldb_private ;
//----------------------------------------------------------------------
// Create an instance of this class. This function is filled into
// the plugin info class that gets handed out by the plugin factory and
// allows the lldb to instantiate an instance of this class.
//----------------------------------------------------------------------
SystemRuntime *
SystemRuntimeMacOSX : : CreateInstance ( Process * process )
{
bool create = false ;
if ( ! create )
{
create = true ;
Module * exe_module = process - > GetTarget ( ) . GetExecutableModulePointer ( ) ;
if ( exe_module )
{
ObjectFile * object_file = exe_module - > GetObjectFile ( ) ;
if ( object_file )
{
create = ( object_file - > GetStrata ( ) = = ObjectFile : : eStrataUser ) ;
}
}
if ( create )
{
const llvm : : Triple & triple_ref = process - > GetTarget ( ) . GetArchitecture ( ) . GetTriple ( ) ;
switch ( triple_ref . getOS ( ) )
{
case llvm : : Triple : : Darwin :
case llvm : : Triple : : MacOSX :
case llvm : : Triple : : IOS :
case llvm : : Triple : : TvOS :
case llvm : : Triple : : WatchOS :
create = triple_ref . getVendor ( ) = = llvm : : Triple : : Apple ;
break ;
default :
create = false ;
break ;
}
}
}
if ( create )
return new SystemRuntimeMacOSX ( process ) ;
return NULL ;
}
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------
SystemRuntimeMacOSX : : SystemRuntimeMacOSX ( Process * process ) :
SystemRuntime ( process ) ,
m_break_id ( LLDB_INVALID_BREAK_ID ) ,
m_mutex ( Mutex : : eMutexTypeRecursive ) ,
m_get_queues_handler ( process ) ,
m_get_pending_items_handler ( process ) ,
m_get_item_info_handler ( process ) ,
m_get_thread_item_info_handler ( process ) ,
m_page_to_free ( LLDB_INVALID_ADDRESS ) ,
m_page_to_free_size ( 0 ) ,
m_lib_backtrace_recording_info ( ) ,
m_dispatch_queue_offsets_addr ( LLDB_INVALID_ADDRESS ) ,
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 ( )
{
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
SystemRuntimeMacOSX : : ~ SystemRuntimeMacOSX ( )
{
Clear ( true ) ;
}
void
SystemRuntimeMacOSX : : Detach ( )
{
m_get_queues_handler . Detach ( ) ;
m_get_pending_items_handler . Detach ( ) ;
m_get_item_info_handler . Detach ( ) ;
m_get_thread_item_info_handler . Detach ( ) ;
}
//----------------------------------------------------------------------
// Clear out the state of this class.
//----------------------------------------------------------------------
void
SystemRuntimeMacOSX : : Clear ( bool clear_process )
{
Mutex : : Locker locker ( m_mutex ) ;
if ( m_process - > IsAlive ( ) & & LLDB_BREAK_ID_IS_VALID ( m_break_id ) )
m_process - > ClearBreakpointSiteByID ( m_break_id ) ;
if ( clear_process )
m_process = NULL ;
m_break_id = LLDB_INVALID_BREAK_ID ;
}
std : : string
SystemRuntimeMacOSX : : GetQueueNameFromThreadQAddress ( addr_t dispatch_qaddr )
{
std : : string dispatch_queue_name ;
if ( dispatch_qaddr = = LLDB_INVALID_ADDRESS | | dispatch_qaddr = = 0 )
return " " ;
ReadLibdispatchOffsets ( ) ;
if ( m_libdispatch_offsets . IsValid ( ) )
{
// dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
// deref it to get the address of the dispatch_queue_t structure for this thread's
// queue.
Error error ;
addr_t dispatch_queue_addr = m_process - > ReadPointerFromMemory ( dispatch_qaddr , error ) ;
if ( error . Success ( ) )
{
if ( m_libdispatch_offsets . dqo_version > = 4 )
{
// libdispatch versions 4+, pointer to dispatch name is in the
// queue structure.
addr_t pointer_to_label_address = dispatch_queue_addr + m_libdispatch_offsets . dqo_label ;
addr_t label_addr = m_process - > ReadPointerFromMemory ( pointer_to_label_address , error ) ;
if ( error . Success ( ) )
{
m_process - > ReadCStringFromMemory ( label_addr , dispatch_queue_name , error ) ;
}
}
else
{
// libdispatch versions 1-3, dispatch name is a fixed width char array
// in the queue structure.
addr_t label_addr = dispatch_queue_addr + m_libdispatch_offsets . dqo_label ;
dispatch_queue_name . resize ( m_libdispatch_offsets . dqo_label_size , ' \0 ' ) ;
size_t bytes_read = m_process - > ReadMemory ( label_addr , & dispatch_queue_name [ 0 ] , m_libdispatch_offsets . dqo_label_size , error ) ;
if ( bytes_read < m_libdispatch_offsets . dqo_label_size )
dispatch_queue_name . erase ( bytes_read ) ;
}
}
}
return dispatch_queue_name ;
}
lldb : : addr_t
SystemRuntimeMacOSX : : GetLibdispatchQueueAddressFromThreadQAddress ( addr_t dispatch_qaddr )
{
addr_t libdispatch_queue_t_address = LLDB_INVALID_ADDRESS ;
Error error ;
libdispatch_queue_t_address = m_process - > ReadPointerFromMemory ( dispatch_qaddr , error ) ;
if ( ! error . Success ( ) )
{
libdispatch_queue_t_address = LLDB_INVALID_ADDRESS ;
}
return libdispatch_queue_t_address ;
}
lldb : : QueueKind
SystemRuntimeMacOSX : : GetQueueKind ( addr_t dispatch_queue_addr )
{
if ( dispatch_queue_addr = = LLDB_INVALID_ADDRESS | | dispatch_queue_addr = = 0 )
return eQueueKindUnknown ;
QueueKind kind = eQueueKindUnknown ;
ReadLibdispatchOffsets ( ) ;
if ( m_libdispatch_offsets . IsValid ( ) & & m_libdispatch_offsets . dqo_version > = 4 )
{
Error error ;
uint64_t width = m_process - > ReadUnsignedIntegerFromMemory ( dispatch_queue_addr + m_libdispatch_offsets . dqo_width , m_libdispatch_offsets . dqo_width_size , 0 , error ) ;
if ( error . Success ( ) )
{
if ( width = = 1 )
{
kind = eQueueKindSerial ;
}
if ( width > 1 )
{
kind = eQueueKindConcurrent ;
}
}
}
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 )
{
if ( thread_sp & & thread_sp - > GetStackFrameCount ( ) > 0 & & thread_sp - > GetFrameWithConcreteFrameIndex ( 0 ) )
{
const SymbolContext sym_ctx ( thread_sp - > GetFrameWithConcreteFrameIndex ( 0 ) - > GetSymbolContext ( eSymbolContextSymbol ) ) ;
static ConstString g_select_symbol ( " __select " ) ;
if ( sym_ctx . GetFunctionName ( ) = = g_select_symbol )
{
return false ;
}
}
return true ;
}
lldb : : queue_id_t
SystemRuntimeMacOSX : : GetQueueIDFromThreadQAddress ( lldb : : addr_t dispatch_qaddr )
{
queue_id_t queue_id = LLDB_INVALID_QUEUE_ID ;
if ( dispatch_qaddr = = LLDB_INVALID_ADDRESS | | dispatch_qaddr = = 0 )
return queue_id ;
ReadLibdispatchOffsets ( ) ;
if ( m_libdispatch_offsets . IsValid ( ) )
{
// dispatch_qaddr is from a thread_info(THREAD_IDENTIFIER_INFO) call for a thread -
// deref it to get the address of the dispatch_queue_t structure for this thread's
// queue.
Error error ;
uint64_t dispatch_queue_addr = m_process - > ReadPointerFromMemory ( dispatch_qaddr , error ) ;
if ( error . Success ( ) )
{
addr_t serialnum_address = dispatch_queue_addr + m_libdispatch_offsets . dqo_serialnum ;
queue_id_t serialnum = m_process - > ReadUnsignedIntegerFromMemory ( serialnum_address , m_libdispatch_offsets . dqo_serialnum_size , LLDB_INVALID_QUEUE_ID , error ) ;
if ( error . Success ( ) )
{
queue_id = serialnum ;
}
}
}
return queue_id ;
}
void
SystemRuntimeMacOSX : : ReadLibdispatchOffsetsAddress ( )
{
if ( m_dispatch_queue_offsets_addr ! = LLDB_INVALID_ADDRESS )
return ;
static ConstString g_dispatch_queue_offsets_symbol_name ( " dispatch_queue_offsets " ) ;
const Symbol * dispatch_queue_offsets_symbol = NULL ;
// libdispatch symbols were in libSystem.B.dylib up through Mac OS X 10.6 ("Snow Leopard")
ModuleSpec libSystem_module_spec ( FileSpec ( " libSystem.B.dylib " , false ) ) ;
ModuleSP module_sp ( m_process - > GetTarget ( ) . GetImages ( ) . FindFirstModule ( libSystem_module_spec ) ) ;
if ( module_sp )
dispatch_queue_offsets_symbol = module_sp - > FindFirstSymbolWithNameAndType ( g_dispatch_queue_offsets_symbol_name , eSymbolTypeData ) ;
// libdispatch symbols are in their own dylib as of Mac OS X 10.7 ("Lion") and later
if ( dispatch_queue_offsets_symbol = = NULL )
{
ModuleSpec libdispatch_module_spec ( FileSpec ( " libdispatch.dylib " , false ) ) ;
module_sp = m_process - > GetTarget ( ) . GetImages ( ) . FindFirstModule ( libdispatch_module_spec ) ;
if ( module_sp )
dispatch_queue_offsets_symbol = module_sp - > FindFirstSymbolWithNameAndType ( g_dispatch_queue_offsets_symbol_name , eSymbolTypeData ) ;
}
if ( dispatch_queue_offsets_symbol )
m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol - > GetLoadAddress ( & m_process - > GetTarget ( ) ) ;
}
void
SystemRuntimeMacOSX : : ReadLibdispatchOffsets ( )
{
if ( m_libdispatch_offsets . IsValid ( ) )
return ;
ReadLibdispatchOffsetsAddress ( ) ;
uint8_t memory_buffer [ sizeof ( struct LibdispatchOffsets ) ] ;
DataExtractor data ( memory_buffer ,
sizeof ( memory_buffer ) ,
m_process - > GetByteOrder ( ) ,
m_process - > GetAddressByteSize ( ) ) ;
Error error ;
if ( m_process - > ReadMemory ( m_dispatch_queue_offsets_addr , memory_buffer , sizeof ( memory_buffer ) , error ) = = sizeof ( memory_buffer ) )
{
lldb : : offset_t data_offset = 0 ;
// The struct LibdispatchOffsets is a series of uint16_t's - extract them all
// in one big go.
data . GetU16 ( & data_offset , & m_libdispatch_offsets . dqo_version , sizeof ( struct LibdispatchOffsets ) / sizeof ( uint16_t ) ) ;
}
}
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 - > 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 - > GetLoadAddress ( & m_process - > GetTarget ( ) ) ;
}
}
}
void
SystemRuntimeMacOSX : : ReadLibdispatchTSDIndexes ( )
{
if ( m_libdispatch_tsd_indexes . IsValid ( ) )
return ;
ReadLibdispatchTSDIndexesAddress ( ) ;
if ( m_dispatch_tsd_indexes_addr ! = LLDB_INVALID_ADDRESS )
{
// We don't need to check the version number right now, it will be at least 2, but
// keep this code around to fetch just the version # for the future where we need
// to fetch alternate versions of the struct.
# if 0
uint16_t dti_version = 2 ;
Address dti_struct_addr ;
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 ;
}
}
# endif
ClangASTContext * ast_ctx = m_process - > GetTarget ( ) . GetScratchClangASTContext ( ) ;
if ( ast_ctx - > getASTContext ( ) & & m_dispatch_tsd_indexes_addr ! = LLDB_INVALID_ADDRESS )
{
CompilerType uint16 = ast_ctx - > GetBuiltinTypeForEncodingAndBitSize ( eEncodingUint , 16 ) ;
CompilerType dispatch_tsd_indexes_s = ast_ctx - > CreateRecordType ( nullptr , lldb : : eAccessPublic , " __lldb_dispatch_tsd_indexes_s " , clang : : TTK_Struct , lldb : : eLanguageTypeC ) ;
ClangASTContext : : StartTagDeclarationDefinition ( dispatch_tsd_indexes_s ) ;
ClangASTContext : : AddFieldToRecordType ( dispatch_tsd_indexes_s , " dti_version " , uint16 , lldb : : eAccessPublic , 0 ) ;
ClangASTContext : : AddFieldToRecordType ( dispatch_tsd_indexes_s , " dti_queue_index " , uint16 , lldb : : eAccessPublic , 0 ) ;
ClangASTContext : : AddFieldToRecordType ( dispatch_tsd_indexes_s , " dti_voucher_index " , uint16 , lldb : : eAccessPublic , 0 ) ;
ClangASTContext : : AddFieldToRecordType ( dispatch_tsd_indexes_s , " dti_qos_class_index " , uint16 , lldb : : eAccessPublic , 0 ) ;
ClangASTContext : : CompleteTagDeclarationDefinition ( dispatch_tsd_indexes_s ) ;
ProcessStructReader struct_reader ( m_process , m_dispatch_tsd_indexes_addr , dispatch_tsd_indexes_s ) ;
m_libdispatch_tsd_indexes . dti_version = struct_reader . GetField < uint16_t > ( ConstString ( " dti_version " ) ) ;
m_libdispatch_tsd_indexes . dti_queue_index = struct_reader . GetField < uint16_t > ( ConstString ( " dti_queue_index " ) ) ;
m_libdispatch_tsd_indexes . dti_voucher_index = struct_reader . GetField < uint16_t > ( ConstString ( " dti_voucher_index " ) ) ;
m_libdispatch_tsd_indexes . dti_qos_class_index = struct_reader . GetField < uint16_t > ( ConstString ( " dti_qos_class_index " ) ) ;
}
}
}
ThreadSP
SystemRuntimeMacOSX : : GetExtendedBacktraceThread ( ThreadSP real_thread , ConstString type )
{
ThreadSP originating_thread_sp ;
if ( BacktraceRecordingHeadersInitialized ( ) & & type = = ConstString ( " libdispatch " ) )
{
Error error ;
// real_thread is either an actual, live thread (in which case we need to call into
// libBacktraceRecording to find its originator) or it is an extended backtrace itself,
// in which case we get the token from it and call into libBacktraceRecording to find
// the originator of that token.
if ( real_thread - > GetExtendedBacktraceToken ( ) ! = LLDB_INVALID_ADDRESS )
{
originating_thread_sp = GetExtendedBacktraceFromItemRef ( real_thread - > GetExtendedBacktraceToken ( ) ) ;
}
else
{
ThreadSP cur_thread_sp ( m_process - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
AppleGetThreadItemInfoHandler : : GetThreadItemInfoReturnInfo ret = m_get_thread_item_info_handler . GetThreadItemInfo ( * cur_thread_sp . get ( ) , real_thread - > GetID ( ) , m_page_to_free , m_page_to_free_size , error ) ;
m_page_to_free = LLDB_INVALID_ADDRESS ;
m_page_to_free_size = 0 ;
if ( ret . item_buffer_ptr ! = 0 & & ret . item_buffer_ptr ! = LLDB_INVALID_ADDRESS & & ret . item_buffer_size > 0 )
{
DataBufferHeap data ( ret . item_buffer_size , 0 ) ;
if ( m_process - > ReadMemory ( ret . item_buffer_ptr , data . GetBytes ( ) , ret . item_buffer_size , error ) & & error . Success ( ) )
{
DataExtractor extractor ( data . GetBytes ( ) , data . GetByteSize ( ) , m_process - > GetByteOrder ( ) , m_process - > GetAddressByteSize ( ) ) ;
ItemInfo item = ExtractItemInfoFromBuffer ( extractor ) ;
bool stop_id_is_valid = true ;
if ( item . stop_id = = 0 )
stop_id_is_valid = false ;
originating_thread_sp . reset ( new HistoryThread ( * m_process ,
item . enqueuing_thread_id ,
item . enqueuing_callstack ,
item . stop_id ,
stop_id_is_valid ) ) ;
originating_thread_sp - > SetExtendedBacktraceToken ( item . item_that_enqueued_this ) ;
originating_thread_sp - > SetQueueName ( item . enqueuing_queue_label . c_str ( ) ) ;
originating_thread_sp - > SetQueueID ( item . enqueuing_queue_serialnum ) ;
// originating_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
}
m_page_to_free = ret . item_buffer_ptr ;
m_page_to_free_size = ret . item_buffer_size ;
}
}
}
return originating_thread_sp ;
}
ThreadSP
SystemRuntimeMacOSX : : GetExtendedBacktraceFromItemRef ( lldb : : addr_t item_ref )
{
ThreadSP return_thread_sp ;
AppleGetItemInfoHandler : : GetItemInfoReturnInfo ret ;
ThreadSP cur_thread_sp ( m_process - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
Error error ;
ret = m_get_item_info_handler . GetItemInfo ( * cur_thread_sp . get ( ) , item_ref , m_page_to_free , m_page_to_free_size , error ) ;
m_page_to_free = LLDB_INVALID_ADDRESS ;
m_page_to_free_size = 0 ;
if ( ret . item_buffer_ptr ! = 0 & & ret . item_buffer_ptr ! = LLDB_INVALID_ADDRESS & & ret . item_buffer_size > 0 )
{
DataBufferHeap data ( ret . item_buffer_size , 0 ) ;
if ( m_process - > ReadMemory ( ret . item_buffer_ptr , data . GetBytes ( ) , ret . item_buffer_size , error ) & & error . Success ( ) )
{
DataExtractor extractor ( data . GetBytes ( ) , data . GetByteSize ( ) , m_process - > GetByteOrder ( ) , m_process - > GetAddressByteSize ( ) ) ;
ItemInfo item = ExtractItemInfoFromBuffer ( extractor ) ;
bool stop_id_is_valid = true ;
if ( item . stop_id = = 0 )
stop_id_is_valid = false ;
return_thread_sp . reset ( new HistoryThread ( * m_process ,
item . enqueuing_thread_id ,
item . enqueuing_callstack ,
item . stop_id ,
stop_id_is_valid ) ) ;
return_thread_sp - > SetExtendedBacktraceToken ( item . item_that_enqueued_this ) ;
return_thread_sp - > SetQueueName ( item . enqueuing_queue_label . c_str ( ) ) ;
return_thread_sp - > SetQueueID ( item . enqueuing_queue_serialnum ) ;
// return_thread_sp->SetThreadName (item.enqueuing_thread_label.c_str());
m_page_to_free = ret . item_buffer_ptr ;
m_page_to_free_size = ret . item_buffer_size ;
}
}
return return_thread_sp ;
}
ThreadSP
SystemRuntimeMacOSX : : GetExtendedBacktraceForQueueItem ( QueueItemSP queue_item_sp , ConstString type )
{
ThreadSP extended_thread_sp ;
if ( type ! = ConstString ( " libdispatch " ) )
return extended_thread_sp ;
bool stop_id_is_valid = true ;
if ( queue_item_sp - > GetStopID ( ) = = 0 )
stop_id_is_valid = false ;
extended_thread_sp . reset ( new HistoryThread ( * m_process ,
queue_item_sp - > GetEnqueueingThreadID ( ) ,
queue_item_sp - > GetEnqueueingBacktrace ( ) ,
queue_item_sp - > GetStopID ( ) ,
stop_id_is_valid ) ) ;
extended_thread_sp - > SetExtendedBacktraceToken ( queue_item_sp - > GetItemThatEnqueuedThis ( ) ) ;
extended_thread_sp - > SetQueueName ( queue_item_sp - > GetQueueLabel ( ) . c_str ( ) ) ;
extended_thread_sp - > SetQueueID ( queue_item_sp - > GetEnqueueingQueueID ( ) ) ;
// extended_thread_sp->SetThreadName (queue_item_sp->GetThreadLabel().c_str());
return extended_thread_sp ;
}
/* Returns true if we were able to get the version / offset information
* out of libBacktraceRecording . false means we were unable to retrieve
* this ; the queue_info_version field will be 0.
*/
bool
SystemRuntimeMacOSX : : BacktraceRecordingHeadersInitialized ( )
{
if ( m_lib_backtrace_recording_info . queue_info_version ! = 0 )
return true ;
addr_t queue_info_version_address = LLDB_INVALID_ADDRESS ;
addr_t queue_info_data_offset_address = LLDB_INVALID_ADDRESS ;
addr_t item_info_version_address = LLDB_INVALID_ADDRESS ;
addr_t item_info_data_offset_address = LLDB_INVALID_ADDRESS ;
Target & target = m_process - > GetTarget ( ) ;
static ConstString introspection_dispatch_queue_info_version ( " __introspection_dispatch_queue_info_version " ) ;
SymbolContextList sc_list ;
if ( m_process - > GetTarget ( ) . GetImages ( ) . FindSymbolsWithNameAndType ( introspection_dispatch_queue_info_version , eSymbolTypeData , sc_list ) > 0 )
{
SymbolContext sc ;
sc_list . GetContextAtIndex ( 0 , sc ) ;
AddressRange addr_range ;
sc . GetAddressRange ( eSymbolContextSymbol , 0 , false , addr_range ) ;
queue_info_version_address = addr_range . GetBaseAddress ( ) . GetLoadAddress ( & target ) ;
}
sc_list . Clear ( ) ;
static ConstString introspection_dispatch_queue_info_data_offset ( " __introspection_dispatch_queue_info_data_offset " ) ;
if ( m_process - > GetTarget ( ) . GetImages ( ) . FindSymbolsWithNameAndType ( introspection_dispatch_queue_info_data_offset , eSymbolTypeData , sc_list ) > 0 )
{
SymbolContext sc ;
sc_list . GetContextAtIndex ( 0 , sc ) ;
AddressRange addr_range ;
sc . GetAddressRange ( eSymbolContextSymbol , 0 , false , addr_range ) ;
queue_info_data_offset_address = addr_range . GetBaseAddress ( ) . GetLoadAddress ( & target ) ;
}
sc_list . Clear ( ) ;
static ConstString introspection_dispatch_item_info_version ( " __introspection_dispatch_item_info_version " ) ;
if ( m_process - > GetTarget ( ) . GetImages ( ) . FindSymbolsWithNameAndType ( introspection_dispatch_item_info_version , eSymbolTypeData , sc_list ) > 0 )
{
SymbolContext sc ;
sc_list . GetContextAtIndex ( 0 , sc ) ;
AddressRange addr_range ;
sc . GetAddressRange ( eSymbolContextSymbol , 0 , false , addr_range ) ;
item_info_version_address = addr_range . GetBaseAddress ( ) . GetLoadAddress ( & target ) ;
}
sc_list . Clear ( ) ;
static ConstString introspection_dispatch_item_info_data_offset ( " __introspection_dispatch_item_info_data_offset " ) ;
if ( m_process - > GetTarget ( ) . GetImages ( ) . FindSymbolsWithNameAndType ( introspection_dispatch_item_info_data_offset , eSymbolTypeData , sc_list ) > 0 )
{
SymbolContext sc ;
sc_list . GetContextAtIndex ( 0 , sc ) ;
AddressRange addr_range ;
sc . GetAddressRange ( eSymbolContextSymbol , 0 , false , addr_range ) ;
item_info_data_offset_address = addr_range . GetBaseAddress ( ) . GetLoadAddress ( & target ) ;
}
if ( queue_info_version_address ! = LLDB_INVALID_ADDRESS
& & queue_info_data_offset_address ! = LLDB_INVALID_ADDRESS
& & item_info_version_address ! = LLDB_INVALID_ADDRESS
& & item_info_data_offset_address ! = LLDB_INVALID_ADDRESS )
{
Error error ;
m_lib_backtrace_recording_info . queue_info_version = m_process - > ReadUnsignedIntegerFromMemory ( queue_info_version_address , 2 , 0 , error ) ;
if ( error . Success ( ) )
{
m_lib_backtrace_recording_info . queue_info_data_offset = m_process - > ReadUnsignedIntegerFromMemory ( queue_info_data_offset_address , 2 , 0 , error ) ;
if ( error . Success ( ) )
{
m_lib_backtrace_recording_info . item_info_version = m_process - > ReadUnsignedIntegerFromMemory ( item_info_version_address , 2 , 0 , error ) ;
if ( error . Success ( ) )
{
m_lib_backtrace_recording_info . item_info_data_offset = m_process - > ReadUnsignedIntegerFromMemory ( item_info_data_offset_address , 2 , 0 , error ) ;
if ( ! error . Success ( ) )
{
m_lib_backtrace_recording_info . queue_info_version = 0 ;
}
}
else
{
m_lib_backtrace_recording_info . queue_info_version = 0 ;
}
}
else
{
m_lib_backtrace_recording_info . queue_info_version = 0 ;
}
}
}
return m_lib_backtrace_recording_info . queue_info_version ! = 0 ;
}
const std : : vector < ConstString > &
SystemRuntimeMacOSX : : GetExtendedBacktraceTypes ( )
{
if ( m_types . size ( ) = = 0 )
{
m_types . push_back ( ConstString ( " libdispatch " ) ) ;
// We could have pthread as another type in the future if we have a way of
// gathering that information & it's useful to distinguish between them.
}
return m_types ;
}
void
SystemRuntimeMacOSX : : PopulateQueueList ( lldb_private : : QueueList & queue_list )
{
if ( BacktraceRecordingHeadersInitialized ( ) )
{
AppleGetQueuesHandler : : GetQueuesReturnInfo queue_info_pointer ;
ThreadSP cur_thread_sp ( m_process - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( cur_thread_sp )
{
Error error ;
queue_info_pointer = m_get_queues_handler . GetCurrentQueues ( * cur_thread_sp . get ( ) , m_page_to_free , m_page_to_free_size , error ) ;
m_page_to_free = LLDB_INVALID_ADDRESS ;
m_page_to_free_size = 0 ;
if ( error . Success ( ) )
{
if ( queue_info_pointer . count > 0
& & queue_info_pointer . queues_buffer_size > 0
& & queue_info_pointer . queues_buffer_ptr ! = 0
& & queue_info_pointer . queues_buffer_ptr ! = LLDB_INVALID_ADDRESS )
{
PopulateQueuesUsingLibBTR ( queue_info_pointer . queues_buffer_ptr , queue_info_pointer . queues_buffer_size , queue_info_pointer . count , queue_list ) ;
}
}
}
}
// We either didn't have libBacktraceRecording (and need to create the queues list based on threads)
// or we did get the queues list from libBacktraceRecording but some special queues may not be
// included in its information. This is needed because libBacktraceRecording
// will only list queues with pending or running items by default - but the magic com.apple.main-thread
// queue on thread 1 is always around.
for ( ThreadSP thread_sp : m_process - > Threads ( ) )
{
2016-01-13 15:06:56 -05:00
if ( thread_sp - > GetAssociatedWithLibdispatchQueue ( ) ! = eLazyBoolNo )
2016-01-06 15:12:03 -05:00
{
2016-01-13 15:06:56 -05:00
if ( thread_sp - > GetQueueID ( ) ! = LLDB_INVALID_QUEUE_ID )
2016-01-06 15:12:03 -05:00
{
2016-01-13 15:06:56 -05:00
if ( queue_list . FindQueueByID ( thread_sp - > GetQueueID ( ) ) . get ( ) = = NULL )
{
QueueSP queue_sp ( new Queue ( m_process - > shared_from_this ( ) , thread_sp - > GetQueueID ( ) , thread_sp - > GetQueueName ( ) ) ) ;
if ( thread_sp - > ThreadHasQueueInformation ( ) )
{
queue_sp - > SetKind ( thread_sp - > GetQueueKind ( ) ) ;
queue_sp - > SetLibdispatchQueueAddress ( thread_sp - > GetQueueLibdispatchQueueAddress ( ) ) ;
queue_list . AddQueue ( queue_sp ) ;
}
else
{
queue_sp - > SetKind ( GetQueueKind ( thread_sp - > GetQueueLibdispatchQueueAddress ( ) ) ) ;
queue_sp - > SetLibdispatchQueueAddress ( thread_sp - > GetQueueLibdispatchQueueAddress ( ) ) ;
queue_list . AddQueue ( queue_sp ) ;
}
}
2016-01-06 15:12:03 -05:00
}
}
}
}
// Returns either an array of introspection_dispatch_item_info_ref's for the pending items on
// a queue or an array introspection_dispatch_item_info_ref's and code addresses for the
// pending items on a queue. The information about each of these pending items then needs to
// be fetched individually by passing the ref to libBacktraceRecording.
SystemRuntimeMacOSX : : PendingItemsForQueue
SystemRuntimeMacOSX : : GetPendingItemRefsForQueue ( lldb : : addr_t queue )
{
PendingItemsForQueue pending_item_refs ;
AppleGetPendingItemsHandler : : GetPendingItemsReturnInfo pending_items_pointer ;
ThreadSP cur_thread_sp ( m_process - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( cur_thread_sp )
{
Error error ;
pending_items_pointer = m_get_pending_items_handler . GetPendingItems ( * cur_thread_sp . get ( ) , queue , m_page_to_free , m_page_to_free_size , error ) ;
m_page_to_free = LLDB_INVALID_ADDRESS ;
m_page_to_free_size = 0 ;
if ( error . Success ( ) )
{
if ( pending_items_pointer . count > 0
& & pending_items_pointer . items_buffer_size > 0
& & pending_items_pointer . items_buffer_ptr ! = 0
& & pending_items_pointer . items_buffer_ptr ! = LLDB_INVALID_ADDRESS )
{
DataBufferHeap data ( pending_items_pointer . items_buffer_size , 0 ) ;
if ( m_process - > ReadMemory ( pending_items_pointer . items_buffer_ptr , data . GetBytes ( ) , pending_items_pointer . items_buffer_size , error ) )
{
DataExtractor extractor ( data . GetBytes ( ) , data . GetByteSize ( ) , m_process - > GetByteOrder ( ) , m_process - > GetAddressByteSize ( ) ) ;
// We either have an array of
// void* item_ref
// (old style) or we have a structure returned which looks like
//
// struct introspection_dispatch_pending_item_info_s {
// void *item_ref;
// void *function_or_block;
// };
//
// struct introspection_dispatch_pending_items_array_s {
// uint32_t version;
// uint32_t size_of_item_info;
// introspection_dispatch_pending_item_info_s items[];
// }
offset_t offset = 0 ;
int i = 0 ;
uint32_t version = extractor . GetU32 ( & offset ) ;
if ( version = = 1 )
{
pending_item_refs . new_style = true ;
uint32_t item_size = extractor . GetU32 ( & offset ) ;
uint32_t start_of_array_offset = offset ;
while ( offset < pending_items_pointer . items_buffer_size & &
static_cast < size_t > ( i ) < pending_items_pointer . count )
{
offset = start_of_array_offset + ( i * item_size ) ;
ItemRefAndCodeAddress item ;
item . item_ref = extractor . GetPointer ( & offset ) ;
item . code_address = extractor . GetPointer ( & offset ) ;
pending_item_refs . item_refs_and_code_addresses . push_back ( item ) ;
i + + ;
}
}
else
{
offset = 0 ;
pending_item_refs . new_style = false ;
while ( offset < pending_items_pointer . items_buffer_size & &
static_cast < size_t > ( i ) < pending_items_pointer . count )
{
ItemRefAndCodeAddress item ;
item . item_ref = extractor . GetPointer ( & offset ) ;
item . code_address = LLDB_INVALID_ADDRESS ;
pending_item_refs . item_refs_and_code_addresses . push_back ( item ) ;
i + + ;
}
}
}
m_page_to_free = pending_items_pointer . items_buffer_ptr ;
m_page_to_free_size = pending_items_pointer . items_buffer_size ;
}
}
}
return pending_item_refs ;
}
void
SystemRuntimeMacOSX : : PopulatePendingItemsForQueue ( Queue * queue )
{
if ( BacktraceRecordingHeadersInitialized ( ) )
{
PendingItemsForQueue pending_item_refs = GetPendingItemRefsForQueue ( queue - > GetLibdispatchQueueAddress ( ) ) ;
for ( ItemRefAndCodeAddress pending_item : pending_item_refs . item_refs_and_code_addresses )
{
Address addr ;
m_process - > GetTarget ( ) . ResolveLoadAddress ( pending_item . code_address , addr ) ;
QueueItemSP queue_item_sp ( new QueueItem ( queue - > shared_from_this ( ) , m_process - > shared_from_this ( ) , pending_item . item_ref , addr ) ) ;
queue - > PushPendingQueueItem ( queue_item_sp ) ;
}
}
}
void
SystemRuntimeMacOSX : : CompleteQueueItem ( QueueItem * queue_item , addr_t item_ref )
{
AppleGetItemInfoHandler : : GetItemInfoReturnInfo ret ;
ThreadSP cur_thread_sp ( m_process - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
Error error ;
ret = m_get_item_info_handler . GetItemInfo ( * cur_thread_sp . get ( ) , item_ref , m_page_to_free , m_page_to_free_size , error ) ;
m_page_to_free = LLDB_INVALID_ADDRESS ;
m_page_to_free_size = 0 ;
if ( ret . item_buffer_ptr ! = 0 & & ret . item_buffer_ptr ! = LLDB_INVALID_ADDRESS & & ret . item_buffer_size > 0 )
{
DataBufferHeap data ( ret . item_buffer_size , 0 ) ;
if ( m_process - > ReadMemory ( ret . item_buffer_ptr , data . GetBytes ( ) , ret . item_buffer_size , error ) & & error . Success ( ) )
{
DataExtractor extractor ( data . GetBytes ( ) , data . GetByteSize ( ) , m_process - > GetByteOrder ( ) , m_process - > GetAddressByteSize ( ) ) ;
ItemInfo item = ExtractItemInfoFromBuffer ( extractor ) ;
queue_item - > SetItemThatEnqueuedThis ( item . item_that_enqueued_this ) ;
queue_item - > SetEnqueueingThreadID ( item . enqueuing_thread_id ) ;
queue_item - > SetEnqueueingQueueID ( item . enqueuing_queue_serialnum ) ;
queue_item - > SetStopID ( item . stop_id ) ;
queue_item - > SetEnqueueingBacktrace ( item . enqueuing_callstack ) ;
queue_item - > SetThreadLabel ( item . enqueuing_thread_label ) ;
queue_item - > SetQueueLabel ( item . enqueuing_queue_label ) ;
queue_item - > SetTargetQueueLabel ( item . target_queue_label ) ;
}
m_page_to_free = ret . item_buffer_ptr ;
m_page_to_free_size = ret . item_buffer_size ;
}
}
void
SystemRuntimeMacOSX : : PopulateQueuesUsingLibBTR ( lldb : : addr_t queues_buffer , uint64_t queues_buffer_size ,
uint64_t count , lldb_private : : QueueList & queue_list )
{
Error error ;
DataBufferHeap data ( queues_buffer_size , 0 ) ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SYSTEM_RUNTIME ) ) ;
if ( m_process - > ReadMemory ( queues_buffer , data . GetBytes ( ) , queues_buffer_size , error ) = = queues_buffer_size & & error . Success ( ) )
{
// We've read the information out of inferior memory; free it on the next call we make
m_page_to_free = queues_buffer ;
m_page_to_free_size = queues_buffer_size ;
DataExtractor extractor ( data . GetBytes ( ) , data . GetByteSize ( ) , m_process - > GetByteOrder ( ) , m_process - > GetAddressByteSize ( ) ) ;
offset_t offset = 0 ;
uint64_t queues_read = 0 ;
// The information about the queues is stored in this format (v1):
// typedef struct introspection_dispatch_queue_info_s {
// uint32_t offset_to_next;
// dispatch_queue_t queue;
// uint64_t serialnum; // queue's serialnum in the process, as provided by libdispatch
// uint32_t running_work_items_count;
// uint32_t pending_work_items_count;
//
// char data[]; // Starting here, we have variable-length data:
// // char queue_label[];
// } introspection_dispatch_queue_info_s;
while ( queues_read < count & & offset < queues_buffer_size )
{
offset_t start_of_this_item = offset ;
uint32_t offset_to_next = extractor . GetU32 ( & offset ) ;
offset + = 4 ; // Skip over the 4 bytes of reserved space
addr_t queue = extractor . GetPointer ( & offset ) ;
uint64_t serialnum = extractor . GetU64 ( & offset ) ;
uint32_t running_work_items_count = extractor . GetU32 ( & offset ) ;
uint32_t pending_work_items_count = extractor . GetU32 ( & offset ) ;
// Read the first field of the variable length data
offset = start_of_this_item + m_lib_backtrace_recording_info . queue_info_data_offset ;
const char * queue_label = extractor . GetCStr ( & offset ) ;
if ( queue_label = = NULL )
queue_label = " " ;
offset_t start_of_next_item = start_of_this_item + offset_to_next ;
offset = start_of_next_item ;
if ( log )
log - > Printf ( " SystemRuntimeMacOSX::PopulateQueuesUsingLibBTR added queue with dispatch_queue_t 0x% " PRIx64 " , serial number 0x% " PRIx64 " , running items %d, pending items %d, name '%s' " , queue , serialnum , running_work_items_count , pending_work_items_count , queue_label ) ;
QueueSP queue_sp ( new Queue ( m_process - > shared_from_this ( ) , serialnum , queue_label ) ) ;
queue_sp - > SetNumRunningWorkItems ( running_work_items_count ) ;
queue_sp - > SetNumPendingWorkItems ( pending_work_items_count ) ;
queue_sp - > SetLibdispatchQueueAddress ( queue ) ;
queue_sp - > SetKind ( GetQueueKind ( queue ) ) ;
queue_list . AddQueue ( queue_sp ) ;
queues_read + + ;
}
}
}
SystemRuntimeMacOSX : : ItemInfo
SystemRuntimeMacOSX : : ExtractItemInfoFromBuffer ( lldb_private : : DataExtractor & extractor )
{
ItemInfo item ;
offset_t offset = 0 ;
item . item_that_enqueued_this = extractor . GetPointer ( & offset ) ;
item . function_or_block = extractor . GetPointer ( & offset ) ;
item . enqueuing_thread_id = extractor . GetU64 ( & offset ) ;
item . enqueuing_queue_serialnum = extractor . GetU64 ( & offset ) ;
item . target_queue_serialnum = extractor . GetU64 ( & offset ) ;
item . enqueuing_callstack_frame_count = extractor . GetU32 ( & offset ) ;
item . stop_id = extractor . GetU32 ( & offset ) ;
offset = m_lib_backtrace_recording_info . item_info_data_offset ;
for ( uint32_t i = 0 ; i < item . enqueuing_callstack_frame_count ; i + + )
{
item . enqueuing_callstack . push_back ( extractor . GetPointer ( & offset ) ) ;
}
item . enqueuing_thread_label = extractor . GetCStr ( & offset ) ;
item . enqueuing_queue_label = extractor . GetCStr ( & offset ) ;
item . target_queue_label = extractor . GetCStr ( & offset ) ;
return item ;
}
void
SystemRuntimeMacOSX : : Initialize ( )
{
PluginManager : : RegisterPlugin ( GetPluginNameStatic ( ) ,
GetPluginDescriptionStatic ( ) ,
CreateInstance ) ;
}
void
SystemRuntimeMacOSX : : Terminate ( )
{
PluginManager : : UnregisterPlugin ( CreateInstance ) ;
}
lldb_private : : ConstString
SystemRuntimeMacOSX : : GetPluginNameStatic ( )
{
static ConstString g_name ( " systemruntime-macosx " ) ;
return g_name ;
}
const char *
SystemRuntimeMacOSX : : GetPluginDescriptionStatic ( )
{
return " System runtime plugin for Mac OS X native libraries. " ;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private : : ConstString
SystemRuntimeMacOSX : : GetPluginName ( )
{
return GetPluginNameStatic ( ) ;
}
uint32_t
SystemRuntimeMacOSX : : GetPluginVersion ( )
{
return 1 ;
}