2010-06-08 16:52:24 +00: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.
//
//===----------------------------------------------------------------------===//
2012-12-05 00:20:57 +00:00
# include "lldb/lldb-python.h"
2011-06-23 17:59:56 +00:00
# include "lldb/Core/Debugger.h"
# include <map>
2011-06-29 22:27:15 +00:00
# include "clang/AST/DeclCXX.h"
# include "clang/AST/Type.h"
2014-06-13 02:37:02 +00:00
# include "llvm/ADT/StringRef.h"
2011-06-29 22:27:15 +00:00
2010-06-08 16:52:24 +00:00
# include "lldb/lldb-private.h"
# include "lldb/Core/ConnectionFileDescriptor.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Core/Module.h"
2012-10-19 18:02:49 +00:00
# include "lldb/Core/PluginManager.h"
2011-05-09 20:18:18 +00:00
# include "lldb/Core/RegisterValue.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/State.h"
2011-06-02 23:58:26 +00:00
# include "lldb/Core/StreamAsynchronousIO.h"
2012-02-21 02:23:08 +00:00
# include "lldb/Core/StreamCallback.h"
2014-01-27 23:43:24 +00:00
# include "lldb/Core/StreamFile.h"
2010-09-19 02:33:57 +00:00
# include "lldb/Core/StreamString.h"
2014-06-13 02:37:02 +00:00
# include "lldb/Core/StructuredData.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/Timer.h"
2011-06-29 22:27:15 +00:00
# include "lldb/Core/ValueObject.h"
2012-01-13 08:39:16 +00:00
# include "lldb/Core/ValueObjectVariable.h"
2013-01-28 23:47:25 +00:00
# include "lldb/DataFormatters/DataVisualization.h"
# include "lldb/DataFormatters/FormatManager.h"
2014-03-25 22:03:52 +00:00
# include "lldb/DataFormatters/TypeSummary.h"
2014-08-21 17:29:12 +00:00
# include "lldb/Host/HostInfo.h"
2011-02-07 23:24:47 +00:00
# include "lldb/Host/Terminal.h"
2014-09-09 20:54:56 +00:00
# include "lldb/Host/ThreadLauncher.h"
2010-06-23 01:19:29 +00:00
# include "lldb/Interpreter/CommandInterpreter.h"
2012-08-22 17:17:09 +00:00
# include "lldb/Interpreter/OptionValueSInt64.h"
# include "lldb/Interpreter/OptionValueString.h"
2012-08-29 21:13:06 +00:00
# include "lldb/Symbol/ClangASTContext.h"
# include "lldb/Symbol/CompileUnit.h"
# include "lldb/Symbol/Function.h"
# include "lldb/Symbol/Symbol.h"
2012-01-13 08:39:16 +00:00
# include "lldb/Symbol/VariableList.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Target/TargetList.h"
# include "lldb/Target/Process.h"
2010-09-19 02:33:57 +00:00
# include "lldb/Target/RegisterContext.h"
2013-12-02 19:35:49 +00:00
# include "lldb/Target/SectionLoadList.h"
2010-09-19 02:33:57 +00:00
# include "lldb/Target/StopInfo.h"
2013-05-20 22:29:23 +00:00
# include "lldb/Target/Target.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Target/Thread.h"
2011-10-14 07:41:33 +00:00
# include "lldb/Utility/AnsiTerminal.h"
2010-06-08 16:52:24 +00:00
2014-08-27 20:15:09 +00:00
# include "llvm/Support/DynamicLibrary.h"
2010-06-08 16:52:24 +00:00
using namespace lldb ;
using namespace lldb_private ;
2010-09-19 02:33:57 +00:00
static uint32_t g_shared_debugger_refcount = 0 ;
2010-06-30 16:22:25 +00:00
static lldb : : user_id_t g_unique_id = 1 ;
2010-09-19 02:33:57 +00: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-06-27 02:42:12 +00:00
// global init constructors
2010-09-19 02:33:57 +00:00
static DebuggerList g_list ;
return g_list ;
}
2011-11-21 21:44:34 +00:00
OptionEnumValueElement
2012-08-22 17:17:09 +00:00
g_show_disassembly_enum_values [ ] =
2011-11-21 21:44:34 +00:00
{
2012-08-22 17:17:09 +00:00
{ 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. " } ,
2011-11-21 21:44:34 +00:00
{ 0 , NULL , NULL }
} ;
2012-08-22 17:17:09 +00:00
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. " } ,
2012-09-13 23:03:20 +00:00
{ 0 , NULL , NULL }
2012-08-22 17:17:09 +00:00
} ;
2011-11-21 21:44:34 +00:00
2012-08-22 17:17:09 +00:00
# define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}"
# define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
2013-07-30 16:44:36 +00:00
# define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\
2012-08-22 17:17:09 +00:00
"{, ${frame.pc}}"\
MODULE_WITH_FUNC\
FILE_AND_LINE\
2013-07-30 16:44:36 +00:00
"{, name = '${thread.name}'}"\
"{, queue = '${thread.queue}'}"\
2014-06-13 02:37:02 +00:00
"{, activity = '${thread.info.activity.name}'}" \
"{, ${thread.info.trace_messages} messages}" \
2012-08-22 17:17:09 +00:00
"{, stop reason = ${thread.stop-reason}}"\
"{\\nReturn value: ${thread.return-value}}"\
2014-07-08 01:07:32 +00:00
"{\\nCompleted expression: ${thread.completed-expression}}"\
2012-08-22 17:17:09 +00:00
"\\n"
# define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
MODULE_WITH_FUNC\
FILE_AND_LINE\
"\\n"
2012-08-23 00:22:02 +00:00
static PropertyDefinition
g_properties [ ] =
2012-08-22 17:17:09 +00:00
{
{ " auto-confirm " , OptionValue : : eTypeBoolean , true , false , NULL , NULL , " If true all confirmation prompts will receive their default reply. " } ,
{ " frame-format " , OptionValue : : eTypeString , 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). " } ,
2012-09-01 00:38:36 +00:00
{ " prompt " , OptionValue : : eTypeString , true , OptionValueString : : eOptionEncodeCharacterEscapeSequences , " (lldb) " , NULL , " The debugger command line prompt displayed for the user. " } ,
2012-08-22 17:17:09 +00:00
{ " 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 : : eTypeString , 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. " } ,
2013-05-23 20:47:45 +00:00
{ " use-color " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " Whether to use Ansi color codes or not. " } ,
2013-10-31 21:01:07 +00:00
{ " auto-one-line-summaries " , OptionValue : : eTypeBoolean , true , true , NULL , NULL , " If true, LLDB will automatically display small structs in one-liner format (default: true). " } ,
2012-10-19 18:02:49 +00:00
{ NULL , OptionValue : : eTypeInvalid , true , 0 , NULL , NULL , NULL }
2012-08-22 17:17:09 +00:00
} ;
enum
{
ePropertyAutoConfirm = 0 ,
ePropertyFrameFormat ,
ePropertyNotiftVoid ,
ePropertyPrompt ,
ePropertyScriptLanguage ,
ePropertyStopDisassemblyCount ,
ePropertyStopDisassemblyDisplay ,
ePropertyStopLineCountAfter ,
ePropertyStopLineCountBefore ,
ePropertyTerminalWidth ,
ePropertyThreadFormat ,
2013-05-23 20:47:45 +00:00
ePropertyUseExternalEditor ,
ePropertyUseColor ,
2013-10-31 21:01:07 +00:00
ePropertyAutoOneLineSummaries
2012-08-22 17:17:09 +00:00
} ;
2013-12-02 19:35:49 +00:00
Debugger : : LoadPluginCallbackType Debugger : : g_load_plugin_callback = NULL ;
2012-09-01 00:38:36 +00:00
Error
Debugger : : SetPropertyValue ( const ExecutionContext * exe_ctx ,
VarSetOperationType op ,
const char * property_path ,
const char * value )
{
2013-05-20 22:29:23 +00:00
bool is_load_script = strcmp ( property_path , " target.load-script-from-symbol-file " ) = = 0 ;
TargetSP target_sp ;
2013-05-21 20:13:34 +00:00
LoadScriptFromSymFile load_script_old_value ;
2013-05-20 22:29:23 +00:00
if ( is_load_script & & exe_ctx - > GetTargetSP ( ) )
{
target_sp = exe_ctx - > GetTargetSP ( ) ;
load_script_old_value = target_sp - > TargetProperties : : GetLoadScriptFromSymbolFile ( ) ;
}
2012-09-01 00:38:36 +00:00
Error error ( Properties : : SetPropertyValue ( exe_ctx , op , property_path , value ) ) ;
if ( error . Success ( ) )
{
2013-05-20 22:29:23 +00:00
// FIXME it would be nice to have "on-change" callbacks for properties
2012-09-01 00:38:36 +00:00
if ( strcmp ( property_path , g_properties [ ePropertyPrompt ] . name ) = = 0 )
{
const char * new_prompt = GetPrompt ( ) ;
2013-05-23 20:47:45 +00:00
std : : string str = lldb_utility : : ansi : : FormatAnsiTerminalCodes ( new_prompt , GetUseColor ( ) ) ;
if ( str . length ( ) )
new_prompt = str . c_str ( ) ;
2014-01-27 23:43:24 +00:00
GetCommandInterpreter ( ) . UpdatePrompt ( new_prompt ) ;
2012-09-01 00:38:36 +00:00
EventSP prompt_change_event_sp ( new Event ( CommandInterpreter : : eBroadcastBitResetPrompt , new EventDataBytes ( new_prompt ) ) ) ;
GetCommandInterpreter ( ) . BroadcastEvent ( prompt_change_event_sp ) ;
}
2013-05-23 20:47:45 +00:00
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 ( ) ) ;
}
2013-05-21 20:13:34 +00:00
else if ( is_load_script & & target_sp & & load_script_old_value = = eLoadScriptFromSymFileWarn )
2013-05-20 22:29:23 +00:00
{
2013-05-21 20:13:34 +00:00
if ( target_sp - > TargetProperties : : GetLoadScriptFromSymbolFile ( ) = = eLoadScriptFromSymFileTrue )
2013-05-20 22:29:23 +00:00
{
std : : list < Error > errors ;
2013-05-21 00:00:30 +00:00
StreamString feedback_stream ;
if ( ! target_sp - > LoadScriptingResources ( errors , & feedback_stream ) )
2013-05-20 22:29:23 +00:00
{
2014-01-27 23:43:24 +00:00
StreamFileSP stream_sp ( GetErrorFile ( ) ) ;
if ( stream_sp )
2013-05-20 22:29:23 +00:00
{
2014-01-27 23:43:24 +00:00
for ( auto error : errors )
{
stream_sp - > Printf ( " %s \n " , error . AsCString ( ) ) ;
}
if ( feedback_stream . GetSize ( ) )
stream_sp - > Printf ( " %s " , feedback_stream . GetData ( ) ) ;
2013-05-20 22:29:23 +00:00
}
}
}
}
2012-09-01 00:38:36 +00:00
}
return error ;
}
2012-08-22 17:17:09 +00:00
bool
Debugger : : GetAutoConfirm ( ) const
{
const uint32_t idx = ePropertyAutoConfirm ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2012-08-22 17:17:09 +00:00
}
const char *
Debugger : : GetFrameFormat ( ) const
{
const uint32_t idx = ePropertyFrameFormat ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsString ( NULL , idx , g_properties [ idx ] . default_cstr_value ) ;
2012-08-22 17:17:09 +00:00
}
bool
Debugger : : GetNotifyVoid ( ) const
{
const uint32_t idx = ePropertyNotiftVoid ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2012-08-22 17:17:09 +00:00
}
const char *
Debugger : : GetPrompt ( ) const
{
const uint32_t idx = ePropertyPrompt ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsString ( NULL , idx , g_properties [ idx ] . default_cstr_value ) ;
2012-08-22 17:17:09 +00:00
}
void
Debugger : : SetPrompt ( const char * p )
{
const uint32_t idx = ePropertyPrompt ;
m_collection_sp - > SetPropertyAtIndexAsString ( NULL , idx , p ) ;
const char * new_prompt = GetPrompt ( ) ;
2013-05-23 20:47:45 +00:00
std : : string str = lldb_utility : : ansi : : FormatAnsiTerminalCodes ( new_prompt , GetUseColor ( ) ) ;
if ( str . length ( ) )
new_prompt = str . c_str ( ) ;
2014-01-27 23:43:24 +00:00
GetCommandInterpreter ( ) . UpdatePrompt ( new_prompt ) ;
2012-08-22 17:17:09 +00:00
}
const char *
Debugger : : GetThreadFormat ( ) const
{
const uint32_t idx = ePropertyThreadFormat ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsString ( NULL , idx , g_properties [ idx ] . default_cstr_value ) ;
2012-08-22 17:17:09 +00:00
}
lldb : : ScriptLanguage
Debugger : : GetScriptLanguage ( ) const
{
const uint32_t idx = ePropertyScriptLanguage ;
2012-08-23 00:22:02 +00:00
return ( lldb : : ScriptLanguage ) m_collection_sp - > GetPropertyAtIndexAsEnumeration ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
2012-08-22 17:17:09 +00:00
}
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 ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
2012-08-22 17:17:09 +00:00
}
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 ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , g_properties [ idx ] . default_uint_value ! = 0 ) ;
2012-08-22 17:17:09 +00:00
}
bool
Debugger : : SetUseExternalEditor ( bool b )
{
const uint32_t idx = ePropertyUseExternalEditor ;
return m_collection_sp - > SetPropertyAtIndexAsBoolean ( NULL , idx , b ) ;
}
2013-05-23 20:47:45 +00:00
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 ;
}
2012-08-22 17:17:09 +00:00
uint32_t
Debugger : : GetStopSourceLineCount ( bool before ) const
{
const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
2012-08-22 17:17:09 +00:00
}
Debugger : : StopDisassemblyType
Debugger : : GetStopDisassemblyDisplay ( ) const
{
const uint32_t idx = ePropertyStopDisassemblyDisplay ;
2012-08-23 00:22:02 +00:00
return ( Debugger : : StopDisassemblyType ) m_collection_sp - > GetPropertyAtIndexAsEnumeration ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
2012-08-22 17:17:09 +00:00
}
uint32_t
Debugger : : GetDisassemblyLineCount ( ) const
{
const uint32_t idx = ePropertyStopDisassemblyCount ;
2012-08-23 00:22:02 +00:00
return m_collection_sp - > GetPropertyAtIndexAsSInt64 ( NULL , idx , g_properties [ idx ] . default_uint_value ) ;
2012-08-22 17:17:09 +00:00
}
2011-11-21 21:44:34 +00:00
2013-10-25 23:09:40 +00:00
bool
2013-10-31 21:01:07 +00:00
Debugger : : GetAutoOneLineSummaries ( ) const
2013-10-25 23:09:40 +00:00
{
2013-10-31 21:01:07 +00:00
const uint32_t idx = ePropertyAutoOneLineSummaries ;
2013-10-25 23:09:40 +00:00
return m_collection_sp - > GetPropertyAtIndexAsBoolean ( NULL , idx , true ) ;
}
2010-09-19 02:33:57 +00:00
# pragma mark Debugger
2012-08-22 17:17:09 +00:00
//const DebuggerPropertiesSP &
//Debugger::GetSettings() const
//{
// return m_properties_sp;
//}
//
2010-11-18 23:32:35 +00:00
2011-01-14 00:29:16 +00:00
int
Debugger : : TestDebuggerRefCount ( )
{
return g_shared_debugger_refcount ;
}
2010-06-08 16:52:24 +00:00
void
2013-12-02 19:35:49 +00:00
Debugger : : Initialize ( LoadPluginCallbackType load_plugin_callback )
2010-06-08 16:52:24 +00:00
{
2013-12-02 19:35:49 +00:00
g_load_plugin_callback = load_plugin_callback ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount + + = = 0 )
2010-11-19 03:46:01 +00:00
lldb_private : : Initialize ( ) ;
2010-06-08 16:52:24 +00:00
}
void
Debugger : : Terminate ( )
{
2010-06-23 01:19:29 +00:00
if ( g_shared_debugger_refcount > 0 )
2010-06-08 16:52:24 +00:00
{
2010-06-23 01:19:29 +00:00
g_shared_debugger_refcount - - ;
if ( g_shared_debugger_refcount = = 0 )
2010-06-08 16:52:24 +00:00
{
2010-11-19 03:46:01 +00:00
lldb_private : : WillTerminate ( ) ;
lldb_private : : Terminate ( ) ;
2011-01-17 21:55:19 +00:00
// Clear our master list of debugger objects
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
GetDebuggerList ( ) . clear ( ) ;
2010-06-08 16:52:24 +00:00
}
}
}
2011-03-10 22:14:10 +00:00
void
Debugger : : SettingsInitialize ( )
{
2012-08-22 18:39:03 +00:00
Target : : SettingsInitialize ( ) ;
2011-03-10 22:14:10 +00:00
}
void
Debugger : : SettingsTerminate ( )
{
2012-08-22 18:39:03 +00:00
Target : : SettingsTerminate ( ) ;
2011-03-10 22:14:10 +00:00
}
2012-09-28 23:57:51 +00:00
bool
2013-04-24 21:29:08 +00:00
Debugger : : LoadPlugin ( const FileSpec & spec , Error & error )
2012-09-28 23:57:51 +00:00
{
2013-12-02 19:35:49 +00:00
if ( g_load_plugin_callback )
2013-04-24 21:29:08 +00:00
{
2014-08-27 20:15:09 +00:00
llvm : : sys : : DynamicLibrary dynlib = g_load_plugin_callback ( shared_from_this ( ) , spec , error ) ;
if ( dynlib . isValid ( ) )
2013-12-02 19:35:49 +00:00
{
2014-08-27 20:15:09 +00:00
m_loaded_plugins . push_back ( dynlib ) ;
2013-12-02 19:35:49 +00:00
return true ;
}
2013-04-24 21:29:08 +00:00
}
2013-12-02 19:35:49 +00:00
else
2013-04-24 21:29:08 +00:00
{
2013-12-02 19:35:49 +00: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-04-24 21:29:08 +00:00
}
2012-09-28 23:57:51 +00:00
return false ;
}
static FileSpec : : EnumerateDirectoryResult
LoadPluginCallback
(
void * baton ,
FileSpec : : FileType file_type ,
const FileSpec & file_spec
)
{
Error error ;
static ConstString g_dylibext ( " dylib " ) ;
2013-07-17 00:26:30 +00:00
static ConstString g_solibext ( " so " ) ;
2012-09-28 23:57:51 +00:00
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 ( ) ;
2013-07-17 00:26:30 +00:00
if ( plugin_file_spec . GetFileNameExtension ( ) ! = g_dylibext & &
plugin_file_spec . GetFileNameExtension ( ) ! = g_solibext )
{
2012-09-28 23:57:51 +00:00
return FileSpec : : eEnumerateDirectoryResultNext ;
2013-07-17 00:26:30 +00:00
}
2012-09-28 23:57:51 +00:00
2013-04-24 21:29:08 +00:00
Error plugin_load_error ;
debugger - > LoadPlugin ( plugin_file_spec , plugin_load_error ) ;
2012-09-28 23:57:51 +00:00
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-06-27 02:42:12 +00:00
// might be enumerating a file system that doesn't have correct file type
2012-09-28 23:57:51 +00: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-08-21 17:29:12 +00:00
if ( HostInfo : : GetLLDBPath ( ePathTypeLLDBSystemPlugins , dir_spec ) )
2012-09-28 23:57:51 +00: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-08-21 17:29:12 +00:00
if ( HostInfo : : GetLLDBPath ( ePathTypeLLDBUserPlugins , dir_spec ) )
2012-09-28 23:57:51 +00: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 ) ;
}
}
2012-10-19 18:02:49 +00:00
PluginManager : : DebuggerInitialize ( * this ) ;
2012-09-28 23:57:51 +00:00
}
2010-06-23 01:19:29 +00:00
DebuggerSP
2012-02-21 02:23:08 +00:00
Debugger : : CreateInstance ( lldb : : LogOutputCallback log_callback , void * baton )
2010-06-23 01:19:29 +00:00
{
2012-02-21 02:23:08 +00:00
DebuggerSP debugger_sp ( new Debugger ( log_callback , baton ) ) ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
2010-06-23 01:19:29 +00:00
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
GetDebuggerList ( ) . push_back ( debugger_sp ) ;
}
2012-09-28 23:57:51 +00:00
debugger_sp - > InstanceInitialize ( ) ;
2010-06-23 01:19:29 +00:00
return debugger_sp ;
}
2011-01-22 01:02:07 +00:00
void
2011-09-17 08:33:22 +00:00
Debugger : : Destroy ( DebuggerSP & debugger_sp )
2011-01-22 01:02:07 +00:00
{
if ( debugger_sp . get ( ) = = NULL )
return ;
2011-09-15 21:36:42 +00:00
debugger_sp - > Clear ( ) ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
2011-01-22 01:02:07 +00:00
{
2012-03-30 20:53:46 +00:00
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
2011-01-22 01:02:07 +00:00
{
2012-03-30 20:53:46 +00:00
if ( ( * pos ) . get ( ) = = debugger_sp . get ( ) )
{
debugger_list . erase ( pos ) ;
return ;
}
2011-01-22 01:02:07 +00:00
}
}
}
2011-09-17 08:33:22 +00:00
DebuggerSP
2010-09-04 00:03:46 +00:00
Debugger : : FindDebuggerWithInstanceName ( const ConstString & instance_name )
{
2011-09-17 08:33:22 +00:00
DebuggerSP debugger_sp ;
2012-08-22 18:39:03 +00:00
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 ;
}
}
}
2010-09-04 00:03:46 +00:00
return debugger_sp ;
}
2010-06-23 01:19:29 +00:00
TargetSP
Debugger : : FindTargetWithProcessID ( lldb : : pid_t pid )
{
2011-09-17 08:33:22 +00:00
TargetSP target_sp ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
2010-06-23 01:19:29 +00:00
{
2012-03-30 20:53:46 +00:00
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 ;
}
2010-06-23 01:19:29 +00:00
}
return target_sp ;
}
2011-11-16 05:37:56 +00:00
TargetSP
Debugger : : FindTargetWithProcess ( Process * process )
{
TargetSP target_sp ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
2011-11-16 05:37:56 +00:00
{
2012-03-30 20:53:46 +00:00
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 ;
}
2011-11-16 05:37:56 +00:00
}
return target_sp ;
}
2014-09-12 01:50:46 +00: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 " ) ,
m_source_manager_ap ( ) ,
m_source_file_cache ( ) ,
m_command_interpreter_ap ( new CommandInterpreter ( * this , eScriptLanguageDefault , false ) ) ,
m_input_reader_stack ( ) ,
m_instance_name ( ) ,
m_loaded_plugins ( )
2010-06-08 16:52:24 +00:00
{
2012-08-22 17:17:09 +00:00
char instance_cstr [ 256 ] ;
snprintf ( instance_cstr , sizeof ( instance_cstr ) , " debugger_%d " , ( int ) GetID ( ) ) ;
m_instance_name . SetCString ( instance_cstr ) ;
2012-02-21 02:23:08 +00:00
if ( log_callback )
m_log_callback_stream_sp . reset ( new StreamCallback ( log_callback , baton ) ) ;
2010-06-23 01:19:29 +00:00
m_command_interpreter_ap - > Initialize ( ) ;
2011-03-19 01:12:21 +00:00
// Always add our default platform to the platform list
PlatformSP default_platform_sp ( Platform : : GetDefaultPlatform ( ) ) ;
assert ( default_platform_sp . get ( ) ) ;
m_platform_list . Append ( default_platform_sp , true ) ;
2012-08-22 17:17:09 +00:00
2012-08-23 00:22:02 +00:00
m_collection_sp - > Initialize ( g_properties ) ;
2012-08-22 17:17:09 +00:00
m_collection_sp - > AppendProperty ( ConstString ( " target " ) ,
ConstString ( " Settings specify to debugging targets. " ) ,
true ,
Target : : GetGlobalProperties ( ) - > GetValueProperties ( ) ) ;
2012-08-23 00:22:02 +00:00
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 ( ) ) ;
}
2012-08-22 17:17:09 +00:00
OptionValueSInt64 * term_width = m_collection_sp - > GetPropertyAtIndexAsOptionValueSInt64 ( NULL , ePropertyTerminalWidth ) ;
term_width - > SetMinimumValue ( 10 ) ;
term_width - > SetMaximumValue ( 1024 ) ;
2013-05-23 20:47:45 +00:00
// Turn off use-color if this is a dumb terminal.
const char * term = getenv ( " TERM " ) ;
if ( term & & ! strcmp ( term , " dumb " ) )
SetUseColor ( false ) ;
2010-06-08 16:52:24 +00:00
}
Debugger : : ~ Debugger ( )
2011-09-15 21:36:42 +00:00
{
Clear ( ) ;
}
void
Debugger : : Clear ( )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
ClearIOHandlers ( ) ;
StopIOHandlerThread ( ) ;
StopEventHandlerThread ( ) ;
2011-10-01 00:45:15 +00:00
m_listener . Clear ( ) ;
2010-06-23 01:19:29 +00:00
int num_targets = m_target_list . GetNumTargets ( ) ;
for ( int i = 0 ; i < num_targets ; i + + )
{
2012-01-14 17:04:19 +00:00
TargetSP target_sp ( m_target_list . GetTargetAtIndex ( i ) ) ;
if ( target_sp )
2011-09-15 21:36:42 +00:00
{
2012-01-14 17:04:19 +00:00
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
if ( process_sp )
2013-02-27 19:13:05 +00:00
process_sp - > Finalize ( ) ;
2012-01-14 17:04:19 +00:00
target_sp - > Destroy ( ) ;
2011-09-15 21:36:42 +00:00
}
2010-06-23 01:19:29 +00:00
}
2012-02-16 06:50:00 +00:00
BroadcasterManager : : Clear ( ) ;
2012-05-16 00:11:54 +00:00
// 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.
2012-11-30 20:23:19 +00:00
m_terminal_state . Clear ( ) ;
2014-01-27 23:43:24 +00:00
if ( m_input_file_sp )
m_input_file_sp - > GetFile ( ) . Close ( ) ;
2014-04-25 00:35:14 +00:00
m_command_interpreter_ap - > Clear ( ) ;
2011-09-15 21:36:42 +00:00
}
2010-06-08 16:52:24 +00:00
2011-05-29 04:06:55 +00:00
bool
Debugger : : GetCloseInputOnEOF ( ) const
{
2014-01-27 23:43:24 +00:00
// return m_input_comm.GetCloseOnEOF();
return false ;
2011-05-29 04:06:55 +00:00
}
void
Debugger : : SetCloseInputOnEOF ( bool b )
{
2014-01-27 23:43:24 +00:00
// m_input_comm.SetCloseOnEOF(b);
2011-05-29 04:06:55 +00:00
}
2010-06-08 16:52:24 +00:00
bool
Debugger : : GetAsyncExecution ( )
{
2010-06-23 01:19:29 +00:00
return ! m_command_interpreter_ap - > GetSynchronous ( ) ;
2010-06-08 16:52:24 +00:00
}
void
Debugger : : SetAsyncExecution ( bool async_execution )
{
2010-06-23 01:19:29 +00:00
m_command_interpreter_ap - > SetSynchronous ( ! async_execution ) ;
2010-06-08 16:52:24 +00:00
}
void
Debugger : : SetInputFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-01-27 23:43:24 +00: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 ( ) ;
2011-02-09 01:08:52 +00:00
if ( in_file . IsValid ( ) = = false )
in_file . SetStream ( stdin , true ) ;
2010-06-08 16:52:24 +00:00
2012-11-30 20:23:19 +00:00
// Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState.
SaveInputTerminalState ( ) ;
2010-06-08 16:52:24 +00:00
}
void
Debugger : : SetOutputFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-01-27 23:43:24 +00: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 ( ) ;
2011-02-09 01:08:52 +00:00
if ( out_file . IsValid ( ) = = false )
out_file . SetStream ( stdout , false ) ;
2011-01-14 00:29:16 +00:00
2012-10-29 21:18:03 +00:00
// 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 ) ;
2010-06-08 16:52:24 +00:00
}
void
Debugger : : SetErrorFileHandle ( FILE * fh , bool tranfer_ownership )
{
2014-01-27 23:43:24 +00: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 ( ) ;
2011-02-09 01:08:52 +00:00
if ( err_file . IsValid ( ) = = false )
err_file . SetStream ( stderr , false ) ;
2010-06-08 16:52:24 +00:00
}
2012-11-30 20:23:19 +00:00
void
Debugger : : SaveInputTerminalState ( )
{
2014-01-27 23:43:24 +00: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 ) ;
}
2012-11-30 20:23:19 +00:00
}
void
Debugger : : RestoreInputTerminalState ( )
{
m_terminal_state . Restore ( ) ;
}
2010-06-08 16:52:24 +00:00
ExecutionContext
2010-08-26 21:32:51 +00:00
Debugger : : GetSelectedExecutionContext ( )
2010-06-08 16:52:24 +00:00
{
ExecutionContext exe_ctx ;
2011-09-22 04:58:26 +00:00
TargetSP target_sp ( GetSelectedTarget ( ) ) ;
exe_ctx . SetTargetSP ( target_sp ) ;
2010-06-08 16:52:24 +00:00
if ( target_sp )
{
2011-09-22 04:58:26 +00:00
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
exe_ctx . SetProcessSP ( process_sp ) ;
if ( process_sp & & process_sp - > IsRunning ( ) = = false )
2010-06-08 16:52:24 +00:00
{
2011-09-22 04:58:26 +00:00
ThreadSP thread_sp ( process_sp - > GetThreadList ( ) . GetSelectedThread ( ) ) ;
if ( thread_sp )
2010-06-08 16:52:24 +00:00
{
2011-09-22 04:58:26 +00:00
exe_ctx . SetThreadSP ( thread_sp ) ;
exe_ctx . SetFrameSP ( thread_sp - > GetSelectedFrame ( ) ) ;
if ( exe_ctx . GetFramePtr ( ) = = NULL )
exe_ctx . SetFrameSP ( thread_sp - > GetStackFrameAtIndex ( 0 ) ) ;
2010-06-08 16:52:24 +00:00
}
}
}
return exe_ctx ;
}
2010-11-19 20:47:54 +00:00
void
Debugger : : DispatchInputInterrupt ( )
{
2014-01-27 23:43:24 +00:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2011-02-10 01:15:13 +00:00
if ( reader_sp )
2014-01-27 23:43:24 +00:00
reader_sp - > Interrupt ( ) ;
2010-11-19 20:47:54 +00:00
}
void
Debugger : : DispatchInputEndOfFile ( )
{
2014-01-27 23:43:24 +00:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2011-02-10 01:15:13 +00:00
if ( reader_sp )
2014-01-27 23:43:24 +00:00
reader_sp - > GotEOF ( ) ;
2010-11-19 20:47:54 +00:00
}
2010-12-20 18:35:50 +00:00
void
2014-01-27 23:43:24 +00:00
Debugger : : ClearIOHandlers ( )
2010-12-20 18:35:50 +00:00
{
2011-02-10 01:15:13 +00:00
// The bottom input reader should be the main debugger input reader. We do not want to close that one here.
2014-01-27 23:43:24 +00:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
2011-06-02 19:18:55 +00:00
while ( m_input_reader_stack . GetSize ( ) > 1 )
2010-12-20 18:35:50 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2010-12-20 18:35:50 +00:00
if ( reader_sp )
{
2014-01-27 23:43:24 +00:00
m_input_reader_stack . Pop ( ) ;
reader_sp - > SetIsDone ( true ) ;
2014-02-24 22:50:57 +00:00
reader_sp - > Cancel ( ) ;
2010-12-20 18:35:50 +00:00
}
}
}
2011-05-02 20:41:46 +00:00
void
2014-01-27 23:43:24 +00:00
Debugger : : ExecuteIOHanders ( )
2011-05-02 20:41:46 +00:00
{
2011-05-09 23:06:58 +00:00
2014-01-27 23:43:24 +00:00
while ( 1 )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( ! reader_sp )
break ;
2014-01-27 23:43:24 +00: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 )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP top_reader_sp = m_input_reader_stack . Top ( ) ;
if ( top_reader_sp & & top_reader_sp - > GetIsDone ( ) )
m_input_reader_stack . Pop ( ) ;
else
break ;
2010-06-08 16:52:24 +00:00
}
}
2014-01-27 23:43:24 +00:00
ClearIOHandlers ( ) ;
}
2010-06-08 16:52:24 +00:00
2014-01-27 23:43:24 +00:00
bool
Debugger : : IsTopIOHandler ( const lldb : : IOHandlerSP & reader_sp )
{
return m_input_reader_stack . IsTop ( reader_sp ) ;
}
ConstString
Debugger : : GetTopIOHandlerControlSequence ( char ch )
{
return m_input_reader_stack . GetTopIOHandlerControlSequence ( ch ) ;
2010-06-08 16:52:24 +00:00
}
void
2014-01-27 23:43:24 +00:00
Debugger : : RunIOHandler ( const IOHandlerSP & reader_sp )
{
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
PushIOHandler ( reader_sp ) ;
2014-06-20 00:23:57 +00: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-01-27 23:43:24 +00: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 )
{
if ( top_reader_sp )
in = top_reader_sp - > GetInputStreamFile ( ) ;
else
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 ) ) ;
}
}
void
Debugger : : PushIOHandler ( const IOHandlerSP & reader_sp )
2010-06-08 16:52:24 +00:00
{
if ( ! reader_sp )
return ;
2011-02-10 01:15:13 +00:00
2014-01-27 23:43:24 +00:00
// Got the current top input reader...
IOHandlerSP top_reader_sp ( m_input_reader_stack . Top ( ) ) ;
2011-02-10 01:15:13 +00:00
2014-02-28 18:22:24 +00: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-01-27 23:43:24 +00:00
2014-02-28 18:22:24 +00: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 ( ) ;
}
2010-06-08 16:52:24 +00:00
}
bool
2014-01-27 23:43:24 +00:00
Debugger : : PopIOHandler ( const IOHandlerSP & pop_reader_sp )
2010-06-08 16:52:24 +00:00
{
bool result = false ;
2014-01-27 23:43:24 +00:00
Mutex : : Locker locker ( m_input_reader_stack . GetMutex ( ) ) ;
2010-06-08 16:52:24 +00:00
// The reader on the stop of the stack is done, so let the next
2014-06-27 02:42:12 +00:00
// read on the stack refresh its prompt and if there is one...
2011-06-02 19:18:55 +00:00
if ( ! m_input_reader_stack . IsEmpty ( ) )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( ! pop_reader_sp | | pop_reader_sp . get ( ) = = reader_sp . get ( ) )
{
2014-01-27 23:43:24 +00:00
reader_sp - > Deactivate ( ) ;
2014-02-28 18:22:24 +00:00
reader_sp - > Cancel ( ) ;
2011-06-02 19:18:55 +00:00
m_input_reader_stack . Pop ( ) ;
2014-01-27 23:43:24 +00:00
reader_sp = m_input_reader_stack . Top ( ) ;
if ( reader_sp )
reader_sp - > Activate ( ) ;
2010-06-08 16:52:24 +00:00
2014-01-27 23:43:24 +00:00
result = true ;
2010-06-08 16:52:24 +00:00
}
}
return result ;
}
bool
2014-01-27 23:43:24 +00:00
Debugger : : HideTopIOHandler ( )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
Mutex : : Locker locker ;
if ( locker . TryLock ( m_input_reader_stack . GetMutex ( ) ) )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
if ( reader_sp )
reader_sp - > Hide ( ) ;
return true ;
2010-06-08 16:52:24 +00:00
}
2014-01-27 23:43:24 +00:00
return false ;
2010-06-08 16:52:24 +00:00
}
void
2014-01-27 23:43:24 +00:00
Debugger : : RefreshTopIOHandler ( )
2010-06-08 16:52:24 +00:00
{
2014-01-27 23:43:24 +00:00
IOHandlerSP reader_sp ( m_input_reader_stack . Top ( ) ) ;
if ( reader_sp )
reader_sp - > Refresh ( ) ;
2010-06-08 16:52:24 +00:00
}
2010-06-23 01:19:29 +00:00
2014-01-27 23:43:24 +00:00
2011-06-02 23:58:26 +00:00
StreamSP
Debugger : : GetAsyncOutputStream ( )
{
return StreamSP ( new StreamAsynchronousIO ( GetCommandInterpreter ( ) ,
CommandInterpreter : : eBroadcastBitAsynchronousOutputData ) ) ;
}
StreamSP
Debugger : : GetAsyncErrorStream ( )
{
return StreamSP ( new StreamAsynchronousIO ( GetCommandInterpreter ( ) ,
CommandInterpreter : : eBroadcastBitAsynchronousErrorData ) ) ;
}
2013-01-25 18:06:21 +00:00
size_t
2012-02-15 02:34:21 +00:00
Debugger : : GetNumDebuggers ( )
{
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
return GetDebuggerList ( ) . size ( ) ;
}
return 0 ;
2012-02-15 02:34:21 +00:00
}
lldb : : DebuggerSP
2013-01-25 18:06:21 +00:00
Debugger : : GetDebuggerAtIndex ( size_t index )
2012-02-15 02:34:21 +00:00
{
DebuggerSP debugger_sp ;
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
{
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
2012-02-15 02:34:21 +00:00
2012-03-30 20:53:46 +00:00
if ( index < debugger_list . size ( ) )
debugger_sp = debugger_list [ index ] ;
}
2012-02-15 02:34:21 +00:00
return debugger_sp ;
}
2010-06-30 16:22:25 +00:00
DebuggerSP
Debugger : : FindDebuggerWithID ( lldb : : user_id_t id )
{
2011-09-17 08:33:22 +00:00
DebuggerSP debugger_sp ;
2010-06-30 16:22:25 +00:00
2012-03-30 20:53:46 +00:00
if ( g_shared_debugger_refcount > 0 )
2010-06-30 16:22:25 +00:00
{
2012-03-30 20:53:46 +00:00
Mutex : : Locker locker ( GetDebuggerListMutex ( ) ) ;
DebuggerList & debugger_list = GetDebuggerList ( ) ;
DebuggerList : : iterator pos , end = debugger_list . end ( ) ;
for ( pos = debugger_list . begin ( ) ; pos ! = end ; + + pos )
2010-06-30 16:22:25 +00:00
{
2012-03-30 20:53:46 +00:00
if ( ( * pos ) . get ( ) - > GetID ( ) = = id )
{
debugger_sp = * pos ;
break ;
}
2010-06-30 16:22:25 +00:00
}
}
return debugger_sp ;
}
2010-09-04 00:03:46 +00:00
2014-03-20 06:08:21 +00:00
#if 0
2010-09-19 02:33:57 +00:00
static void
2013-11-04 09:33:30 +00:00
TestPromptFormats (StackFrame *frame)
2010-09-19 02:33:57 +00:00
{
if (frame == NULL)
return;
StreamString s;
const char *prompt_format =
"{addr = '${addr}'\n}"
"{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}"
"{function.name = '${function.name}'\n}"
2012-01-14 17:04:19 +00:00
"{function.name-with-args = '${function.name-with-args}'\n}"
2010-09-19 02:33:57 +00:00
"{function.addr-offset = '${function.addr-offset}'\n}"
"{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;
2010-10-04 01:05:56 +00:00
frame->CalculateExecutionContext(exe_ctx);
2013-05-23 20:47:45 +00:00
if (Debugger::FormatPrompt (prompt_format, &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s))
2010-09-19 02:33:57 +00:00
{
printf("%s\n", s.GetData());
}
else
{
printf ("what we got: %s\n", s.GetData());
}
}
2014-03-20 06:08:21 +00:00
#endif
2010-09-19 02:33:57 +00:00
2011-07-06 02:13:41 +00:00
static bool
2011-08-23 00:32:52 +00:00
ScanFormatDescriptor ( const char * var_name_begin ,
const char * var_name_end ,
const char * * var_name_final ,
const char * * percent_position ,
2011-09-17 08:33:22 +00:00
Format * custom_format ,
2011-08-23 00:32:52 +00:00
ValueObject : : ValueObjectRepresentationStyle * val_obj_display )
2011-07-06 02:13:41 +00:00
{
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_TYPES ) ) ;
2011-07-06 02:13:41 +00:00
* percent_position = : : strchr ( var_name_begin , ' % ' ) ;
2011-07-06 04:07:21 +00:00
if ( ! * percent_position | | * percent_position > var_name_end )
2011-07-22 17:03:19 +00:00
{
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ScanFormatDescriptor] no format descriptor in string, skipping " ) ;
2011-07-06 02:13:41 +00:00
* var_name_final = var_name_end ;
2011-07-22 17:03:19 +00:00
}
2011-07-06 02:13:41 +00:00
else
{
* var_name_final = * percent_position ;
2013-05-06 17:18:22 +00:00
std : : string format_name ( * var_name_final + 1 , var_name_end - * var_name_final - 1 ) ;
2011-07-22 17:03:19 +00:00
if ( log )
2013-06-18 18:23:07 +00:00
log - > Printf ( " [ScanFormatDescriptor] parsing %s as a format descriptor " , format_name . c_str ( ) ) ;
2013-05-06 17:18:22 +00:00
if ( ! FormatManager : : GetFormatFromCString ( format_name . c_str ( ) ,
2011-07-06 02:13:41 +00:00
true ,
* custom_format ) )
{
2011-07-22 17:03:19 +00:00
if ( log )
2013-06-18 18:23:07 +00:00
log - > Printf ( " [ScanFormatDescriptor] %s is an unknown format " , format_name . c_str ( ) ) ;
2013-05-06 17:18:22 +00:00
switch ( format_name . front ( ) )
{
case ' @ ' : // if this is an @ sign, print ObjC description
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleLanguageSpecific ;
break ;
case ' V ' : // if this is a V, print the value using the default format
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleValue ;
break ;
case ' L ' : // if this is an L, print the location of the value
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleLocation ;
break ;
case ' S ' : // if this is an S, print the summary after all
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleSummary ;
break ;
case ' # ' : // if this is a '#', print the number of children
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleChildrenCount ;
break ;
case ' T ' : // if this is a 'T', print the type
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleType ;
break ;
2013-06-21 00:04:51 +00:00
case ' N ' : // if this is a 'N', print the name
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleName ;
break ;
case ' > ' : // if this is a '>', print the name
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleExpressionPath ;
break ;
2013-05-06 17:18:22 +00:00
default :
2013-05-15 18:27:08 +00:00
if ( log )
log - > Printf ( " ScanFormatDescriptor] %s is an error, leaving the previous value alone " , format_name . c_str ( ) ) ;
2013-05-06 17:18:22 +00:00
break ;
}
2011-07-06 02:13:41 +00:00
}
// a good custom format tells us to print the value using it
else
2011-07-22 17:03:19 +00:00
{
if ( log )
2013-06-18 18:23:07 +00:00
log - > Printf ( " [ScanFormatDescriptor] will display value for this VO " ) ;
2012-03-19 22:58:49 +00:00
* val_obj_display = ValueObject : : eValueObjectRepresentationStyleValue ;
2011-07-22 17:03:19 +00:00
}
2011-07-06 02:13:41 +00:00
}
2011-07-22 17:03:19 +00:00
if ( log )
2013-06-18 18:23:07 +00:00
log - > Printf ( " [ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d " ,
2011-07-22 17:03:19 +00:00
* custom_format ,
* val_obj_display ) ;
2011-07-06 02:13:41 +00:00
return true ;
}
static bool
2011-08-23 00:32:52 +00:00
ScanBracketedRange ( const char * var_name_begin ,
const char * var_name_end ,
const char * var_name_final ,
const char * * open_bracket_position ,
const char * * separator_position ,
const char * * close_bracket_position ,
const char * * var_name_final_if_array_range ,
int64_t * index_lower ,
int64_t * index_higher )
2011-07-06 02:13:41 +00:00
{
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_TYPES ) ) ;
2011-07-06 02:13:41 +00:00
* open_bracket_position = : : strchr ( var_name_begin , ' [ ' ) ;
2011-07-06 04:07:21 +00:00
if ( * open_bracket_position & & * open_bracket_position < var_name_final )
2011-07-06 02:13:41 +00:00
{
* separator_position = : : strchr ( * open_bracket_position , ' - ' ) ; // might be NULL if this is a simple var[N] bitfield
* close_bracket_position = : : strchr ( * open_bracket_position , ' ] ' ) ;
// as usual, we assume that [] will come before %
//printf("trying to expand a []\n");
* var_name_final_if_array_range = * open_bracket_position ;
2011-07-06 04:07:21 +00:00
if ( * close_bracket_position - * open_bracket_position = = 1 )
2011-07-06 02:13:41 +00:00
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ScanBracketedRange] '[]' detected.. going from 0 to end of data " ) ;
2011-07-06 02:13:41 +00:00
* index_lower = 0 ;
}
else if ( * separator_position = = NULL | | * separator_position > var_name_end )
{
char * end = NULL ;
* index_lower = : : strtoul ( * open_bracket_position + 1 , & end , 0 ) ;
* index_higher = * index_lower ;
2011-07-22 17:03:19 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " [ScanBracketedRange] [% " PRId64 " ] detected, high index is same " , * index_lower ) ;
2011-07-06 02:13:41 +00:00
}
2011-07-06 04:07:21 +00:00
else if ( * close_bracket_position & & * close_bracket_position < var_name_end )
2011-07-06 02:13:41 +00:00
{
char * end = NULL ;
* index_lower = : : strtoul ( * open_bracket_position + 1 , & end , 0 ) ;
* index_higher = : : strtoul ( * separator_position + 1 , & end , 0 ) ;
2011-07-22 17:03:19 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " [ScanBracketedRange] [% " PRId64 " -% " PRId64 " ] detected " , * index_lower , * index_higher ) ;
2011-07-06 02:13:41 +00:00
}
else
2011-07-22 17:03:19 +00:00
{
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ScanBracketedRange] expression is erroneous, cannot extract indices out of it " ) ;
2011-07-06 02:13:41 +00:00
return false ;
2011-07-22 17:03:19 +00:00
}
2011-07-06 02:13:41 +00:00
if ( * index_lower > * index_higher & & * index_higher > 0 )
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ScanBracketedRange] swapping indices " ) ;
2013-01-25 18:06:21 +00:00
int64_t temp = * index_lower ;
2011-07-06 02:13:41 +00:00
* index_lower = * index_higher ;
* index_higher = temp ;
}
}
2011-07-22 17:03:19 +00:00
else if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ScanBracketedRange] no bracketed range, skipping entirely " ) ;
2011-07-06 02:13:41 +00:00
return true ;
}
2013-07-30 16:44:36 +00:00
template < typename T >
static bool RunScriptFormatKeyword ( Stream & s , ScriptInterpreter * script_interpreter , T t , const std : : string & script_name )
{
if ( script_interpreter )
{
Error script_error ;
std : : string script_output ;
if ( script_interpreter - > RunScriptFormatKeyword ( script_name . c_str ( ) , t , script_output , script_error ) & & script_error . Success ( ) )
{
s . Printf ( " %s " , script_output . c_str ( ) ) ;
return true ;
}
else
{
s . Printf ( " <error: %s> " , script_error . AsCString ( ) ) ;
}
}
return false ;
}
2011-07-06 02:13:41 +00:00
static ValueObjectSP
2011-08-23 00:32:52 +00:00
ExpandIndexedExpression ( ValueObject * valobj ,
2013-01-25 18:06:21 +00:00
size_t index ,
2013-11-04 09:33:30 +00:00
StackFrame * frame ,
2011-08-23 00:32:52 +00:00
bool deref_pointer )
2011-07-06 02:13:41 +00:00
{
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_TYPES ) ) ;
2011-07-08 02:51:01 +00:00
const char * ptr_deref_format = " [%d] " ;
2013-02-01 23:59:44 +00:00
std : : string ptr_deref_buffer ( 10 , 0 ) ;
: : sprintf ( & ptr_deref_buffer [ 0 ] , ptr_deref_format , index ) ;
2011-07-22 17:03:19 +00:00
if ( log )
2013-02-01 23:59:44 +00:00
log - > Printf ( " [ExpandIndexedExpression] name to deref: %s " , ptr_deref_buffer . c_str ( ) ) ;
2011-07-08 02:51:01 +00:00
const char * first_unparsed ;
ValueObject : : GetValueForExpressionPathOptions options ;
ValueObject : : ExpressionPathEndResultType final_value_type ;
ValueObject : : ExpressionPathScanEndReason reason_to_stop ;
2012-03-19 22:58:49 +00:00
ValueObject : : ExpressionPathAftermath what_next = ( deref_pointer ? ValueObject : : eExpressionPathAftermathDereference : ValueObject : : eExpressionPathAftermathNothing ) ;
2013-02-01 23:59:44 +00:00
ValueObjectSP item = valobj - > GetValueForExpressionPath ( ptr_deref_buffer . c_str ( ) ,
2011-07-08 02:51:01 +00:00
& first_unparsed ,
& reason_to_stop ,
& final_value_type ,
options ,
& what_next ) ;
if ( ! item )
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d, "
2011-07-22 17:03:19 +00:00
" final_value_type %d " ,
2011-07-08 02:51:01 +00:00
first_unparsed , reason_to_stop , final_value_type ) ;
}
2011-07-06 02:13:41 +00:00
else
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d, "
2011-07-22 17:03:19 +00:00
" final_value_type %d " ,
2011-07-08 02:51:01 +00:00
first_unparsed , reason_to_stop , final_value_type ) ;
2011-07-06 02:13:41 +00:00
}
return item ;
}
2013-07-30 16:44:36 +00:00
static inline bool
IsToken ( const char * var_name_begin , const char * var )
{
return ( : : strncmp ( var_name_begin , var , strlen ( var ) ) = = 0 ) ;
}
static bool
IsTokenWithFormat ( const char * var_name_begin , const char * var , std : : string & format , const char * default_format ,
const ExecutionContext * exe_ctx_ptr , const SymbolContext * sc_ptr )
{
int var_len = strlen ( var ) ;
if ( : : strncmp ( var_name_begin , var , var_len ) = = 0 )
{
var_name_begin + = var_len ;
if ( * var_name_begin = = ' } ' )
{
format = default_format ;
return true ;
}
else if ( * var_name_begin = = ' % ' )
{
// Allow format specifiers: x|X|u with optional width specifiers.
// ${thread.id%x} ; hex
// ${thread.id%X} ; uppercase hex
// ${thread.id%u} ; unsigned decimal
// ${thread.id%8.8X} ; width.precision + specifier
// ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id)
int dot_count = 0 ;
const char * specifier = NULL ;
int width_precision_length = 0 ;
const char * width_precision = + + var_name_begin ;
while ( isdigit ( * var_name_begin ) | | * var_name_begin = = ' . ' )
{
dot_count + = ( * var_name_begin = = ' . ' ) ;
if ( dot_count > 1 )
break ;
var_name_begin + + ;
width_precision_length + + ;
}
if ( IsToken ( var_name_begin , " tid} " ) )
{
Target * target = Target : : GetTargetFromContexts ( exe_ctx_ptr , sc_ptr ) ;
if ( target )
{
ArchSpec arch ( target - > GetArchitecture ( ) ) ;
llvm : : Triple : : OSType ostype = arch . IsValid ( ) ? arch . GetTriple ( ) . getOS ( ) : llvm : : Triple : : UnknownOS ;
if ( ( ostype = = llvm : : Triple : : FreeBSD ) | | ( ostype = = llvm : : Triple : : Linux ) )
specifier = PRIu64 ;
}
if ( ! specifier )
{
format = default_format ;
return true ;
}
}
else if ( IsToken ( var_name_begin , " x} " ) )
specifier = PRIx64 ;
else if ( IsToken ( var_name_begin , " X} " ) )
specifier = PRIX64 ;
else if ( IsToken ( var_name_begin , " u} " ) )
specifier = PRIu64 ;
if ( specifier )
{
format = " % " ;
if ( width_precision_length )
format + = std : : string ( width_precision , width_precision_length ) ;
format + = specifier ;
return true ;
}
}
}
return false ;
}
2014-06-13 02:37:02 +00:00
// Find information for the "thread.info.*" specifiers in a format string
static bool
FormatThreadExtendedInfoRecurse
(
const char * var_name_begin ,
StructuredData : : ObjectSP thread_info_dictionary ,
const SymbolContext * sc ,
const ExecutionContext * exe_ctx ,
Stream & s
)
{
bool var_success = false ;
std : : string token_format ;
llvm : : StringRef var_name ( var_name_begin ) ;
size_t percent_idx = var_name . find ( ' % ' ) ;
size_t close_curly_idx = var_name . find ( ' } ' ) ;
llvm : : StringRef path = var_name ;
llvm : : StringRef formatter = var_name ;
// 'path' will be the dot separated list of objects to transverse up until we hit
// a close curly brace, a percent sign, or an end of string.
if ( percent_idx ! = llvm : : StringRef : : npos | | close_curly_idx ! = llvm : : StringRef : : npos )
{
if ( percent_idx ! = llvm : : StringRef : : npos & & close_curly_idx ! = llvm : : StringRef : : npos )
{
if ( percent_idx < close_curly_idx )
{
path = var_name . slice ( 0 , percent_idx ) ;
formatter = var_name . substr ( percent_idx ) ;
}
else
{
path = var_name . slice ( 0 , close_curly_idx ) ;
formatter = var_name . substr ( close_curly_idx ) ;
}
}
else if ( percent_idx ! = llvm : : StringRef : : npos )
{
path = var_name . slice ( 0 , percent_idx ) ;
formatter = var_name . substr ( percent_idx ) ;
}
else if ( close_curly_idx ! = llvm : : StringRef : : npos )
{
path = var_name . slice ( 0 , close_curly_idx ) ;
formatter = var_name . substr ( close_curly_idx ) ;
}
}
StructuredData : : ObjectSP value = thread_info_dictionary - > GetObjectForDotSeparatedPath ( path ) ;
if ( value . get ( ) )
{
if ( value - > GetType ( ) = = StructuredData : : Type : : eTypeInteger )
{
if ( IsTokenWithFormat ( formatter . str ( ) . c_str ( ) , " " , token_format , " 0x%4.4 " PRIx64 , exe_ctx , sc ) )
{
s . Printf ( token_format . c_str ( ) , value - > GetAsInteger ( ) - > GetValue ( ) ) ;
var_success = true ;
}
}
else if ( value - > GetType ( ) = = StructuredData : : Type : : eTypeFloat )
{
s . Printf ( " %f " , value - > GetAsFloat ( ) - > GetValue ( ) ) ;
var_success = true ;
}
else if ( value - > GetType ( ) = = StructuredData : : Type : : eTypeString )
{
s . Printf ( " %s " , value - > GetAsString ( ) - > GetValue ( ) . c_str ( ) ) ;
var_success = true ;
}
else if ( value - > GetType ( ) = = StructuredData : : Type : : eTypeArray )
{
if ( value - > GetAsArray ( ) - > GetSize ( ) > 0 )
{
s . Printf ( " %zu " , value - > GetAsArray ( ) - > GetSize ( ) ) ;
var_success = true ;
}
}
else if ( value - > GetType ( ) = = StructuredData : : Type : : eTypeDictionary )
{
s . Printf ( " %zu " , value - > GetAsDictionary ( ) - > GetKeys ( ) - > GetAsArray ( ) - > GetSize ( ) ) ;
var_success = true ;
}
}
return var_success ;
}
2013-05-23 20:47:45 +00:00
static bool
FormatPromptRecurse
2010-09-19 02:33:57 +00:00
(
const char * format ,
const SymbolContext * sc ,
const ExecutionContext * exe_ctx ,
const Address * addr ,
Stream & s ,
2011-06-29 22:27:15 +00:00
const char * * end ,
2011-08-17 22:13:59 +00:00
ValueObject * valobj
2010-09-19 02:33:57 +00:00
)
{
2011-08-17 22:13:59 +00:00
ValueObject * realvalobj = NULL ; // makes it super-easy to parse pointers
2010-09-19 02:33:57 +00:00
bool success = true ;
const char * p ;
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_TYPES ) ) ;
2013-05-23 20:47:45 +00:00
2010-09-19 02:33:57 +00:00
for ( p = format ; * p ! = ' \0 ' ; + + p )
{
2011-08-17 22:13:59 +00:00
if ( realvalobj )
2011-06-29 22:27:15 +00:00
{
2011-08-17 22:13:59 +00:00
valobj = realvalobj ;
realvalobj = NULL ;
2011-06-29 22:27:15 +00:00
}
2010-09-19 02:33:57 +00:00
size_t non_special_chars = : : strcspn ( p , " ${} \\ " ) ;
if ( non_special_chars > 0 )
{
if ( success )
s . Write ( p , non_special_chars ) ;
p + = non_special_chars ;
}
if ( * p = = ' \0 ' )
{
break ;
}
else if ( * p = = ' { ' )
{
// Start a new scope that must have everything it needs if it is to
// to make it into the final output stream "s". If you want to make
// a format that only prints out the function or symbol name if there
// is one in the symbol context you can use:
// "{function =${function.name}}"
// The first '{' starts a new scope that end with the matching '}' at
// the end of the string. The contents "function =${function.name}"
// will then be evaluated and only be output if there is a function
// or symbol with a valid name.
StreamString sub_strm ;
+ + p ; // Skip the '{'
2013-05-23 20:47:45 +00:00
if ( FormatPromptRecurse ( p , sc , exe_ctx , addr , sub_strm , & p , valobj ) )
2010-09-19 02:33:57 +00:00
{
// The stream had all it needed
s . Write ( sub_strm . GetData ( ) , sub_strm . GetSize ( ) ) ;
}
if ( * p ! = ' } ' )
{
success = false ;
break ;
}
}
else if ( * p = = ' } ' )
{
// End of a enclosing scope
break ;
}
else if ( * p = = ' $ ' )
{
// We have a prompt variable to print
+ + p ;
if ( * p = = ' { ' )
{
+ + p ;
const char * var_name_begin = p ;
const char * var_name_end = : : strchr ( p , ' } ' ) ;
if ( var_name_end & & var_name_begin < var_name_end )
{
// if we have already failed to parse, skip this variable
if ( success )
{
const char * cstr = NULL ;
2013-07-30 16:44:36 +00:00
std : : string token_format ;
2010-09-19 02:33:57 +00:00
Address format_addr ;
bool calculate_format_addr_function_offset = false ;
// Set reg_kind and reg_num to invalid values
RegisterKind reg_kind = kNumRegisterKinds ;
uint32_t reg_num = LLDB_INVALID_REGNUM ;
FileSpec format_file_spec ;
2011-03-24 21:19:54 +00:00
const RegisterInfo * reg_info = NULL ;
2010-09-19 02:33:57 +00:00
RegisterContext * reg_ctx = NULL ;
2011-07-06 02:13:41 +00:00
bool do_deref_pointer = false ;
2012-03-19 22:58:49 +00:00
ValueObject : : ExpressionPathScanEndReason reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEndOfString ;
ValueObject : : ExpressionPathEndResultType final_value_type = ValueObject : : eExpressionPathEndResultTypePlain ;
2011-07-08 02:51:01 +00:00
2010-09-19 02:33:57 +00:00
// Each variable must set success to true below...
bool var_success = false ;
switch ( var_name_begin [ 0 ] )
{
2011-06-29 22:27:15 +00:00
case ' * ' :
case ' v ' :
2011-07-29 19:53:35 +00:00
case ' s ' :
2011-06-29 22:27:15 +00:00
{
2011-08-17 22:13:59 +00:00
if ( ! valobj )
2011-07-29 19:53:35 +00:00
break ;
2011-08-02 17:27:39 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] initial string: %s " , var_name_begin ) ;
2011-08-02 17:27:39 +00:00
2011-07-29 19:53:35 +00:00
// check for *var and *svar
if ( * var_name_begin = = ' * ' )
{
do_deref_pointer = true ;
var_name_begin + + ;
2013-06-18 18:23:07 +00:00
if ( log )
log - > Printf ( " [Debugger::FormatPrompt] found a deref, new string is: %s " , var_name_begin ) ;
2011-07-29 19:53:35 +00:00
}
2011-08-02 17:27:39 +00:00
2011-07-29 19:53:35 +00:00
if ( * var_name_begin = = ' s ' )
{
2012-03-27 02:35:13 +00:00
if ( ! valobj - > IsSynthetic ( ) )
valobj = valobj - > GetSyntheticValue ( ) . get ( ) ;
2012-03-19 22:58:49 +00:00
if ( ! valobj )
break ;
2011-07-29 19:53:35 +00:00
var_name_begin + + ;
2013-06-18 18:23:07 +00:00
if ( log )
log - > Printf ( " [Debugger::FormatPrompt] found a synthetic, new string is: %s " , var_name_begin ) ;
2011-07-29 19:53:35 +00:00
}
// should be a 'v' by now
if ( * var_name_begin ! = ' v ' )
break ;
2011-08-02 17:27:39 +00:00
if ( log )
2013-06-18 18:23:07 +00:00
log - > Printf ( " [Debugger::FormatPrompt] string I am working with: %s " , var_name_begin ) ;
2011-08-02 17:27:39 +00:00
2011-07-08 02:51:01 +00:00
ValueObject : : ExpressionPathAftermath what_next = ( do_deref_pointer ?
2012-03-19 22:58:49 +00:00
ValueObject : : eExpressionPathAftermathDereference : ValueObject : : eExpressionPathAftermathNothing ) ;
2011-07-08 02:51:01 +00:00
ValueObject : : GetValueForExpressionPathOptions options ;
2011-08-11 17:08:01 +00:00
options . DontCheckDotVsArrowSyntax ( ) . DoAllowBitfieldSyntax ( ) . DoAllowFragileIVar ( ) . DoAllowSyntheticChildren ( ) ;
2012-03-19 22:58:49 +00:00
ValueObject : : ValueObjectRepresentationStyle val_obj_display = ValueObject : : eValueObjectRepresentationStyleSummary ;
2011-07-06 04:07:21 +00:00
ValueObject * target = NULL ;
2011-09-17 08:33:22 +00:00
Format custom_format = eFormatInvalid ;
2011-07-06 04:07:21 +00:00
const char * var_name_final = NULL ;
const char * var_name_final_if_array_range = NULL ;
const char * close_bracket_position = NULL ;
int64_t index_lower = - 1 ;
int64_t index_higher = - 1 ;
bool is_array_range = false ;
2011-07-08 02:51:01 +00:00
const char * first_unparsed ;
2011-08-18 16:38:26 +00:00
bool was_plain_var = false ;
bool was_var_format = false ;
2012-05-08 21:49:57 +00:00
bool was_var_indexed = false ;
2011-07-08 02:51:01 +00:00
2011-08-17 22:13:59 +00:00
if ( ! valobj ) break ;
// simplest case ${var}, just print valobj's value
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " var} " ) )
2011-06-29 22:27:15 +00:00
{
2011-08-18 16:38:26 +00:00
was_plain_var = true ;
2011-08-17 22:13:59 +00:00
target = valobj ;
2012-03-19 22:58:49 +00:00
val_obj_display = ValueObject : : eValueObjectRepresentationStyleValue ;
2011-07-06 04:07:21 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " var% " ) )
2011-07-06 04:07:21 +00:00
{
2011-08-18 16:38:26 +00:00
was_var_format = true ;
2011-07-06 04:07:21 +00:00
// this is a variable with some custom format applied to it
const char * percent_position ;
2011-08-17 22:13:59 +00:00
target = valobj ;
2012-03-19 22:58:49 +00:00
val_obj_display = ValueObject : : eValueObjectRepresentationStyleValue ;
2011-07-06 04:07:21 +00:00
ScanFormatDescriptor ( var_name_begin ,
var_name_end ,
& var_name_final ,
& percent_position ,
& custom_format ,
& val_obj_display ) ;
}
// this is ${var.something} or multiple .something nested
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " var " ) )
2011-07-06 04:07:21 +00:00
{
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " var[ " ) )
2012-05-08 21:49:57 +00:00
was_var_indexed = true ;
2011-07-06 04:07:21 +00:00
const char * percent_position ;
ScanFormatDescriptor ( var_name_begin ,
var_name_end ,
& var_name_final ,
& percent_position ,
& custom_format ,
& val_obj_display ) ;
const char * open_bracket_position ;
const char * separator_position ;
ScanBracketedRange ( var_name_begin ,
var_name_end ,
var_name_final ,
& open_bracket_position ,
& separator_position ,
& close_bracket_position ,
& var_name_final_if_array_range ,
& index_lower ,
& index_higher ) ;
Error error ;
2011-07-08 02:51:01 +00:00
2013-02-01 23:59:44 +00:00
std : : string expr_path ( var_name_final - var_name_begin - 1 , 0 ) ;
memcpy ( & expr_path [ 0 ] , var_name_begin + 3 , var_name_final - var_name_begin - 3 ) ;
if ( log )
log - > Printf ( " [Debugger::FormatPrompt] symbol to expand: %s " , expr_path . c_str ( ) ) ;
target = valobj - > GetValueForExpressionPath ( expr_path . c_str ( ) ,
2011-07-08 02:51:01 +00:00
& first_unparsed ,
& reason_to_stop ,
& final_value_type ,
options ,
& what_next ) . get ( ) ;
if ( ! target )
2011-07-06 02:13:41 +00:00
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d, "
2011-07-22 17:03:19 +00:00
" final_value_type %d " ,
2011-07-08 02:51:01 +00:00
first_unparsed , reason_to_stop , final_value_type ) ;
break ;
2011-07-06 02:13:41 +00:00
}
2011-07-08 02:51:01 +00:00
else
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d, "
2011-07-22 17:03:19 +00:00
" final_value_type %d " ,
2011-07-08 02:51:01 +00:00
first_unparsed , reason_to_stop , final_value_type ) ;
}
2011-06-29 22:27:15 +00:00
}
2011-07-06 04:07:21 +00:00
else
2011-07-06 02:13:41 +00:00
break ;
2011-07-08 02:51:01 +00:00
2012-03-19 22:58:49 +00:00
is_array_range = ( final_value_type = = ValueObject : : eExpressionPathEndResultTypeBoundedRange | |
final_value_type = = ValueObject : : eExpressionPathEndResultTypeUnboundedRange ) ;
2011-07-08 02:51:01 +00:00
2012-03-19 22:58:49 +00:00
do_deref_pointer = ( what_next = = ValueObject : : eExpressionPathAftermathDereference ) ;
2011-07-06 02:13:41 +00:00
2011-07-06 19:27:11 +00:00
if ( do_deref_pointer & & ! is_array_range )
2011-07-06 02:13:41 +00:00
{
2011-07-06 04:07:21 +00:00
// I have not deref-ed yet, let's do it
// this happens when we are not going through GetValueForVariableExpressionPath
// to get to the target ValueObject
2011-07-06 02:13:41 +00:00
Error error ;
2011-07-06 04:07:21 +00:00
target = target - > Dereference ( error ) . get ( ) ;
2011-08-23 00:32:52 +00:00
if ( error . Fail ( ) )
{
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] ERROR: %s \n " , error . AsCString ( " unknown " ) ) ; \
2011-08-23 00:32:52 +00:00
break ;
}
2011-07-06 04:07:21 +00:00
do_deref_pointer = false ;
}
2011-07-12 22:56:10 +00:00
2014-03-11 18:17:23 +00:00
if ( ! target )
{
if ( log )
log - > Printf ( " [Debugger::FormatPrompt] could not calculate target for prompt expression " ) ;
break ;
}
2012-05-08 21:49:57 +00:00
// we do not want to use the summary for a bitfield of type T:n
// if we were originally dealing with just a T - that would get
// us into an endless recursion
if ( target - > IsBitfield ( ) & & was_var_indexed )
{
// TODO: check for a (T:n)-specific summary - we should still obey that
StreamString bitfield_name ;
bitfield_name . Printf ( " %s:%d " , target - > GetTypeName ( ) . AsCString ( ) , target - > GetBitfieldBitSize ( ) ) ;
lldb : : TypeNameSpecifierImplSP type_sp ( new TypeNameSpecifierImpl ( bitfield_name . GetData ( ) , false ) ) ;
if ( ! DataVisualization : : GetSummaryForType ( type_sp ) )
val_obj_display = ValueObject : : eValueObjectRepresentationStyleValue ;
}
2011-08-18 16:38:26 +00:00
// TODO use flags for these
2013-07-11 22:46:58 +00:00
const uint32_t type_info_flags = target - > GetClangType ( ) . GetTypeInfo ( NULL ) ;
bool is_array = ( type_info_flags & ClangASTType : : eTypeIsArray ) ! = 0 ;
bool is_pointer = ( type_info_flags & ClangASTType : : eTypeIsPointer ) ! = 0 ;
bool is_aggregate = target - > GetClangType ( ) . IsAggregateType ( ) ;
2011-07-12 22:56:10 +00:00
2012-03-19 22:58:49 +00:00
if ( ( is_array | | is_pointer ) & & ( ! is_array_range ) & & val_obj_display = = ValueObject : : eValueObjectRepresentationStyleValue ) // this should be wrong, but there are some exceptions
2011-07-12 22:56:10 +00:00
{
2011-08-18 16:38:26 +00:00
StreamString str_temp ;
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] I am into array || pointer && !range " ) ;
2011-08-19 21:13:46 +00:00
2013-03-25 21:06:13 +00:00
if ( target - > HasSpecialPrintableRepresentation ( val_obj_display , custom_format ) )
2011-08-18 16:38:26 +00:00
{
2011-08-19 21:13:46 +00:00
// try to use the special cases
var_success = target - > DumpPrintableRepresentation ( str_temp ,
val_obj_display ,
custom_format ) ;
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] special cases did%s match " , var_success ? " " : " n't " ) ;
2011-08-19 21:13:46 +00:00
// should not happen
2013-03-25 21:06:13 +00:00
if ( var_success )
2011-08-19 21:13:46 +00:00
s < < str_temp . GetData ( ) ;
2011-08-18 16:38:26 +00:00
var_success = true ;
2011-08-19 21:13:46 +00:00
break ;
2011-08-18 16:38:26 +00:00
}
else
2011-08-19 21:13:46 +00:00
{
2011-08-23 21:26:09 +00:00
if ( was_plain_var ) // if ${var}
2011-08-19 21:13:46 +00:00
{
s < < target - > GetTypeName ( ) < < " @ " < < target - > GetLocationAsCString ( ) ;
}
2011-08-23 21:26:09 +00:00
else if ( is_pointer ) // if pointer, value is the address stored
{
2012-07-17 03:23:13 +00:00
target - > DumpPrintableRepresentation ( s ,
val_obj_display ,
custom_format ,
ValueObject : : ePrintableRepresentationSpecialCasesDisable ) ;
2011-08-23 21:26:09 +00:00
}
2011-08-19 21:13:46 +00:00
var_success = true ;
break ;
}
}
// if directly trying to print ${var}, and this is an aggregate, display a nice
// type @ location message
if ( is_aggregate & & was_plain_var )
{
s < < target - > GetTypeName ( ) < < " @ " < < target - > GetLocationAsCString ( ) ;
var_success = true ;
2011-08-18 16:38:26 +00:00
break ;
}
2011-08-19 21:13:46 +00:00
// if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it
2012-03-19 22:58:49 +00:00
if ( is_aggregate & & ( ( was_var_format & & val_obj_display = = ValueObject : : eValueObjectRepresentationStyleValue ) ) )
2011-08-18 16:38:26 +00:00
{
s < < " <invalid use of aggregate type> " ;
var_success = true ;
2011-07-12 22:56:10 +00:00
break ;
}
2011-07-06 04:07:21 +00:00
if ( ! is_array_range )
2011-07-22 17:03:19 +00:00
{
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] dumping ordinary printable output " ) ;
2011-07-06 04:07:21 +00:00
var_success = target - > DumpPrintableRepresentation ( s , val_obj_display , custom_format ) ;
2011-07-22 17:03:19 +00:00
}
2011-07-06 04:07:21 +00:00
else
2011-07-22 17:03:19 +00:00
{
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] checking if I can handle as array " ) ;
2011-07-06 04:07:21 +00:00
if ( ! is_array & & ! is_pointer )
break ;
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] handle as array " ) ;
2011-07-08 02:51:01 +00:00
const char * special_directions = NULL ;
StreamString special_directions_writer ;
2011-07-06 04:07:21 +00:00
if ( close_bracket_position & & ( var_name_end - close_bracket_position > 1 ) )
{
2011-07-08 02:51:01 +00:00
ConstString additional_data ;
additional_data . SetCStringWithLength ( close_bracket_position + 1 , var_name_end - close_bracket_position - 1 ) ;
special_directions_writer . Printf ( " ${%svar%s} " ,
do_deref_pointer ? " * " : " " ,
additional_data . GetCString ( ) ) ;
special_directions = special_directions_writer . GetData ( ) ;
2011-07-06 04:07:21 +00:00
}
// let us display items index_lower thru index_higher of this array
s . PutChar ( ' [ ' ) ;
var_success = true ;
if ( index_higher < 0 )
2011-08-17 22:13:59 +00:00
index_higher = valobj - > GetNumChildren ( ) - 1 ;
2011-07-06 04:07:21 +00:00
2012-02-17 07:49:44 +00:00
uint32_t max_num_children = target - > GetTargetSP ( ) - > GetMaximumNumberOfChildrenToDisplay ( ) ;
2011-08-12 02:00:06 +00:00
2011-07-06 04:07:21 +00:00
for ( ; index_lower < = index_higher ; index_lower + + )
{
2011-09-22 04:58:26 +00:00
ValueObject * item = ExpandIndexedExpression ( target ,
index_lower ,
exe_ctx - > GetFramePtr ( ) ,
false ) . get ( ) ;
2011-07-06 04:07:21 +00:00
2011-07-08 02:51:01 +00:00
if ( ! item )
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " [Debugger::FormatPrompt] ERROR in getting child item at index % " PRId64 , index_lower ) ;
2011-07-08 02:51:01 +00:00
}
else
{
2011-07-22 17:03:19 +00:00
if ( log )
2012-10-17 22:23:56 +00:00
log - > Printf ( " [Debugger::FormatPrompt] special_directions for child item: %s " , special_directions ) ;
2011-07-08 02:51:01 +00:00
}
2011-07-06 04:07:21 +00:00
if ( ! special_directions )
var_success & = item - > DumpPrintableRepresentation ( s , val_obj_display , custom_format ) ;
else
2013-05-23 20:47:45 +00:00
var_success & = FormatPromptRecurse ( special_directions , sc , exe_ctx , addr , s , NULL , item ) ;
2011-07-06 04:07:21 +00:00
2011-08-12 02:00:06 +00:00
if ( - - max_num_children = = 0 )
{
s . PutCString ( " , ... " ) ;
break ;
}
2011-07-06 04:07:21 +00:00
if ( index_lower < index_higher )
s . PutChar ( ' , ' ) ;
}
s . PutChar ( ' ] ' ) ;
2011-07-06 02:13:41 +00:00
}
2011-06-29 22:27:15 +00:00
}
2011-07-06 02:13:41 +00:00
break ;
2010-09-19 02:33:57 +00:00
case ' a ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " addr} " ) )
2010-09-19 02:33:57 +00:00
{
if ( addr & & addr - > IsValid ( ) )
{
var_success = true ;
format_addr = * addr ;
}
}
break ;
case ' p ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " process. " ) )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
if ( exe_ctx )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
Process * process = exe_ctx - > GetProcessPtr ( ) ;
if ( process )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
var_name_begin + = : : strlen ( " process. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsTokenWithFormat ( var_name_begin , " id " , token_format , " % " PRIu64 , exe_ctx , sc ) )
2010-09-19 02:33:57 +00:00
{
2013-07-30 16:44:36 +00:00
s . Printf ( token_format . c_str ( ) , process - > GetID ( ) ) ;
2011-09-22 04:58:26 +00:00
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( ( IsToken ( var_name_begin , " name} " ) ) | |
( IsToken ( var_name_begin , " file.basename} " ) ) | |
( IsToken ( var_name_begin , " file.fullpath} " ) ) )
2011-09-22 04:58:26 +00:00
{
Module * exe_module = process - > GetTarget ( ) . GetExecutableModulePointer ( ) ;
if ( exe_module )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
if ( var_name_begin [ 0 ] = = ' n ' | | var_name_begin [ 5 ] = = ' f ' )
{
format_file_spec . GetFilename ( ) = exe_module - > GetFileSpec ( ) . GetFilename ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2011-09-22 04:58:26 +00:00
}
else
{
format_file_spec = exe_module - > GetFileSpec ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2011-09-22 04:58:26 +00:00
}
2010-09-19 02:33:57 +00:00
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " script: " ) )
2013-06-20 23:40:21 +00:00
{
var_name_begin + = : : strlen ( " script: " ) ;
std : : string script_name ( var_name_begin , var_name_end ) ;
ScriptInterpreter * script_interpreter = process - > GetTarget ( ) . GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
2013-07-30 16:44:36 +00:00
if ( RunScriptFormatKeyword ( s , script_interpreter , process , script_name ) )
var_success = true ;
2013-06-20 23:40:21 +00:00
}
2010-09-19 02:33:57 +00:00
}
2011-09-22 04:58:26 +00:00
}
2010-09-19 02:33:57 +00:00
}
break ;
case ' t ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " thread. " ) )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
if ( exe_ctx )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
Thread * thread = exe_ctx - > GetThreadPtr ( ) ;
if ( thread )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
var_name_begin + = : : strlen ( " thread. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsTokenWithFormat ( var_name_begin , " id " , token_format , " 0x%4.4 " PRIx64 , exe_ctx , sc ) )
2010-09-19 02:33:57 +00:00
{
2013-07-30 16:44:36 +00:00
s . Printf ( token_format . c_str ( ) , thread - > GetID ( ) ) ;
2011-09-22 04:58:26 +00:00
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsTokenWithFormat ( var_name_begin , " protocol_id " , token_format , " 0x%4.4 " PRIx64 , exe_ctx , sc ) )
2013-05-01 21:54:04 +00:00
{
2013-07-30 16:44:36 +00:00
s . Printf ( token_format . c_str ( ) , thread - > GetProtocolID ( ) ) ;
2013-05-01 21:54:04 +00:00
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsTokenWithFormat ( var_name_begin , " index " , token_format , " % " PRIu64 , exe_ctx , sc ) )
2011-09-22 04:58:26 +00:00
{
2013-07-30 16:44:36 +00:00
s . Printf ( token_format . c_str ( ) , ( uint64_t ) thread - > GetIndexID ( ) ) ;
2011-09-22 04:58:26 +00:00
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " name} " ) )
2011-09-22 04:58:26 +00:00
{
cstr = thread - > GetName ( ) ;
var_success = cstr & & cstr [ 0 ] ;
if ( var_success )
2010-09-19 02:33:57 +00:00
s . PutCString ( cstr ) ;
2011-09-22 04:58:26 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " queue} " ) )
2011-09-22 04:58:26 +00:00
{
cstr = thread - > GetQueueName ( ) ;
var_success = cstr & & cstr [ 0 ] ;
if ( var_success )
s . PutCString ( cstr ) ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " stop-reason} " ) )
2011-09-22 04:58:26 +00:00
{
StopInfoSP stop_info_sp = thread - > GetStopInfo ( ) ;
2012-10-16 00:09:33 +00:00
if ( stop_info_sp & & stop_info_sp - > IsValid ( ) )
2011-09-22 04:58:26 +00:00
{
cstr = stop_info_sp - > GetDescription ( ) ;
if ( cstr & & cstr [ 0 ] )
{
s . PutCString ( cstr ) ;
var_success = true ;
}
2010-09-19 02:33:57 +00:00
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " return-value} " ) )
2011-12-17 01:35:57 +00:00
{
StopInfoSP stop_info_sp = thread - > GetStopInfo ( ) ;
2012-10-16 00:09:33 +00:00
if ( stop_info_sp & & stop_info_sp - > IsValid ( ) )
2011-12-17 01:35:57 +00:00
{
ValueObjectSP return_valobj_sp = StopInfo : : GetReturnValueObject ( stop_info_sp ) ;
if ( return_valobj_sp )
{
2013-09-30 19:11:51 +00:00
return_valobj_sp - > Dump ( s ) ;
2011-12-22 19:12:40 +00:00
var_success = true ;
2011-12-17 01:35:57 +00:00
}
}
}
2014-07-08 01:07:32 +00:00
else if ( IsToken ( var_name_begin , " completed-expression} " ) )
{
StopInfoSP stop_info_sp = thread - > GetStopInfo ( ) ;
if ( stop_info_sp & & stop_info_sp - > IsValid ( ) )
{
ClangExpressionVariableSP expression_var_sp = StopInfo : : GetExpressionVariable ( stop_info_sp ) ;
if ( expression_var_sp & & expression_var_sp - > GetValueObject ( ) )
{
expression_var_sp - > GetValueObject ( ) - > Dump ( s ) ;
var_success = true ;
}
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " script: " ) )
2013-06-20 23:40:21 +00:00
{
var_name_begin + = : : strlen ( " script: " ) ;
std : : string script_name ( var_name_begin , var_name_end ) ;
ScriptInterpreter * script_interpreter = thread - > GetProcess ( ) - > GetTarget ( ) . GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
2013-07-30 16:44:36 +00:00
if ( RunScriptFormatKeyword ( s , script_interpreter , thread , script_name ) )
var_success = true ;
2013-06-20 23:40:21 +00:00
}
2014-06-13 02:37:02 +00:00
else if ( IsToken ( var_name_begin , " info. " ) )
{
var_name_begin + = : : strlen ( " info. " ) ;
StructuredData : : ObjectSP object_sp = thread - > GetExtendedInfo ( ) ;
if ( object_sp & & object_sp - > GetType ( ) = = StructuredData : : Type : : eTypeDictionary )
{
var_success = FormatThreadExtendedInfoRecurse ( var_name_begin , object_sp , sc , exe_ctx , s ) ;
}
}
2010-09-19 02:33:57 +00:00
}
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " target. " ) )
2010-09-19 02:33:57 +00:00
{
2012-08-22 17:17:09 +00:00
// TODO: hookup properties
// if (!target_properties_sp)
// {
// Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
// if (target)
// target_properties_sp = target->GetProperties();
// }
//
// if (target_properties_sp)
// {
// var_name_begin += ::strlen ("target.");
// const char *end_property = strchr(var_name_begin, '}');
// if (end_property)
// {
// ConstString property_name(var_name_begin, end_property - var_name_begin);
// std::string property_value (target_properties_sp->GetPropertyValue(property_name));
// if (!property_value.empty())
// {
// s.PutCString (property_value.c_str());
// var_success = true;
// }
// }
// }
2010-10-04 01:05:56 +00:00
Target * target = Target : : GetTargetFromContexts ( exe_ctx , sc ) ;
if ( target )
2010-09-19 02:33:57 +00:00
{
var_name_begin + = : : strlen ( " target. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " arch} " ) )
2010-09-19 02:33:57 +00:00
{
ArchSpec arch ( target - > GetArchitecture ( ) ) ;
if ( arch . IsValid ( ) )
{
2011-02-23 00:35:02 +00:00
s . PutCString ( arch . GetArchitectureName ( ) ) ;
2010-09-19 02:33:57 +00:00
var_success = true ;
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " script: " ) )
2013-06-20 23:40:21 +00:00
{
var_name_begin + = : : strlen ( " script: " ) ;
std : : string script_name ( var_name_begin , var_name_end ) ;
ScriptInterpreter * script_interpreter = target - > GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
2013-07-30 16:44:36 +00:00
if ( RunScriptFormatKeyword ( s , script_interpreter , target , script_name ) )
var_success = true ;
2013-06-20 23:40:21 +00:00
}
2012-08-22 17:17:09 +00:00
}
2010-09-19 02:33:57 +00:00
}
break ;
case ' m ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " module. " ) )
2010-09-19 02:33:57 +00:00
{
2010-10-04 01:05:56 +00:00
if ( sc & & sc - > module_sp . get ( ) )
2010-09-19 02:33:57 +00:00
{
2010-10-04 01:05:56 +00:00
Module * module = sc - > module_sp . get ( ) ;
2010-09-19 02:33:57 +00:00
var_name_begin + = : : strlen ( " module. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " file. " ) )
2010-09-19 02:33:57 +00:00
{
if ( module - > GetFileSpec ( ) )
{
var_name_begin + = : : strlen ( " file. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " basename} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec . GetFilename ( ) = module - > GetFileSpec ( ) . GetFilename ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " fullpath} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec = module - > GetFileSpec ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
}
}
}
}
break ;
case ' f ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " file. " ) )
2010-09-19 02:33:57 +00:00
{
if ( sc & & sc - > comp_unit ! = NULL )
{
var_name_begin + = : : strlen ( " file. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " basename} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec . GetFilename ( ) = sc - > comp_unit - > GetFilename ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " fullpath} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec = * sc - > comp_unit ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " frame. " ) )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
if ( exe_ctx )
2010-09-19 02:33:57 +00:00
{
2013-11-04 09:33:30 +00:00
StackFrame * frame = exe_ctx - > GetFramePtr ( ) ;
2011-09-22 04:58:26 +00:00
if ( frame )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
var_name_begin + = : : strlen ( " frame. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " index} " ) )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
s . Printf ( " %u " , frame - > GetFrameIndex ( ) ) ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " pc} " ) )
2011-09-22 04:58:26 +00:00
{
reg_kind = eRegisterKindGeneric ;
reg_num = LLDB_REGNUM_GENERIC_PC ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " sp} " ) )
2011-09-22 04:58:26 +00:00
{
reg_kind = eRegisterKindGeneric ;
reg_num = LLDB_REGNUM_GENERIC_SP ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " fp} " ) )
2011-09-22 04:58:26 +00:00
{
reg_kind = eRegisterKindGeneric ;
reg_num = LLDB_REGNUM_GENERIC_FP ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " flags} " ) )
2011-09-22 04:58:26 +00:00
{
reg_kind = eRegisterKindGeneric ;
reg_num = LLDB_REGNUM_GENERIC_FLAGS ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " reg. " ) )
2011-09-22 04:58:26 +00:00
{
reg_ctx = frame - > GetRegisterContext ( ) . get ( ) ;
if ( reg_ctx )
2010-09-19 02:33:57 +00:00
{
2011-09-22 04:58:26 +00:00
var_name_begin + = : : strlen ( " reg. " ) ;
if ( var_name_begin < var_name_end )
{
std : : string reg_name ( var_name_begin , var_name_end ) ;
reg_info = reg_ctx - > GetRegisterInfoByName ( reg_name . c_str ( ) ) ;
if ( reg_info )
var_success = true ;
}
2010-09-19 02:33:57 +00:00
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " script: " ) )
2013-06-20 23:40:21 +00:00
{
var_name_begin + = : : strlen ( " script: " ) ;
std : : string script_name ( var_name_begin , var_name_end ) ;
ScriptInterpreter * script_interpreter = frame - > GetThread ( ) - > GetProcess ( ) - > GetTarget ( ) . GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
2013-07-30 16:44:36 +00:00
if ( RunScriptFormatKeyword ( s , script_interpreter , frame , script_name ) )
var_success = true ;
2013-06-20 23:40:21 +00:00
}
2010-09-19 02:33:57 +00:00
}
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " function. " ) )
2010-09-19 02:33:57 +00:00
{
if ( sc & & ( sc - > function ! = NULL | | sc - > symbol ! = NULL ) )
{
var_name_begin + = : : strlen ( " function. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " id} " ) )
2010-09-19 02:33:57 +00:00
{
if ( sc - > function )
2012-11-29 21:49:15 +00:00
s . Printf ( " function{0x%8.8 " PRIx64 " } " , sc - > function - > GetID ( ) ) ;
2010-09-19 02:33:57 +00:00
else
s . Printf ( " symbol[%u] " , sc - > symbol - > GetID ( ) ) ;
var_success = true ;
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " name} " ) )
2010-09-19 02:33:57 +00:00
{
if ( sc - > function )
cstr = sc - > function - > GetName ( ) . AsCString ( NULL ) ;
else if ( sc - > symbol )
cstr = sc - > symbol - > GetName ( ) . AsCString ( NULL ) ;
if ( cstr )
{
s . PutCString ( cstr ) ;
2010-10-04 17:26:49 +00:00
if ( sc - > block )
{
Block * inline_block = sc - > block - > GetContainingInlinedBlock ( ) ;
if ( inline_block )
{
const InlineFunctionInfo * inline_info = sc - > block - > GetInlinedFunctionInfo ( ) ;
if ( inline_info )
{
s . PutCString ( " [inlined] " ) ;
inline_info - > GetName ( ) . Dump ( & s ) ;
}
}
}
2010-09-19 02:33:57 +00:00
var_success = true ;
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " name-with-args} " ) )
2012-01-13 08:39:16 +00:00
{
// Print the function name with arguments in it
if ( sc - > function )
{
var_success = true ;
ExecutionContextScope * exe_scope = exe_ctx ? exe_ctx - > GetBestExecutionContextScope ( ) : NULL ;
cstr = sc - > function - > GetName ( ) . AsCString ( NULL ) ;
if ( cstr )
{
const InlineFunctionInfo * inline_info = NULL ;
VariableListSP variable_list_sp ;
bool get_function_vars = true ;
if ( sc - > block )
{
Block * inline_block = sc - > block - > GetContainingInlinedBlock ( ) ;
if ( inline_block )
{
get_function_vars = false ;
inline_info = sc - > block - > GetInlinedFunctionInfo ( ) ;
if ( inline_info )
variable_list_sp = inline_block - > GetBlockVariableList ( true ) ;
}
}
if ( get_function_vars )
{
variable_list_sp = sc - > function - > GetBlock ( true ) . GetBlockVariableList ( true ) ;
}
if ( inline_info )
{
s . PutCString ( cstr ) ;
s . PutCString ( " [inlined] " ) ;
cstr = inline_info - > GetName ( ) . GetCString ( ) ;
}
VariableList args ;
if ( variable_list_sp )
2013-05-08 20:27:37 +00:00
variable_list_sp - > AppendVariablesWithScope ( eValueTypeVariableArgument , args ) ;
2012-01-13 08:39:16 +00:00
if ( args . GetSize ( ) > 0 )
{
const char * open_paren = strchr ( cstr , ' ( ' ) ;
2014-08-16 00:56:04 +00:00
const char * close_paren = nullptr ;
const char * generic = strchr ( cstr , ' < ' ) ;
// if before the arguments list begins there is a template sign
// then scan to the end of the generic args before you try to find
// the arguments list
if ( generic & & open_paren & & generic < open_paren )
{
int generic_depth = 1 ;
+ + generic ;
for ( ;
* generic & & generic_depth > 0 ;
generic + + )
{
if ( * generic = = ' < ' )
generic_depth + + ;
if ( * generic = = ' > ' )
generic_depth - - ;
}
if ( * generic )
open_paren = strchr ( generic , ' ( ' ) ;
else
open_paren = nullptr ;
}
2012-01-13 08:39:16 +00:00
if ( open_paren )
2013-03-26 01:45:43 +00:00
{
2013-07-30 16:44:36 +00:00
if ( IsToken ( open_paren , " (anonymous namespace) " ) )
2013-03-26 01:45:43 +00:00
{
open_paren = strchr ( open_paren + strlen ( " (anonymous namespace) " ) , ' ( ' ) ;
if ( open_paren )
close_paren = strchr ( open_paren , ' ) ' ) ;
}
else
close_paren = strchr ( open_paren , ' ) ' ) ;
}
2012-01-13 08:39:16 +00:00
if ( open_paren )
s . Write ( cstr , open_paren - cstr + 1 ) ;
else
{
s . PutCString ( cstr ) ;
s . PutChar ( ' ( ' ) ;
}
2012-01-18 21:56:18 +00:00
const size_t num_args = args . GetSize ( ) ;
2012-01-13 08:39:16 +00:00
for ( size_t arg_idx = 0 ; arg_idx < num_args ; + + arg_idx )
{
2014-03-25 22:03:52 +00:00
std : : string buffer ;
2012-01-13 08:39:16 +00:00
VariableSP var_sp ( args . GetVariableAtIndex ( arg_idx ) ) ;
ValueObjectSP var_value_sp ( ValueObjectVariable : : Create ( exe_scope , var_sp ) ) ;
2014-03-25 22:03:52 +00:00
const char * var_representation = nullptr ;
2012-01-13 08:39:16 +00:00
const char * var_name = var_value_sp - > GetName ( ) . GetCString ( ) ;
2014-03-25 22:03:52 +00:00
if ( var_value_sp - > GetClangType ( ) . IsAggregateType ( ) & &
DataVisualization : : ShouldPrintAsOneLiner ( * var_value_sp . get ( ) ) )
{
static StringSummaryFormat format ( TypeSummaryImpl : : Flags ( )
. SetHideItemNames ( false )
. SetShowMembersOneLiner ( true ) ,
" " ) ;
format . FormatObject ( var_value_sp . get ( ) , buffer ) ;
var_representation = buffer . c_str ( ) ;
}
else
var_representation = var_value_sp - > GetValueAsCString ( ) ;
2012-12-10 22:26:34 +00:00
if ( arg_idx > 0 )
s . PutCString ( " , " ) ;
2012-01-13 08:39:16 +00:00
if ( var_value_sp - > GetError ( ) . Success ( ) )
2013-05-08 20:27:37 +00:00
{
2014-03-25 22:03:52 +00:00
if ( var_representation )
s . Printf ( " %s=%s " , var_name , var_representation ) ;
2013-05-08 20:27:37 +00:00
else
s . Printf ( " %s=%s at %s " , var_name , var_value_sp - > GetTypeName ( ) . GetCString ( ) , var_value_sp - > GetLocationAsCString ( ) ) ;
}
2012-12-10 22:26:34 +00:00
else
s . Printf ( " %s=<unavailable> " , var_name ) ;
2012-01-13 08:39:16 +00:00
}
if ( close_paren )
s . PutCString ( close_paren ) ;
else
s . PutChar ( ' ) ' ) ;
}
else
{
s . PutCString ( cstr ) ;
}
}
}
else if ( sc - > symbol )
{
cstr = sc - > symbol - > GetName ( ) . AsCString ( NULL ) ;
if ( cstr )
{
s . PutCString ( cstr ) ;
var_success = true ;
}
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " addr-offset} " ) )
2010-09-19 02:33:57 +00:00
{
var_success = addr ! = NULL ;
if ( var_success )
{
format_addr = * addr ;
calculate_format_addr_function_offset = true ;
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " line-offset} " ) )
2010-09-19 02:33:57 +00:00
{
var_success = sc - > line_entry . range . GetBaseAddress ( ) . IsValid ( ) ;
if ( var_success )
{
format_addr = sc - > line_entry . range . GetBaseAddress ( ) ;
calculate_format_addr_function_offset = true ;
}
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " pc-offset} " ) )
2010-09-19 02:33:57 +00:00
{
2013-11-04 09:33:30 +00:00
StackFrame * frame = exe_ctx - > GetFramePtr ( ) ;
2011-09-22 04:58:26 +00:00
var_success = frame ! = NULL ;
2010-09-19 02:33:57 +00:00
if ( var_success )
{
2011-09-22 04:58:26 +00:00
format_addr = frame - > GetFrameCodeAddress ( ) ;
2010-09-19 02:33:57 +00:00
calculate_format_addr_function_offset = true ;
}
}
}
}
break ;
case ' l ' :
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " line. " ) )
2010-09-19 02:33:57 +00:00
{
if ( sc & & sc - > line_entry . IsValid ( ) )
{
var_name_begin + = : : strlen ( " line. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " file. " ) )
2010-09-19 02:33:57 +00:00
{
var_name_begin + = : : strlen ( " file. " ) ;
2013-07-30 16:44:36 +00:00
if ( IsToken ( var_name_begin , " basename} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec . GetFilename ( ) = sc - > line_entry . file . GetFilename ( ) ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( IsToken ( var_name_begin , " fullpath} " ) )
2010-09-19 02:33:57 +00:00
{
format_file_spec = sc - > line_entry . file ;
2013-10-04 21:35:29 +00:00
var_success = ( bool ) format_file_spec ;
2010-09-19 02:33:57 +00:00
}
}
2013-07-30 16:44:36 +00:00
else if ( IsTokenWithFormat ( var_name_begin , " number " , token_format , " % " PRIu64 , exe_ctx , sc ) )
2010-09-19 02:33:57 +00:00
{
var_success = true ;
2013-07-30 16:44:36 +00:00
s . Printf ( token_format . c_str ( ) , ( uint64_t ) sc - > line_entry . line ) ;
2010-09-19 02:33:57 +00:00
}
2013-07-30 16:44:36 +00:00
else if ( ( IsToken ( var_name_begin , " start-addr} " ) ) | |
( IsToken ( var_name_begin , " end-addr} " ) ) )
2010-09-19 02:33:57 +00:00
{
var_success = sc & & sc - > line_entry . range . GetBaseAddress ( ) . IsValid ( ) ;
if ( var_success )
{
format_addr = sc - > line_entry . range . GetBaseAddress ( ) ;
if ( var_name_begin [ 0 ] = = ' e ' )
format_addr . Slide ( sc - > line_entry . range . GetByteSize ( ) ) ;
}
}
}
}
break ;
}
if ( var_success )
{
// If format addr is valid, then we need to print an address
if ( reg_num ! = LLDB_INVALID_REGNUM )
{
2013-11-04 09:33:30 +00:00
StackFrame * frame = exe_ctx - > GetFramePtr ( ) ;
2010-09-19 02:33:57 +00:00
// We have a register value to display...
if ( reg_num = = LLDB_REGNUM_GENERIC_PC & & reg_kind = = eRegisterKindGeneric )
{
2011-09-22 04:58:26 +00:00
format_addr = frame - > GetFrameCodeAddress ( ) ;
2010-09-19 02:33:57 +00:00
}
else
{
if ( reg_ctx = = NULL )
2011-09-22 04:58:26 +00:00
reg_ctx = frame - > GetRegisterContext ( ) . get ( ) ;
2010-09-19 02:33:57 +00:00
if ( reg_ctx )
{
if ( reg_kind ! = kNumRegisterKinds )
reg_num = reg_ctx - > ConvertRegisterKindToRegisterNumber ( reg_kind , reg_num ) ;
reg_info = reg_ctx - > GetRegisterInfoAtIndex ( reg_num ) ;
var_success = reg_info ! = NULL ;
}
}
}
if ( reg_info ! = NULL )
{
2011-05-09 20:18:18 +00:00
RegisterValue reg_value ;
var_success = reg_ctx - > ReadRegister ( reg_info , reg_value ) ;
if ( var_success )
2010-09-19 02:33:57 +00:00
{
2011-05-15 04:12:07 +00:00
reg_value . Dump ( & s , reg_info , false , false , eFormatDefault ) ;
2010-09-19 02:33:57 +00:00
}
}
if ( format_file_spec )
{
s < < format_file_spec ;
}
// If format addr is valid, then we need to print an address
if ( format_addr . IsValid ( ) )
{
2010-10-04 01:05:56 +00:00
var_success = false ;
2010-09-19 02:33:57 +00:00
if ( calculate_format_addr_function_offset )
{
Address func_addr ;
2010-10-04 01:05:56 +00:00
if ( sc )
{
if ( sc - > function )
2010-10-04 17:26:49 +00:00
{
2010-10-04 01:05:56 +00:00
func_addr = sc - > function - > GetAddressRange ( ) . GetBaseAddress ( ) ;
2010-10-04 17:26:49 +00:00
if ( sc - > block )
{
// Check to make sure we aren't in an inline
// function. If we are, use the inline block
// range that contains "format_addr" since
// blocks can be discontiguous.
Block * inline_block = sc - > block - > GetContainingInlinedBlock ( ) ;
AddressRange inline_range ;
if ( inline_block & & inline_block - > GetRangeContainingAddress ( format_addr , inline_range ) )
func_addr = inline_range . GetBaseAddress ( ) ;
}
}
2012-03-07 21:03:09 +00:00
else if ( sc - > symbol & & sc - > symbol - > ValueIsAddress ( ) )
func_addr = sc - > symbol - > GetAddress ( ) ;
2010-10-04 01:05:56 +00:00
}
if ( func_addr . IsValid ( ) )
2010-09-19 02:33:57 +00:00
{
if ( func_addr . GetSection ( ) = = format_addr . GetSection ( ) )
{
addr_t func_file_addr = func_addr . GetFileAddress ( ) ;
addr_t addr_file_addr = format_addr . GetFileAddress ( ) ;
if ( addr_file_addr > func_file_addr )
2012-11-29 21:49:15 +00:00
s . Printf ( " + % " PRIu64 , addr_file_addr - func_file_addr ) ;
2010-09-19 02:33:57 +00:00
else if ( addr_file_addr < func_file_addr )
2012-11-29 21:49:15 +00:00
s . Printf ( " - % " PRIu64 , func_file_addr - addr_file_addr ) ;
2010-10-04 01:05:56 +00:00
var_success = true ;
2010-09-19 02:33:57 +00:00
}
else
2010-10-04 01:05:56 +00:00
{
Target * target = Target : : GetTargetFromContexts ( exe_ctx , sc ) ;
if ( target )
{
addr_t func_load_addr = func_addr . GetLoadAddress ( target ) ;
addr_t addr_load_addr = format_addr . GetLoadAddress ( target ) ;
if ( addr_load_addr > func_load_addr )
2012-11-29 21:49:15 +00:00
s . Printf ( " + % " PRIu64 , addr_load_addr - func_load_addr ) ;
2010-10-04 01:05:56 +00:00
else if ( addr_load_addr < func_load_addr )
2012-11-29 21:49:15 +00:00
s . Printf ( " - % " PRIu64 , func_load_addr - addr_load_addr ) ;
2010-10-04 01:05:56 +00:00
var_success = true ;
}
}
2010-09-19 02:33:57 +00:00
}
}
else
{
2010-10-04 01:05:56 +00:00
Target * target = Target : : GetTargetFromContexts ( exe_ctx , sc ) ;
2010-09-19 02:33:57 +00:00
addr_t vaddr = LLDB_INVALID_ADDRESS ;
2010-10-04 01:05:56 +00:00
if ( exe_ctx & & ! target - > GetSectionLoadList ( ) . IsEmpty ( ) )
vaddr = format_addr . GetLoadAddress ( target ) ;
2010-09-19 02:33:57 +00:00
if ( vaddr = = LLDB_INVALID_ADDRESS )
vaddr = format_addr . GetFileAddress ( ) ;
if ( vaddr ! = LLDB_INVALID_ADDRESS )
2010-10-04 01:05:56 +00:00
{
2011-02-15 21:59:32 +00:00
int addr_width = target - > GetArchitecture ( ) . GetAddressByteSize ( ) * 2 ;
2010-11-19 04:16:11 +00:00
if ( addr_width = = 0 )
addr_width = 16 ;
2012-11-29 21:49:15 +00:00
s . Printf ( " 0x%*.* " PRIx64 , addr_width , addr_width , vaddr ) ;
2010-10-04 01:05:56 +00:00
var_success = true ;
}
2010-09-19 02:33:57 +00:00
}
}
}
if ( var_success = = false )
success = false ;
}
p = var_name_end ;
}
else
break ;
}
else
{
// We got a dollar sign with no '{' after it, it must just be a dollar sign
s . PutChar ( * p ) ;
}
}
else if ( * p = = ' \\ ' )
{
+ + p ; // skip the slash
switch ( * p )
{
case ' a ' : s . PutChar ( ' \a ' ) ; break ;
case ' b ' : s . PutChar ( ' \b ' ) ; break ;
case ' f ' : s . PutChar ( ' \f ' ) ; break ;
case ' n ' : s . PutChar ( ' \n ' ) ; break ;
case ' r ' : s . PutChar ( ' \r ' ) ; break ;
case ' t ' : s . PutChar ( ' \t ' ) ; break ;
case ' v ' : s . PutChar ( ' \v ' ) ; break ;
case ' \' ' : s . PutChar ( ' \' ' ) ; break ;
case ' \\ ' : s . PutChar ( ' \\ ' ) ; break ;
case ' 0 ' :
// 1 to 3 octal chars
{
2010-10-04 01:05:56 +00:00
// Make a string that can hold onto the initial zero char,
// up to 3 octal digits, and a terminating NULL.
char oct_str [ 5 ] = { 0 , 0 , 0 , 0 , 0 } ;
int i ;
for ( i = 0 ; ( p [ i ] > = ' 0 ' & & p [ i ] < = ' 7 ' ) & & i < 4 ; + + i )
oct_str [ i ] = p [ i ] ;
// We don't want to consume the last octal character since
// the main for loop will do this for us, so we advance p by
// one less than i (even if i is zero)
p + = i - 1 ;
unsigned long octal_value = : : strtoul ( oct_str , NULL , 8 ) ;
if ( octal_value < = UINT8_MAX )
2010-09-19 02:33:57 +00:00
{
2013-01-25 18:06:21 +00:00
s . PutChar ( ( char ) octal_value ) ;
2010-09-19 02:33:57 +00:00
}
}
break ;
case ' x ' :
// hex number in the format
2010-10-04 01:05:56 +00:00
if ( isxdigit ( p [ 1 ] ) )
2010-09-19 02:33:57 +00:00
{
2010-10-04 01:05:56 +00:00
+ + p ; // Skip the 'x'
2010-09-19 02:33:57 +00:00
2010-10-04 01:05:56 +00:00
// Make a string that can hold onto two hex chars plus a
// NULL terminator
char hex_str [ 3 ] = { 0 , 0 , 0 } ;
hex_str [ 0 ] = * p ;
if ( isxdigit ( p [ 1 ] ) )
2010-09-19 02:33:57 +00:00
{
2010-10-04 01:05:56 +00:00
+ + p ; // Skip the first of the two hex chars
hex_str [ 1 ] = * p ;
}
unsigned long hex_value = strtoul ( hex_str , NULL , 16 ) ;
if ( hex_value < = UINT8_MAX )
2013-01-25 18:06:21 +00:00
s . PutChar ( ( char ) hex_value ) ;
2010-10-04 01:05:56 +00:00
}
else
{
s . PutChar ( ' x ' ) ;
2010-09-19 02:33:57 +00:00
}
break ;
default :
2010-10-04 01:05:56 +00:00
// Just desensitize any other character by just printing what
// came after the '\'
s < < * p ;
2010-09-19 02:33:57 +00:00
break ;
}
}
}
if ( end )
* end = p ;
return success ;
}
2013-05-23 20:47:45 +00:00
bool
Debugger : : FormatPrompt
(
const char * format ,
const SymbolContext * sc ,
const ExecutionContext * exe_ctx ,
const Address * addr ,
Stream & s ,
ValueObject * valobj
)
{
bool use_color = exe_ctx ? exe_ctx - > GetTargetRef ( ) . GetDebugger ( ) . GetUseColor ( ) : true ;
std : : string format_str = lldb_utility : : ansi : : FormatAnsiTerminalCodes ( format , use_color ) ;
if ( format_str . length ( ) )
format = format_str . c_str ( ) ;
return FormatPromptRecurse ( format , sc , exe_ctx , addr , s , NULL , valobj ) ;
}
2012-02-21 02:23:08 +00:00
void
Debugger : : SetLoggingCallback ( lldb : : LogOutputCallback log_callback , void * baton )
{
2012-02-22 22:49:20 +00:00
// 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.
2012-02-21 02:23:08 +00:00
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 ;
2012-08-09 00:50:26 +00:00
if ( m_log_callback_stream_sp )
2012-02-21 02:23:08 +00:00
{
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-01-27 23:43:24 +00:00
log_stream_sp = GetOutputFile ( ) ;
2012-02-21 02:23:08 +00:00
}
else
{
LogStreamMap : : iterator pos = m_log_streams . find ( log_file ) ;
2013-01-08 00:01:36 +00:00
if ( pos ! = m_log_streams . end ( ) )
log_stream_sp = pos - > second . lock ( ) ;
if ( ! log_stream_sp )
2012-02-21 02:23:08 +00:00
{
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 ;
2013-05-10 21:47:16 +00:00
if ( Log : : GetLogChannelCallbacks ( ConstString ( channel ) , log_callbacks ) )
2012-02-21 02:23:08 +00:00
{
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 ;
}
2013-03-19 00:20:55 +00:00
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-01-27 23:43:24 +00: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 ;
}
// 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 ( ) ) ;
2014-02-28 18:22:24 +00:00
StreamString output_stream ;
StreamString error_stream ;
2014-01-27 23:43:24 +00:00
const bool gui_enabled = IsForwardingEvents ( ) ;
2014-02-28 18:22:24 +00:00
if ( ! gui_enabled )
{
bool pop_process_io_handler = false ;
assert ( process_sp ) ;
2014-01-27 23:43:24 +00:00
2014-02-28 18:22:24 +00:00
if ( event_type & Process : : eBroadcastBitSTDOUT | | event_type & Process : : eBroadcastBitStateChanged )
2014-01-27 23:43:24 +00:00
{
2014-02-28 18:22:24 +00:00
GetProcessSTDOUT ( process_sp . get ( ) , & output_stream ) ;
}
if ( event_type & Process : : eBroadcastBitSTDERR | | event_type & Process : : eBroadcastBitStateChanged )
{
GetProcessSTDERR ( process_sp . get ( ) , & error_stream ) ;
}
if ( event_type & Process : : eBroadcastBitStateChanged )
{
// Drain all stout and stderr so we don't see any output come after
// we print our prompts
2014-01-27 23:43:24 +00:00
// Something changed in the process; get the event and report the process's current status and location to
// the user.
StateType event_state = Process : : ProcessEventData : : GetStateFromEvent ( event_sp . get ( ) ) ;
if ( event_state = = eStateInvalid )
return ;
switch ( event_state )
{
case eStateInvalid :
case eStateUnloaded :
case eStateConnected :
case eStateAttaching :
case eStateLaunching :
case eStateStepping :
case eStateDetached :
{
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " Process % " PRIu64 " %s \n " ,
process_sp - > GetID ( ) ,
StateAsCString ( event_state ) ) ;
if ( event_state = = eStateDetached )
pop_process_io_handler = true ;
2014-01-27 23:43:24 +00:00
}
break ;
case eStateRunning :
// Don't be chatty when we run...
break ;
case eStateExited :
2014-02-28 18:22:24 +00:00
process_sp - > GetStatus ( output_stream ) ;
pop_process_io_handler = true ;
2014-01-27 23:43:24 +00:00
break ;
case eStateStopped :
case eStateCrashed :
case eStateSuspended :
// Make sure the program hasn't been auto-restarted:
if ( Process : : ProcessEventData : : GetRestartedFromEvent ( event_sp . get ( ) ) )
{
size_t num_reasons = Process : : ProcessEventData : : GetNumRestartedReasons ( event_sp . get ( ) ) ;
if ( num_reasons > 0 )
{
// FIXME: Do we want to report this, or would that just be annoyingly chatty?
if ( num_reasons = = 1 )
{
const char * reason = Process : : ProcessEventData : : GetRestartedReasonAtIndex ( event_sp . get ( ) , 0 ) ;
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " Process % " PRIu64 " stopped and restarted: %s \n " ,
process_sp - > GetID ( ) ,
reason ? reason : " <UNKNOWN REASON> " ) ;
2014-01-27 23:43:24 +00:00
}
else
{
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " Process % " PRIu64 " stopped and restarted, reasons: \n " ,
process_sp - > GetID ( ) ) ;
2014-01-27 23:43:24 +00:00
for ( size_t i = 0 ; i < num_reasons ; i + + )
{
const char * reason = Process : : ProcessEventData : : GetRestartedReasonAtIndex ( event_sp . get ( ) , i ) ;
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " \t %s \n " , reason ? reason : " <UNKNOWN REASON> " ) ;
2014-01-27 23:43:24 +00:00
}
}
}
}
else
{
2014-03-07 11:20:03 +00:00
// Lock the thread list so it doesn't change on us, this is the scope for the locker:
2014-01-27 23:43:24 +00:00
{
2014-03-07 11:20:03 +00:00
ThreadList & thread_list = process_sp - > GetThreadList ( ) ;
Mutex : : Locker locker ( thread_list . GetMutex ( ) ) ;
ThreadSP curr_thread ( thread_list . GetSelectedThread ( ) ) ;
ThreadSP thread ;
StopReason curr_thread_stop_reason = eStopReasonInvalid ;
if ( curr_thread )
curr_thread_stop_reason = curr_thread - > GetStopReason ( ) ;
if ( ! curr_thread | |
! curr_thread - > IsValid ( ) | |
curr_thread_stop_reason = = eStopReasonInvalid | |
curr_thread_stop_reason = = eStopReasonNone )
2014-01-27 23:43:24 +00:00
{
2014-03-07 11:20:03 +00:00
// Prefer a thread that has just completed its plan over another thread as current thread.
ThreadSP plan_thread ;
ThreadSP other_thread ;
const size_t num_threads = thread_list . GetSize ( ) ;
size_t i ;
for ( i = 0 ; i < num_threads ; + + i )
2014-01-27 23:43:24 +00:00
{
2014-03-07 11:20:03 +00:00
thread = thread_list . GetThreadAtIndex ( i ) ;
StopReason thread_stop_reason = thread - > GetStopReason ( ) ;
switch ( thread_stop_reason )
{
case eStopReasonInvalid :
case eStopReasonNone :
break ;
case eStopReasonTrace :
case eStopReasonBreakpoint :
case eStopReasonWatchpoint :
case eStopReasonSignal :
case eStopReasonException :
case eStopReasonExec :
case eStopReasonThreadExiting :
if ( ! other_thread )
other_thread = thread ;
break ;
case eStopReasonPlanComplete :
if ( ! plan_thread )
plan_thread = thread ;
break ;
}
}
if ( plan_thread )
thread_list . SetSelectedThreadByID ( plan_thread - > GetID ( ) ) ;
else if ( other_thread )
thread_list . SetSelectedThreadByID ( other_thread - > GetID ( ) ) ;
else
{
if ( curr_thread & & curr_thread - > IsValid ( ) )
thread = curr_thread ;
else
thread = thread_list . GetThreadAtIndex ( 0 ) ;
if ( thread )
thread_list . SetSelectedThreadByID ( thread - > GetID ( ) ) ;
2014-01-27 23:43:24 +00:00
}
}
}
2014-03-07 11:20:03 +00:00
// Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
// e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
// have a hard time restarting the process.
2014-01-27 23:43:24 +00:00
if ( GetTargetList ( ) . GetSelectedTarget ( ) . get ( ) = = & process_sp - > GetTarget ( ) )
{
const bool only_threads_with_stop_reason = true ;
const uint32_t start_frame = 0 ;
const uint32_t num_frames = 1 ;
const uint32_t num_frames_with_source = 1 ;
2014-02-28 18:22:24 +00:00
process_sp - > GetStatus ( output_stream ) ;
process_sp - > GetThreadStatus ( output_stream ,
2014-01-27 23:43:24 +00:00
only_threads_with_stop_reason ,
start_frame ,
num_frames ,
num_frames_with_source ) ;
}
else
{
uint32_t target_idx = GetTargetList ( ) . GetIndexOfTarget ( process_sp - > GetTarget ( ) . shared_from_this ( ) ) ;
if ( target_idx ! = UINT32_MAX )
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " Target %d: ( " , target_idx ) ;
2014-01-27 23:43:24 +00:00
else
2014-02-28 18:22:24 +00:00
output_stream . Printf ( " Target <unknown index>: ( " ) ;
process_sp - > GetTarget ( ) . Dump ( & output_stream , eDescriptionLevelBrief ) ;
output_stream . Printf ( " ) stopped. \n " ) ;
2014-01-27 23:43:24 +00:00
}
2014-02-28 18:22:24 +00:00
// Pop the process IO handler
pop_process_io_handler = true ;
2014-01-27 23:43:24 +00:00
}
break ;
}
}
2014-02-28 18:22:24 +00:00
if ( output_stream . GetSize ( ) | | error_stream . GetSize ( ) )
{
StreamFileSP error_stream_sp ( GetOutputFile ( ) ) ;
2014-03-03 19:15:20 +00:00
bool top_io_handler_hid = false ;
if ( process_sp - > ProcessIOHandlerIsActive ( ) = = false )
top_io_handler_hid = HideTopIOHandler ( ) ;
2014-02-28 18:22:24 +00:00
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-01-27 23:43:24 +00: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 ) ;
bool done = false ;
while ( ! done )
{
// Mutex::Locker locker;
// if (locker.TryLock(m_input_reader_stack.GetMutex()))
// {
// if (m_input_reader_stack.IsEmpty())
// break;
// }
//
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 ( )
{
2014-09-09 20:54:56 +00:00
if ( m_event_handler_thread . GetState ( ) ! = eThreadStateRunning )
m_event_handler_thread = ThreadLauncher : : LaunchThread ( " lldb.debugger.event-handler " , EventHandlerThread , this , NULL ) ;
return m_event_handler_thread . GetState ( ) = = eThreadStateRunning ;
2014-01-27 23:43:24 +00:00
}
void
Debugger : : StopEventHandlerThread ( )
{
2014-09-09 20:54:56 +00:00
if ( m_event_handler_thread . GetState ( ) = = eThreadStateRunning )
2014-01-27 23:43:24 +00:00
{
GetCommandInterpreter ( ) . BroadcastEvent ( CommandInterpreter : : eBroadcastBitQuitCommandReceived ) ;
2014-09-09 20:54:56 +00:00
m_event_handler_thread . Join ( nullptr ) ;
m_event_handler_thread . Reset ( ) ;
2014-01-27 23:43:24 +00: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 ( )
{
2014-09-09 20:54:56 +00:00
if ( m_io_handler_thread . GetState ( ) ! = eThreadStateRunning )
m_io_handler_thread = ThreadLauncher : : LaunchThread ( " lldb.debugger.io-handler " , IOHandlerThread , this , NULL ) ;
return m_io_handler_thread . GetState ( ) = = eThreadStateRunning ;
2014-01-27 23:43:24 +00:00
}
void
Debugger : : StopIOHandlerThread ( )
{
2014-09-09 20:54:56 +00:00
if ( m_io_handler_thread . GetState ( ) = = eThreadStateRunning )
2014-01-27 23:43:24 +00:00
{
if ( m_input_file_sp )
m_input_file_sp - > GetFile ( ) . Close ( ) ;
2014-09-09 20:54:56 +00:00
m_io_handler_thread . Join ( nullptr ) ;
m_io_handler_thread . Reset ( ) ;
2014-01-27 23:43:24 +00:00
}
}