2013-08-23 13:46:38 -04:00
//===-- Debugger.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/lldb-python.h"
# include "lldb/Core/Debugger.h"
# include <map>
# include "clang/AST/DeclCXX.h"
# include "clang/AST/Type.h"
2014-11-25 16:00:58 -05:00
# include "llvm/ADT/StringRef.h"
2013-08-23 13:46:38 -04:00
# include "lldb/lldb-private.h"
2015-02-08 20:44:09 -05:00
# include "lldb/Core/FormatEntity.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/Module.h"
# include "lldb/Core/PluginManager.h"
# include "lldb/Core/RegisterValue.h"
# include "lldb/Core/State.h"
# include "lldb/Core/StreamAsynchronousIO.h"
# include "lldb/Core/StreamCallback.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Core/StreamFile.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/StreamString.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Core/StructuredData.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Core/Timer.h"
# include "lldb/Core/ValueObject.h"
# include "lldb/Core/ValueObjectVariable.h"
# include "lldb/DataFormatters/DataVisualization.h"
# include "lldb/DataFormatters/FormatManager.h"
2014-11-25 16:00:58 -05:00
# include "lldb/DataFormatters/TypeSummary.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/ConnectionFileDescriptor.h"
2014-11-25 16:00:58 -05:00
# include "lldb/Host/HostInfo.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Terminal.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Host/ThreadLauncher.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/OptionValueSInt64.h"
# include "lldb/Interpreter/OptionValueString.h"
# include "lldb/Symbol/ClangASTContext.h"
# include "lldb/Symbol/CompileUnit.h"
# include "lldb/Symbol/Function.h"
# include "lldb/Symbol/Symbol.h"
# include "lldb/Symbol/VariableList.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Target/CPPLanguageRuntime.h"
# include "lldb/Target/ObjCLanguageRuntime.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/TargetList.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/RegisterContext.h"
2013-12-03 13:51:59 -05:00
# include "lldb/Target/SectionLoadList.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/StopInfo.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
# include "lldb/Utility/AnsiTerminal.h"
2014-11-25 16:00:58 -05:00
# include "llvm/Support/DynamicLibrary.h"
2013-08-23 13:46:38 -04:00
using namespace lldb ;
using namespace lldb_private ;
static uint32_t g_shared_debugger_refcount = 0 ;
static lldb : : user_id_t g_unique_id = 1 ;
2015-02-06 16:38:51 -05:00
static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024 ;
2013-08-23 13:46:38 -04:00
# pragma mark Static Functions
static Mutex &
GetDebuggerListMutex ( )
{
static Mutex g_mutex ( Mutex : : eMutexTypeRecursive ) ;
return g_mutex ;
}
typedef std : : vector < DebuggerSP > DebuggerList ;
static DebuggerList &
GetDebuggerList ( )
{
// hide the static debugger list inside a singleton accessor to avoid
2014-11-25 16:00:58 -05:00
// global init constructors
2013-08-23 13:46:38 -04:00
static DebuggerList g_list ;
return g_list ;
}
OptionEnumValueElement
g_show_disassembly_enum_values [ ] =
{
{ Debugger : : eStopDisassemblyTypeNever , " never " , " Never show disassembly when displaying a stop context. " } ,
{ Debugger : : eStopDisassemblyTypeNoSource , " no-source " , " Show disassembly when there is no source information, or the source file is missing when displaying a stop context. " } ,
{ Debugger : : eStopDisassemblyTypeAlways , " always " , " Always show disassembly when displaying a stop context. " } ,
{ 0 , NULL , NULL }
} ;
OptionEnumValueElement
g_language_enumerators [ ] =
{
{ eScriptLanguageNone , " none " , " Disable scripting languages. " } ,
{ eScriptLanguagePython , " python " , " Select python as the default scripting language. " } ,
{ eScriptLanguageDefault , " default " , " Select the lldb default as the default scripting language. " } ,
{ 0 , NULL , NULL }
} ;
# define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}"
# define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
# define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\
" {, ${frame.pc}} " \
MODULE_WITH_FUNC \
FILE_AND_LINE \
" {, name = '${thread.name}'} " \
" {, queue = '${thread.queue}'} " \
2014-11-25 16:00:58 -05:00
" {, activity = '${thread.info.activity.name}'} " \
" {, ${thread.info.trace_messages} messages} " \
2013-08-23 13:46:38 -04:00
" {, stop reason = ${thread.stop-reason}} " \
" { \\ nReturn value: ${thread.return-value}} " \
2014-11-25 16:00:58 -05:00
" { \\ nCompleted expression: ${thread.completed-expression}} " \
2013-08-23 13:46:38 -04:00
" \\ n "
# define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
MODULE_WITH_FUNC \
FILE_AND_LINE \
" \\ n "
2015-02-06 16:38:51 -05:00
# define DEFAULT_DISASSEMBLY_FORMAT "${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: "
2013-08-23 13:46:38 -04:00
static PropertyDefinition
g_properties [ ] =
{
2015-02-08 20:44:09 -05:00
{ " auto-confirm " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " If true all confirmation prompts will receive their default reply. " } ,
{ " disassembly-format " , OptionValue : : eTypeFormatEntity , true , 0 , DEFAULT_DISASSEMBLY_FORMAT , NULL , " The default disassembly format string to use when disassembling instruction sequences. " } ,
{ " frame-format " , OptionValue : : eTypeFormatEntity , true , 0 , DEFAULT_FRAME_FORMAT , NULL , " The default frame format string to use when displaying stack frame information for threads. " } ,
{ " notify-void " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " Notify the user explicitly if an expression returns void (default: false). " } ,
{ " prompt " , OptionValue : : eTypeString , true , OptionValueString : : eOptionEncodeCharacterEscapeSequences , " (lldb) " , NULL , " The debugger command line prompt displayed for the user. " } ,
{ " script-lang " , OptionValue : : eTypeEnum , true , eScriptLanguagePython , NULL , g_language_enumerators , " The script language to be used for evaluating user-written scripts. " } ,
{ " stop-disassembly-count " , OptionValue : : eTypeSInt64 , true , 4 , NULL , NULL , " The number of disassembly lines to show when displaying a stopped context. " } ,
{ " stop-disassembly-display " , OptionValue : : eTypeEnum , true , Debugger : : eStopDisassemblyTypeNoSource , NULL , g_show_disassembly_enum_values , " Control when to display disassembly when displaying a stopped context. " } ,
{ " stop-line-count-after " , OptionValue : : eTypeSInt64 , true , 3 , NULL , NULL , " The number of sources lines to display that come after the current source line when displaying a stopped context. " } ,
{ " stop-line-count-before " , OptionValue : : eTypeSInt64 , true , 3 , NULL , NULL , " The number of sources lines to display that come before the current source line when displaying a stopped context. " } ,
{ " term-width " , OptionValue : : eTypeSInt64 , true , 80 , NULL , NULL , " The maximum number of columns to use for displaying text. " } ,
{ " thread-format " , OptionValue : : eTypeFormatEntity , true , 0 , DEFAULT_THREAD_FORMAT , NULL , " The default thread format string to use when displaying thread information. " } ,
{ " use-external-editor " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " Whether to use an external editor or not. " } ,
{ " use-color " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " Whether to use Ansi color codes or not. " } ,
{ " auto-one-line-summaries " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, LLDB will automatically display small structs in one-liner format (default: true). " } ,
{ " escape-non-printables " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, LLDB will automatically escape non-printable and escape characters when formatting strings. " } ,
{ NULL , OptionValue : : eTypeInvalid , true , 0 , NULL , NULL , NULL }
2013-08-23 13:46:38 -04:00
} ;
enum
{
ePropertyAutoConfirm = 0 ,
2015-02-06 16:38:51 -05:00
ePropertyDisassemblyFormat ,
2013-08-23 13:46:38 -04:00
ePropertyFrameFormat ,
ePropertyNotiftVoid ,
ePropertyPrompt ,
ePropertyScriptLanguage ,
ePropertyStopDisassemblyCount ,
ePropertyStopDisassemblyDisplay ,
ePropertyStopLineCountAfter ,
ePropertyStopLineCountBefore ,
ePropertyTerminalWidth ,
ePropertyThreadFormat ,
ePropertyUseExternalEditor ,
ePropertyUseColor ,
2015-02-06 16:38:51 -05:00
ePropertyAutoOneLineSummaries ,
ePropertyEscapeNonPrintables
2013-08-23 13:46:38 -04:00
} ;
2013-12-03 13:51:59 -05:00
Debugger : : LoadPluginCallbackType Debugger : : g_load_plugin_callback = NULL ;
2013-08-23 13:46:38 -04:00
Error
Debugger : : SetPropertyValue ( const ExecutionContext * exe_ctx ,
VarSetOperationType op ,
const char * property_path ,
const char * value )
{
bool is_load_script = strcmp ( property_path , " target.load-script-from-symbol-file " ) = = 0 ;
2015-02-06 16:38:51 -05:00
bool is_escape_non_printables = strcmp ( property_path , " escape-non-printables " ) = = 0 ;
2013-08-23 13:46:38 -04:00
TargetSP target_sp ;
LoadScriptFromSymFile load_script_old_value ;
if ( is_load_script & & exe_ctx - > GetTargetSP ( ) )
{
target_sp = exe_ctx - > GetTargetSP ( ) ;
load_script_old_value = target_sp - > TargetProperties : : GetLoadScriptFromSymbolFile ( ) ;
}
Error error ( Properties : : SetPropertyValue ( exe_ctx , op , property_path , value ) ) ;
if ( error . Success ( ) )
{
// FIXME it would be nice to have "on-change" callbacks for properties
if ( strcmp ( property_path , g_properties [ ePropertyPrompt ] . name ) = = 0 )
{
const char * new_prompt = GetPrompt ( ) ;
std : : string str = lldb_utility : : ansi : : FormatAnsiTerminalCodes ( new_prompt , GetUseColor ( ) ) ;
if ( str . length ( ) )
new_prompt = str . c_str ( ) ;
2014-02-18 11:23:10 -05:00
GetCommandInterpreter ( ) . UpdatePrompt ( new_prompt ) ;
2013-08-23 13:46:38 -04:00
EventSP prompt_change_event_sp ( new Event ( CommandInterpreter : : eBroadcastBitResetPrompt , new EventDataBytes ( new_prompt ) ) ) ;
GetCommandInterpreter ( ) . BroadcastEvent ( prompt_change_event_sp ) ;
}
else if ( strcmp ( property_path , g_properties [ ePropertyUseColor ] . name ) = = 0 )
{
// use-color changed. Ping the prompt so it can reset the ansi terminal codes.
SetPrompt ( GetPrompt ( ) ) ;
}
else if ( is_load_script & & target_sp & & load_script_old_value = = eLoadScriptFromSymFileWarn )
{
if ( target_sp - > TargetProperties : : GetLoadScriptFromSymbolFile ( ) = = eLoadScriptFromSymFileTrue )
{
std : : list < Error > errors ;
StreamString feedback_stream ;
if ( ! target_sp - > LoadScriptingResources ( errors , & feedback_stream ) )
{
2014-02-18 11:23:10 -05:00
StreamFileSP stream_sp ( GetErrorFile ( ) ) ;
if ( stream_sp )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
for ( auto error : errors )
{
stream_sp - > Printf ( " %s \n " , error . AsCString ( ) ) ;
}
if ( feedback_stream . GetSize ( ) )
stream_sp - > Printf ( " %s " , feedback_stream . GetData ( ) ) ;
2013-08-23 13:46:38 -04:00
}
}
}
}
2015-02-06 16:38:51 -05:00
else if ( is_escape_non_printables )
{
DataVisualization : : ForceUpdate ( ) ;
}
2013-08-23 13:46:38 -04:00
}
return error ;
}
bool
Debugger : : GetAutoConfirm ( ) const
{
const uint32_t idx = ePropertyAutoConfirm ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
2015-02-08 20:44:09 -05:00
const FormatEntity : : Entry *
2015-02-06 16:38:51 -05:00
Debugger : : GetDisassemblyFormat ( ) const
{
const uint32_t idx = ePropertyDisassemblyFormat ;
2015-02-08 20:44:09 -05:00
return m_collection_sp - > GetPropertyAtIndexAsFormatEntity ( NULL , idx ) ;
2015-02-06 16:38:51 -05:00
}
2015-02-08 20:44:09 -05:00
const FormatEntity : : Entry *
2013-08-23 13:46:38 -04:00
Debugger : : GetFrameFormat ( ) const
{
const uint32_t idx = ePropertyFrameFormat ;
2015-02-08 20:44:09 -05:00
return m_collection_sp - > GetPropertyAtIndexAsFormatEntity ( NULL , idx ) ;
2013-08-23 13:46:38 -04:00
}
bool
Debugger : : GetNotifyVoid ( ) const
{
const uint32_t idx = ePropertyNotiftVoid ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
const char *
Debugger : : GetPrompt ( ) const
{
const uint32_t idx = ePropertyPrompt ;
return m_collection_sp - > GetPropertyAtIndexAsString ( NULL , idx , g_properties [ idx ] . default_cstr_value ) ;
}
void
Debugger : : SetPrompt ( const char * p )
{
const uint32_t idx = ePropertyPrompt ;
m_collection_sp - > SetPropertyAtIndexAsString ( NULL , idx , p ) ;
const char * new_prompt = GetPrompt ( ) ;
std : : string str = lldb_utility : : ansi : : FormatAnsiTerminalCodes ( new_prompt , GetUseColor ( ) ) ;
if ( str . length ( ) )
new_prompt = str . c_str ( ) ;
2014-02-18 11:23:10 -05:00
GetCommandInterpreter ( ) . UpdatePrompt ( new_prompt ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-08 20:44:09 -05:00
const FormatEntity : : Entry *
2013-08-23 13:46:38 -04:00
Debugger : : GetThreadFormat ( ) const
{
const uint32_t idx = ePropertyThreadFormat ;
2015-02-08 20:44:09 -05:00
return m_collection_sp - > GetPropertyAtIndexAsFormatEntity ( NULL , idx ) ;
2013-08-23 13:46:38 -04:00
}
lldb : : ScriptLanguage
Debugger : : GetScriptLanguage ( ) const
{
const uint32_t idx = ePropertyScriptLanguage ;
return ( lldb : : ScriptLanguage ) m_collection_sp - > GetPropertyAtIndexAsEnumeration ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
bool
Debugger : : SetScriptLanguage ( lldb : : ScriptLanguage script_lang )
{
const uint32_t idx = ePropertyScriptLanguage ;
return m_collection_sp - > SetPropertyAtIndexAsEnumeration ( NULL , idx , script_lang ) ;
}
uint32_t
Debugger : : GetTerminalWidth ( ) const
{
const uint32_t idx = ePropertyTerminalWidth ;
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
bool
Debugger : : SetTerminalWidth ( uint32_t term_width )
{
const uint32_t idx = ePropertyTerminalWidth ;
return m_collection_sp - > SetPropertyAtIndexAsSInt64 ( NULL , idx , term_width ) ;
}
bool
Debugger : : GetUseExternalEditor ( ) const
{
const uint32_t idx = ePropertyUseExternalEditor ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
bool
Debugger : : SetUseExternalEditor ( bool b )
{
const uint32_t idx = ePropertyUseExternalEditor ;
return m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , b ) ;
}
bool
Debugger : : GetUseColor ( ) const
{
const uint32_t idx = ePropertyUseColor ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
}
bool
Debugger : : SetUseColor ( bool b )
{
const uint32_t idx = ePropertyUseColor ;
bool ret = m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , b ) ;
SetPrompt ( GetPrompt ( ) ) ;
return ret ;
}
uint32_t
Debugger : : GetStopSourceLineCount ( bool before ) const
{
const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter ;
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
Debugger : : StopDisassemblyType
Debugger : : GetStopDisassemblyDisplay ( ) const
{
const uint32_t idx = ePropertyStopDisassemblyDisplay ;
return ( Debugger : : StopDisassemblyType ) m_collection_sp - > GetPropertyAtIndexAsEnumeration ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
uint32_t
Debugger : : GetDisassemblyLineCount ( ) const
{
const uint32_t idx = ePropertyStopDisassemblyCount ;
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
}
2013-11-06 11:48:53 -05:00
bool
Debugger : : GetAutoOneLineSummaries ( ) const
{
const uint32_t idx = ePropertyAutoOneLineSummaries ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , true ) ;
2015-02-06 16:38:51 -05:00
}
2013-11-06 11:48:53 -05:00
2015-02-06 16:38:51 -05:00
bool
Debugger : : GetEscapeNonPrintables ( ) const
{
const uint32_t idx = ePropertyEscapeNonPrintables ;
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , true ) ;
2013-11-06 11:48:53 -05:00
}
2013-08-23 13:46:38 -04:00
# pragma mark Debugger
//const DebuggerPropertiesSP &
//Debugger::GetSettings() const
//{
// return m_properties_sp;
//}
//
int
Debugger : : TestDebuggerRefCount ( )
{
return g_shared_debugger_refcount ;
}
void
2013-12-03 13:51:59 -05:00
Debugger : : Initialize ( LoadPluginCallbackType load_plugin_callback )
2013-08-23 13:46:38 -04:00
{
2013-12-03 13:51:59 -05:00
g_load_plugin_callback = load_plugin_callback ;
2013-08-23 13:46:38 -04:00
if ( g_shared_debugger_refcount + + = = 0 )
lldb_private : : Initialize ( ) ;
}
void
Debugger : : Terminate ( )
{
if ( g_shared_debugger_refcount > 0 )
{
g_shared_debugger_refcount - - ;
if ( g_shared_debugger_refcount = = 0 )
{
lldb_private : : WillTerminate ( ) ;
lldb_private : : Terminate ( ) ;
// Clear our master list of debugger objects
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
GetDebuggerList ( ) . clear ( ) ;
}
}
}
void
Debugger : : SettingsInitialize ( )
{
Target : : SettingsInitialize ( ) ;
}
void
Debugger : : SettingsTerminate ( )
{
Target : : SettingsTerminate ( ) ;
}
bool
Debugger : : LoadPlugin ( const FileSpec & spec , Error & error )
{
2013-12-03 13:51:59 -05:00
if ( g_load_plugin_callback )
2013-08-23 13:46:38 -04:00
{
2014-11-25 16:00:58 -05:00
llvm : : sys : : DynamicLibrary dynlib = g_load_plugin_callback ( shared_from_this ( ) , spec , error ) ;
if ( dynlib . isValid ( ) )
2013-12-03 13:51:59 -05:00
{
2014-11-25 16:00:58 -05:00
m_loaded_plugins . push_back ( dynlib ) ;
2013-12-03 13:51:59 -05:00
return true ;
}
2013-08-23 13:46:38 -04:00
}
2013-12-03 13:51:59 -05:00
else
2013-08-23 13:46:38 -04:00
{
2013-12-03 13:51:59 -05:00
// The g_load_plugin_callback is registered in SBDebugger::Initialize()
// and if the public API layer isn't available (code is linking against
// all of the internal LLDB static libraries), then we can't load plugins
error . SetErrorString ( " Public API layer is not available " ) ;
2013-08-23 13:46:38 -04:00
}
return false ;
}
static FileSpec : : EnumerateDirectoryResult
LoadPluginCallback
(
void * baton ,
FileSpec : : FileType file_type ,
const FileSpec & file_spec
)
{
Error error ;
static ConstString g_dylibext ( " dylib " ) ;
static ConstString g_solibext ( " so " ) ;
if ( ! baton )
return FileSpec : : eEnumerateDirectoryResultQuit ;
Debugger * debugger = ( Debugger * ) baton ;
// If we have a regular file, a symbolic link or unknown file type, try
// and process the file. We must handle unknown as sometimes the directory
// enumeration might be enumerating a file system that doesn't have correct
// file type information.
if ( file_type = = FileSpec : : eFileTypeRegular | |
file_type = = FileSpec : : eFileTypeSymbolicLink | |
file_type = = FileSpec : : eFileTypeUnknown )
{
FileSpec plugin_file_spec ( file_spec ) ;
plugin_file_spec . ResolvePath ( ) ;
if ( plugin_file_spec . GetFileNameExtension ( ) ! = g_dylibext & &
plugin_file_spec . GetFileNameExtension ( ) ! = g_solibext )
{
return FileSpec : : eEnumerateDirectoryResultNext ;
}
Error plugin_load_error ;
debugger - > LoadPlugin ( plugin_file_spec , plugin_load_error ) ;
return FileSpec : : eEnumerateDirectoryResultNext ;
}
else if ( file_type = = FileSpec : : eFileTypeUnknown | |
file_type = = FileSpec : : eFileTypeDirectory | |
file_type = = FileSpec : : eFileTypeSymbolicLink )
{
// Try and recurse into anything that a directory or symbolic link.
// We must also do this for unknown as sometimes the directory enumeration
2014-11-25 16:00:58 -05:00
// might be enumerating a file system that doesn't have correct file type
2013-08-23 13:46:38 -04:00
// information.
return FileSpec : : eEnumerateDirectoryResultEnter ;
}
return FileSpec : : eEnumerateDirectoryResultNext ;
}
void
Debugger : : InstanceInitialize ( )
{
FileSpec dir_spec ;
const bool find_directories = true ;
const bool find_files = true ;
const bool find_other = true ;
char dir_path [ PATH_MAX ] ;
2014-11-25 16:00:58 -05:00
if ( HostInfo : : GetLLDBPath ( ePathTypeLLDBSystemPlugins , dir_spec ) )
2013-08-23 13:46:38 -04:00
{
if ( dir_spec . Exists ( ) & & dir_spec . GetPath ( dir_path , sizeof ( dir_path ) ) )
{
FileSpec : : EnumerateDirectory ( dir_path ,
find_directories ,
find_files ,
find_other ,
LoadPluginCallback ,
this ) ;
}
}
2014-11-25 16:00:58 -05:00
if ( HostInfo : : GetLLDBPath ( ePathTypeLLDBUserPlugins , dir_spec ) )
2013-08-23 13:46:38 -04:00
{
if ( dir_spec . Exists ( ) & & dir_spec . GetPath ( dir_path , sizeof ( dir_path ) ) )
{
FileSpec : : EnumerateDirectory ( dir_path ,
find_directories ,
find_files ,
find_other ,
LoadPluginCallback ,
this ) ;
}
}
PluginManager : : DebuggerInitialize ( * this ) ;
}
DebuggerSP
Debugger : : CreateInstance ( lldb : : LogOutputCallback log_callback , void * baton )
{
DebuggerSP debugger_sp ( new Debugger ( log_callback , baton ) ) ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
GetDebuggerList ( ) . push_back ( debugger_sp ) ;
}
debugger_sp - > InstanceInitialize ( ) ;
return debugger_sp ;
}
void
Debugger : : Destroy ( DebuggerSP & debugger_sp )
{
if ( debugger_sp . get ( ) = = NULL )
return ;
debugger_sp - > Clear ( ) ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
{
if ( ( * pos ) . get ( ) = = debugger_sp . get ( ) )
{
debugger_list . erase ( pos ) ;
return ;
}
}
}
}
DebuggerSP
Debugger : : FindDebuggerWithInstanceName ( const ConstString & instance_name )
{
DebuggerSP debugger_sp ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
{
if ( ( * pos ) . get ( ) - > m_instance_name = = instance_name )
{
debugger_sp = * pos ;
break ;
}
}
}
return debugger_sp ;
}
TargetSP
Debugger : : FindTargetWithProcessID ( lldb : : pid_t pid )
{
TargetSP target_sp ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
{
target_sp = ( * pos ) - > GetTargetList ( ) . FindTargetWithProcessID ( pid ) ;
if ( target_sp )
break ;
}
}
return target_sp ;
}
TargetSP
Debugger : : FindTargetWithProcess ( Process * process )
{
TargetSP target_sp ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
{
target_sp = ( * pos ) - > GetTargetList ( ) . FindTargetWithProcess ( process ) ;
if ( target_sp )
break ;
}
}
return target_sp ;
}
2015-02-06 16:38:51 -05:00
Debugger : : Debugger ( lldb : : LogOutputCallback log_callback , void * baton ) :
UserID ( g_unique_id + + ) ,
Properties ( OptionValuePropertiesSP ( new OptionValueProperties ( ) ) ) ,
m_input_file_sp ( new StreamFile ( stdin , false ) ) ,
m_output_file_sp ( new StreamFile ( stdout , false ) ) ,
m_error_file_sp ( new StreamFile ( stderr , false ) ) ,
m_terminal_state ( ) ,
m_target_list ( * this ) ,
m_platform_list ( ) ,
m_listener ( " lldb.Debugger " ) ,
2013-08-23 13:46:38 -04:00
m_source_manager_ap ( ) ,
m_source_file_cache ( ) ,
2015-02-06 16:38:51 -05:00
m_command_interpreter_ap ( new CommandInterpreter ( * this , eScriptLanguageDefault , false ) ) ,
m_input_reader_stack ( ) ,
m_instance_name ( ) ,
m_loaded_plugins ( ) ,
m_event_handler_thread ( ) ,
m_io_handler_thread ( ) ,
m_sync_broadcaster ( NULL , " lldb.debugger.sync " )
2013-08-23 13:46:38 -04:00
{
char instance_cstr [ 256 ] ;
snprintf ( instance_cstr , sizeof ( instance_cstr ) , " debugger_%d " , ( int ) GetID ( ) ) ;
m_instance_name . SetCString ( instance_cstr ) ;
if ( log_callback )
m_log_callback_stream_sp . reset ( new StreamCallback ( log_callback , baton ) ) ;
m_command_interpreter_ap - > Initialize ( ) ;
// Always add our default platform to the platform list
2015-02-06 16:38:51 -05:00
PlatformSP default_platform_sp ( Platform : : GetHostPlatform ( ) ) ;
2013-08-23 13:46:38 -04:00
assert ( default_platform_sp . get ( ) ) ;
m_platform_list . Append ( default_platform_sp , true ) ;
m_collection_sp - > Initialize ( g_properties ) ;
m_collection_sp - > AppendProperty ( ConstString ( " target " ) ,
ConstString ( " Settings specify to debugging targets. " ) ,
true ,
Target : : GetGlobalProperties ( ) - > GetValueProperties ( ) ) ;
if ( m_command_interpreter_ap . get ( ) )
{
m_collection_sp - > AppendProperty ( ConstString ( " interpreter " ) ,
ConstString ( " Settings specify to the debugger's command interpreter. " ) ,
true ,
m_command_interpreter_ap - > GetValueProperties ( ) ) ;
}
OptionValueSInt64 * term_width = m_collection_sp - > GetPropertyAtIndexAsOptionValueSInt64 ( NULL , ePropertyTerminalWidth ) ;
term_width - > SetMinimumValue ( 10 ) ;
term_width - > SetMaximumValue ( 1024 ) ;
// Turn off use-color if this is a dumb terminal.
const char * term = getenv ( " TERM " ) ;
if ( term & & ! strcmp ( term , " dumb " ) )
SetUseColor ( false ) ;
}
Debugger : : ~ Debugger ( )
{
Clear ( ) ;
}
void
Debugger : : Clear ( )
{
2014-02-18 11:23:10 -05:00
ClearIOHandlers ( ) ;
StopIOHandlerThread ( ) ;
StopEventHandlerThread ( ) ;
2013-08-23 13:46:38 -04:00
m_listener . Clear ( ) ;
int num_targets = m_target_list . GetNumTargets ( ) ;
for ( int i = 0 ; i < num_targets ; i + + )
{
TargetSP target_sp ( m_target_list . GetTargetAtIndex ( i ) ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
process_sp - > Finalize ( ) ;
target_sp - > Destroy ( ) ;
}
}
BroadcasterManager : : Clear ( ) ;
// Close the input file _before_ we close the input read communications class
// as it does NOT own the input file, our m_input_file does.
m_terminal_state . Clear ( ) ;
2014-02-18 11:23:10 -05:00
if ( m_input_file_sp )
m_input_file_sp - > GetFile ( ) . Close ( ) ;
2014-11-25 16:00:58 -05:00
m_command_interpreter_ap - > Clear ( ) ;
2013-08-23 13:46:38 -04:00
}
bool
Debugger : : GetCloseInputOnEOF ( ) const
{
2014-02-18 11:23:10 -05:00
// return m_input_comm.GetCloseOnEOF();
return false ;
2013-08-23 13:46:38 -04:00
}
void
Debugger : : SetCloseInputOnEOF ( bool b )
{
2014-02-18 11:23:10 -05:00
// m_input_comm.SetCloseOnEOF(b);
2013-08-23 13:46:38 -04:00
}
bool
Debugger : : GetAsyncExecution ( )
{
return ! m_command_interpreter_ap - > GetSynchronous ( ) ;
}
void
Debugger : : SetAsyncExecution ( bool async_execution )
{
m_command_interpreter_ap - > SetSynchronous ( ! async_execution ) ;
}
void
Debugger : : SetInputFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-02-18 11:23:10 -05:00
if ( m_input_file_sp )
m_input_file_sp - > GetFile ( ) . SetStream ( fh , tranfer_ownership ) ;
else
m_input_file_sp . reset ( new StreamFile ( fh , tranfer_ownership ) ) ;
File & in_file = m_input_file_sp - > GetFile ( ) ;
2013-08-23 13:46:38 -04:00
if ( in_file . IsValid ( ) = = false )
in_file . SetStream ( stdin , true ) ;
// Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState.
SaveInputTerminalState ( ) ;
}
void
Debugger : : SetOutputFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-02-18 11:23:10 -05:00
if ( m_output_file_sp )
m_output_file_sp - > GetFile ( ) . SetStream ( fh , tranfer_ownership ) ;
else
m_output_file_sp . reset ( new StreamFile ( fh , tranfer_ownership ) ) ;
File & out_file = m_output_file_sp - > GetFile ( ) ;
2013-08-23 13:46:38 -04:00
if ( out_file . IsValid ( ) = = false )
out_file . SetStream ( stdout , false ) ;
// do not create the ScriptInterpreter just for setting the output file handle
// as the constructor will know how to do the right thing on its own
const bool can_create = false ;
ScriptInterpreter * script_interpreter = GetCommandInterpreter ( ) . GetScriptInterpreter ( can_create ) ;
if ( script_interpreter )
script_interpreter - > ResetOutputFileHandle ( fh ) ;
}
void
Debugger : : SetErrorFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-02-18 11:23:10 -05:00
if ( m_error_file_sp )
m_error_file_sp - > GetFile ( ) . SetStream ( fh , tranfer_ownership ) ;
else
m_error_file_sp . reset ( new StreamFile ( fh , tranfer_ownership ) ) ;
File & err_file = m_error_file_sp - > GetFile ( ) ;
2013-08-23 13:46:38 -04:00
if ( err_file . IsValid ( ) = = false )
err_file . SetStream ( stderr , false ) ;
}
void
Debugger : : SaveInputTerminalState ( )
{
2014-02-18 11:23:10 -05:00
if ( m_input_file_sp )
{
File & in_file = m_input_file_sp - > GetFile ( ) ;
if ( in_file . GetDescriptor ( ) ! = File : : kInvalidDescriptor )
m_terminal_state . Save ( in_file . GetDescriptor ( ) , true ) ;
}
2013-08-23 13:46:38 -04:00
}
void
Debugger : : RestoreInputTerminalState ( )
{
m_terminal_state . Restore ( ) ;
}
ExecutionContext
Debugger : : GetSelectedExecutionContext ( )
{
ExecutionContext exe_ctx ;
TargetSP target_sp ( GetSelectedTarget ( ) ) ;
exe_ctx . SetTargetSP ( target_sp ) ;
if ( target_sp )
{
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
exe_ctx . SetProcessSP ( process_sp ) ;
if ( process_sp & & process_sp - > IsRunning ( ) = = false )
{
ThreadSP thread_sp ( process_sp - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( thread_sp )
{
exe_ctx . SetThreadSP ( thread_sp ) ;
exe_ctx . SetFrameSP ( thread_sp - > GetSelectedFrame ( ) ) ;
if ( exe_ctx . GetFramePtr ( ) = = NULL )
exe_ctx . SetFrameSP ( thread_sp - > GetStackFrameAtIndex ( 0 ) ) ;
}
}
}
return exe_ctx ;
}
void
Debugger : : DispatchInputInterrupt ( )
{
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( reader_sp )
2014-02-18 11:23:10 -05:00
reader_sp - > Interrupt ( ) ;
2013-08-23 13:46:38 -04:00
}
void
Debugger : : DispatchInputEndOfFile ( )
{
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( reader_sp )
2014-02-18 11:23:10 -05:00
reader_sp - > GotEOF ( ) ;
2013-08-23 13:46:38 -04:00
}
void
2014-02-18 11:23:10 -05:00
Debugger : : ClearIOHandlers ( )
2013-08-23 13:46:38 -04:00
{
// The bottom input reader should be the main debugger input reader. We do not want to close that one here.
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
2013-08-23 13:46:38 -04:00
while ( m_input_reader_stack . GetSize ( ) > 1 )
{
2014-02-18 11:23:10 -05:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( reader_sp )
{
2014-02-18 11:23:10 -05:00
m_input_reader_stack . Pop ( ) ;
reader_sp - > SetIsDone ( true ) ;
2014-02-25 16:42:16 -05:00
reader_sp - > Cancel ( ) ;
2013-08-23 13:46:38 -04:00
}
}
}
void
2014-02-18 11:23:10 -05:00
Debugger : : ExecuteIOHanders ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
while ( 1 )
{
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
if ( ! reader_sp )
break ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
reader_sp - > Activate ( ) ;
reader_sp - > Run ( ) ;
reader_sp - > Deactivate ( ) ;
// Remove all input readers that are done from the top of the stack
while ( 1 )
{
IOHandlerSP top_reader_sp = m_input_reader_stack . Top ( ) ;
if ( top_reader_sp & & top_reader_sp - > GetIsDone ( ) )
m_input_reader_stack . Pop ( ) ;
else
break ;
}
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
ClearIOHandlers ( ) ;
2013-08-23 13:46:38 -04:00
}
bool
2014-02-18 11:23:10 -05:00
Debugger : : IsTopIOHandler ( const lldb : : IOHandlerSP & reader_sp )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
return m_input_reader_stack . IsTop ( reader_sp ) ;
}
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
ConstString
Debugger : : GetTopIOHandlerControlSequence ( char ch )
{
return m_input_reader_stack . GetTopIOHandlerControlSequence ( ch ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-08 20:44:09 -05:00
const char *
Debugger : : GetIOHandlerCommandPrefix ( )
{
return m_input_reader_stack . GetTopIOHandlerCommandPrefix ( ) ;
}
const char *
Debugger : : GetIOHandlerHelpPrologue ( )
{
return m_input_reader_stack . GetTopIOHandlerHelpPrologue ( ) ;
}
2013-08-23 13:46:38 -04:00
void
2014-02-18 11:23:10 -05:00
Debugger : : RunIOHandler ( const IOHandlerSP & reader_sp )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
PushIOHandler ( reader_sp ) ;
2014-11-25 16:00:58 -05:00
IOHandlerSP top_reader_sp = reader_sp ;
while ( top_reader_sp )
{
top_reader_sp - > Activate ( ) ;
top_reader_sp - > Run ( ) ;
top_reader_sp - > Deactivate ( ) ;
if ( top_reader_sp . get ( ) = = reader_sp . get ( ) )
{
if ( PopIOHandler ( reader_sp ) )
break ;
}
while ( 1 )
{
top_reader_sp = m_input_reader_stack . Top ( ) ;
if ( top_reader_sp & & top_reader_sp - > GetIsDone ( ) )
m_input_reader_stack . Pop ( ) ;
else
break ;
}
}
2014-02-18 11:23:10 -05:00
}
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
void
Debugger : : AdoptTopIOHandlerFilesIfInvalid ( StreamFileSP & in , StreamFileSP & out , StreamFileSP & err )
{
// Before an IOHandler runs, it must have in/out/err streams.
// This function is called when one ore more of the streams
// are NULL. We use the top input reader's in/out/err streams,
// or fall back to the debugger file handles, or we fall back
// onto stdin/stdout/stderr as a last resort.
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
IOHandlerSP top_reader_sp ( m_input_reader_stack . Top ( ) ) ;
// If no STDIN has been set, then set it appropriately
if ( ! in )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
if ( top_reader_sp )
in = top_reader_sp - > GetInputStreamFile ( ) ;
2013-08-23 13:46:38 -04:00
else
2014-02-18 11:23:10 -05:00
in = GetInputFile ( ) ;
// If there is nothing, use stdin
if ( ! in )
in = StreamFileSP ( new StreamFile ( stdin , false ) ) ;
}
// If no STDOUT has been set, then set it appropriately
if ( ! out )
{
if ( top_reader_sp )
out = top_reader_sp - > GetOutputStreamFile ( ) ;
else
out = GetOutputFile ( ) ;
// If there is nothing, use stdout
if ( ! out )
out = StreamFileSP ( new StreamFile ( stdout , false ) ) ;
}
// If no STDERR has been set, then set it appropriately
if ( ! err )
{
if ( top_reader_sp )
err = top_reader_sp - > GetErrorStreamFile ( ) ;
else
err = GetErrorFile ( ) ;
// If there is nothing, use stderr
if ( ! err )
err = StreamFileSP ( new StreamFile ( stdout , false ) ) ;
2013-08-23 13:46:38 -04:00
}
}
void
2014-02-18 11:23:10 -05:00
Debugger : : PushIOHandler ( const IOHandlerSP & reader_sp )
2013-08-23 13:46:38 -04:00
{
if ( ! reader_sp )
return ;
2014-02-18 11:23:10 -05:00
// Got the current top input reader...
IOHandlerSP top_reader_sp ( m_input_reader_stack . Top ( ) ) ;
2013-08-23 13:46:38 -04:00
2014-11-25 16:00:58 -05:00
// Don't push the same IO handler twice...
if ( reader_sp . get ( ) ! = top_reader_sp . get ( ) )
{
// Push our new input reader
m_input_reader_stack . Push ( reader_sp ) ;
2014-02-18 11:23:10 -05:00
2014-11-25 16:00:58 -05:00
// Interrupt the top input reader to it will exit its Run() function
// and let this new input reader take over
if ( top_reader_sp )
top_reader_sp - > Deactivate ( ) ;
}
2013-08-23 13:46:38 -04:00
}
bool
2014-02-18 11:23:10 -05:00
Debugger : : PopIOHandler ( const IOHandlerSP & pop_reader_sp )
2013-08-23 13:46:38 -04:00
{
bool result = false ;
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
2013-08-23 13:46:38 -04:00
// The reader on the stop of the stack is done, so let the next
2014-11-25 16:00:58 -05:00
// read on the stack refresh its prompt and if there is one...
2013-08-23 13:46:38 -04:00
if ( ! m_input_reader_stack . IsEmpty ( ) )
{
2014-02-18 11:23:10 -05:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( ! pop_reader_sp | | pop_reader_sp . get ( ) = = reader_sp . get ( ) )
{
2014-02-18 11:23:10 -05:00
reader_sp - > Deactivate ( ) ;
2014-11-25 16:00:58 -05:00
reader_sp - > Cancel ( ) ;
2013-08-23 13:46:38 -04:00
m_input_reader_stack . Pop ( ) ;
2014-02-18 11:23:10 -05:00
reader_sp = m_input_reader_stack . Top ( ) ;
if ( reader_sp )
reader_sp - > Activate ( ) ;
2013-08-23 13:46:38 -04:00
2014-02-18 11:23:10 -05:00
result = true ;
2013-08-23 13:46:38 -04:00
}
}
return result ;
}
bool
2014-02-18 11:23:10 -05:00
Debugger : : HideTopIOHandler ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
Mutex : : Locker locker ;
if ( locker . TryLock ( m_input_reader_stack . GetMutex ( ) ) )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
if ( reader_sp )
reader_sp - > Hide ( ) ;
return true ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
return false ;
2013-08-23 13:46:38 -04:00
}
void
2014-02-18 11:23:10 -05:00
Debugger : : RefreshTopIOHandler ( )
2013-08-23 13:46:38 -04:00
{
2014-02-18 11:23:10 -05:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
if ( reader_sp )
reader_sp - > Refresh ( ) ;
2013-08-23 13:46:38 -04:00
}
2014-02-18 11:23:10 -05:00
2013-08-23 13:46:38 -04:00
StreamSP
Debugger : : GetAsyncOutputStream ( )
{
return StreamSP ( new StreamAsynchronousIO ( GetCommandInterpreter ( ) ,
CommandInterpreter : : eBroadcastBitAsynchronousOutputData ) ) ;
}
StreamSP
Debugger : : GetAsyncErrorStream ( )
{
return StreamSP ( new StreamAsynchronousIO ( GetCommandInterpreter ( ) ,
CommandInterpreter : : eBroadcastBitAsynchronousErrorData ) ) ;
}
size_t
Debugger : : GetNumDebuggers ( )
{
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
return GetDebuggerList ( ) . size ( ) ;
}
return 0 ;
}
lldb : : DebuggerSP
Debugger : : GetDebuggerAtIndex ( size_t index )
{
DebuggerSP debugger_sp ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
if ( index < debugger_list . size ( ) )
debugger_sp = debugger_list [ index ] ;
}
return debugger_sp ;
}
DebuggerSP
Debugger : : FindDebuggerWithID ( lldb : : user_id_t id )
{
DebuggerSP debugger_sp ;
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
{
if ( ( * pos ) . get ( ) - > GetID ( ) = = id )
{
debugger_sp = * pos ;
break ;
}
}
}
return debugger_sp ;
}
2014-11-25 16:00:58 -05:00
#if 0
2013-08-23 13:46:38 -04:00
static void
TestPromptFormats ( StackFrame * frame )
{
if ( frame = = NULL )
return ;
StreamString s ;
const char * prompt_format =
" {addr = '${addr}' \n } "
2015-02-06 16:38:51 -05:00
" {addr-file-or-load = '${addr-file-or-load}' \n } "
" {current-pc-arrow = '${current-pc-arrow}' \n } "
2013-08-23 13:46:38 -04:00
" {process.id = '${process.id}' \n } "
" {process.name = '${process.name}' \n } "
" {process.file.basename = '${process.file.basename}' \n } "
" {process.file.fullpath = '${process.file.fullpath}' \n } "
" {thread.id = '${thread.id}' \n } "
" {thread.index = '${thread.index}' \n } "
" {thread.name = '${thread.name}' \n } "
" {thread.queue = '${thread.queue}' \n } "
" {thread.stop-reason = '${thread.stop-reason}' \n } "
" {target.arch = '${target.arch}' \n } "
" {module.file.basename = '${module.file.basename}' \n } "
" {module.file.fullpath = '${module.file.fullpath}' \n } "
" {file.basename = '${file.basename}' \n } "
" {file.fullpath = '${file.fullpath}' \n } "
" {frame.index = '${frame.index}' \n } "
" {frame.pc = '${frame.pc}' \n } "
" {frame.sp = '${frame.sp}' \n } "
" {frame.fp = '${frame.fp}' \n } "
" {frame.flags = '${frame.flags}' \n } "
" {frame.reg.rdi = '${frame.reg.rdi}' \n } "
" {frame.reg.rip = '${frame.reg.rip}' \n } "
" {frame.reg.rsp = '${frame.reg.rsp}' \n } "
" {frame.reg.rbp = '${frame.reg.rbp}' \n } "
" {frame.reg.rflags = '${frame.reg.rflags}' \n } "
" {frame.reg.xmm0 = '${frame.reg.xmm0}' \n } "
" {frame.reg.carp = '${frame.reg.carp}' \n } "
" {function.id = '${function.id}' \n } "
2015-02-06 16:38:51 -05:00
" {function.changed = '${function.changed}' \n } "
" {function.initial-function = '${function.initial-function}' \n } "
2013-08-23 13:46:38 -04:00
" {function.name = '${function.name}' \n } "
2015-02-06 16:38:51 -05:00
" {function.name-without-args = '${function.name-without-args}' \n } "
2013-08-23 13:46:38 -04:00
" {function.name-with-args = '${function.name-with-args}' \n } "
" {function.addr-offset = '${function.addr-offset}' \n } "
2015-02-06 16:38:51 -05:00
" {function.concrete-only-addr-offset-no-padding = '${function.concrete-only-addr-offset-no-padding}' \n } "
2013-08-23 13:46:38 -04:00
" {function.line-offset = '${function.line-offset}' \n } "
" {function.pc-offset = '${function.pc-offset}' \n } "
" {line.file.basename = '${line.file.basename}' \n } "
" {line.file.fullpath = '${line.file.fullpath}' \n } "
" {line.number = '${line.number}' \n } "
" {line.start-addr = '${line.start-addr}' \n } "
" {line.end-addr = '${line.end-addr}' \n } "
;
SymbolContext sc ( frame - > GetSymbolContext ( eSymbolContextEverything ) ) ;
ExecutionContext exe_ctx ;
frame - > CalculateExecutionContext ( exe_ctx ) ;
if ( Debugger : : FormatPrompt ( prompt_format , & sc , & exe_ctx , & sc . line_entry . range . GetBaseAddress ( ) , s ) )
{
printf ( " %s \n " , s . GetData ( ) ) ;
}
else
{
printf ( " what we got: %s \n " , s . GetData ( ) ) ;
}
}
2014-11-25 16:00:58 -05:00
# endif
2013-08-23 13:46:38 -04:00
2015-02-06 16:38:51 -05:00
bool
2015-02-08 20:44:09 -05:00
Debugger : : FormatDisassemblerAddress ( const FormatEntity : : Entry * format ,
2015-02-06 16:38:51 -05:00
const SymbolContext * sc ,
const SymbolContext * prev_sc ,
const ExecutionContext * exe_ctx ,
const Address * addr ,
Stream & s )
{
2015-02-08 20:44:09 -05:00
FormatEntity : : Entry format_entry ;
if ( format = = NULL )
2015-02-06 16:38:51 -05:00
{
2015-02-08 20:44:09 -05:00
if ( exe_ctx ! = NULL & & exe_ctx - > HasTargetScope ( ) )
format = exe_ctx - > GetTargetRef ( ) . GetDebugger ( ) . GetDisassemblyFormat ( ) ;
if ( format = = NULL )
{
FormatEntity : : Parse ( " ${addr}: " , format_entry ) ;
format = & format_entry ;
}
2015-02-06 16:38:51 -05:00
}
bool function_changed = false ;
bool initial_function = false ;
if ( prev_sc & & ( prev_sc - > function | | prev_sc - > symbol ) )
{
if ( sc & & ( sc - > function | | sc - > symbol ) )
{
if ( prev_sc - > symbol & & sc - > symbol )
{
if ( ! sc - > symbol - > Compare ( prev_sc - > symbol - > GetName ( ) , prev_sc - > symbol - > GetType ( ) ) )
{
function_changed = true ;
}
}
else if ( prev_sc - > function & & sc - > function )
{
if ( prev_sc - > function - > GetMangled ( ) ! = sc - > function - > GetMangled ( ) )
{
function_changed = true ;
}
}
}
}
// The first context on a list of instructions will have a prev_sc that
// has no Function or Symbol -- if SymbolContext had an IsValid() method, it
// would return false. But we do get a prev_sc pointer.
if ( ( sc & & ( sc - > function | | sc - > symbol ) )
& & prev_sc & & ( prev_sc - > function = = NULL & & prev_sc - > symbol = = NULL ) )
{
initial_function = true ;
}
2015-02-08 20:44:09 -05:00
return FormatEntity : : Format ( * format , s , sc , exe_ctx , addr , NULL , function_changed , initial_function ) ;
2013-08-23 13:46:38 -04:00
}
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
void
Debugger : : SetLoggingCallback ( lldb : : LogOutputCallback log_callback , void * baton )
{
// For simplicity's sake, I am not going to deal with how to close down any
// open logging streams, I just redirect everything from here on out to the
// callback.
m_log_callback_stream_sp . reset ( new StreamCallback ( log_callback , baton ) ) ;
}
bool
Debugger : : EnableLog ( const char * channel , const char * * categories , const char * log_file , uint32_t log_options , Stream & error_stream )
{
Log : : Callbacks log_callbacks ;
StreamSP log_stream_sp ;
if ( m_log_callback_stream_sp )
{
log_stream_sp = m_log_callback_stream_sp ;
// For now when using the callback mode you always get thread & timestamp.
log_options | = LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME ;
}
else if ( log_file = = NULL | | * log_file = = ' \0 ' )
{
2014-02-18 11:23:10 -05:00
log_stream_sp = GetOutputFile ( ) ;
2013-08-23 13:46:38 -04:00
}
else
{
LogStreamMap : : iterator pos = m_log_streams . find ( log_file ) ;
if ( pos ! = m_log_streams . end ( ) )
log_stream_sp = pos - > second . lock ( ) ;
if ( ! log_stream_sp )
{
log_stream_sp . reset ( new StreamFile ( log_file ) ) ;
m_log_streams [ log_file ] = log_stream_sp ;
}
}
assert ( log_stream_sp . get ( ) ) ;
if ( log_options = = 0 )
log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE ;
if ( Log : : GetLogChannelCallbacks ( ConstString ( channel ) , log_callbacks ) )
{
log_callbacks . enable ( log_stream_sp , log_options , categories , & error_stream ) ;
return true ;
}
else
{
LogChannelSP log_channel_sp ( LogChannel : : FindPlugin ( channel ) ) ;
if ( log_channel_sp )
{
if ( log_channel_sp - > Enable ( log_stream_sp , log_options , & error_stream , categories ) )
{
return true ;
}
else
{
error_stream . Printf ( " Invalid log channel '%s'. \n " , channel ) ;
return false ;
}
}
else
{
error_stream . Printf ( " Invalid log channel '%s'. \n " , channel ) ;
return false ;
}
}
return false ;
}
SourceManager &
Debugger : : GetSourceManager ( )
{
if ( m_source_manager_ap . get ( ) = = NULL )
m_source_manager_ap . reset ( new SourceManager ( shared_from_this ( ) ) ) ;
return * m_source_manager_ap ;
}
2014-02-18 11:23:10 -05:00
// This function handles events that were broadcast by the process.
void
Debugger : : HandleBreakpointEvent ( const EventSP & event_sp )
{
using namespace lldb ;
const uint32_t event_type = Breakpoint : : BreakpointEventData : : GetBreakpointEventTypeFromEvent ( event_sp ) ;
// if (event_type & eBreakpointEventTypeAdded
// || event_type & eBreakpointEventTypeRemoved
// || event_type & eBreakpointEventTypeEnabled
// || event_type & eBreakpointEventTypeDisabled
// || event_type & eBreakpointEventTypeCommandChanged
// || event_type & eBreakpointEventTypeConditionChanged
// || event_type & eBreakpointEventTypeIgnoreChanged
// || event_type & eBreakpointEventTypeLocationsResolved)
// {
// // Don't do anything about these events, since the breakpoint commands already echo these actions.
// }
//
if ( event_type & eBreakpointEventTypeLocationsAdded )
{
uint32_t num_new_locations = Breakpoint : : BreakpointEventData : : GetNumBreakpointLocationsFromEvent ( event_sp ) ;
if ( num_new_locations > 0 )
{
BreakpointSP breakpoint = Breakpoint : : BreakpointEventData : : GetBreakpointFromEvent ( event_sp ) ;
StreamFileSP output_sp ( GetOutputFile ( ) ) ;
if ( output_sp )
{
output_sp - > Printf ( " %d location%s added to breakpoint %d \n " ,
num_new_locations ,
num_new_locations = = 1 ? " " : " s " ,
breakpoint - > GetID ( ) ) ;
RefreshTopIOHandler ( ) ;
}
}
}
// else if (event_type & eBreakpointEventTypeLocationsRemoved)
// {
// // These locations just get disabled, not sure it is worth spamming folks about this on the command line.
// }
// else if (event_type & eBreakpointEventTypeLocationsResolved)
// {
// // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy.
// }
}
size_t
Debugger : : GetProcessSTDOUT ( Process * process , Stream * stream )
{
size_t total_bytes = 0 ;
if ( stream = = NULL )
stream = GetOutputFile ( ) . get ( ) ;
if ( stream )
{
// The process has stuff waiting for stdout; get it and write it out to the appropriate place.
if ( process = = NULL )
{
TargetSP target_sp = GetTargetList ( ) . GetSelectedTarget ( ) ;
if ( target_sp )
process = target_sp - > GetProcessSP ( ) . get ( ) ;
}
if ( process )
{
Error error ;
size_t len ;
char stdio_buffer [ 1024 ] ;
while ( ( len = process - > GetSTDOUT ( stdio_buffer , sizeof ( stdio_buffer ) , error ) ) > 0 )
{
stream - > Write ( stdio_buffer , len ) ;
total_bytes + = len ;
}
}
stream - > Flush ( ) ;
}
return total_bytes ;
}
size_t
Debugger : : GetProcessSTDERR ( Process * process , Stream * stream )
{
size_t total_bytes = 0 ;
if ( stream = = NULL )
stream = GetOutputFile ( ) . get ( ) ;
if ( stream )
{
// The process has stuff waiting for stderr; get it and write it out to the appropriate place.
if ( process = = NULL )
{
TargetSP target_sp = GetTargetList ( ) . GetSelectedTarget ( ) ;
if ( target_sp )
process = target_sp - > GetProcessSP ( ) . get ( ) ;
}
if ( process )
{
Error error ;
size_t len ;
char stdio_buffer [ 1024 ] ;
while ( ( len = process - > GetSTDERR ( stdio_buffer , sizeof ( stdio_buffer ) , error ) ) > 0 )
{
stream - > Write ( stdio_buffer , len ) ;
total_bytes + = len ;
}
}
stream - > Flush ( ) ;
}
return total_bytes ;
}
2015-02-06 16:38:51 -05:00
2014-02-18 11:23:10 -05:00
// This function handles events that were broadcast by the process.
void
Debugger : : HandleProcessEvent ( const EventSP & event_sp )
{
using namespace lldb ;
const uint32_t event_type = event_sp - > GetType ( ) ;
ProcessSP process_sp = Process : : ProcessEventData : : GetProcessFromEvent ( event_sp . get ( ) ) ;
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
StreamString output_stream ;
StreamString error_stream ;
2014-02-18 11:23:10 -05:00
const bool gui_enabled = IsForwardingEvents ( ) ;
2014-11-25 16:00:58 -05:00
if ( ! gui_enabled )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
bool pop_process_io_handler = false ;
assert ( process_sp ) ;
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
if ( event_type & Process : : eBroadcastBitSTDOUT | | event_type & Process : : eBroadcastBitStateChanged )
2014-02-18 11:23:10 -05:00
{
2014-11-25 16:00:58 -05:00
GetProcessSTDOUT ( process_sp . get ( ) , & output_stream ) ;
}
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
if ( event_type & Process : : eBroadcastBitSTDERR | | event_type & Process : : eBroadcastBitStateChanged )
{
GetProcessSTDERR ( process_sp . get ( ) , & error_stream ) ;
}
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
if ( event_type & Process : : eBroadcastBitStateChanged )
{
2015-02-06 16:38:51 -05:00
Process : : HandleProcessStateChangedEvent ( event_sp , & output_stream , pop_process_io_handler ) ;
2014-02-18 11:23:10 -05:00
}
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
if ( output_stream . GetSize ( ) | | error_stream . GetSize ( ) )
{
StreamFileSP error_stream_sp ( GetOutputFile ( ) ) ;
bool top_io_handler_hid = false ;
2015-02-06 16:38:51 -05:00
2014-11-25 16:00:58 -05:00
if ( process_sp - > ProcessIOHandlerIsActive ( ) = = false )
top_io_handler_hid = HideTopIOHandler ( ) ;
if ( output_stream . GetSize ( ) )
{
StreamFileSP output_stream_sp ( GetOutputFile ( ) ) ;
if ( output_stream_sp )
output_stream_sp - > Write ( output_stream . GetData ( ) , output_stream . GetSize ( ) ) ;
}
if ( error_stream . GetSize ( ) )
{
StreamFileSP error_stream_sp ( GetErrorFile ( ) ) ;
if ( error_stream_sp )
error_stream_sp - > Write ( error_stream . GetData ( ) , error_stream . GetSize ( ) ) ;
}
if ( top_io_handler_hid )
RefreshTopIOHandler ( ) ;
}
if ( pop_process_io_handler )
process_sp - > PopProcessIOHandler ( ) ;
}
2014-02-18 11:23:10 -05:00
}
void
Debugger : : HandleThreadEvent ( const EventSP & event_sp )
{
// At present the only thread event we handle is the Frame Changed event,
// and all we do for that is just reprint the thread status for that thread.
using namespace lldb ;
const uint32_t event_type = event_sp - > GetType ( ) ;
if ( event_type = = Thread : : eBroadcastBitStackChanged | |
event_type = = Thread : : eBroadcastBitThreadSelected )
{
ThreadSP thread_sp ( Thread : : ThreadEventData : : GetThreadFromEvent ( event_sp . get ( ) ) ) ;
if ( thread_sp )
{
HideTopIOHandler ( ) ;
StreamFileSP stream_sp ( GetOutputFile ( ) ) ;
thread_sp - > GetStatus ( * stream_sp , 0 , 1 , 1 ) ;
RefreshTopIOHandler ( ) ;
}
}
}
bool
Debugger : : IsForwardingEvents ( )
{
return ( bool ) m_forward_listener_sp ;
}
void
Debugger : : EnableForwardEvents ( const ListenerSP & listener_sp )
{
m_forward_listener_sp = listener_sp ;
}
void
Debugger : : CancelForwardEvents ( const ListenerSP & listener_sp )
{
m_forward_listener_sp . reset ( ) ;
}
void
Debugger : : DefaultEventHandler ( )
{
Listener & listener ( GetListener ( ) ) ;
ConstString broadcaster_class_target ( Target : : GetStaticBroadcasterClass ( ) ) ;
ConstString broadcaster_class_process ( Process : : GetStaticBroadcasterClass ( ) ) ;
ConstString broadcaster_class_thread ( Thread : : GetStaticBroadcasterClass ( ) ) ;
BroadcastEventSpec target_event_spec ( broadcaster_class_target ,
Target : : eBroadcastBitBreakpointChanged ) ;
BroadcastEventSpec process_event_spec ( broadcaster_class_process ,
Process : : eBroadcastBitStateChanged |
Process : : eBroadcastBitSTDOUT |
Process : : eBroadcastBitSTDERR ) ;
BroadcastEventSpec thread_event_spec ( broadcaster_class_thread ,
Thread : : eBroadcastBitStackChanged |
Thread : : eBroadcastBitThreadSelected ) ;
listener . StartListeningForEventSpec ( * this , target_event_spec ) ;
listener . StartListeningForEventSpec ( * this , process_event_spec ) ;
listener . StartListeningForEventSpec ( * this , thread_event_spec ) ;
listener . StartListeningForEvents ( m_command_interpreter_ap . get ( ) ,
CommandInterpreter : : eBroadcastBitQuitCommandReceived |
CommandInterpreter : : eBroadcastBitAsynchronousOutputData |
CommandInterpreter : : eBroadcastBitAsynchronousErrorData ) ;
2015-02-06 16:38:51 -05:00
// Let the thread that spawned us know that we have started up and
// that we are now listening to all required events so no events get missed
m_sync_broadcaster . BroadcastEvent ( eBroadcastBitEventThreadIsListening ) ;
2014-02-18 11:23:10 -05:00
bool done = false ;
while ( ! done )
{
EventSP event_sp ;
if ( listener . WaitForEvent ( NULL , event_sp ) )
{
if ( event_sp )
{
Broadcaster * broadcaster = event_sp - > GetBroadcaster ( ) ;
if ( broadcaster )
{
uint32_t event_type = event_sp - > GetType ( ) ;
ConstString broadcaster_class ( broadcaster - > GetBroadcasterClass ( ) ) ;
if ( broadcaster_class = = broadcaster_class_process )
{
HandleProcessEvent ( event_sp ) ;
}
else if ( broadcaster_class = = broadcaster_class_target )
{
if ( Breakpoint : : BreakpointEventData : : GetEventDataFromEvent ( event_sp . get ( ) ) )
{
HandleBreakpointEvent ( event_sp ) ;
}
}
else if ( broadcaster_class = = broadcaster_class_thread )
{
HandleThreadEvent ( event_sp ) ;
}
else if ( broadcaster = = m_command_interpreter_ap . get ( ) )
{
if ( event_type & CommandInterpreter : : eBroadcastBitQuitCommandReceived )
{
done = true ;
}
else if ( event_type & CommandInterpreter : : eBroadcastBitAsynchronousErrorData )
{
const char * data = reinterpret_cast < const char * > ( EventDataBytes : : GetBytesFromEvent ( event_sp . get ( ) ) ) ;
if ( data & & data [ 0 ] )
{
StreamFileSP error_sp ( GetErrorFile ( ) ) ;
if ( error_sp )
{
HideTopIOHandler ( ) ;
error_sp - > PutCString ( data ) ;
error_sp - > Flush ( ) ;
RefreshTopIOHandler ( ) ;
}
}
}
else if ( event_type & CommandInterpreter : : eBroadcastBitAsynchronousOutputData )
{
const char * data = reinterpret_cast < const char * > ( EventDataBytes : : GetBytesFromEvent ( event_sp . get ( ) ) ) ;
if ( data & & data [ 0 ] )
{
StreamFileSP output_sp ( GetOutputFile ( ) ) ;
if ( output_sp )
{
HideTopIOHandler ( ) ;
output_sp - > PutCString ( data ) ;
output_sp - > Flush ( ) ;
RefreshTopIOHandler ( ) ;
}
}
}
}
}
if ( m_forward_listener_sp )
m_forward_listener_sp - > AddEvent ( event_sp ) ;
}
}
}
}
lldb : : thread_result_t
Debugger : : EventHandlerThread ( lldb : : thread_arg_t arg )
{
( ( Debugger * ) arg ) - > DefaultEventHandler ( ) ;
return NULL ;
}
bool
Debugger : : StartEventHandlerThread ( )
{
2015-02-06 16:38:51 -05:00
if ( ! m_event_handler_thread . IsJoinable ( ) )
{
// We must synchronize with the DefaultEventHandler() thread to ensure
// it is up and running and listening to events before we return from
// this function. We do this by listening to events for the
// eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
Listener listener ( " lldb.debugger.event-handler " ) ;
listener . StartListeningForEvents ( & m_sync_broadcaster , eBroadcastBitEventThreadIsListening ) ;
// Use larger 8MB stack for this thread
m_event_handler_thread = ThreadLauncher : : LaunchThread ( " lldb.debugger.event-handler " , EventHandlerThread ,
this ,
NULL ,
g_debugger_event_thread_stack_bytes ) ;
// Make sure DefaultEventHandler() is running and listening to events before we return
// from this function. We are only listening for events of type
// eBroadcastBitEventThreadIsListening so we don't need to check the event, we just need
// to wait an infinite amount of time for it (NULL timeout as the first parameter)
lldb : : EventSP event_sp ;
listener . WaitForEvent ( NULL , event_sp ) ;
}
return m_event_handler_thread . IsJoinable ( ) ;
2014-02-18 11:23:10 -05:00
}
void
Debugger : : StopEventHandlerThread ( )
{
2015-02-06 16:38:51 -05:00
if ( m_event_handler_thread . IsJoinable ( ) )
2014-02-18 11:23:10 -05:00
{
GetCommandInterpreter ( ) . BroadcastEvent ( CommandInterpreter : : eBroadcastBitQuitCommandReceived ) ;
2015-02-06 16:38:51 -05:00
m_event_handler_thread . Join ( nullptr ) ;
2014-02-18 11:23:10 -05:00
}
}
lldb : : thread_result_t
Debugger : : IOHandlerThread ( lldb : : thread_arg_t arg )
{
Debugger * debugger = ( Debugger * ) arg ;
debugger - > ExecuteIOHanders ( ) ;
debugger - > StopEventHandlerThread ( ) ;
return NULL ;
}
bool
Debugger : : StartIOHandlerThread ( )
{
2015-02-06 16:38:51 -05:00
if ( ! m_io_handler_thread . IsJoinable ( ) )
m_io_handler_thread = ThreadLauncher : : LaunchThread ( " lldb.debugger.io-handler " ,
IOHandlerThread ,
this ,
NULL ,
8 * 1024 * 1024 ) ; // Use larger 8MB stack for this thread
return m_io_handler_thread . IsJoinable ( ) ;
2014-02-18 11:23:10 -05:00
}
void
Debugger : : StopIOHandlerThread ( )
{
2015-02-06 16:38:51 -05:00
if ( m_io_handler_thread . IsJoinable ( ) )
2014-02-18 11:23:10 -05:00
{
if ( m_input_file_sp )
m_input_file_sp - > GetFile ( ) . Close ( ) ;
2015-02-06 16:38:51 -05:00
m_io_handler_thread . Join ( nullptr ) ;
2014-02-18 11:23:10 -05:00
}
}
2015-02-06 16:38:51 -05:00
Target *
Debugger : : GetDummyTarget ( )
{
return m_target_list . GetDummyTarget ( * this ) . get ( ) ;
}
Target *
Debugger : : GetSelectedOrDummyTarget ( bool prefer_dummy )
{
Target * target = nullptr ;
if ( ! prefer_dummy )
{
target = m_target_list . GetSelectedTarget ( ) . get ( ) ;
if ( target )
return target ;
}
return GetDummyTarget ( ) ;
}
2014-02-18 11:23:10 -05:00