diff options
author | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2015-07-03 16:57:06 +0000 |
commit | 5e95aa85bb660d45e9905ef1d7180b2678280660 (patch) | |
tree | 3c2e41c3be19b7fc7666ed45a5f91ec3b6e35f2a /source | |
parent | 12bd4897ff0678fa663e09d78ebc22dd255ceb86 (diff) | |
download | src-5e95aa85bb660d45e9905ef1d7180b2678280660.tar.gz src-5e95aa85bb660d45e9905ef1d7180b2678280660.zip |
Import LLDB as of upstream SVN 241361 (git 612c075f)vendor/lldb/lldb-r241361
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=285101
svn path=/vendor/lldb/lldb-r241361/; revision=285102; tag=vendor/lldb/lldb-r241361
Diffstat (limited to 'source')
443 files changed, 46348 insertions, 19605 deletions
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp index d6e32b60059b..f95fcb8b3985 100644 --- a/source/API/SBAddress.cpp +++ b/source/API/SBAddress.cpp @@ -14,7 +14,9 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Core/StreamString.h" #include "lldb/Host/Mutex.h" +#include "lldb/Symbol/LineEntry.h" #include "lldb/Target/Target.h" diff --git a/source/API/SBAttachInfo.cpp b/source/API/SBAttachInfo.cpp new file mode 100644 index 000000000000..07446df27dff --- /dev/null +++ b/source/API/SBAttachInfo.cpp @@ -0,0 +1,242 @@ +//===-- SBAttachInfo.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBAttachInfo.h" + +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBListener.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + + +SBAttachInfo::SBAttachInfo () : + m_opaque_sp (new ProcessAttachInfo()) +{ +} + +SBAttachInfo::SBAttachInfo (lldb::pid_t pid) : + m_opaque_sp (new ProcessAttachInfo()) +{ + m_opaque_sp->SetProcessID (pid); +} + +SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) : + m_opaque_sp (new ProcessAttachInfo()) +{ + if (path && path[0]) + m_opaque_sp->GetExecutableFile().SetFile(path, false); + m_opaque_sp->SetWaitForLaunch (wait_for); +} + +SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) : + m_opaque_sp (new ProcessAttachInfo()) +{ + *m_opaque_sp = *rhs.m_opaque_sp; +} + +SBAttachInfo::~SBAttachInfo() +{ +} + +lldb_private::ProcessAttachInfo & +SBAttachInfo::ref () +{ + return *m_opaque_sp; +} + +SBAttachInfo & +SBAttachInfo::operator = (const SBAttachInfo &rhs) +{ + if (this != &rhs) + *m_opaque_sp = *rhs.m_opaque_sp; + return *this; +} + +lldb::pid_t +SBAttachInfo::GetProcessID () +{ + return m_opaque_sp->GetProcessID(); +} + +void +SBAttachInfo::SetProcessID (lldb::pid_t pid) +{ + m_opaque_sp->SetProcessID (pid); +} + + +uint32_t +SBAttachInfo::GetResumeCount () +{ + return m_opaque_sp->GetResumeCount(); +} + +void +SBAttachInfo::SetResumeCount (uint32_t c) +{ + m_opaque_sp->SetResumeCount (c); +} + +const char * +SBAttachInfo::GetProcessPluginName () +{ + return m_opaque_sp->GetProcessPluginName(); +} + +void +SBAttachInfo::SetProcessPluginName (const char *plugin_name) +{ + return m_opaque_sp->SetProcessPluginName (plugin_name); +} + +void +SBAttachInfo::SetExecutable (const char *path) +{ + if (path && path[0]) + m_opaque_sp->GetExecutableFile().SetFile(path, false); + else + m_opaque_sp->GetExecutableFile().Clear(); +} + +void +SBAttachInfo::SetExecutable (SBFileSpec exe_file) +{ + if (exe_file.IsValid()) + m_opaque_sp->GetExecutableFile() = exe_file.ref(); + else + m_opaque_sp->GetExecutableFile().Clear(); +} + +bool +SBAttachInfo::GetWaitForLaunch () +{ + return m_opaque_sp->GetWaitForLaunch(); +} + +void +SBAttachInfo::SetWaitForLaunch (bool b) +{ + m_opaque_sp->SetWaitForLaunch (b); +} + +bool +SBAttachInfo::GetIgnoreExisting () +{ + return m_opaque_sp->GetIgnoreExisting(); +} + +void +SBAttachInfo::SetIgnoreExisting (bool b) +{ + m_opaque_sp->SetIgnoreExisting (b); +} + +uint32_t +SBAttachInfo::GetUserID() +{ + return m_opaque_sp->GetUserID(); +} + +uint32_t +SBAttachInfo::GetGroupID() +{ + return m_opaque_sp->GetGroupID(); +} + +bool +SBAttachInfo::UserIDIsValid () +{ + return m_opaque_sp->UserIDIsValid(); +} + +bool +SBAttachInfo::GroupIDIsValid () +{ + return m_opaque_sp->GroupIDIsValid(); +} + +void +SBAttachInfo::SetUserID (uint32_t uid) +{ + m_opaque_sp->SetUserID (uid); +} + +void +SBAttachInfo::SetGroupID (uint32_t gid) +{ + m_opaque_sp->SetGroupID (gid); +} + +uint32_t +SBAttachInfo::GetEffectiveUserID() +{ + return m_opaque_sp->GetEffectiveUserID(); +} + +uint32_t +SBAttachInfo::GetEffectiveGroupID() +{ + return m_opaque_sp->GetEffectiveGroupID(); +} + +bool +SBAttachInfo::EffectiveUserIDIsValid () +{ + return m_opaque_sp->EffectiveUserIDIsValid(); +} + +bool +SBAttachInfo::EffectiveGroupIDIsValid () +{ + return m_opaque_sp->EffectiveGroupIDIsValid (); +} + +void +SBAttachInfo::SetEffectiveUserID (uint32_t uid) +{ + m_opaque_sp->SetEffectiveUserID(uid); +} + +void +SBAttachInfo::SetEffectiveGroupID (uint32_t gid) +{ + m_opaque_sp->SetEffectiveGroupID(gid); +} + +lldb::pid_t +SBAttachInfo::GetParentProcessID () +{ + return m_opaque_sp->GetParentProcessID(); +} + +void +SBAttachInfo::SetParentProcessID (lldb::pid_t pid) +{ + m_opaque_sp->SetParentProcessID (pid); +} + +bool +SBAttachInfo::ParentProcessIDIsValid() +{ + return m_opaque_sp->ParentProcessIDIsValid(); +} + +SBListener +SBAttachInfo::GetListener () +{ + return SBListener(m_opaque_sp->GetListener()); +} + +void +SBAttachInfo::SetListener (SBListener &listener) +{ + m_opaque_sp->SetListener(listener.GetSP()); +} diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp index 193d06e4d920..d901e728105b 100644 --- a/source/API/SBCommandInterpreter.cpp +++ b/source/API/SBCommandInterpreter.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/lldb-types.h" #include "lldb/Core/SourceManager.h" #include "lldb/Core/Listener.h" @@ -20,6 +18,7 @@ #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBEvent.h" #include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBTarget.h" @@ -446,6 +445,37 @@ SBCommandInterpreter::GetDebugger () return sb_debugger; } +bool +SBCommandInterpreter::GetPromptOnQuit() +{ + if (m_opaque_ptr) + return m_opaque_ptr->GetPromptOnQuit(); + return false; +} + +void +SBCommandInterpreter::SetPromptOnQuit (bool b) +{ + if (m_opaque_ptr) + m_opaque_ptr->SetPromptOnQuit(b); +} + +void +SBCommandInterpreter::ResolveCommand(const char *command_line, SBCommandReturnObject &result) +{ + result.Clear(); + if (command_line && m_opaque_ptr) + { + m_opaque_ptr->ResolveCommand(command_line, result.ref()); + } + else + { + result->AppendError("SBCommandInterpreter or the command line is not valid"); + result->SetStatus(eReturnStatusFailed); + } +} + + CommandInterpreter * SBCommandInterpreter::get () { @@ -532,7 +562,7 @@ SBCommandInterpreter::GetBroadcaster () const char * SBCommandInterpreter::GetBroadcasterClass () { - return Communication::GetStaticBroadcasterClass().AsCString(); + return CommandInterpreter::GetStaticBroadcasterClass().AsCString(); } const char * @@ -548,6 +578,12 @@ SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgume } bool +SBCommandInterpreter::EventIsCommandInterpreterEvent (const lldb::SBEvent &event) +{ + return event.GetBroadcasterClass() == SBCommandInterpreter::GetBroadcasterClass(); +} + +bool SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name, lldb::CommandOverrideCallback callback, void *baton) @@ -566,170 +602,6 @@ SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name, return false; } -#ifndef LLDB_DISABLE_PYTHON - -// Defined in the SWIG source file -extern "C" void -init_lldb(void); - -// these are the Pythonic implementations of the required callbacks -// these are scripting-language specific, which is why they belong here -// we still need to use function pointers to them instead of relying -// on linkage-time resolution because the SWIG stuff and this file -// get built at different times -extern "C" bool -LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& sb_frame, - const lldb::BreakpointLocationSP& sb_bp_loc); - -extern "C" bool -LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name, - const char *session_dictionary_name, - const lldb::StackFrameSP& sb_frame, - const lldb::WatchpointSP& sb_wp); - -extern "C" bool -LLDBSwigPythonCallTypeScript (const char *python_function_name, - void *session_dictionary, - const lldb::ValueObjectSP& valobj_sp, - void** pyfunct_wrapper, - const lldb::TypeSummaryOptionsSP& options_sp, - std::string& retval); - -extern "C" void* -LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ValueObjectSP& valobj_sp); - - -extern "C" void* -LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ThreadPlanSP& thread_plan_sp); - -extern "C" bool -LLDBSWIGPythonCallThreadPlan (void *implementor, - const char *method_name, - Event *event_sp, - bool &got_error); - -extern "C" uint32_t -LLDBSwigPython_CalculateNumChildren (void *implementor); - -extern "C" void * -LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx); - -extern "C" int -LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name); - -extern "C" void * -LLDBSWIGPython_CastPyObjectToSBValue (void* data); - -extern lldb::ValueObjectSP -LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data); - -extern "C" bool -LLDBSwigPython_UpdateSynthProviderInstance (void* implementor); - -extern "C" bool -LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor); - -extern "C" void * -LLDBSwigPython_GetValueSynthProviderInstance (void* implementor); - -extern "C" bool -LLDBSwigPythonCallCommand (const char *python_function_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger, - const char* args, - lldb_private::CommandReturnObject &cmd_retobj, - lldb::ExecutionContextRefSP exe_ctx_ref_sp); - -extern "C" bool -LLDBSwigPythonCallModuleInit (const char *python_module_name, - const char *session_dictionary_name, - lldb::DebuggerSP& debugger); - -extern "C" void* -LLDBSWIGPythonCreateOSPlugin (const char *python_class_name, - const char *session_dictionary_name, - const lldb::ProcessSP& process_sp); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name, - const char* session_dictionary_name, - lldb::ProcessSP& process, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name, - const char* session_dictionary_name, - lldb::ThreadSP& thread, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name, - const char* session_dictionary_name, - lldb::TargetSP& target, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name, - const char* session_dictionary_name, - lldb::StackFrameSP& frame, - std::string& output); - -extern "C" bool -LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name, - const char* session_dictionary_name, - lldb::ValueObjectSP& value, - std::string& output); - -extern "C" void* -LLDBSWIGPython_GetDynamicSetting (void* module, - const char* setting, - const lldb::TargetSP& target_sp); - - -#endif - -void -SBCommandInterpreter::InitializeSWIG () -{ - static bool g_initialized = false; - if (!g_initialized) - { - g_initialized = true; -#ifndef LLDB_DISABLE_PYTHON - ScriptInterpreter::InitializeInterpreter (init_lldb, - LLDBSwigPythonBreakpointCallbackFunction, - LLDBSwigPythonWatchpointCallbackFunction, - LLDBSwigPythonCallTypeScript, - LLDBSwigPythonCreateSyntheticProvider, - LLDBSwigPython_CalculateNumChildren, - LLDBSwigPython_GetChildAtIndex, - LLDBSwigPython_GetIndexOfChildWithName, - LLDBSWIGPython_CastPyObjectToSBValue, - LLDBSWIGPython_GetValueObjectSPFromSBValue, - LLDBSwigPython_UpdateSynthProviderInstance, - LLDBSwigPython_MightHaveChildrenSynthProviderInstance, - LLDBSwigPython_GetValueSynthProviderInstance, - LLDBSwigPythonCallCommand, - LLDBSwigPythonCallModuleInit, - LLDBSWIGPythonCreateOSPlugin, - LLDBSWIGPythonRunScriptKeywordProcess, - LLDBSWIGPythonRunScriptKeywordThread, - LLDBSWIGPythonRunScriptKeywordTarget, - LLDBSWIGPythonRunScriptKeywordFrame, - LLDBSWIGPythonRunScriptKeywordValue, - LLDBSWIGPython_GetDynamicSetting, - LLDBSwigPythonCreateScriptedThreadPlan, - LLDBSWIGPythonCallThreadPlan); -#endif - } -} - lldb::SBCommand SBCommandInterpreter::AddMultiwordCommand (const char* name, const char* help) { @@ -780,6 +652,28 @@ SBCommand::GetHelp () return NULL; } +const char* +SBCommand::GetHelpLong () +{ + if (IsValid ()) + return m_opaque_sp->GetHelpLong (); + return NULL; +} + +void +SBCommand::SetHelp (const char* help) +{ + if (IsValid()) + m_opaque_sp->SetHelp(help); +} + +void +SBCommand::SetHelpLong (const char* help) +{ + if (IsValid()) + m_opaque_sp->SetHelpLong(help); +} + lldb::SBCommand SBCommand::AddMultiwordCommand (const char* name, const char* help) { @@ -809,3 +703,17 @@ SBCommand::AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, c return lldb::SBCommand(); } +uint32_t +SBCommand::GetFlags () +{ + if (!IsValid()) + return 0; + return m_opaque_sp->GetFlags().Get(); +} + +void +SBCommand::SetFlags (uint32_t flags) +{ + if (IsValid()) + m_opaque_sp->GetFlags().Set(flags); +} diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp index a95f2ffc06d9..df2019f5a46b 100644 --- a/source/API/SBDebugger.cpp +++ b/source/API/SBDebugger.cpp @@ -7,12 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBDebugger.h" #include "lldb/lldb-private.h" +#include "lldb/API/SystemInitializerFull.h" #include "lldb/API/SBListener.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" @@ -33,46 +32,24 @@ #include "lldb/API/SBTypeSummary.h" #include "lldb/API/SBTypeSynthetic.h" - #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/OptionGroupPlatform.h" #include "lldb/Target/Process.h" #include "lldb/Target/TargetList.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/DynamicLibrary.h" using namespace lldb; using namespace lldb_private; -SBInputReader::SBInputReader() -{ -} -SBInputReader::~SBInputReader() -{ -} - -SBError -SBInputReader::Initialize(lldb::SBDebugger& sb_debugger, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool) -{ - return SBError(); -} - -void -SBInputReader::SetIsDone(bool) -{ -} -bool -SBInputReader::IsActive() const -{ - return false; -} - static llvm::sys::DynamicLibrary LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error) { @@ -107,6 +84,34 @@ LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& er return llvm::sys::DynamicLibrary(); } +static llvm::ManagedStatic<SystemLifetimeManager> g_debugger_lifetime; + +SBInputReader::SBInputReader() +{ +} +SBInputReader::~SBInputReader() +{ +} + +SBError +SBInputReader::Initialize(lldb::SBDebugger &sb_debugger, + unsigned long (*)(void *, lldb::SBInputReader *, lldb::InputReaderAction, char const *, + unsigned long), + void *, lldb::InputReaderGranularity, char const *, char const *, bool) +{ + return SBError(); +} + +void +SBInputReader::SetIsDone(bool) +{ +} +bool +SBInputReader::IsActive() const +{ + return false; +} + void SBDebugger::Initialize () { @@ -115,15 +120,13 @@ SBDebugger::Initialize () if (log) log->Printf ("SBDebugger::Initialize ()"); - SBCommandInterpreter::InitializeSWIG (); - - Debugger::Initialize(LoadPlugin); + g_debugger_lifetime->Initialize(llvm::make_unique<SystemInitializerFull>(), LoadPlugin); } void SBDebugger::Terminate () { - Debugger::Terminate(); + g_debugger_lifetime->Terminate(); } void diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp index c62c495b87c8..164636defc9a 100644 --- a/source/API/SBEvent.cpp +++ b/source/API/SBEvent.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBEvent.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp index 448ff4cf6dd6..43b7d03064f5 100644 --- a/source/API/SBExpressionOptions.cpp +++ b/source/API/SBExpressionOptions.cpp @@ -185,6 +185,17 @@ SBExpressionOptions::SetSuppressPersistentResult (bool b) return m_opaque_ap->SetResultIsInternal (b); } +const char * +SBExpressionOptions::GetPrefix () const +{ + return m_opaque_ap->GetPrefix(); +} + +void +SBExpressionOptions::SetPrefix (const char *prefix) +{ + return m_opaque_ap->SetPrefix(prefix); +} EvaluateExpressionOptions * SBExpressionOptions::get() const diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp index 8d63fc587d81..dd7435de1b5b 100644 --- a/source/API/SBFileSpec.cpp +++ b/source/API/SBFileSpec.cpp @@ -93,9 +93,8 @@ SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len) { llvm::SmallString<64> result(src_path); lldb_private::FileSpec::Resolve (result); - size_t result_length = std::min(dst_len-1, result.size()); - ::strncpy(dst_path, result.c_str(), result_length + 1); - return result_length; + ::snprintf(dst_path, dst_len, "%s", result.c_str()); + return std::min(dst_len-1, result.size()); } const char * @@ -120,18 +119,19 @@ SBFileSpec::GetFilename() const const char * SBFileSpec::GetDirectory() const { - const char *s = m_opaque_ap->GetDirectory().AsCString(); + FileSpec directory{*m_opaque_ap}; + directory.GetFilename().Clear(); Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) { - if (s) + if (directory) log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"", - static_cast<void*>(m_opaque_ap.get()), s); + static_cast<void*>(m_opaque_ap.get()), directory.GetCString()); else log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL", static_cast<void*>(m_opaque_ap.get())); } - return s; + return directory.GetCString(); } void diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp index 325f40fd5b56..e845aef41f45 100644 --- a/source/API/SBFrame.cpp +++ b/source/API/SBFrame.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/ValueObjectRegister.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Expression/ClangPersistentVariables.h" #include "lldb/Expression/ClangUserExpression.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/Block.h" @@ -44,6 +45,7 @@ #include "lldb/API/SBStream.h" #include "lldb/API/SBSymbolContext.h" #include "lldb/API/SBThread.h" +#include "lldb/API/SBVariablesOptions.h" using namespace lldb; using namespace lldb_private; @@ -452,6 +454,17 @@ SBFrame::GetFrameID () const return frame_idx; } +lldb::addr_t +SBFrame::GetCFA () const +{ + ExecutionContext exe_ctx(m_opaque_sp.get()); + StackFrame *frame = exe_ctx.GetFramePtr(); + if (frame) + return frame->GetStackID().GetCallFrameAddress(); + return LLDB_INVALID_ADDRESS; +} + + addr_t SBFrame::GetPC () const { @@ -868,32 +881,30 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy case eValueTypeVariableArgument: // function argument variables case eValueTypeVariableLocal: // function local variables { - SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock)); + SymbolContext sc(frame->GetSymbolContext(eSymbolContextBlock)); const bool can_create = true; const bool get_parent_variables = true; const bool stop_if_block_is_inlined_function = true; - if (sc.block && sc.block->AppendVariables (can_create, - get_parent_variables, - stop_if_block_is_inlined_function, - &variable_list)) + if (sc.block) + sc.block->AppendVariables(can_create, + get_parent_variables, + stop_if_block_is_inlined_function, + &variable_list); + if (value_type == eValueTypeVariableGlobal) { - if (value_type == eValueTypeVariableGlobal) - { - const bool get_file_globals = true; - VariableList* frame_vars = frame->GetVariableList(get_file_globals); - if (frame_vars) - frame_vars->AppendVariablesIfUnique(variable_list); - } - ConstString const_name(name); - VariableSP variable_sp(variable_list.FindVariable(const_name,value_type)); - if (variable_sp) - { - value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues); - sb_value.SetSP (value_sp, use_dynamic); - break; - } + const bool get_file_globals = true; + VariableList *frame_vars = frame->GetVariableList(get_file_globals); + if (frame_vars) + frame_vars->AppendVariablesIfUnique(variable_list); + } + ConstString const_name(name); + VariableSP variable_sp(variable_list.FindVariable(const_name, value_type)); + if (variable_sp) + { + value_sp = frame->GetValueObjectForFrameVariable(variable_sp, eNoDynamicValues); + sb_value.SetSP(value_sp, use_dynamic); } } break; @@ -1075,18 +1086,44 @@ SBFrame::GetVariables (bool arguments, if (frame && target) { lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue(); - value_list = GetVariables (arguments, locals, statics, in_scope_only, use_dynamic); + const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false; + + SBVariablesOptions options; + options.SetIncludeArguments(arguments); + options.SetIncludeLocals(locals); + options.SetIncludeStatics(statics); + options.SetInScopeOnly(in_scope_only); + options.SetIncludeRuntimeSupportValues(include_runtime_support_values); + options.SetUseDynamic(use_dynamic); + + value_list = GetVariables (options); } return value_list; } -SBValueList +lldb::SBValueList SBFrame::GetVariables (bool arguments, bool locals, bool statics, bool in_scope_only, lldb::DynamicValueType use_dynamic) { + ExecutionContext exe_ctx(m_opaque_sp.get()); + Target *target = exe_ctx.GetTargetPtr(); + const bool include_runtime_support_values = target ? target->GetDisplayRuntimeSupportValues() : false; + SBVariablesOptions options; + options.SetIncludeArguments(arguments); + options.SetIncludeLocals(locals); + options.SetIncludeStatics(statics); + options.SetInScopeOnly(in_scope_only); + options.SetIncludeRuntimeSupportValues(include_runtime_support_values); + options.SetUseDynamic(use_dynamic); + return GetVariables(options); +} + +SBValueList +SBFrame::GetVariables (const lldb::SBVariablesOptions& options) +{ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBValueList value_list; @@ -1096,10 +1133,19 @@ SBFrame::GetVariables (bool arguments, StackFrame *frame = NULL; Target *target = exe_ctx.GetTargetPtr(); + const bool statics = options.GetIncludeStatics(); + const bool arguments = options.GetIncludeArguments(); + const bool locals = options.GetIncludeLocals(); + const bool in_scope_only = options.GetInScopeOnly(); + const bool include_runtime_support_values = options.GetIncludeRuntimeSupportValues(); + const lldb::DynamicValueType use_dynamic = options.GetUseDynamic(); + if (log) - log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i)", - arguments, locals, statics, in_scope_only); - + log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i runtime=%i dynamic=%i)", + arguments, locals, + statics, in_scope_only, + include_runtime_support_values, use_dynamic); + Process *process = exe_ctx.GetProcessPtr(); if (target && process) { @@ -1147,6 +1193,12 @@ SBFrame::GetVariables (bool arguments, continue; ValueObjectSP valobj_sp(frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues)); + + if (false == include_runtime_support_values && + valobj_sp && + true == valobj_sp->IsRuntimeSupportValue()) + continue; + SBValue value_sb; value_sb.SetSP(valobj_sp,use_dynamic); value_list.Append(value_sb); @@ -1449,6 +1501,12 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option bool SBFrame::IsInlined() { + return static_cast<const SBFrame*>(this)->IsInlined(); +} + +bool +SBFrame::IsInlined() const +{ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); ExecutionContext exe_ctx(m_opaque_sp.get()); StackFrame *frame = NULL; @@ -1486,6 +1544,12 @@ SBFrame::IsInlined() const char * SBFrame::GetFunctionName() { + return static_cast<const SBFrame*>(this)->GetFunctionName(); +} + +const char * +SBFrame::GetFunctionName() const +{ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); const char *name = NULL; ExecutionContext exe_ctx(m_opaque_sp.get()); @@ -1538,4 +1602,3 @@ SBFrame::GetFunctionName() } return name; } - diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp index 6158418d2f2a..36be94801863 100644 --- a/source/API/SBInstruction.cpp +++ b/source/API/SBInstruction.cpp @@ -180,7 +180,7 @@ SBInstruction::GetDescription (lldb::SBStream &s) // didn't have a stream already created, one will get created... FormatEntity::Entry format; FormatEntity::Parse("${addr}: ", format); - m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format); + m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0); return true; } return false; @@ -202,7 +202,7 @@ SBInstruction::Print (FILE *out) StreamFile out_stream (out, false); FormatEntity::Entry format; FormatEntity::Parse("${addr}: ", format); - m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format); + m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0); } } diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp index 812824b4d2e5..34b0e05079f8 100644 --- a/source/API/SBInstructionList.cpp +++ b/source/API/SBInstructionList.cpp @@ -120,7 +120,7 @@ SBInstructionList::GetDescription (lldb::SBStream &description) module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc); } - inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format); + inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format, 0); sref.EOL(); } return true; diff --git a/source/API/SBLanguageRuntime.cpp b/source/API/SBLanguageRuntime.cpp new file mode 100644 index 000000000000..93a54cd76dff --- /dev/null +++ b/source/API/SBLanguageRuntime.cpp @@ -0,0 +1,26 @@ +//===-- SBLanguageRuntime.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBLanguageRuntime.h" +#include "lldb/Target/LanguageRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +lldb::LanguageType +SBLanguageRuntime::GetLanguageTypeFromString (const char *string) +{ + return LanguageRuntime::GetLanguageTypeFromString(string); +} + +const char * +SBLanguageRuntime::GetNameForLanguageType (lldb::LanguageType language) +{ + return LanguageRuntime::GetNameForLanguageType(language); +} diff --git a/source/API/SBLaunchInfo.cpp b/source/API/SBLaunchInfo.cpp index dcb0e1b488ba..54bed8799b8b 100644 --- a/source/API/SBLaunchInfo.cpp +++ b/source/API/SBLaunchInfo.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBFileSpec.h" @@ -36,6 +34,12 @@ SBLaunchInfo::ref () return *m_opaque_sp; } +const lldb_private::ProcessLaunchInfo & +SBLaunchInfo::ref () const +{ + return *m_opaque_sp; +} + lldb::pid_t SBLaunchInfo::GetProcessID() { @@ -169,13 +173,13 @@ SBLaunchInfo::Clear () const char * SBLaunchInfo::GetWorkingDirectory () const { - return m_opaque_sp->GetWorkingDirectory(); + return m_opaque_sp->GetWorkingDirectory().GetCString(); } void SBLaunchInfo::SetWorkingDirectory (const char *working_dir) { - m_opaque_sp->SetWorkingDirectory(working_dir); + m_opaque_sp->SetWorkingDirectory(FileSpec{working_dir, false}); } uint32_t @@ -217,6 +221,18 @@ SBLaunchInfo::SetShell (const char * path) m_opaque_sp->SetShell (FileSpec(path, false)); } +bool +SBLaunchInfo::GetShellExpandArguments () +{ + return m_opaque_sp->GetShellExpandArguments(); +} + +void +SBLaunchInfo::SetShellExpandArguments (bool expand) +{ + m_opaque_sp->SetShellExpandArguments(expand); +} + uint32_t SBLaunchInfo::GetResumeCount () { @@ -244,7 +260,7 @@ SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd) bool SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write) { - return m_opaque_sp->AppendOpenFileAction(fd, path, read, write); + return m_opaque_sp->AppendOpenFileAction(fd, FileSpec{path, false}, read, write); } bool diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp index 87318739a3a4..643c82d70f78 100644 --- a/source/API/SBListener.cpp +++ b/source/API/SBListener.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBListener.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBDebugger.h" diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp index 0d7dda1aa1f7..0249a7edcd2b 100644 --- a/source/API/SBModule.cpp +++ b/source/API/SBModule.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Symtab.h" @@ -211,34 +212,28 @@ SBModule::GetUUIDString () const { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - static char uuid_string_buffer[80]; - const char *uuid_c_string = NULL; - std::string uuid_string; + const char *uuid_cstr = NULL; ModuleSP module_sp (GetSP ()); if (module_sp) - uuid_string = module_sp->GetUUID().GetAsString(); - - if (!uuid_string.empty()) { - strncpy (uuid_string_buffer, uuid_string.c_str(), sizeof (uuid_string_buffer)); - uuid_string_buffer[sizeof (uuid_string_buffer) - 1] = '\0'; - uuid_c_string = uuid_string_buffer; + // We are going to return a "const char *" value through the public + // API, so we need to constify it so it gets added permanently the + // string pool and then we don't need to worry about the lifetime of the + // string as it will never go away once it has been put into the ConstString + // string pool + uuid_cstr = ConstString(module_sp->GetUUID().GetAsString()).GetCString(); } - if (log) + if (uuid_cstr && uuid_cstr[0]) { - if (!uuid_string.empty()) - { - StreamString s; - module_sp->GetUUID().Dump (&s); - log->Printf ("SBModule(%p)::GetUUIDString () => %s", - static_cast<void*>(module_sp.get()), s.GetData()); - } - else - log->Printf ("SBModule(%p)::GetUUIDString () => NULL", - static_cast<void*>(module_sp.get())); + if (log) + log->Printf ("SBModule(%p)::GetUUIDString () => %s", static_cast<void*>(module_sp.get()), uuid_cstr); + return uuid_cstr; } - return uuid_c_string; + + if (log) + log->Printf ("SBModule(%p)::GetUUIDString () => NULL", static_cast<void*>(module_sp.get())); + return NULL; } @@ -690,3 +685,30 @@ SBModule::GetVersion (uint32_t *versions, uint32_t num_versions) } } +lldb::SBFileSpec +SBModule::GetSymbolFileSpec() const +{ + lldb::SBFileSpec sb_file_spec; + ModuleSP module_sp(GetSP()); + if (module_sp) + { + SymbolVendor *symbol_vendor_ptr = module_sp->GetSymbolVendor(); + if (symbol_vendor_ptr) + sb_file_spec.SetFileSpec(symbol_vendor_ptr->GetMainFileSpec()); + } + return sb_file_spec; +} + +lldb::SBAddress +SBModule::GetObjectFileHeaderAddress() const +{ + lldb::SBAddress sb_addr; + ModuleSP module_sp (GetSP ()); + if (module_sp) + { + ObjectFile *objfile_ptr = module_sp->GetObjectFile(); + if (objfile_ptr) + sb_addr.ref() = objfile_ptr->GetHeaderAddress(); + } + return sb_addr; +} diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp index b23891d39c21..5662f36b514d 100644 --- a/source/API/SBPlatform.cpp +++ b/source/API/SBPlatform.cpp @@ -329,9 +329,9 @@ SBPlatform::SetWorkingDirectory(const char *path) if (platform_sp) { if (path) - platform_sp->SetWorkingDirectory(ConstString(path)); + platform_sp->SetWorkingDirectory(FileSpec{path, false}); else - platform_sp->SetWorkingDirectory(ConstString()); + platform_sp->SetWorkingDirectory(FileSpec{}); return true; } return false; @@ -378,7 +378,7 @@ SBPlatform::GetTriple() PlatformSP platform_sp(GetSP()); if (platform_sp) { - ArchSpec arch(platform_sp->GetRemoteSystemArchitecture()); + ArchSpec arch(platform_sp->GetSystemArchitecture()); if (arch.IsValid()) { // Const-ify the string so we don't need to worry about the lifetime of the string @@ -545,7 +545,7 @@ SBPlatform::Run (SBPlatformShellCommand &shell_command) shell_command.SetWorkingDirectory(working_dir); } return platform_sp->RunShellCommand(command, - working_dir, + FileSpec{working_dir, false}, &shell_command.m_opaque_ptr->m_status, &shell_command.m_opaque_ptr->m_signo, &shell_command.m_opaque_ptr->m_output, @@ -598,7 +598,7 @@ SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions) PlatformSP platform_sp(GetSP()); if (platform_sp) { - sb_error.ref() = platform_sp->MakeDirectory(path, file_permissions); + sb_error.ref() = platform_sp->MakeDirectory(FileSpec{path, false}, file_permissions); } else { @@ -614,7 +614,7 @@ SBPlatform::GetFilePermissions (const char *path) if (platform_sp) { uint32_t file_permissions = 0; - platform_sp->GetFilePermissions(path, file_permissions); + platform_sp->GetFilePermissions(FileSpec{path, false}, file_permissions); return file_permissions; } return 0; @@ -628,7 +628,7 @@ SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions) PlatformSP platform_sp(GetSP()); if (platform_sp) { - sb_error.ref() = platform_sp->SetFilePermissions(path, file_permissions); + sb_error.ref() = platform_sp->SetFilePermissions(FileSpec{path, false}, file_permissions); } else { diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp index 9a0b23bc93d2..a1dbf686da03 100644 --- a/source/API/SBProcess.cpp +++ b/source/API/SBProcess.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBProcess.h" // C Includes @@ -169,11 +167,11 @@ SBProcess::RemoteLaunch (char const **argv, { if (stop_at_entry) launch_flags |= eLaunchFlagStopAtEntry; - ProcessLaunchInfo launch_info (stdin_path, - stdout_path, - stderr_path, - working_directory, - launch_flags); + ProcessLaunchInfo launch_info(FileSpec{stdin_path, false}, + FileSpec{stdout_path, false}, + FileSpec{stderr_path, false}, + FileSpec{working_directory, false}, + launch_flags); Module *exe_module = process_sp->GetTarget().GetExecutableModulePointer(); if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); @@ -603,6 +601,30 @@ SBProcess::GetStopID(bool include_expression_stops) return 0; } +SBEvent +SBProcess::GetStopEventForStopID(uint32_t stop_id) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + SBEvent sb_event; + EventSP event_sp; + ProcessSP process_sp(GetSP()); + if (process_sp) + { + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); + event_sp = process_sp->GetStopEventForStopID(stop_id); + sb_event.reset(event_sp); + } + + if (log) + log->Printf ("SBProcess(%p)::GetStopEventForStopID (stop_id=%" PRIu32 ") => SBEvent(%p)", + static_cast<void*>(process_sp.get()), + stop_id, + static_cast<void*>(event_sp.get())); + + return sb_event; +} + StateType SBProcess::GetState () { @@ -768,7 +790,7 @@ SBProcess::Destroy () if (process_sp) { Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); - sb_error.SetError(process_sp->Destroy()); + sb_error.SetError(process_sp->Destroy(false)); } else sb_error.SetErrorString ("SBProcess is invalid"); @@ -821,7 +843,7 @@ SBProcess::Kill () if (process_sp) { Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); - sb_error.SetError (process_sp->Destroy()); + sb_error.SetError (process_sp->Destroy(true)); } else sb_error.SetErrorString ("SBProcess is invalid"); @@ -918,9 +940,9 @@ SBProcess::GetThreadByID (tid_t tid) ProcessSP process_sp(GetSP()); if (process_sp) { - Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); Process::StopLocker stop_locker; const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock()); + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); thread_sp = process_sp->GetThreadList().FindThreadByID (tid, can_update); sb_thread.SetThread (thread_sp); } @@ -942,9 +964,9 @@ SBProcess::GetThreadByIndexID (uint32_t index_id) ProcessSP process_sp(GetSP()); if (process_sp) { - Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); Process::StopLocker stop_locker; const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock()); + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); thread_sp = process_sp->GetThreadList().FindThreadByIndexID (index_id, can_update); sb_thread.SetThread (thread_sp); } @@ -999,9 +1021,15 @@ SBProcess::GetProcessFromEvent (const SBEvent &event) } bool +SBProcess::GetInterruptedFromEvent (const SBEvent &event) +{ + return Process::ProcessEventData::GetInterruptedFromEvent(event.get()); +} + +bool SBProcess::EventIsProcessEvent (const SBEvent &event) { - return strcmp (event.GetBroadcasterClass(), SBProcess::GetBroadcasterClass()) == 0; + return event.GetBroadcasterClass() == SBProcess::GetBroadcasterClass(); } SBBroadcaster diff --git a/source/API/SBQueue.cpp b/source/API/SBQueue.cpp index b19ed72543c2..be4c5fda1540 100644 --- a/source/API/SBQueue.cpp +++ b/source/API/SBQueue.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include <inttypes.h> #include "lldb/API/SBQueue.h" diff --git a/source/API/SBQueueItem.cpp b/source/API/SBQueueItem.cpp index 6a1aa7bec61a..e7a199b9f0b4 100644 --- a/source/API/SBQueueItem.cpp +++ b/source/API/SBQueueItem.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" #include "lldb/lldb-forward.h" #include "lldb/API/SBAddress.h" diff --git a/source/API/SBSourceManager.cpp b/source/API/SBSourceManager.cpp index 0b8cbfceda0f..8196b91d00b3 100644 --- a/source/API/SBSourceManager.cpp +++ b/source/API/SBSourceManager.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBDebugger.h" #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBTarget.h" diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp index 12a3b317d501..246a455d93a7 100644 --- a/source/API/SBSymbol.cpp +++ b/source/API/SBSymbol.cpp @@ -137,10 +137,11 @@ SBSymbol::GetInstructions (SBTarget target, const char *flavor_string) } if (m_opaque_ptr->ValueIsAddress()) { - ModuleSP module_sp (m_opaque_ptr->GetAddress().GetModule()); + const Address &symbol_addr = m_opaque_ptr->GetAddressRef(); + ModuleSP module_sp = symbol_addr.GetModule(); if (module_sp) { - AddressRange symbol_range (m_opaque_ptr->GetAddress(), m_opaque_ptr->GetByteSize()); + AddressRange symbol_range (symbol_addr, m_opaque_ptr->GetByteSize()); const bool prefer_file_cache = false; sb_instructions.SetDisassembler (Disassembler::DisassembleRange (module_sp->GetArchitecture (), NULL, @@ -172,7 +173,7 @@ SBSymbol::GetStartAddress () SBAddress addr; if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress()) { - addr.SetAddress (&m_opaque_ptr->GetAddress()); + addr.SetAddress (&m_opaque_ptr->GetAddressRef()); } return addr; } @@ -186,7 +187,7 @@ SBSymbol::GetEndAddress () lldb::addr_t range_size = m_opaque_ptr->GetByteSize(); if (range_size > 0) { - addr.SetAddress (&m_opaque_ptr->GetAddress()); + addr.SetAddress (&m_opaque_ptr->GetAddressRef()); addr->Slide (m_opaque_ptr->GetByteSize()); } } diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp index b13d8289560f..923885223a5f 100644 --- a/source/API/SBTarget.cpp +++ b/source/API/SBTarget.cpp @@ -7,14 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTarget.h" #include "lldb/lldb-public.h" -#include "lldb/API/SBDebugger.h" #include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBEvent.h" #include "lldb/API/SBExpressionOptions.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBListener.h" @@ -47,12 +46,16 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/DeclVendor.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/LanguageRuntime.h" +#include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" - +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" @@ -66,230 +69,31 @@ using namespace lldb_private; #define DEFAULT_DISASM_BYTE_SIZE 32 +namespace { -SBAttachInfo::SBAttachInfo () : - m_opaque_sp (new ProcessAttachInfo()) -{ -} - -SBAttachInfo::SBAttachInfo (lldb::pid_t pid) : - m_opaque_sp (new ProcessAttachInfo()) -{ - m_opaque_sp->SetProcessID (pid); -} - -SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) : - m_opaque_sp (new ProcessAttachInfo()) -{ - if (path && path[0]) - m_opaque_sp->GetExecutableFile().SetFile(path, false); - m_opaque_sp->SetWaitForLaunch (wait_for); -} - -SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) : - m_opaque_sp (new ProcessAttachInfo()) -{ - *m_opaque_sp = *rhs.m_opaque_sp; -} - -SBAttachInfo::~SBAttachInfo() -{ -} - -lldb_private::ProcessAttachInfo & -SBAttachInfo::ref () -{ - return *m_opaque_sp; -} - -SBAttachInfo & -SBAttachInfo::operator = (const SBAttachInfo &rhs) -{ - if (this != &rhs) - *m_opaque_sp = *rhs.m_opaque_sp; - return *this; -} - -lldb::pid_t -SBAttachInfo::GetProcessID () -{ - return m_opaque_sp->GetProcessID(); -} - -void -SBAttachInfo::SetProcessID (lldb::pid_t pid) -{ - m_opaque_sp->SetProcessID (pid); -} - - -uint32_t -SBAttachInfo::GetResumeCount () -{ - return m_opaque_sp->GetResumeCount(); -} - -void -SBAttachInfo::SetResumeCount (uint32_t c) -{ - m_opaque_sp->SetResumeCount (c); -} - -const char * -SBAttachInfo::GetProcessPluginName () -{ - return m_opaque_sp->GetProcessPluginName(); -} - -void -SBAttachInfo::SetProcessPluginName (const char *plugin_name) -{ - return m_opaque_sp->SetProcessPluginName (plugin_name); -} - -void -SBAttachInfo::SetExecutable (const char *path) -{ - if (path && path[0]) - m_opaque_sp->GetExecutableFile().SetFile(path, false); - else - m_opaque_sp->GetExecutableFile().Clear(); -} - -void -SBAttachInfo::SetExecutable (SBFileSpec exe_file) -{ - if (exe_file.IsValid()) - m_opaque_sp->GetExecutableFile() = exe_file.ref(); - else - m_opaque_sp->GetExecutableFile().Clear(); -} - -bool -SBAttachInfo::GetWaitForLaunch () -{ - return m_opaque_sp->GetWaitForLaunch(); -} - -void -SBAttachInfo::SetWaitForLaunch (bool b) -{ - m_opaque_sp->SetWaitForLaunch (b); -} - -bool -SBAttachInfo::GetIgnoreExisting () -{ - return m_opaque_sp->GetIgnoreExisting(); -} - -void -SBAttachInfo::SetIgnoreExisting (bool b) -{ - m_opaque_sp->SetIgnoreExisting (b); -} - -uint32_t -SBAttachInfo::GetUserID() -{ - return m_opaque_sp->GetUserID(); -} - -uint32_t -SBAttachInfo::GetGroupID() -{ - return m_opaque_sp->GetGroupID(); -} - -bool -SBAttachInfo::UserIDIsValid () -{ - return m_opaque_sp->UserIDIsValid(); -} - -bool -SBAttachInfo::GroupIDIsValid () -{ - return m_opaque_sp->GroupIDIsValid(); -} - -void -SBAttachInfo::SetUserID (uint32_t uid) -{ - m_opaque_sp->SetUserID (uid); -} - -void -SBAttachInfo::SetGroupID (uint32_t gid) -{ - m_opaque_sp->SetGroupID (gid); -} - -uint32_t -SBAttachInfo::GetEffectiveUserID() -{ - return m_opaque_sp->GetEffectiveUserID(); -} - -uint32_t -SBAttachInfo::GetEffectiveGroupID() -{ - return m_opaque_sp->GetEffectiveGroupID(); -} - -bool -SBAttachInfo::EffectiveUserIDIsValid () -{ - return m_opaque_sp->EffectiveUserIDIsValid(); -} - -bool -SBAttachInfo::EffectiveGroupIDIsValid () -{ - return m_opaque_sp->EffectiveGroupIDIsValid (); -} - -void -SBAttachInfo::SetEffectiveUserID (uint32_t uid) -{ - m_opaque_sp->SetEffectiveUserID(uid); -} - -void -SBAttachInfo::SetEffectiveGroupID (uint32_t gid) -{ - m_opaque_sp->SetEffectiveGroupID(gid); -} - -lldb::pid_t -SBAttachInfo::GetParentProcessID () -{ - return m_opaque_sp->GetParentProcessID(); -} - -void -SBAttachInfo::SetParentProcessID (lldb::pid_t pid) +Error +AttachToProcess (ProcessAttachInfo &attach_info, Target &target) { - m_opaque_sp->SetParentProcessID (pid); -} + Mutex::Locker api_locker (target.GetAPIMutex ()); -bool -SBAttachInfo::ParentProcessIDIsValid() -{ - return m_opaque_sp->ParentProcessIDIsValid(); -} + auto process_sp = target.GetProcessSP (); + if (process_sp) + { + const auto state = process_sp->GetState (); + if (process_sp->IsAlive () && state == eStateConnected) + { + // If we are already connected, then we have already specified the + // listener, so if a valid listener is supplied, we need to error out + // to let the client know. + if (attach_info.GetListener ()) + return Error ("process is connected and already has a listener, pass empty listener"); + } + } -SBListener -SBAttachInfo::GetListener () -{ - return SBListener(m_opaque_sp->GetListener()); + return target.Attach (attach_info, nullptr); } -void -SBAttachInfo::SetListener (SBListener &listener) -{ - m_opaque_sp->SetListener(listener.GetSP()); -} +} // namespace //---------------------------------------------------------------------- // SBTarget constructor @@ -324,6 +128,32 @@ SBTarget::~SBTarget() { } +bool +SBTarget::EventIsTargetEvent (const SBEvent &event) +{ + return Target::TargetEventData::GetEventDataFromEvent(event.get()) != NULL; +} + +SBTarget +SBTarget::GetTargetFromEvent (const SBEvent &event) +{ + return Target::TargetEventData::GetTargetFromEvent (event.get()); +} + +uint32_t +SBTarget::GetNumModulesFromEvent (const SBEvent &event) +{ + const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get()); + return module_list.GetSize(); +} + +SBModule +SBTarget::GetModuleAtIndexFromEvent (const uint32_t idx, const SBEvent &event) +{ + const ModuleList module_list = Target::TargetEventData::GetModuleListFromEvent (event.get()); + return SBModule(module_list.GetModuleAtIndex(idx)); +} + const char * SBTarget::GetBroadcasterClassName () { @@ -513,7 +343,11 @@ SBTarget::Launch if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO")) launch_flags |= eLaunchFlagDisableSTDIO; - ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags); + ProcessLaunchInfo launch_info(FileSpec{stdin_path, false}, + FileSpec{stdout_path, false}, + FileSpec{stderr_path, false}, + FileSpec{working_directory, false}, + launch_flags); Module *exe_module = target_sp->GetExecutableModulePointer(); if (exe_module) @@ -613,7 +447,6 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error) Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) @@ -622,72 +455,34 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error) if (target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) + ProcessAttachInfo &attach_info = sb_attach_info.ref(); + if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid()) { - state = process_sp->GetState(); - - if (process_sp->IsAlive() && state != eStateConnected) + PlatformSP platform_sp = target_sp->GetPlatform(); + // See if we can pre-verify if a process exists or not + if (platform_sp && platform_sp->IsConnected()) { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); + lldb::pid_t attach_pid = attach_info.GetProcessID(); + ProcessInstanceInfo instance_info; + if (platform_sp->GetProcessInfo(attach_pid, instance_info)) + { + attach_info.SetUserID(instance_info.GetEffectiveUserID()); + } else - error.SetErrorString ("a process is already being debugged"); - if (log) - log->Printf ("SBTarget(%p)::Attach (...) => error %s", - static_cast<void*>(target_sp.get()), - error.GetCString()); - return sb_process; - } - } - - if (state != eStateConnected) - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - - if (process_sp) - { - ProcessAttachInfo &attach_info = sb_attach_info.ref(); - if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid()) - { - PlatformSP platform_sp = target_sp->GetPlatform(); - // See if we can pre-verify if a process exists or not - if (platform_sp && platform_sp->IsConnected()) { - lldb::pid_t attach_pid = attach_info.GetProcessID(); - ProcessInstanceInfo instance_info; - if (platform_sp->GetProcessInfo(attach_pid, instance_info)) + error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid); + if (log) { - attach_info.SetUserID(instance_info.GetEffectiveUserID()); - } - else - { - error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid); - if (log) - { - log->Printf ("SBTarget(%p)::Attach (...) => error %s", - static_cast<void*>(target_sp.get()), error.GetCString()); - } - return sb_process; + log->Printf ("SBTarget(%p)::Attach (...) => error %s", + static_cast<void*>(target_sp.get()), error.GetCString()); } + return sb_process; } } - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - sb_process.SetSP (process_sp); - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); } + error.SetError(AttachToProcess(attach_info, *target_sp)); + if (error.Success()) + sb_process.SetSP(target_sp->GetProcessSP()); } else { @@ -697,7 +492,7 @@ SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error) if (log) log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)", static_cast<void*>(target_sp.get()), - static_cast<void*>(process_sp.get())); + static_cast<void*>(sb_process.GetSP().get())); return sb_process; } @@ -726,87 +521,37 @@ SBTarget::AttachToProcessWithID Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...", - static_cast<void*>(target_sp.get()), pid); + log->Printf ("SBTarget(%p)::%s (listener, pid=%" PRId64 ", error)...", + static_cast<void*>(target_sp.get()), + __FUNCTION__, + pid); if (target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) - { - state = process_sp->GetState(); - - if (process_sp->IsAlive() && state != eStateConnected) - { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); - else - error.SetErrorString ("a process is already being debugged"); - return sb_process; - } - } - - if (state == eStateConnected) - { - // If we are already connected, then we have already specified the - // listener, so if a valid listener is supplied, we need to error out - // to let the client know. - if (listener.IsValid()) - { - error.SetErrorString ("process is connected and already has a listener, pass empty listener"); - return sb_process; - } - } - else - { - if (listener.IsValid()) - process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL); - else - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - } - if (process_sp) - { - sb_process.SetSP (process_sp); + ProcessAttachInfo attach_info; + attach_info.SetProcessID (pid); + if (listener.IsValid()) + attach_info.SetListener(listener.GetSP()); - ProcessAttachInfo attach_info; - attach_info.SetProcessID (pid); + ProcessInstanceInfo instance_info; + if (target_sp->GetPlatform ()->GetProcessInfo (pid, instance_info)) + attach_info.SetUserID (instance_info.GetEffectiveUserID ()); - PlatformSP platform_sp = target_sp->GetPlatform(); - ProcessInstanceInfo instance_info; - if (platform_sp->GetProcessInfo(pid, instance_info)) - { - attach_info.SetUserID(instance_info.GetEffectiveUserID()); - } - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } + error.SetError (AttachToProcess (attach_info, *target_sp)); + if (error.Success ()) + sb_process.SetSP (target_sp->GetProcessSP ()); } else - { error.SetErrorString ("SBTarget is invalid"); - } if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)", - static_cast<void*>(target_sp.get()), - static_cast<void*>(process_sp.get())); + log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)", + static_cast<void*>(target_sp.get ()), + __FUNCTION__, + static_cast<void*>(sb_process.GetSP().get ())); return sb_process; } @@ -822,82 +567,35 @@ SBTarget::AttachToProcessWithName Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) - log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...", - static_cast<void*>(target_sp.get()), name, + log->Printf ("SBTarget(%p)::%s (listener, name=%s, wait_for=%s, error)...", + static_cast<void*>(target_sp.get()), + __FUNCTION__, + name, wait_for ? "true" : "false"); if (name && target_sp) { - Mutex::Locker api_locker (target_sp->GetAPIMutex()); - - StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); - if (process_sp) - { - state = process_sp->GetState(); - - if (process_sp->IsAlive() && state != eStateConnected) - { - if (state == eStateAttaching) - error.SetErrorString ("process attach is in progress"); - else - error.SetErrorString ("a process is already being debugged"); - return sb_process; - } - } - - if (state == eStateConnected) - { - // If we are already connected, then we have already specified the - // listener, so if a valid listener is supplied, we need to error out - // to let the client know. - if (listener.IsValid()) - { - error.SetErrorString ("process is connected and already has a listener, pass empty listener"); - return sb_process; - } - } - else - { - if (listener.IsValid()) - process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL); - else - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - } + ProcessAttachInfo attach_info; + attach_info.GetExecutableFile().SetFile(name, false); + attach_info.SetWaitForLaunch(wait_for); + if (listener.IsValid()) + attach_info.SetListener(listener.GetSP()); - if (process_sp) - { - sb_process.SetSP (process_sp); - ProcessAttachInfo attach_info; - attach_info.GetExecutableFile().SetFile(name, false); - attach_info.SetWaitForLaunch(wait_for); - error.SetError (process_sp->Attach (attach_info)); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } + error.SetError (AttachToProcess (attach_info, *target_sp)); + if (error.Success ()) + sb_process.SetSP (target_sp->GetProcessSP ()); } else - { error.SetErrorString ("SBTarget is invalid"); - } if (log) - log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)", + log->Printf ("SBTarget(%p)::%s (...) => SBProcess(%p)", static_cast<void*>(target_sp.get()), - static_cast<void*>(process_sp.get())); + __FUNCTION__, + static_cast<void*>(sb_process.GetSP().get())); return sb_process; } @@ -1112,7 +810,8 @@ SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec, const LazyBool skip_prologue = eLazyBoolCalculate; const bool internal = false; const bool hardware = false; - *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware); + const LazyBool move_to_nearest_code = eLazyBoolCalculate; + *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal, hardware, move_to_nearest_code); } if (log) @@ -1359,6 +1058,7 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, RegularExpression regexp(source_regex); FileSpecList source_file_spec_list; const bool hardware = false; + const LazyBool move_to_nearest_code = eLazyBoolCalculate; source_file_spec_list.Append (source_file.ref()); if (module_name && module_name[0]) @@ -1366,11 +1066,11 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, FileSpecList module_spec_list; module_spec_list.Append (FileSpec (module_name, false)); - *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code); } else { - *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false, hardware, move_to_nearest_code); } } @@ -1387,9 +1087,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, } lldb::SBBreakpoint -SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, - const SBFileSpecList &module_list, - const lldb::SBFileSpecList &source_file_list) +SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, + const SBFileSpecList &module_list, + const lldb::SBFileSpecList &source_file_list) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); @@ -1399,8 +1099,9 @@ SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, { Mutex::Locker api_locker (target_sp->GetAPIMutex()); const bool hardware = false; + const LazyBool move_to_nearest_code = eLazyBoolCalculate; RegularExpression regexp(source_regex); - *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware); + *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false, hardware, move_to_nearest_code); } if (log) @@ -2679,3 +2380,20 @@ SBTarget::GetStackRedZoneSize() return 0; } +lldb::SBLaunchInfo +SBTarget::GetLaunchInfo () const +{ + lldb::SBLaunchInfo launch_info(NULL); + TargetSP target_sp(GetSP()); + if (target_sp) + launch_info.ref() = m_opaque_sp->GetProcessLaunchInfo(); + return launch_info; +} + +void +SBTarget::SetLaunchInfo (const lldb::SBLaunchInfo &launch_info) +{ + TargetSP target_sp(GetSP()); + if (target_sp) + m_opaque_sp->SetProcessLaunchInfo(launch_info.ref()); +} diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp index 9fe0d029496c..dfc7ce9629f3 100644 --- a/source/API/SBThread.cpp +++ b/source/API/SBThread.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBThread.h" #include "lldb/API/SBSymbolContext.h" @@ -20,13 +18,15 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredData.h" +#include "lldb/Core/ValueObject.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Process.h" #include "lldb/Target/Queue.h" -#include "lldb/Symbol/SymbolContext.h" -#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Target/UnixSignals.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadPlan.h" @@ -114,13 +114,13 @@ SBThread::GetQueue () const else { if (log) - log->Printf ("SBThread(%p)::GetQueueKind() => error: process is running", + log->Printf ("SBThread(%p)::GetQueue() => error: process is running", static_cast<void*>(exe_ctx.GetThreadPtr())); } } if (log) - log->Printf ("SBThread(%p)::GetQueueKind () => SBQueue(%p)", + log->Printf ("SBThread(%p)::GetQueue () => SBQueue(%p)", static_cast<void*>(exe_ctx.GetThreadPtr()), static_cast<void*>(queue_sp.get())); return sb_queue; diff --git a/source/API/SBThreadPlan.cpp b/source/API/SBThreadPlan.cpp index 02b1a8d893b6..2fcd72149409 100644 --- a/source/API/SBThreadPlan.cpp +++ b/source/API/SBThreadPlan.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBThread.h" #include "lldb/API/SBSymbolContext.h" diff --git a/source/API/SBTypeCategory.cpp b/source/API/SBTypeCategory.cpp index 66cf46236c65..ee9553ca6abd 100644 --- a/source/API/SBTypeCategory.cpp +++ b/source/API/SBTypeCategory.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeCategory.h" #include "lldb/API/SBTypeFilter.h" diff --git a/source/API/SBTypeFilter.cpp b/source/API/SBTypeFilter.cpp index 605e92de6991..8af3e1ff8641 100644 --- a/source/API/SBTypeFilter.cpp +++ b/source/API/SBTypeFilter.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeFilter.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBTypeFormat.cpp b/source/API/SBTypeFormat.cpp index d3ec9bc00bd0..9548fe904cdc 100644 --- a/source/API/SBTypeFormat.cpp +++ b/source/API/SBTypeFormat.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeFormat.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBTypeNameSpecifier.cpp b/source/API/SBTypeNameSpecifier.cpp index 3d03c6a0c539..c58747170b5a 100644 --- a/source/API/SBTypeNameSpecifier.cpp +++ b/source/API/SBTypeNameSpecifier.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeNameSpecifier.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp index 8a235bf50080..2c114545419c 100644 --- a/source/API/SBTypeSummary.cpp +++ b/source/API/SBTypeSummary.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeSummary.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBTypeSynthetic.cpp b/source/API/SBTypeSynthetic.cpp index 681ed6c032ab..6f9951dc5559 100644 --- a/source/API/SBTypeSynthetic.cpp +++ b/source/API/SBTypeSynthetic.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBTypeSynthetic.h" #include "lldb/API/SBStream.h" diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp index edecb93944ad..ef62c30e42cf 100644 --- a/source/API/SBValue.cpp +++ b/source/API/SBValue.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/API/SBValue.h" #include "lldb/API/SBDeclaration.h" @@ -63,13 +61,19 @@ public: lldb::DynamicValueType use_dynamic, bool use_synthetic, const char *name = NULL) : - m_valobj_sp(in_valobj_sp), + m_valobj_sp(), m_use_dynamic(use_dynamic), m_use_synthetic(use_synthetic), m_name (name) { - if (!m_name.IsEmpty() && m_valobj_sp) - m_valobj_sp->SetName(m_name); + if (in_valobj_sp) + { + if ( (m_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false)) ) + { + if (!m_name.IsEmpty()) + m_valobj_sp->SetName(m_name); + } + } } ValueImpl (const ValueImpl& rhs) : @@ -152,10 +156,20 @@ public: return ValueObjectSP(); } - if (value_sp->GetDynamicValue(m_use_dynamic)) - value_sp = value_sp->GetDynamicValue(m_use_dynamic); - if (value_sp->GetSyntheticValue(m_use_synthetic)) - value_sp = value_sp->GetSyntheticValue(m_use_synthetic); + if (m_use_dynamic != eNoDynamicValues) + { + ValueObjectSP dynamic_sp = value_sp->GetDynamicValue(m_use_dynamic); + if (dynamic_sp) + value_sp = dynamic_sp; + } + + if (m_use_synthetic) + { + ValueObjectSP synthetic_sp = value_sp->GetSyntheticValue(m_use_synthetic); + if (synthetic_sp) + value_sp = synthetic_sp; + } + if (!value_sp) error.SetErrorString("invalid value object"); if (!m_name.IsEmpty()) @@ -969,14 +983,7 @@ SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool child_sp = value_sp->GetChildAtIndex (idx, can_create); if (can_create_synthetic && !child_sp) { - if (value_sp->IsPointerType()) - { - child_sp = value_sp->GetSyntheticArrayMemberFromPointer(idx, can_create); - } - else if (value_sp->IsArrayType()) - { - child_sp = value_sp->GetSyntheticArrayMemberFromArray(idx, can_create); - } + child_sp = value_sp->GetSyntheticArrayMember(idx, can_create); } } @@ -1244,6 +1251,22 @@ SBValue::MightHaveChildren () return has_children; } +bool +SBValue::IsRuntimeSupportValue () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + bool is_support = false; + ValueLocker locker; + lldb::ValueObjectSP value_sp(GetSP(locker)); + if (value_sp) + is_support = value_sp->IsRuntimeSupportValue(); + + if (log) + log->Printf ("SBValue(%p)::IsRuntimeSupportValue() => %i", + static_cast<void*>(value_sp.get()), is_support); + return is_support; +} + uint32_t SBValue::GetNumChildren () { diff --git a/source/API/SBVariablesOptions.cpp b/source/API/SBVariablesOptions.cpp new file mode 100644 index 000000000000..7c453567c0ae --- /dev/null +++ b/source/API/SBVariablesOptions.cpp @@ -0,0 +1,254 @@ +//===-- SBVariablesOptions.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "lldb/API/SBVariablesOptions.h" + +using namespace lldb; +using namespace lldb_private; + +class VariablesOptionsImpl +{ +public: + VariablesOptionsImpl () : + m_include_arguments(false), + m_include_locals(false), + m_include_statics(false), + m_in_scope_only(false), + m_include_runtime_support_values(false), + m_use_dynamic(lldb::eNoDynamicValues) + {} + + VariablesOptionsImpl (const VariablesOptionsImpl&) = default; + + ~VariablesOptionsImpl () = default; + + VariablesOptionsImpl& + operator = (const VariablesOptionsImpl&) = default; + + bool + GetIncludeArguments () const + { + return m_include_arguments; + } + + void + SetIncludeArguments (bool b) + { + m_include_arguments = b; + } + + bool + GetIncludeLocals () const + { + return m_include_locals; + } + + void + SetIncludeLocals (bool b) + { + m_include_locals = b; + } + + bool + GetIncludeStatics () const + { + return m_include_statics; + } + + void + SetIncludeStatics (bool b) + { + m_include_statics = b; + } + + bool + GetInScopeOnly () const + { + return m_in_scope_only; + } + + void + SetInScopeOnly (bool b) + { + m_in_scope_only = b; + } + + bool + GetIncludeRuntimeSupportValues () const + { + return m_include_runtime_support_values; + } + + void + SetIncludeRuntimeSupportValues (bool b) + { + m_include_runtime_support_values = b; + } + + lldb::DynamicValueType + GetUseDynamic () const + { + return m_use_dynamic; + } + + void + SetUseDynamic (lldb::DynamicValueType d) + { + m_use_dynamic = d; + } + + +private: + bool m_include_arguments : 1; + bool m_include_locals : 1; + bool m_include_statics : 1; + bool m_in_scope_only : 1; + bool m_include_runtime_support_values : 1; + lldb::DynamicValueType m_use_dynamic; +}; + +SBVariablesOptions::SBVariablesOptions () : +m_opaque_ap(new VariablesOptionsImpl()) +{ +} + +SBVariablesOptions::SBVariablesOptions (const SBVariablesOptions& options) : +m_opaque_ap(new VariablesOptionsImpl(options.ref())) +{ +} + +SBVariablesOptions& +SBVariablesOptions::operator = (const SBVariablesOptions& options) +{ + m_opaque_ap.reset(new VariablesOptionsImpl(options.ref())); + return *this; +} + +SBVariablesOptions::~SBVariablesOptions () = default; + +bool +SBVariablesOptions::IsValid () const +{ + return m_opaque_ap.get() != nullptr; +} + +bool +SBVariablesOptions::GetIncludeArguments () const +{ + return m_opaque_ap->GetIncludeArguments(); +} + +void +SBVariablesOptions::SetIncludeArguments (bool arguments) +{ + m_opaque_ap->SetIncludeArguments(arguments); +} + +bool +SBVariablesOptions::GetIncludeLocals () const +{ + return m_opaque_ap->GetIncludeLocals(); +} + +void +SBVariablesOptions::SetIncludeLocals (bool locals) +{ + m_opaque_ap->SetIncludeLocals(locals); +} + +bool +SBVariablesOptions::GetIncludeStatics () const +{ + return m_opaque_ap->GetIncludeStatics(); +} + +void +SBVariablesOptions::SetIncludeStatics (bool statics) +{ + m_opaque_ap->SetIncludeStatics(statics); +} + +bool +SBVariablesOptions::GetInScopeOnly () const +{ + return m_opaque_ap->GetInScopeOnly(); +} + +void +SBVariablesOptions::SetInScopeOnly (bool in_scope_only) +{ + m_opaque_ap->SetInScopeOnly(in_scope_only); +} + +bool +SBVariablesOptions::GetIncludeRuntimeSupportValues () const +{ + return m_opaque_ap->GetIncludeRuntimeSupportValues(); +} + +void +SBVariablesOptions::SetIncludeRuntimeSupportValues (bool runtime_support_values) +{ + m_opaque_ap->SetIncludeRuntimeSupportValues(runtime_support_values); +} + +lldb::DynamicValueType +SBVariablesOptions::GetUseDynamic () const +{ + return m_opaque_ap->GetUseDynamic(); +} + +void +SBVariablesOptions::SetUseDynamic (lldb::DynamicValueType dynamic) +{ + m_opaque_ap->SetUseDynamic(dynamic); +} + +VariablesOptionsImpl * +SBVariablesOptions::operator->() +{ + return m_opaque_ap.operator->(); +} + +const VariablesOptionsImpl * +SBVariablesOptions::operator->() const +{ + return m_opaque_ap.operator->(); +} + +VariablesOptionsImpl * +SBVariablesOptions::get () +{ + return m_opaque_ap.get(); +} + +VariablesOptionsImpl & +SBVariablesOptions::ref() +{ + return *m_opaque_ap; +} + +const VariablesOptionsImpl & +SBVariablesOptions::ref() const +{ + return *m_opaque_ap; +} + +SBVariablesOptions::SBVariablesOptions (VariablesOptionsImpl *lldb_object_ptr) : +m_opaque_ap(std::move(lldb_object_ptr)) +{ +} + +void +SBVariablesOptions::SetOptions (VariablesOptionsImpl *lldb_object_ptr) +{ + m_opaque_ap.reset(std::move(lldb_object_ptr)); +} + diff --git a/source/API/SystemInitializerFull.cpp b/source/API/SystemInitializerFull.cpp new file mode 100644 index 000000000000..731d38a37bee --- /dev/null +++ b/source/API/SystemInitializerFull.cpp @@ -0,0 +1,392 @@ +//===-- SystemInitializerFull.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SystemInitializerFull.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Host/Host.h" +#include "lldb/Initialization/SystemInitializerCommon.h" + +#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h" +#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" +#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h" +#include "Plugins/ABI/SysV-arm/ABISysV_arm.h" +#include "Plugins/ABI/SysV-arm64/ABISysV_arm64.h" +#include "Plugins/ABI/SysV-i386/ABISysV_i386.h" +#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h" +#include "Plugins/ABI/SysV-ppc/ABISysV_ppc.h" +#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h" +#include "Plugins/ABI/SysV-mips/ABISysV_mips.h" +#include "Plugins/ABI/SysV-mips64/ABISysV_mips64.h" +#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" +#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" +#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h" +#include "Plugins/JITLoader/GDB/JITLoaderGDB.h" +#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h" +#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h" +#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h" +#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h" +#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h" +#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" +#include "Plugins/Process/elf-core/ProcessElfCore.h" +#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h" +#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" +#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" +#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" +#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h" +#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" + +#if defined(__APPLE__) +#include "Plugins/Process/mach-core/ProcessMachCore.h" +#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h" +#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h" +#endif + +#if defined(__FreeBSD__) +#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" +#endif + +#if defined(_MSC_VER) +#include "lldb/Host/windows/windows.h" +#include "Plugins/Process/Windows/DynamicLoaderWindows.h" +#include "Plugins/Process/Windows/ProcessWindows.h" +#endif + +#if !defined(LLDB_DISABLE_PYTHON) +#include "lldb/Interpreter/ScriptInterpreterPython.h" +#endif + +#include "llvm/Support/TargetSelect.h" + +#include <string> + +using namespace lldb_private; + +#ifndef LLDB_DISABLE_PYTHON + +// Defined in the SWIG source file +extern "C" void +init_lldb(void); + +// these are the Pythonic implementations of the required callbacks +// these are scripting-language specific, which is why they belong here +// we still need to use function pointers to them instead of relying +// on linkage-time resolution because the SWIG stuff and this file +// get built at different times +extern "C" bool +LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name, + const char *session_dictionary_name, + const lldb::StackFrameSP& sb_frame, + const lldb::BreakpointLocationSP& sb_bp_loc); + +extern "C" bool +LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name, + const char *session_dictionary_name, + const lldb::StackFrameSP& sb_frame, + const lldb::WatchpointSP& sb_wp); + +extern "C" bool +LLDBSwigPythonCallTypeScript (const char *python_function_name, + void *session_dictionary, + const lldb::ValueObjectSP& valobj_sp, + void** pyfunct_wrapper, + const lldb::TypeSummaryOptionsSP& options_sp, + std::string& retval); + +extern "C" void* +LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ValueObjectSP& valobj_sp); + +extern "C" void* +LLDBSwigPythonCreateCommandObject (const char *python_class_name, + const char *session_dictionary_name, + const lldb::DebuggerSP debugger_sp); + +extern "C" void* +LLDBSwigPythonCreateScriptedThreadPlan (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ThreadPlanSP& thread_plan_sp); + +extern "C" bool +LLDBSWIGPythonCallThreadPlan (void *implementor, + const char *method_name, + Event *event_sp, + bool &got_error); + +extern "C" size_t +LLDBSwigPython_CalculateNumChildren (void *implementor); + +extern "C" void * +LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx); + +extern "C" int +LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name); + +extern "C" void * +LLDBSWIGPython_CastPyObjectToSBValue (void* data); + +extern lldb::ValueObjectSP +LLDBSWIGPython_GetValueObjectSPFromSBValue (void* data); + +extern "C" bool +LLDBSwigPython_UpdateSynthProviderInstance (void* implementor); + +extern "C" bool +LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor); + +extern "C" void * +LLDBSwigPython_GetValueSynthProviderInstance (void* implementor); + +extern "C" bool +LLDBSwigPythonCallCommand (const char *python_function_name, + const char *session_dictionary_name, + lldb::DebuggerSP& debugger, + const char* args, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp); + +extern "C" bool +LLDBSwigPythonCallCommandObject (void *implementor, + lldb::DebuggerSP& debugger, + const char* args, + lldb_private::CommandReturnObject& cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp); + +extern "C" bool +LLDBSwigPythonCallModuleInit (const char *python_module_name, + const char *session_dictionary_name, + lldb::DebuggerSP& debugger); + +extern "C" void* +LLDBSWIGPythonCreateOSPlugin (const char *python_class_name, + const char *session_dictionary_name, + const lldb::ProcessSP& process_sp); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name, + const char* session_dictionary_name, + lldb::ProcessSP& process, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name, + const char* session_dictionary_name, + lldb::ThreadSP& thread, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name, + const char* session_dictionary_name, + lldb::TargetSP& target, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name, + const char* session_dictionary_name, + lldb::StackFrameSP& frame, + std::string& output); + +extern "C" bool +LLDBSWIGPythonRunScriptKeywordValue (const char* python_function_name, + const char* session_dictionary_name, + lldb::ValueObjectSP& value, + std::string& output); + +extern "C" void* +LLDBSWIGPython_GetDynamicSetting (void* module, + const char* setting, + const lldb::TargetSP& target_sp); + + +#endif + +SystemInitializerFull::SystemInitializerFull() +{ +} + +SystemInitializerFull::~SystemInitializerFull() +{ +} + +void +SystemInitializerFull::Initialize() +{ + InitializeSWIG(); + + SystemInitializerCommon::Initialize(); + + // Initialize LLVM and Clang + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + + ABIMacOSX_i386::Initialize(); + ABIMacOSX_arm::Initialize(); + ABIMacOSX_arm64::Initialize(); + ABISysV_arm::Initialize(); + ABISysV_arm64::Initialize(); + ABISysV_i386::Initialize(); + ABISysV_x86_64::Initialize(); + ABISysV_ppc::Initialize(); + ABISysV_ppc64::Initialize(); + ABISysV_mips::Initialize(); + ABISysV_mips64::Initialize(); + DisassemblerLLVMC::Initialize(); + + JITLoaderGDB::Initialize(); + ProcessElfCore::Initialize(); + MemoryHistoryASan::Initialize(); + AddressSanitizerRuntime::Initialize(); + + SymbolVendorELF::Initialize(); + SymbolFileDWARF::Initialize(); + SymbolFileSymtab::Initialize(); + UnwindAssemblyInstEmulation::Initialize(); + UnwindAssembly_x86::Initialize(); + EmulateInstructionARM64::Initialize(); + SymbolFileDWARFDebugMap::Initialize(); + ItaniumABILanguageRuntime::Initialize(); + AppleObjCRuntimeV2::Initialize(); + AppleObjCRuntimeV1::Initialize(); + SystemRuntimeMacOSX::Initialize(); + RenderScriptRuntime::Initialize(); + +#if defined(_MSC_VER) + DynamicLoaderWindows::Initialize(); + ProcessWindows::Initialize(); +#endif +#if defined(__FreeBSD__) + ProcessFreeBSD::Initialize(); +#endif +#if defined(__APPLE__) + SymbolVendorMacOSX::Initialize(); + ProcessKDP::Initialize(); + ProcessMachCore::Initialize(); +#endif + //---------------------------------------------------------------------- + // Platform agnostic plugins + //---------------------------------------------------------------------- + platform_gdb_server::PlatformRemoteGDBServer::Initialize(); + + process_gdb_remote::ProcessGDBRemote::Initialize(); + DynamicLoaderStatic::Initialize(); + + // Scan for any system or user LLDB plug-ins + PluginManager::Initialize(); + + // The process settings need to know about installed plug-ins, so the Settings must be initialized + // AFTER PluginManager::Initialize is called. + + Debugger::SettingsInitialize(); +} + +void SystemInitializerFull::InitializeSWIG() +{ +#if !defined(LLDB_DISABLE_PYTHON) + ScriptInterpreterPython::InitializeInterpreter( + init_lldb, + LLDBSwigPythonBreakpointCallbackFunction, + LLDBSwigPythonWatchpointCallbackFunction, + LLDBSwigPythonCallTypeScript, + LLDBSwigPythonCreateSyntheticProvider, + LLDBSwigPythonCreateCommandObject, + LLDBSwigPython_CalculateNumChildren, + LLDBSwigPython_GetChildAtIndex, + LLDBSwigPython_GetIndexOfChildWithName, + LLDBSWIGPython_CastPyObjectToSBValue, + LLDBSWIGPython_GetValueObjectSPFromSBValue, + LLDBSwigPython_UpdateSynthProviderInstance, + LLDBSwigPython_MightHaveChildrenSynthProviderInstance, + LLDBSwigPython_GetValueSynthProviderInstance, + LLDBSwigPythonCallCommand, + LLDBSwigPythonCallCommandObject, + LLDBSwigPythonCallModuleInit, + LLDBSWIGPythonCreateOSPlugin, + LLDBSWIGPythonRunScriptKeywordProcess, + LLDBSWIGPythonRunScriptKeywordThread, + LLDBSWIGPythonRunScriptKeywordTarget, + LLDBSWIGPythonRunScriptKeywordFrame, + LLDBSWIGPythonRunScriptKeywordValue, + LLDBSWIGPython_GetDynamicSetting, + LLDBSwigPythonCreateScriptedThreadPlan, + LLDBSWIGPythonCallThreadPlan); +#endif +} + +void +SystemInitializerFull::Terminate() +{ + Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + Debugger::SettingsTerminate(); + + // Terminate and unload and loaded system or user LLDB plug-ins + PluginManager::Terminate(); + ABIMacOSX_i386::Terminate(); + ABIMacOSX_arm::Terminate(); + ABIMacOSX_arm64::Terminate(); + ABISysV_arm::Terminate(); + ABISysV_arm64::Terminate(); + ABISysV_i386::Terminate(); + ABISysV_x86_64::Terminate(); + ABISysV_ppc::Terminate(); + ABISysV_ppc64::Terminate(); + ABISysV_mips::Terminate(); + ABISysV_mips64::Terminate(); + DisassemblerLLVMC::Terminate(); + + JITLoaderGDB::Terminate(); + ProcessElfCore::Terminate(); + MemoryHistoryASan::Terminate(); + AddressSanitizerRuntime::Terminate(); + SymbolVendorELF::Terminate(); + SymbolFileDWARF::Terminate(); + SymbolFileSymtab::Terminate(); + UnwindAssembly_x86::Terminate(); + UnwindAssemblyInstEmulation::Terminate(); + EmulateInstructionARM64::Terminate(); + SymbolFileDWARFDebugMap::Terminate(); + ItaniumABILanguageRuntime::Terminate(); + AppleObjCRuntimeV2::Terminate(); + AppleObjCRuntimeV1::Terminate(); + SystemRuntimeMacOSX::Terminate(); + RenderScriptRuntime::Terminate(); + +#if defined(__APPLE__) + ProcessMachCore::Terminate(); + ProcessKDP::Terminate(); + SymbolVendorMacOSX::Terminate(); +#endif +#if defined(_MSC_VER) + DynamicLoaderWindows::Terminate(); +#endif + +#if defined(__FreeBSD__) + ProcessFreeBSD::Terminate(); +#endif + Debugger::SettingsTerminate(); + + platform_gdb_server::PlatformRemoteGDBServer::Terminate(); + process_gdb_remote::ProcessGDBRemote::Terminate(); + DynamicLoaderStatic::Terminate(); + + // Now shutdown the common parts, in reverse order. + SystemInitializerCommon::Terminate(); +} + +void SystemInitializerFull::TerminateSWIG() +{ + +} diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp index beb0f6bc5a6e..23d484f0f68a 100644 --- a/source/Breakpoint/Breakpoint.cpp +++ b/source/Breakpoint/Breakpoint.cpp @@ -31,7 +31,6 @@ #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" -#include "lldb/lldb-private-log.h" #include "llvm/Support/Casting.h" using namespace lldb; @@ -877,25 +876,18 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l { s->Printf ("no locations (pending)."); } - else if (num_locations == 1) + else if (num_locations == 1 && show_locations == false) { - // If there is one location only, we'll just print that location information. But don't do this if - // show locations is true, then that will be handled below. - if (show_locations == false) - { - GetLocationAtIndex(0)->GetDescription(s, level); - } - else - { - s->Printf ("%zd locations.", num_locations); - } + // There is only one location, so we'll just print that location information. + GetLocationAtIndex(0)->GetDescription(s, level); } else { - s->Printf ("%zd locations.", num_locations); + s->Printf ("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations)); } s->EOL(); break; + case lldb::eDescriptionLevelVerbose: // Verbose mode does a debug dump of the breakpoint Dump (s); @@ -957,6 +949,34 @@ Breakpoint::GetFilterDescription (Stream *s) m_filter_sp->GetDescription (s); } +bool +Breakpoint::EvaluatePrecondition (StoppointCallbackContext &context) +{ + if (!m_precondition_sp) + return true; + + return m_precondition_sp->EvaluatePrecondition(context); +} + +bool +Breakpoint::BreakpointPrecondition::EvaluatePrecondition(StoppointCallbackContext &context) +{ + return true; +} + +void +Breakpoint::BreakpointPrecondition::DescribePrecondition(Stream &stream, lldb::DescriptionLevel level) +{ +} + +Error +Breakpoint::BreakpointPrecondition::ConfigurePrecondition(Args &options) +{ + Error error; + error.SetErrorString("Base breakpoint precondition has no options."); + return error; +} + void Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind) { diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp index 85233c9374cb..ef9144778df0 100644 --- a/source/Breakpoint/BreakpointLocation.cpp +++ b/source/Breakpoint/BreakpointLocation.cpp @@ -7,15 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes // C++ Includes #include <string> // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-log.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -23,6 +20,8 @@ #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/ClangUserExpression.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Target.h" @@ -535,6 +534,7 @@ bool BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp) { m_bp_site_sp = bp_site_sp; + SendBreakpointLocationChangedEvent (eBreakpointEventTypeLocationsResolved); return true; } @@ -590,7 +590,7 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) s->PutCString ("re-exported target = "); else s->PutCString("where = "); - sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true); + sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true, true); } else { diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp index 5756ccedfaa4..5b6e746f911d 100644 --- a/source/Breakpoint/BreakpointLocationCollection.cpp +++ b/source/Breakpoint/BreakpointLocationCollection.cpp @@ -138,11 +138,17 @@ bool BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context) { bool shouldStop = false; - const size_t count = GetSize(); - for (size_t i = 0; i < count; i++) + size_t i = 0; + size_t prev_size = GetSize(); + while (i < prev_size) { + // ShouldStop can remove the breakpoint from the list if (GetByIndex(i)->ShouldStop(context)) shouldStop = true; + + if (prev_size == GetSize()) + i++; + prev_size = GetSize(); } return shouldStop; } diff --git a/source/Breakpoint/BreakpointResolver.cpp b/source/Breakpoint/BreakpointResolver.cpp index 33b0ff40e35f..f02eadf86a7c 100644 --- a/source/Breakpoint/BreakpointResolver.cpp +++ b/source/Breakpoint/BreakpointResolver.cpp @@ -25,7 +25,6 @@ #include "lldb/Target/Target.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" -#include "lldb/lldb-private-log.h" using namespace lldb_private; using namespace lldb; diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp index d6647130c54c..193bc413af05 100644 --- a/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/source/Breakpoint/BreakpointResolverAddress.cpp @@ -13,11 +13,11 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-log.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" +#include "lldb/Target/Process.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp index 950054c3d720..408998ec83ab 100644 --- a/source/Breakpoint/BreakpointResolverFileLine.cpp +++ b/source/Breakpoint/BreakpointResolverFileLine.cpp @@ -19,7 +19,6 @@ #include "lldb/Core/StreamString.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; @@ -33,13 +32,15 @@ BreakpointResolverFileLine::BreakpointResolverFileLine const FileSpec &file_spec, uint32_t line_no, bool check_inlines, - bool skip_prologue + bool skip_prologue, + bool exact_match ) : BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), m_file_spec (file_spec), m_line_number (line_no), m_inlines (check_inlines), - m_skip_prologue(skip_prologue) + m_skip_prologue(skip_prologue), + m_exact_match(exact_match) { } @@ -79,7 +80,7 @@ BreakpointResolverFileLine::SearchCallback if (cu_sp) { if (filter.CompUnitPasses(*cu_sp)) - cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list); + cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, m_exact_match, eSymbolContextEverything, sc_list); } } StreamString s; @@ -101,7 +102,7 @@ BreakpointResolverFileLine::GetDepth() void BreakpointResolverFileLine::GetDescription (Stream *s) { - s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number); + s->Printf ("file = '%s', line = %u, exact_match = %d", m_file_spec.GetPath().c_str(), m_line_number, m_exact_match); } void @@ -117,7 +118,8 @@ BreakpointResolverFileLine::CopyForBreakpoint (Breakpoint &breakpoint) m_file_spec, m_line_number, m_inlines, - m_skip_prologue)); + m_skip_prologue, + m_exact_match)); return ret_sp; } diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp index c71d9bf5ba8c..e7bce0524c57 100644 --- a/source/Breakpoint/BreakpointResolverFileRegex.cpp +++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -19,7 +19,6 @@ #include "lldb/Core/StreamString.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/Target.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; @@ -30,10 +29,12 @@ using namespace lldb_private; BreakpointResolverFileRegex::BreakpointResolverFileRegex ( Breakpoint *bkpt, - RegularExpression ®ex + RegularExpression ®ex, + bool exact_match ) : BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver), - m_regex (regex) + m_regex (regex), + m_exact_match (exact_match) { } @@ -65,9 +66,8 @@ BreakpointResolverFileRegex::SearchCallback { SymbolContextList sc_list; const bool search_inlines = false; - const bool exact = false; - cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, exact, eSymbolContextEverything, sc_list); + cu->ResolveSymbolContext (cu_file_spec, line_matches[i], search_inlines, m_exact_match, eSymbolContextEverything, sc_list); const bool skip_prologue = true; BreakpointResolver::SetSCMatchesByLine (filter, sc_list, skip_prologue, m_regex.GetText()); @@ -86,7 +86,7 @@ BreakpointResolverFileRegex::GetDepth() void BreakpointResolverFileRegex::GetDescription (Stream *s) { - s->Printf ("source regex = \"%s\"", m_regex.GetText()); + s->Printf ("source regex = \"%s\", exact_match = %d", m_regex.GetText(), m_exact_match); } void @@ -98,7 +98,7 @@ BreakpointResolverFileRegex::Dump (Stream *s) const lldb::BreakpointResolverSP BreakpointResolverFileRegex::CopyForBreakpoint (Breakpoint &breakpoint) { - lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex)); + lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(&breakpoint, m_regex, m_exact_match)); return ret_sp; } diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp index 469514b03f8a..e9ce812e7732 100644 --- a/source/Breakpoint/BreakpointSite.cpp +++ b/source/Breakpoint/BreakpointSite.cpp @@ -11,11 +11,14 @@ // C Includes // C++ Includes +#include <inttypes.h> + // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSiteList.h" +#include "lldb/Core/Stream.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp index c65dd9d460f4..37696e3bbfdb 100644 --- a/source/Commands/CommandCompletions.cpp +++ b/source/Commands/CommandCompletions.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes #include <sys/stat.h> #if defined(__APPLE__) || defined(__linux__) @@ -25,6 +23,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" #include "lldb/Target/Target.h" diff --git a/source/Commands/CommandObjectApropos.cpp b/source/Commands/CommandObjectApropos.cpp index 02dc7269775d..47890b1e83b7 100644 --- a/source/Commands/CommandObjectApropos.cpp +++ b/source/Commands/CommandObjectApropos.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectApropos.h" // C Includes @@ -17,6 +15,7 @@ // Project includes #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/Property.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" diff --git a/source/Commands/CommandObjectArgs.cpp b/source/Commands/CommandObjectArgs.cpp index b0fe42bc2446..cf32d104911c 100644 --- a/source/Commands/CommandObjectArgs.cpp +++ b/source/Commands/CommandObjectArgs.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectArgs.h" // C Includes @@ -25,8 +23,10 @@ #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Variable.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp index 025524b3b9a5..4cbcb70d5fd2 100644 --- a/source/Commands/CommandObjectBreakpoint.cpp +++ b/source/Commands/CommandObjectBreakpoint.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectBreakpoint.h" #include "CommandObjectBreakpointCommand.h" @@ -21,12 +19,14 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamString.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Target/StackFrame.h" @@ -110,9 +110,11 @@ public: m_catch_bp (false), m_throw_bp (true), m_hardware (false), - m_language (eLanguageTypeUnknown), + m_exception_language (eLanguageTypeUnknown), m_skip_prologue (eLazyBoolCalculate), - m_one_shot (false) + m_one_shot (false), + m_all_files (false), + m_move_to_nearest_code (eLazyBoolCalculate) { } @@ -135,15 +137,23 @@ public: } break; + case 'A': + m_all_files = true; + break; + case 'b': m_func_names.push_back (option_arg); m_func_name_type_mask |= eFunctionNameTypeBase; break; case 'C': - m_column = StringConvert::ToUInt32 (option_arg, 0); + { + bool success; + m_column = StringConvert::ToUInt32 (option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("invalid column number: %s", option_arg); break; - + } case 'c': m_condition.assign(option_arg); break; @@ -162,16 +172,16 @@ public: case eLanguageTypeC: case eLanguageTypeC99: case eLanguageTypeC11: - m_language = eLanguageTypeC; + m_exception_language = eLanguageTypeC; break; case eLanguageTypeC_plus_plus: case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: case eLanguageTypeC_plus_plus_14: - m_language = eLanguageTypeC_plus_plus; + m_exception_language = eLanguageTypeC_plus_plus; break; case eLanguageTypeObjC: - m_language = eLanguageTypeObjC; + m_exception_language = eLanguageTypeObjC; break; case eLanguageTypeObjC_plus_plus: error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c"); @@ -231,8 +241,28 @@ public: break; case 'l': - m_line_num = StringConvert::ToUInt32 (option_arg, 0); + { + bool success; + m_line_num = StringConvert::ToUInt32 (option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat ("invalid line number: %s.", option_arg); + break; + } + + case 'm': + { + bool success; + bool value; + value = Args::StringToBoolean (option_arg, true, &success); + if (value) + m_move_to_nearest_code = eLazyBoolYes; + else + m_move_to_nearest_code = eLazyBoolNo; + + if (!success) + error.SetErrorStringWithFormat ("Invalid boolean value for move-to-nearest-code option: '%s'", option_arg); break; + } case 'M': m_func_names.push_back (option_arg); @@ -253,6 +283,11 @@ public: m_one_shot = true; break; + case 'O': + m_exception_extra_args.AppendArgument ("-O"); + m_exception_extra_args.AppendArgument (option_arg); + break; + case 'p': m_source_text_regexp.assign (option_arg); break; @@ -334,11 +369,14 @@ public: m_catch_bp = false; m_throw_bp = true; m_hardware = false; - m_language = eLanguageTypeUnknown; + m_exception_language = eLanguageTypeUnknown; m_skip_prologue = eLazyBoolCalculate; m_one_shot = false; m_use_dummy = false; m_breakpoint_names.clear(); + m_all_files = false; + m_exception_extra_args.Clear(); + m_move_to_nearest_code = eLazyBoolCalculate; } const OptionDefinition* @@ -372,10 +410,13 @@ public: bool m_catch_bp; bool m_throw_bp; bool m_hardware; // Request to use hardware breakpoints - lldb::LanguageType m_language; + lldb::LanguageType m_exception_language; LazyBool m_skip_prologue; bool m_one_shot; bool m_use_dummy; + bool m_all_files; + Args m_exception_extra_args; + LazyBool m_move_to_nearest_code; }; @@ -413,7 +454,7 @@ protected: break_type = eSetTypeFunctionRegexp; else if (!m_options.m_source_text_regexp.empty()) break_type = eSetTypeSourceRegexp; - else if (m_options.m_language != eLanguageTypeUnknown) + else if (m_options.m_exception_language != eLanguageTypeUnknown) break_type = eSetTypeException; Breakpoint *bp = NULL; @@ -453,7 +494,8 @@ protected: check_inlines, m_options.m_skip_prologue, internal, - m_options.m_hardware).get(); + m_options.m_hardware, + m_options.m_move_to_nearest_code).get(); } break; @@ -505,7 +547,7 @@ protected: { const size_t num_files = m_options.m_filenames.GetSize(); - if (num_files == 0) + if (num_files == 0 && !m_options.m_all_files) { FileSpec file; if (!GetDefaultFile (target, file, result)) @@ -534,15 +576,27 @@ protected: &(m_options.m_filenames), regexp, internal, - m_options.m_hardware).get(); + m_options.m_hardware, + m_options.m_move_to_nearest_code).get(); } break; case eSetTypeException: { - bp = target->CreateExceptionBreakpoint (m_options.m_language, + Error precond_error; + bp = target->CreateExceptionBreakpoint (m_options.m_exception_language, m_options.m_catch_bp, m_options.m_throw_bp, - m_options.m_hardware).get(); + internal, + &m_options.m_exception_extra_args, + &precond_error).get(); + if (precond_error.Fail()) + { + result.AppendErrorWithFormat("Error setting extra exception arguments: %s", + precond_error.AsCString()); + target->RemoveBreakpointByID(bp->GetID()); + result.SetStatus(eReturnStatusFailed); + return false; + } } break; default: @@ -654,6 +708,7 @@ private: #define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 ) #define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 ) #define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) ) +#define LLDB_OPT_MOVE_TO_NEAREST_CODE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_9 ) OptionDefinition CommandObjectBreakpointSet::CommandOptions::g_option_table[] = @@ -729,6 +784,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = "specified with the -f option. The -f option can be specified more than once. " "If no source files are specified, uses the current \"default source file\"" }, + { LLDB_OPT_SET_9, false, "all-files", 'A', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "All files are searched for source pattern matches." }, + { LLDB_OPT_SET_10, true, "language-exception", 'E', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage, "Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.)" }, @@ -738,6 +796,10 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Set the breakpoint on exception catcH." }, +// Don't add this option till it actually does something useful... +// { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeTypeName, +// "The breakpoint will only stop if an exception Object of this type is thrown. Can be repeated multiple times to stop for multiple object types" }, + { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." }, @@ -747,6 +809,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Adds this to the list of names for this breakopint."}, + { LLDB_OPT_MOVE_TO_NEAREST_CODE, false, "move-to-nearest-code", 'm', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, + "Move breakpoints to nearest code. If not set the target.move-to-nearest-code setting is used." }, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1940,15 +2005,15 @@ public: { case 'N': if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success()) - m_name.SetValueFromCString(option_value); + m_name.SetValueFromString(option_value); break; case 'B': - if (m_breakpoint.SetValueFromCString(option_value).Fail()) + if (m_breakpoint.SetValueFromString(option_value).Fail()) error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value); break; case 'D': - if (m_use_dummy.SetValueFromCString(option_value).Fail()) + if (m_use_dummy.SetValueFromString(option_value).Fail()) error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value); break; @@ -2188,7 +2253,6 @@ public: } protected: -protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp index 8f8404b712a5..180ab600a50e 100644 --- a/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/source/Commands/CommandObjectBreakpointCommand.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes // C++ Includes diff --git a/source/Commands/CommandObjectBugreport.cpp b/source/Commands/CommandObjectBugreport.cpp new file mode 100644 index 000000000000..f171d2f6267f --- /dev/null +++ b/source/Commands/CommandObjectBugreport.cpp @@ -0,0 +1,145 @@ +//===-- CommandObjectBugreport.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectBugreport.h" + +// C Includes +#include <cstdio> + +// C++ Includes +// Other libraries and framework includes + +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionGroupOutputFile.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// "bugreport unwind" +//------------------------------------------------------------------------- + +class CommandObjectBugreportUnwind : public CommandObjectParsed +{ +public: + CommandObjectBugreportUnwind(CommandInterpreter &interpreter) : + CommandObjectParsed(interpreter, + "bugreport unwind", + "Create a bugreport for a bug in the stack unwinding code.", + nullptr), + m_option_group(interpreter), + m_outfile_options() + { + m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); + m_option_group.Finalize(); + } + + ~CommandObjectBugreportUnwind() + { + } + + Options * + GetOptions() override + { + return &m_option_group; + } + +protected: + bool + DoExecute(Args& command, CommandReturnObject &result) override + { + StringList commands; + commands.AppendString("thread backtrace"); + + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (thread) + { + char command_buffer[256]; + + uint32_t frame_count = thread->GetStackFrameCount(); + for (uint32_t i = 0; i < frame_count; ++i) + { + StackFrameSP frame = thread->GetStackFrameAtIndex(i); + lldb::addr_t pc = frame->GetStackID().GetPC(); + + snprintf(command_buffer, sizeof(command_buffer), "disassemble --bytes --address 0x%" PRIx64, pc); + commands.AppendString(command_buffer); + + snprintf(command_buffer, sizeof(command_buffer), "image show-unwind --address 0x%" PRIx64, pc); + commands.AppendString(command_buffer); + } + } + + const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue(); + if (outfile_spec) + { + char path[PATH_MAX]; + outfile_spec.GetPath (path, sizeof(path)); + + uint32_t open_options = File::eOpenOptionWrite | + File::eOpenOptionCanCreate | + File::eOpenOptionAppend | + File::eOpenOptionCloseOnExec; + + const bool append = m_outfile_options.GetAppend().GetCurrentValue(); + if (!append) + open_options |= File::eOpenOptionTruncate; + + StreamFileSP outfile_stream = std::make_shared<StreamFile>(); + Error error = outfile_stream->GetFile().Open(path, open_options); + if (error.Fail()) + { + result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n", + path, + append ? "append" : "write", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + result.SetImmediateOutputStream(outfile_stream); + } + + CommandInterpreterRunOptions options; + options.SetStopOnError(false); + options.SetEchoCommands(true); + options.SetPrintResults(true); + options.SetAddToHistory(false); + m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result); + + return result.Succeeded(); + } + +private: + OptionGroupOptions m_option_group; + OptionGroupOutputFile m_outfile_options; +}; + +#pragma mark CommandObjectMultiwordBugreport + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBugreport +//------------------------------------------------------------------------- + +CommandObjectMultiwordBugreport::CommandObjectMultiwordBugreport(CommandInterpreter &interpreter) : + CommandObjectMultiword(interpreter, + "bugreport", + "Set of commands for creating domain specific bugreports.", + "bugreport <subcommand> [<subcommand-options>]") +{ + + LoadSubCommand("unwind", CommandObjectSP(new CommandObjectBugreportUnwind(interpreter))); +} + +CommandObjectMultiwordBugreport::~CommandObjectMultiwordBugreport () +{ +} diff --git a/source/Commands/CommandObjectBugreport.h b/source/Commands/CommandObjectBugreport.h new file mode 100644 index 000000000000..d062e0d79373 --- /dev/null +++ b/source/Commands/CommandObjectBugreport.h @@ -0,0 +1,36 @@ +//===-- CommandObjectBugreport.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectBugreport_h_ +#define liblldb_CommandObjectBugreport_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBugreport +//------------------------------------------------------------------------- + +class CommandObjectMultiwordBugreport : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordBugreport(CommandInterpreter &interpreter); + + virtual + ~CommandObjectMultiwordBugreport(); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectBugreport_h_ diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp index f98eac055f24..5fd99cfdabf4 100644 --- a/source/Commands/CommandObjectCommands.cpp +++ b/source/Commands/CommandObjectCommands.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectCommands.h" // C Includes @@ -29,7 +27,6 @@ #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" using namespace lldb; using namespace lldb_private; @@ -85,7 +82,7 @@ protected: switch (short_option) { case 'c': - error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_count.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 's': if (option_arg && strcmp("end", option_arg) == 0) @@ -94,10 +91,10 @@ protected: m_start_idx.SetOptionWasSet(); } else - error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_start_idx.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 'e': - error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign); + error = m_stop_idx.SetValueFromString(option_arg,eVarSetOperationAssign); break; case 'C': m_clear.SetCurrentValue(true); @@ -326,15 +323,15 @@ protected: switch (short_option) { case 'e': - error = m_stop_on_error.SetValueFromCString(option_arg); + error = m_stop_on_error.SetValueFromString(option_arg); break; case 'c': - error = m_stop_on_continue.SetValueFromCString(option_arg); + error = m_stop_on_continue.SetValueFromString(option_arg); break; case 's': - error = m_silent_run.SetValueFromCString(option_arg); + error = m_silent_run.SetValueFromString(option_arg); break; default: @@ -1430,6 +1427,130 @@ protected: }; +class CommandObjectScriptingObject : public CommandObjectRaw +{ +private: + StructuredData::GenericSP m_cmd_obj_sp; + ScriptedCommandSynchronicity m_synchro; + bool m_fetched_help_short:1; + bool m_fetched_help_long:1; + +public: + + CommandObjectScriptingObject (CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch) : + CommandObjectRaw (interpreter, + name.c_str(), + NULL, + NULL), + m_cmd_obj_sp(cmd_obj_sp), + m_synchro(synch), + m_fetched_help_short(false), + m_fetched_help_long(false) + { + StreamString stream; + stream.Printf("For more information run 'help %s'",name.c_str()); + SetHelp(stream.GetData()); + if (ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter()) + GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); + } + + virtual + ~CommandObjectScriptingObject () + { + } + + virtual bool + IsRemovable () const + { + return true; + } + + StructuredData::GenericSP + GetImplementingObject () + { + return m_cmd_obj_sp; + } + + ScriptedCommandSynchronicity + GetSynchronicity () + { + return m_synchro; + } + + virtual const char * + GetHelp () + { + if (!m_fetched_help_short) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + if (scripter) + { + std::string docstring; + m_fetched_help_short = scripter->GetShortHelpForCommandObject(m_cmd_obj_sp,docstring); + if (!docstring.empty()) + SetHelp(docstring); + } + } + return CommandObjectRaw::GetHelp(); + } + + virtual const char * + GetHelpLong () + { + if (!m_fetched_help_long) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + if (scripter) + { + std::string docstring; + m_fetched_help_long = scripter->GetLongHelpForCommandObject(m_cmd_obj_sp,docstring); + if (!docstring.empty()) + SetHelpLong(docstring); + } + } + return CommandObjectRaw::GetHelpLong(); + } + +protected: + virtual bool + DoExecute (const char *raw_command_line, CommandReturnObject &result) + { + ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter(); + + Error error; + + result.SetStatus(eReturnStatusInvalid); + + if (!scripter || scripter->RunScriptBasedCommand(m_cmd_obj_sp, + raw_command_line, + m_synchro, + result, + error, + m_exe_ctx) == false) + { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + else + { + // Don't change the status if the command already set it... + if (result.GetStatus() == eReturnStatusInvalid) + { + if (result.GetOutputData() == NULL || result.GetOutputData()[0] == '\0') + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + } + } + + return result.Succeeded(); + } + +}; + //------------------------------------------------------------------------- // CommandObjectCommandsScriptImport //------------------------------------------------------------------------- @@ -1449,7 +1570,7 @@ public: // Define the first (and only) variant of this arg. cmd_arg.arg_type = eArgTypeFilename; - cmd_arg.arg_repetition = eArgRepeatPlain; + cmd_arg.arg_repetition = eArgRepeatPlus; // There is only one variant this argument could be; put it into the argument entry. arg1.push_back (cmd_arg); @@ -1549,7 +1670,6 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { result.AppendError ("only scripting language supported for module importing is currently Python"); @@ -1558,36 +1678,40 @@ protected: } size_t argc = command.GetArgumentCount(); - - if (argc != 1) + if (0 == argc) { - result.AppendError ("'command script import' requires one argument"); + result.AppendError("command script import needs one or more arguments"); result.SetStatus (eReturnStatusFailed); return false; } - std::string path = command.GetArgumentAtIndex(0); - Error error; - - const bool init_session = true; - // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that - // commands won't ever be recursively invoked, but it's actually possible to craft - // a Python script that does other "command script imports" in __lldb_init_module - // the real fix is to have recursive commands possible with a CommandInvocation object - // separate from the CommandObject itself, so that recursive command invocations - // won't stomp on each other (wrt to execution contents, options, and more) - m_exe_ctx.Clear(); - if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), - m_options.m_allow_reload, - init_session, - error)) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else + for (size_t i = 0; + i < argc; + i++) { - result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); - result.SetStatus (eReturnStatusFailed); + std::string path = command.GetArgumentAtIndex(i); + Error error; + + const bool init_session = true; + // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that + // commands won't ever be recursively invoked, but it's actually possible to craft + // a Python script that does other "command script imports" in __lldb_init_module + // the real fix is to have recursive commands possible with a CommandInvocation object + // separate from the CommandObject itself, so that recursive command invocations + // won't stomp on each other (wrt to execution contents, options, and more) + m_exe_ctx.Clear(); + if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(), + m_options.m_allow_reload, + init_session, + error)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } } return result.Succeeded(); @@ -1652,7 +1776,11 @@ protected: public: CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) + Options (interpreter), + m_class_name(), + m_funct_name(), + m_short_help(), + m_synchronicity(eScriptedCommandSynchronicitySynchronous) { } @@ -1671,6 +1799,10 @@ protected: if (option_arg) m_funct_name.assign(option_arg); break; + case 'c': + if (option_arg) + m_class_name.assign(option_arg); + break; case 'h': if (option_arg) m_short_help.assign(option_arg); @@ -1691,6 +1823,7 @@ protected: void OptionParsingStarting () { + m_class_name.clear(); m_funct_name.clear(); m_short_help.clear(); m_synchronicity = eScriptedCommandSynchronicitySynchronous; @@ -1708,6 +1841,7 @@ protected: // Instance variables to hold the values for command options. + std::string m_class_name; std::string m_funct_name; std::string m_short_help; ScriptedCommandSynchronicity m_synchronicity; @@ -1812,20 +1946,55 @@ protected: m_short_help.assign(m_options.m_short_help); m_synchronicity = m_options.m_synchronicity; - if (m_options.m_funct_name.empty()) + if (m_options.m_class_name.empty()) { - m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt - *this, // IOHandlerDelegate - true, // Run IOHandler in async mode - NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + if (m_options.m_funct_name.empty()) + { + m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + } + else + { + CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, + m_cmd_name, + m_options.m_funct_name, + m_options.m_short_help, + m_synchronicity)); + if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError("cannot add command"); + result.SetStatus (eReturnStatusFailed); + } + } } else { - CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, - m_cmd_name, - m_options.m_funct_name, - m_options.m_short_help, - m_synchronicity)); + ScriptInterpreter *interpreter = GetCommandInterpreter().GetScriptInterpreter(); + if (!interpreter) + { + result.AppendError("cannot find ScriptInterpreter"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto cmd_obj_sp = interpreter->CreateScriptCommandObject(m_options.m_class_name.c_str()); + if (!cmd_obj_sp) + { + result.AppendError("cannot create helper object"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + CommandObjectSP new_cmd(new CommandObjectScriptingObject(m_interpreter, + m_cmd_name, + cmd_obj_sp, + m_synchronicity)); if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { result.SetStatus (eReturnStatusSuccessFinishNoResult); @@ -1859,8 +2028,9 @@ OptionDefinition CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "function", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."}, + { LLDB_OPT_SET_2, false, "class", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "Name of the Python class to bind to this command name."}, { LLDB_OPT_SET_1, false, "help" , 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeHelpText, "The help text to display for this command."}, - { LLDB_OPT_SET_1, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, + { LLDB_OPT_SET_ALL, false, "synchronicity", 's', OptionParser::eRequiredArgument, NULL, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; diff --git a/source/Commands/CommandObjectDisassemble.cpp b/source/Commands/CommandObjectDisassemble.cpp index 2ba47be1ecf0..1e575fe963f3 100644 --- a/source/Commands/CommandObjectDisassemble.cpp +++ b/source/Commands/CommandObjectDisassemble.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectDisassemble.h" // C Includes diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp index e87399f97baa..f4bb8fbac11e 100644 --- a/source/Commands/CommandObjectExpression.cpp +++ b/source/Commands/CommandObjectExpression.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectExpression.h" // C Includes @@ -196,7 +194,7 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete "expression", "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.", NULL, - eFlagProcessMustBePaused | eFlagTryTargetAPILock), + eCommandProcessMustBePaused | eCommandTryTargetAPILock), IOHandlerDelegate (IOHandlerDelegate::Completion::Expression), m_option_group (interpreter), m_format_options (eFormatDefault), @@ -487,7 +485,7 @@ CommandObjectExpression::DoExecute if (end_options) { - Args args (command, end_options - command); + Args args (llvm::StringRef(command, end_options - command)); if (!ParseOptions (args, result)) return false; diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp index 4458a692a189..d8b65e3b551a 100644 --- a/source/Commands/CommandObjectFrame.cpp +++ b/source/Commands/CommandObjectFrame.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectFrame.h" // C Includes @@ -65,10 +63,10 @@ public: "frame info", "List information about the currently selected frame in the current thread.", "frame info", - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { } @@ -156,10 +154,10 @@ public: "frame select", "Select a frame by index from within the current thread and make it the current frame.", NULL, - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options (interpreter) { CommandArgumentEntry arg; @@ -192,7 +190,7 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - // No need to check "thread" for validity as eFlagRequiresThread ensures it is valid + // No need to check "thread" for validity as eCommandRequiresThread ensures it is valid Thread *thread = m_exe_ctx.GetThreadPtr(); uint32_t frame_idx = UINT32_MAX; @@ -314,11 +312,11 @@ public: "Children of aggregate variables can be specified such as " "'var->child.x'.", NULL, - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused | - eFlagRequiresProcess), + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused | + eCommandRequiresProcess), m_option_group (interpreter), m_option_variable(true), // Include the frame specific options by passing "true" m_option_format (eFormatDefault), @@ -385,7 +383,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - // No need to check "frame" for validity as eFlagRequiresFrame ensures it is valid + // No need to check "frame" for validity as eCommandRequiresFrame ensures it is valid StackFrame *frame = m_exe_ctx.GetFramePtr(); Stream &s = result.GetOutputStream(); @@ -522,30 +520,31 @@ protected: { var_sp = variable_list->GetVariableAtIndex(i); bool dump_variable = true; + std::string scope_string; switch (var_sp->GetScope()) { case eValueTypeVariableGlobal: dump_variable = m_option_variable.show_globals; if (dump_variable && m_option_variable.show_scope) - s.PutCString("GLOBAL: "); + scope_string = "GLOBAL: "; break; case eValueTypeVariableStatic: dump_variable = m_option_variable.show_globals; if (dump_variable && m_option_variable.show_scope) - s.PutCString("STATIC: "); + scope_string = "STATIC: "; break; case eValueTypeVariableArgument: dump_variable = m_option_variable.show_args; if (dump_variable && m_option_variable.show_scope) - s.PutCString(" ARG: "); + scope_string = " ARG: "; break; case eValueTypeVariableLocal: dump_variable = m_option_variable.show_locals; if (dump_variable && m_option_variable.show_scope) - s.PutCString(" LOCAL: "); + scope_string = " LOCAL: "; break; default: @@ -555,7 +554,7 @@ protected: if (dump_variable) { // Use the variable object code to make sure we are - // using the same APIs as the the public API will be + // using the same APIs as the public API will be // using... valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); @@ -568,6 +567,13 @@ protected: // that are not in scope to avoid extra unneeded output if (valobj_sp->IsInScope ()) { + if (false == valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && + true == valobj_sp->IsRuntimeSupportValue()) + continue; + + if (!scope_string.empty()) + s.PutCString(scope_string.c_str()); + if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) { var_sp->GetDeclaration ().DumpStopContext (&s, false); diff --git a/source/Commands/CommandObjectGUI.cpp b/source/Commands/CommandObjectGUI.cpp index 359d6d2892d0..0991c7e84874 100644 --- a/source/Commands/CommandObjectGUI.cpp +++ b/source/Commands/CommandObjectGUI.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectGUI.h" // C Includes diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp index b02515e2d1e8..18dc44a32b5a 100644 --- a/source/Commands/CommandObjectHelp.cpp +++ b/source/Commands/CommandObjectHelp.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectHelp.h" // C Includes diff --git a/source/Commands/CommandObjectLanguage.cpp b/source/Commands/CommandObjectLanguage.cpp new file mode 100644 index 000000000000..9d4b85630a1f --- /dev/null +++ b/source/Commands/CommandObjectLanguage.cpp @@ -0,0 +1,44 @@ +//===-- CommandObjectLanguage.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectLanguage.h" + +#include "lldb/Host/Host.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +#include "lldb/Target/LanguageRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +CommandObjectLanguage::CommandObjectLanguage (CommandInterpreter &interpreter) : +CommandObjectMultiword (interpreter, + "language", + "A set of commands for managing language-specific functionality.'.", + "language <language-name> <subcommand> [<subcommand-options>]" + ) +{ + //Let the LanguageRuntime populates this command with subcommands + LanguageRuntime::InitializeCommands(this); +} + +void +CommandObjectLanguage::GenerateHelpText (Stream &output_stream) { + CommandObjectMultiword::GenerateHelpText(output_stream); + + output_stream << "\nlanguage name can be one of the following:\n"; + + LanguageRuntime::PrintAllLanguages(output_stream, " ", "\n"); +} + +CommandObjectLanguage::~CommandObjectLanguage () +{ +} diff --git a/source/Commands/CommandObjectLanguage.h b/source/Commands/CommandObjectLanguage.h new file mode 100644 index 000000000000..751fe1440a8b --- /dev/null +++ b/source/Commands/CommandObjectLanguage.h @@ -0,0 +1,41 @@ +//===-- CommandObjectLanguage.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectLanguage_h_ +#define liblldb_CommandObjectLanguage_h_ + +// C Includes +// C++ Includes + + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-types.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + class CommandObjectLanguage : public CommandObjectMultiword + { + public: + CommandObjectLanguage (CommandInterpreter &interpreter); + + virtual + ~CommandObjectLanguage (); + + virtual void + GenerateHelpText (Stream &output_stream); + + protected: + bool + DoExecute (Args& command, CommandReturnObject &result); + }; +} // namespace lldb_private + +#endif // liblldb_CommandObjectLanguage_h_ diff --git a/source/Commands/CommandObjectLog.cpp b/source/Commands/CommandObjectLog.cpp index aa09f53c792b..e68eaf17bb9f 100644 --- a/source/Commands/CommandObjectLog.cpp +++ b/source/Commands/CommandObjectLog.cpp @@ -7,16 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectLog.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-log.h" - #include "lldb/Interpreter/Args.h" #include "lldb/Core/Debugger.h" #include "lldb/Host/FileSpec.h" @@ -148,6 +144,7 @@ public: case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break; + case 'a': log_options |= LLDB_LOG_OPTION_APPEND; break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -225,6 +222,7 @@ CommandObjectLogEnable::CommandOptions::g_option_table[] = { LLDB_OPT_SET_1, false, "pid-tid", 'p', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." }, { LLDB_OPT_SET_1, false, "thread-name",'n', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." }, { LLDB_OPT_SET_1, false, "stack", 'S', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." }, +{ LLDB_OPT_SET_1, false, "append", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Append to the log file instead of overwriting." }, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp index dac6dd81651b..d589800299a3 100644 --- a/source/Commands/CommandObjectMemory.cpp +++ b/source/Commands/CommandObjectMemory.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectMemory.h" // C Includes @@ -16,6 +14,7 @@ // C++ Includes // Other libraries and framework includes +#include "clang/AST/Decl.h" // Project includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" @@ -24,6 +23,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Expression/ClangPersistentVariables.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -95,7 +95,7 @@ public: switch (short_option) { case 'l': - error = m_num_per_line.SetValueFromCString (option_arg); + error = m_num_per_line.SetValueFromString (option_arg); if (m_num_per_line.GetCurrentValue() == 0) error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg); break; @@ -105,7 +105,7 @@ public: break; case 't': - error = m_view_as_type.SetValueFromCString (option_arg); + error = m_view_as_type.SetValueFromString (option_arg); break; case 'r': @@ -313,7 +313,7 @@ public: "memory read", "Read from the memory of the process being debugged.", NULL, - eFlagRequiresTarget | eFlagProcessMustBePaused), + eCommandRequiresTarget | eCommandProcessMustBePaused), m_option_group (interpreter), m_format_options (eFormatBytesWithASCII, 1, 8), m_memory_options (), @@ -386,7 +386,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid + // No need to check "target" for validity as eCommandRequiresTarget ensures it is valid Target *target = m_exe_ctx.GetTargetPtr(); const size_t argc = command.GetArgumentCount(); @@ -532,7 +532,7 @@ protected: clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name)); if (tdecl) { - clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl()); + clang_ast_type.SetClangType(&tdecl->getASTContext(),(const lldb::clang_type_t)tdecl->getTypeForDecl()); } } @@ -742,6 +742,7 @@ protected: auto data_addr = addr; auto count = item_count; item_count = 0; + bool break_on_no_NULL = false; while (item_count < count) { std::string buffer; @@ -754,17 +755,24 @@ protected: result.SetStatus(eReturnStatusFailed); return false; } + if (item_byte_size == read) { result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr); - break; + --read; + break_on_no_NULL = true; } - read+=1; // account for final NULL byte + else + ++read; // account for final NULL byte + memcpy(data_ptr, &buffer[0], read); data_ptr += read; data_addr += read; bytes_read += read; item_count++; // if we break early we know we only read item_count strings + + if (break_on_no_NULL) + break; } data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1)); } @@ -981,20 +989,20 @@ public: switch (short_option) { case 'e': - m_expr.SetValueFromCString(option_arg); + m_expr.SetValueFromString(option_arg); break; case 's': - m_string.SetValueFromCString(option_arg); + m_string.SetValueFromString(option_arg); break; case 'c': - if (m_count.SetValueFromCString(option_arg).Fail()) + if (m_count.SetValueFromString(option_arg).Fail()) error.SetErrorString("unrecognized value for count"); break; case 'o': - if (m_offset.SetValueFromCString(option_arg).Fail()) + if (m_offset.SetValueFromString(option_arg).Fail()) error.SetErrorString("unrecognized value for dump-offset"); break; @@ -1024,7 +1032,7 @@ public: "memory find", "Find a value in the memory of the process being debugged.", NULL, - eFlagRequiresProcess | eFlagProcessMustBeLaunched), + eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_option_group (interpreter), m_memory_options () { @@ -1070,7 +1078,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid + // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid Process *process = m_exe_ctx.GetProcessPtr(); const size_t argc = command.GetArgumentCount(); @@ -1325,7 +1333,7 @@ public: "memory write", "Write to the memory of the process being debugged.", NULL, - eFlagRequiresProcess | eFlagProcessMustBeLaunched), + eCommandRequiresProcess | eCommandProcessMustBeLaunched), m_option_group (interpreter), m_format_options (eFormatBytes, 1, UINT64_MAX), m_memory_options () @@ -1402,7 +1410,7 @@ protected: virtual bool DoExecute (Args& command, CommandReturnObject &result) { - // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid + // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid Process *process = m_exe_ctx.GetProcessPtr(); const size_t argc = command.GetArgumentCount(); @@ -1692,7 +1700,7 @@ public: "memory history", "Prints out the recorded stack traces for allocation/deallocation of a memory address.", NULL, - eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched) + eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBePaused | eCommandProcessMustBeLaunched) { CommandArgumentEntry arg1; CommandArgumentData addr_arg; diff --git a/source/Commands/CommandObjectMultiword.cpp b/source/Commands/CommandObjectMultiword.cpp index 69b178da46ba..2f0e2a78a0cc 100644 --- a/source/Commands/CommandObjectMultiword.cpp +++ b/source/Commands/CommandObjectMultiword.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/Interpreter/CommandObjectMultiword.h" // C Includes // C++ Includes @@ -153,7 +151,7 @@ CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &re error_msg.append (GetCommandName()); error_msg.append (" "); error_msg.append (sub_command); - error_msg.append ("'"); + error_msg.append ("'."); if (num_subcmd_matches > 0) { @@ -251,23 +249,27 @@ CommandObjectMultiword::HandleCompletion &temp_matches); if (cmd_obj != NULL) { - matches.DeleteStringAtIndex (0); - input.Shift(); - cursor_char_position = 0; - input.AppendArgument (""); - return cmd_obj->HandleCompletion (input, - cursor_index, - cursor_char_position, - match_start_point, - max_return_elements, - word_complete, - matches); + if (input.GetArgumentCount() == 1) + { + word_complete = true; + } + else + { + matches.DeleteStringAtIndex (0); + input.Shift(); + cursor_char_position = 0; + input.AppendArgument (""); + return cmd_obj->HandleCompletion (input, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + word_complete, + matches); + } } - else - return matches.GetSize(); } - else - return matches.GetSize(); + return matches.GetSize(); } else { diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp index 959c5cd1d0d7..866587fb4ebc 100644 --- a/source/Commands/CommandObjectPlatform.cpp +++ b/source/Commands/CommandObjectPlatform.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectPlatform.h" // C Includes @@ -558,7 +556,7 @@ protected: if (platform_sp) { if (m_option_working_dir.GetOptionValue().OptionWasSet()) - platform_sp->SetWorkingDirectory (ConstString(m_option_working_dir.GetOptionValue().GetCurrentValue().GetPath().c_str())); + platform_sp->SetWorkingDirectory(m_option_working_dir.GetOptionValue().GetCurrentValue()); } else { @@ -572,10 +570,7 @@ protected: GetOptions () { if (m_options.DidFinalize() == false) - { - m_options.Append(new OptionPermissions()); m_options.Finalize(); - } return &m_options; } protected: @@ -621,7 +616,7 @@ public: mode = options_permissions->m_permissions; else mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX; - Error error = platform_sp->MakeDirectory(cmd_line.c_str(), mode); + Error error = platform_sp->MakeDirectory(FileSpec{cmd_line, false}, mode); if (error.Success()) { result.SetStatus (eReturnStatusSuccessFinishResult); @@ -1201,7 +1196,7 @@ public: } else { - result.AppendMessageWithFormat("Eroor getting file size of %s (remote)\n", remote_file_path.c_str()); + result.AppendMessageWithFormat("Error getting file size of %s (remote)\n", remote_file_path.c_str()); result.SetStatus (eReturnStatusFailed); } } @@ -1241,8 +1236,8 @@ public: const char* dst = args.GetArgumentAtIndex(1); FileSpec src_fs(src, true); - FileSpec dst_fs(dst, false); - + FileSpec dst_fs(dst ? dst : src_fs.GetFilename().GetCString(), false); + PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); if (platform_sp) { @@ -1277,7 +1272,7 @@ public: "platform process launch", "Launch a new process on a remote platform.", "platform process launch program", - eFlagRequiresTarget | eFlagTryTargetAPILock), + eCommandRequiresTarget | eCommandTryTargetAPILock), m_options (interpreter) { } @@ -1975,7 +1970,7 @@ CommandObjectPlatformProcessAttach::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "plugin", 'P' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."}, { LLDB_OPT_SET_1, false, "pid", 'p' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."}, { LLDB_OPT_SET_2, false, "name", 'n' , OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."}, - { LLDB_OPT_SET_2, false, "waitfor", 'w' , OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Wait for the the process with <process-name> to launch."}, + { LLDB_OPT_SET_2, false, "waitfor", 'w' , OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."}, { 0, false, NULL , 0 , 0 , NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -2085,7 +2080,7 @@ public: CommandObjectPlatformShell (CommandInterpreter &interpreter) : CommandObjectRaw (interpreter, "platform shell", - "Run a shell command on a the selected platform.", + "Run a shell command on the selected platform.", "platform shell <shell-command>", 0), m_options(interpreter) @@ -2142,7 +2137,7 @@ public: if (end_options) { - Args args (raw_command_line, end_options - raw_command_line); + Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line)); if (!ParseOptions (args, result)) return false; } @@ -2155,7 +2150,7 @@ public: Error error; if (platform_sp) { - const char *working_dir = NULL; + FileSpec working_dir{}; std::string output; int status = -1; int signo = -1; diff --git a/source/Commands/CommandObjectPlugin.cpp b/source/Commands/CommandObjectPlugin.cpp index 658c077bc3ea..63fa4a82cf91 100644 --- a/source/Commands/CommandObjectPlugin.cpp +++ b/source/Commands/CommandObjectPlugin.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectPlugin.h" #include "lldb/Host/Host.h" diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index d47311e5cb5f..4414bdf2a2c8 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectProcess.h" // C Includes @@ -32,6 +30,7 @@ #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/UnixSignals.h" using namespace lldb; using namespace lldb_private; @@ -92,7 +91,7 @@ protected: } else { - Error destroy_error (process->Destroy()); + Error destroy_error (process->Destroy(false)); if (destroy_error.Success()) { result.SetStatus (eReturnStatusSuccessFinishResult); @@ -124,7 +123,7 @@ public: "process launch", "Launch the executable in the debugger.", NULL, - eFlagRequiresTarget, + eCommandRequiresTarget, "restart"), m_options (interpreter) { @@ -249,9 +248,7 @@ protected: if (launch_args.GetArgumentCount() == 0) { - Args target_setting_args; - if (target->GetRunArguments(target_setting_args)) - m_options.launch_info.GetArguments().AppendArguments (target_setting_args); + m_options.launch_info.GetArguments().AppendArguments (target->GetProcessLaunchInfo().GetArguments()); } else { @@ -265,13 +262,18 @@ protected: if (error.Success()) { - const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName(); ProcessSP process_sp (target->GetProcessSP()); if (process_sp) { + // There is a race condition where this thread will return up the call stack to the main command + // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has + // a chance to call PushProcessIOHandler(). + process_sp->SyncIOHandler (0, 2000); + const char *data = stream.GetData(); if (data && strlen(data) > 0) result.AppendMessage(stream.GetData()); + const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName(); result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname); result.SetStatus (eReturnStatusSuccessFinishResult); result.SetDidChangeProcessState (true); @@ -529,8 +531,6 @@ protected: ModuleSP old_exec_module_sp = target->GetExecutableModule(); ArchSpec old_arch_spec = target->GetArchitecture(); - ProcessSP process_sp; - Error error; if (command.GetArgumentCount()) { result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); @@ -539,70 +539,21 @@ protected: } m_interpreter.UpdateExecutionContext(nullptr); - ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack")); - m_options.attach_info.SetHijackListener(listener_sp); - - // If no process info was specified, then use the target executable - // name as the process to attach to by default - if (!m_options.attach_info.ProcessInfoSpecified ()) - { - if (old_exec_module_sp) - m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename(); - - if (!m_options.attach_info.ProcessInfoSpecified ()) - { - error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option"); - } - } - + StreamString stream; + const auto error = target->Attach(m_options.attach_info, &stream); if (error.Success()) { - if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess()) - { - target->SetPlatform(platform_sp); - process = platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), target, error).get(); - } - else - { - if (state != eStateConnected) - { - const char *plugin_name = m_options.attach_info.GetProcessPluginName(); - process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, nullptr).get(); - if (process == nullptr) - error.SetErrorStringWithFormat("failed to create process using plugin %s", plugin_name); - } - if (process) - { - process->HijackProcessEvents(listener_sp.get()); - error = process->Attach(m_options.attach_info); - } - } - } - - if (error.Success() && process != nullptr) - { - result.SetStatus (eReturnStatusSuccessContinuingNoResult); - StreamString stream; - StateType state = process->WaitForProcessToStop (nullptr, nullptr, false, listener_sp.get(), &stream); - - process->RestoreProcessEvents(); - result.SetDidChangeProcessState (true); - - if (stream.GetData()) - result.AppendMessage(stream.GetData()); - - if (state == eStateStopped) + ProcessSP process_sp (target->GetProcessSP()); + if (process_sp) { + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetStatus (eReturnStatusSuccessFinishNoResult); + result.SetDidChangeProcessState (true); } else { - const char *exit_desc = process->GetExitDescription(); - if (exit_desc) - result.AppendErrorWithFormat ("attach failed: %s", exit_desc); - else - result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); - process->Destroy(); + result.AppendError("no error returned from Target::Attach, and target has no process"); result.SetStatus (eReturnStatusFailed); } } @@ -686,10 +637,10 @@ public: "process continue", "Continue execution of all threads in the current process.", "process continue", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options(interpreter) { } @@ -809,6 +760,8 @@ protected: } } + const uint32_t iohandler_id = process->GetIOHandlerID(); + StreamString stream; Error error; if (synchronous_execution) @@ -819,9 +772,9 @@ protected: if (error.Success()) { // There is a race condition where this thread will return up the call stack to the main command - // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has - // a chance to call PushProcessIOHandler(). - process->SyncIOHandler(2000); + // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has + // a chance to call PushProcessIOHandler(). + process->SyncIOHandler(iohandler_id, 2000); result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) @@ -947,9 +900,9 @@ public: "process detach", "Detach from the current process being debugged.", "process detach", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched), + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched), m_options(interpreter) { } @@ -1228,10 +1181,10 @@ public: "process load", "Load a shared library into the current process.", "process load <filename> [<filename> ...]", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { } @@ -1285,10 +1238,10 @@ public: "process unload", "Unload a shared library from the current process using the index returned by a previous call to \"process load\".", "process unload <index>", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { } @@ -1349,7 +1302,7 @@ public: "process signal", "Send a UNIX signal to the current process being debugged.", NULL, - eFlagRequiresProcess | eFlagTryTargetAPILock) + eCommandRequiresProcess | eCommandTryTargetAPILock) { CommandArgumentEntry arg; CommandArgumentData signal_arg; @@ -1431,9 +1384,9 @@ public: "process interrupt", "Interrupt the current process being debugged.", "process interrupt", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched) { } @@ -1493,9 +1446,9 @@ public: "process kill", "Terminate the current process being debugged.", "process kill", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched) { } @@ -1518,7 +1471,7 @@ protected: if (command.GetArgumentCount() == 0) { - Error error (process->Destroy()); + Error error (process->Destroy(true)); if (error.Success()) { result.SetStatus (eReturnStatusSuccessFinishResult); @@ -1554,9 +1507,9 @@ public: "process save-core", "Save the current process as a core file using an appropriate file type.", "process save-core FILE", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched) { } @@ -1618,7 +1571,7 @@ public: "process status", "Show the current status and location of executing process.", "process status", - eFlagRequiresProcess | eFlagTryTargetAPILock) + eCommandRequiresProcess | eCommandTryTargetAPILock) { } @@ -1632,7 +1585,7 @@ public: { Stream &strm = result.GetOutputStream(); result.SetStatus (eReturnStatusSuccessFinishNoResult); - // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid + // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid Process *process = m_exe_ctx.GetProcessPtr(); const bool only_threads_with_stop_reason = true; const uint32_t start_frame = 0; @@ -1776,8 +1729,8 @@ public: void PrintSignalHeader (Stream &str) { - str.Printf ("NAME PASS STOP NOTIFY\n"); - str.Printf ("========== ===== ===== ======\n"); + str.Printf ("NAME PASS STOP NOTIFY\n"); + str.Printf ("=========== ===== ===== ======\n"); } void @@ -1787,7 +1740,7 @@ public: bool suppress; bool notify; - str.Printf ("%-10s ", sig_name); + str.Printf ("%-11s ", sig_name); if (signals.GetSignalInfo (signo, suppress, stop, notify)) { bool pass = !suppress; diff --git a/source/Commands/CommandObjectQuit.cpp b/source/Commands/CommandObjectQuit.cpp index dd0efc61b2d0..31f82b987c1c 100644 --- a/source/Commands/CommandObjectQuit.cpp +++ b/source/Commands/CommandObjectQuit.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectQuit.h" // C Includes @@ -17,6 +15,7 @@ // Project includes #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Commands/CommandObjectRegister.cpp b/source/Commands/CommandObjectRegister.cpp index 81b79b8cd8b2..fae5af42f405 100644 --- a/source/Commands/CommandObjectRegister.cpp +++ b/source/Commands/CommandObjectRegister.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectRegister.h" // C Includes @@ -25,6 +23,7 @@ #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionValueArray.h" +#include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -47,10 +46,10 @@ public: "register read", "Dump the contents of one or more register values from the current frame. If no register is specified, dumps them all.", NULL, - eFlagRequiresFrame | - eFlagRequiresRegContext | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresFrame | + eCommandRequiresRegContext | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_option_group (interpreter), m_format_options (eFormatDefault), m_command_options () @@ -143,7 +142,7 @@ public: const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx); if (reg_set) { - strm.Printf ("%s:\n", reg_set->name); + strm.Printf ("%s:\n", (reg_set->name ? reg_set->name : "unknown") ); strm.IndentMore (); const size_t num_registers = reg_set->num_registers; for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) @@ -376,10 +375,10 @@ public: "register write", "Modify a single register value.", NULL, - eFlagRequiresFrame | - eFlagRequiresRegContext | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused) + eCommandRequiresFrame | + eCommandRequiresRegContext | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) { CommandArgumentEntry arg1; CommandArgumentEntry arg2; diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp index ed677afabcb5..ccbf98c767f1 100644 --- a/source/Commands/CommandObjectSettings.cpp +++ b/source/Commands/CommandObjectSettings.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectSettings.h" // C Includes @@ -18,6 +16,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/OptionValueProperties.h" using namespace lldb; using namespace lldb_private; @@ -243,7 +242,7 @@ protected: // Split the raw command into var_name and value pair. llvm::StringRef raw_str(command); std::string var_value_string = raw_str.split(var_name).second.str(); - const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false); + const char *var_value_cstr = Args::StripSpaces(var_value_string, true, false, false); Error error; if (m_options.m_global) diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp index a88a9b1f0cac..7c5f127cb51a 100644 --- a/source/Commands/CommandObjectSource.cpp +++ b/source/Commands/CommandObjectSource.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectSource.h" // C Includes @@ -253,7 +251,7 @@ public: "source list", "Display source code (as specified) based on the current executable's debug info.", NULL, - eFlagRequiresTarget), + eCommandRequiresTarget), m_options (interpreter) { } @@ -539,9 +537,9 @@ protected: { SymbolContext sc; sc_list_symbols.GetContextAtIndex (i, sc); - if (sc.symbol) + if (sc.symbol && sc.symbol->ValueIsAddress()) { - const Address &base_address = sc.symbol->GetAddress(); + const Address &base_address = sc.symbol->GetAddressRef(); Function *function = base_address.CalculateSymbolContextFunction(); if (function) { @@ -690,13 +688,15 @@ protected: bool show_module = true; bool show_inlined_frames = true; const bool show_function_arguments = true; + const bool show_function_name = true; sc.DumpStopContext(&result.GetOutputStream(), m_exe_ctx.GetBestExecutionContextScope(), sc.line_entry.range.GetBaseAddress(), show_fullpaths, show_module, show_inlined_frames, - show_function_arguments); + show_function_arguments, + show_function_name); result.GetOutputStream().EOL(); if (m_options.num_lines == 0) diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp index 5093c3b99339..e9fa084fc0b5 100644 --- a/source/Commands/CommandObjectSyntax.cpp +++ b/source/Commands/CommandObjectSyntax.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectSyntax.h" // C Includes diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp index 9188283966f1..448da0ede245 100644 --- a/source/Commands/CommandObjectTarget.cpp +++ b/source/Commands/CommandObjectTarget.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectTarget.h" // C Includes @@ -50,6 +48,7 @@ #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" @@ -388,6 +387,12 @@ protected: core_file.GetPath(core_path, sizeof(core_path)); if (core_file.Exists()) { + if (!core_file.Readable()) + { + result.AppendMessageWithFormat ("Core file '%s' is not readable.\n", core_path); + result.SetStatus (eReturnStatusFailed); + return false; + } FileSpec core_file_dir; core_file_dir.GetDirectory() = core_file.GetDirectory(); target_sp->GetExecutableSearchPaths ().Append (core_file_dir); @@ -600,10 +605,20 @@ public: "Delete one or more targets by target index.", NULL, 0), - m_option_group (interpreter), - m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', "Perform extra cleanup to minimize memory consumption after deleting the target.", false, false) - { - m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group(interpreter), + m_all_option(LLDB_OPT_SET_1, false, "all", 'a', "Delete all targets.", false, true), + m_cleanup_option( + LLDB_OPT_SET_1, + false, + "clean", 'c', + "Perform extra cleanup to minimize memory consumption after deleting the target. " + "By default, LLDB will keep in memory any modules previously loaded by the target as well " + "as all of its debug info. Specifying --clean will unload all of these shared modules and " + "cause them to be reparsed again the next time the target is run", + false, true) + { + m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Finalize(); } @@ -625,90 +640,89 @@ protected: const size_t argc = args.GetArgumentCount(); std::vector<TargetSP> delete_target_list; TargetList &target_list = m_interpreter.GetDebugger().GetTargetList(); - bool success = true; TargetSP target_sp; - if (argc > 0) + + if (m_all_option.GetOptionValue()) + { + for (int i = 0; i < target_list.GetNumTargets(); ++i) + delete_target_list.push_back(target_list.GetTargetAtIndex(i)); + } + else if (argc > 0) { const uint32_t num_targets = target_list.GetNumTargets(); // Bail out if don't have any targets. if (num_targets == 0) { result.AppendError("no targets to delete"); result.SetStatus(eReturnStatusFailed); - success = false; + return false; } - for (uint32_t arg_idx = 0; success && arg_idx < argc; ++arg_idx) + for (uint32_t arg_idx = 0; arg_idx < argc; ++arg_idx) { const char *target_idx_arg = args.GetArgumentAtIndex(arg_idx); + bool success = false; uint32_t target_idx = StringConvert::ToUInt32 (target_idx_arg, UINT32_MAX, 0, &success); - if (success) + if (!success) { - if (target_idx < num_targets) - { - target_sp = target_list.GetTargetAtIndex (target_idx); - if (target_sp) - { - delete_target_list.push_back (target_sp); - continue; - } - } - if (num_targets > 1) - result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n", - target_idx, - num_targets - 1); - else - result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n", - target_idx); - + result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg); result.SetStatus (eReturnStatusFailed); - success = false; + return false; } - else + if (target_idx < num_targets) { - result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg); - result.SetStatus (eReturnStatusFailed); - success = false; + target_sp = target_list.GetTargetAtIndex (target_idx); + if (target_sp) + { + delete_target_list.push_back (target_sp); + continue; + } } + if (num_targets > 1) + result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n", + target_idx, + num_targets - 1); + else + result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n", + target_idx); + + result.SetStatus (eReturnStatusFailed); + return false; } } else { target_sp = target_list.GetSelectedTarget(); - if (target_sp) - { - delete_target_list.push_back (target_sp); - } - else + if (!target_sp) { result.AppendErrorWithFormat("no target is currently selected\n"); result.SetStatus (eReturnStatusFailed); - success = false; + return false; } + delete_target_list.push_back (target_sp); } - if (success) + + const size_t num_targets_to_delete = delete_target_list.size(); + for (size_t idx = 0; idx < num_targets_to_delete; ++idx) { - const size_t num_targets_to_delete = delete_target_list.size(); - for (size_t idx = 0; idx < num_targets_to_delete; ++idx) - { - target_sp = delete_target_list[idx]; - target_list.DeleteTarget(target_sp); - target_sp->Destroy(); - } - // If "--clean" was specified, prune any orphaned shared modules from - // the global shared module list - if (m_cleanup_option.GetOptionValue ()) - { - const bool mandatory = true; - ModuleList::RemoveOrphanSharedModules(mandatory); - } - result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete); - result.SetStatus(eReturnStatusSuccessFinishResult); + target_sp = delete_target_list[idx]; + target_list.DeleteTarget(target_sp); + target_sp->Destroy(); + } + // If "--clean" was specified, prune any orphaned shared modules from + // the global shared module list + if (m_cleanup_option.GetOptionValue ()) + { + const bool mandatory = true; + ModuleList::RemoveOrphanSharedModules(mandatory); } + result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete); + result.SetStatus(eReturnStatusSuccessFinishResult); - return result.Succeeded(); + return true; } OptionGroupOptions m_option_group; + OptionGroupBoolean m_all_option; OptionGroupBoolean m_cleanup_option; }; @@ -730,7 +744,7 @@ public: "target variable", "Read global variable(s) prior to, or while running your binary.", NULL, - eFlagRequiresTarget), + eCommandRequiresTarget), m_option_group (interpreter), m_option_variable (false), // Don't include frame options m_option_format (eFormatDefault), @@ -773,6 +787,10 @@ public: { DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions()); + if (false == valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && + true == valobj_sp->IsRuntimeSupportValue()) + return; + switch (var_sp->GetScope()) { case eValueTypeVariableGlobal: @@ -1722,17 +1740,16 @@ LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *mod DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); strm.IndentMore (); - //Symtab::DumpSymbolHeader (&strm); for (i=0; i < num_matches; ++i) { Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]); - DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(), - symbol->GetAddress(), - verbose, - strm); - -// strm.Indent (); -// symbol->Dump (&strm, interpreter.GetExecutionContext().GetTargetPtr(), i); + if (symbol && symbol->ValueIsAddress()) + { + DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(), + symbol->GetAddressRef(), + verbose, + strm); + } } strm.IndentLess (); return num_matches; @@ -2547,7 +2564,7 @@ public: "target modules dump line-table", "Dump the line table for one or more compilation units.", NULL, - eFlagRequiresTarget) + eCommandRequiresTarget) { } @@ -3462,28 +3479,24 @@ protected: case 's': case 'S': { - SymbolVendor *symbol_vendor = module->GetSymbolVendor(); + const SymbolVendor *symbol_vendor = module->GetSymbolVendor(); if (symbol_vendor) { - SymbolFile *symbol_file = symbol_vendor->GetSymbolFile(); - if (symbol_file) + const FileSpec symfile_spec = symbol_vendor->GetMainFileSpec(); + if (format_char == 'S') { - if (format_char == 'S') + // Dump symbol file only if different from module file + if (!symfile_spec || symfile_spec == module->GetFileSpec()) { - FileSpec &symfile_spec = symbol_file->GetObjectFile()->GetFileSpec(); - // Dump symbol file only if different from module file - if (!symfile_spec || symfile_spec == module->GetFileSpec()) - { - print_space = false; - break; - } - // Add a newline and indent past the index - strm.Printf ("\n%*s", indent, ""); + print_space = false; + break; } - DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); - dump_object_name = true; - break; + // Add a newline and indent past the index + strm.Printf ("\n%*s", indent, ""); } + DumpFullpath (strm, &symfile_spec, width); + dump_object_name = true; + break; } strm.Printf("%.*s", width, "<NONE>"); } @@ -3641,10 +3654,10 @@ public: "target modules show-unwind", "Show synthesized unwind instructions for a function.", NULL, - eFlagRequiresTarget | - eFlagRequiresProcess | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresTarget | + eCommandRequiresProcess | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options (interpreter) { } @@ -3767,7 +3780,7 @@ protected: { result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", callsite_unwind_plan->GetSourceName().AsCString()); } - UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get()); + UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*target, *thread.get()); if (fast_unwind_plan.get()) { result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString()); @@ -4001,7 +4014,7 @@ public: "target modules lookup", "Look up information within executable and dependent shared library images.", NULL, - eFlagRequiresTarget), + eCommandRequiresTarget), m_options (interpreter) { CommandArgumentEntry arg; @@ -4381,7 +4394,7 @@ public: CommandObjectParsed (interpreter, "target symbols add", "Add a debug symbol file to one of the target's current modules by specifying a path to a debug symbols file, or using the options to specify a module to download symbols for.", - "target symbols add [<symfile>]", eFlagRequiresTarget), + "target symbols add [<symfile>]", eCommandRequiresTarget), m_option_group (interpreter), m_file_option (LLDB_OPT_SET_1, false, "shlib", 's', CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Fullpath or basename for module to find debug symbols for."), m_current_frame_option (LLDB_OPT_SET_2, false, "frame", 'F', "Locate the debug symbols the currently selected frame.", false, true) diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index 199d16b85205..5f38ad4900d6 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectThread.h" // C Includes @@ -18,6 +16,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/State.h" #include "lldb/Core/SourceManager.h" +#include "lldb/Core/ValueObject.h" #include "lldb/Host/Host.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -240,11 +239,11 @@ public: "thread backtrace", "Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.", NULL, - eFlagRequiresProcess | - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresProcess | + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options(interpreter) { } @@ -432,6 +431,12 @@ public: m_step_in_avoid_no_debug = eLazyBoolCalculate; m_step_out_avoid_no_debug = eLazyBoolCalculate; m_run_mode = eOnlyDuringStepping; + + // Check if we are in Non-Stop mode + lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget(); + if (target_sp.get() != nullptr && target_sp->GetNonStopModeEnabled()) + m_run_mode = eOnlyThisThread; + m_avoid_regexp.clear(); m_step_in_target.clear(); m_class_name.clear(); @@ -465,11 +470,11 @@ public: StepType step_type, StepScope step_scope) : CommandObjectParsed (interpreter, name, help, syntax, - eFlagRequiresProcess | - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresProcess | + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_step_type (step_type), m_step_scope (step_scope), m_options (interpreter) @@ -579,6 +584,7 @@ protected: if (m_step_type == eStepTypeInto) { StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); + assert(frame != nullptr); if (frame->HasDebugInformation ()) { @@ -667,6 +673,8 @@ protected: process->GetThreadList().SetSelectedThreadByID (thread->GetID()); + const uint32_t iohandler_id = process->GetIOHandlerID(); + StreamString stream; Error error; if (synchronous_execution) @@ -677,7 +685,7 @@ protected: // There is a race condition where this thread will return up the call stack to the main command handler // and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has // a chance to call PushProcessIOHandler(). - process->SyncIOHandler(2000); + process->SyncIOHandler(iohandler_id, 2000); if (synchronous_execution) { @@ -752,10 +760,10 @@ public: "thread continue", "Continue execution of one or more threads in an active process.", NULL, - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused) + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) { CommandArgumentEntry arg; CommandArgumentData thread_idx_arg; @@ -1064,10 +1072,10 @@ public: "thread until", "Run the current or specified thread until it reaches a given line number or address or leaves the current function.", NULL, - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options (interpreter) { CommandArgumentEntry arg; @@ -1343,10 +1351,10 @@ public: "thread select", "Select a thread as the currently active thread.", NULL, - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { CommandArgumentEntry arg; CommandArgumentData thread_idx_arg; @@ -1419,10 +1427,10 @@ public: "thread list", "Show a summary of all current threads in a process.", "thread list", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { } @@ -1464,10 +1472,10 @@ public: "thread info", "Show an extended summary of information about thread(s) in a process.", "thread info", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused), + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused), m_options (interpreter) { m_add_return = false; @@ -1656,10 +1664,10 @@ public: "Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value," " or with the -x option from the innermost function evaluation.", "thread return", - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options (interpreter) { CommandArgumentEntry arg; @@ -1884,10 +1892,10 @@ public: "thread jump", "Sets the program counter to a new address.", "thread jump", - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options (interpreter) { } @@ -2068,11 +2076,11 @@ public: "Show thread plans for one or more threads. If no threads are specified, show the " "currently selected thread. Use the thread-index \"all\" to see all threads.", NULL, - eFlagRequiresProcess | - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresProcess | + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_options(interpreter) { } @@ -2120,11 +2128,11 @@ public: "Only user visible plans can be discarded, use the index from \"thread plan list\"" " without the \"-i\" argument.", NULL, - eFlagRequiresProcess | - eFlagRequiresThread | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ) + eCommandRequiresProcess | + eCommandRequiresThread | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ) { CommandArgumentEntry arg; CommandArgumentData plan_index_arg; diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp index 3a4c60c00f8b..7c8061a6ca08 100644 --- a/source/Commands/CommandObjectType.cpp +++ b/source/Commands/CommandObjectType.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectType.h" // C Includes @@ -4249,7 +4247,7 @@ public: nullptr, nullptr, nullptr, - eFlagRequiresFrame), + eCommandRequiresFrame), m_formatter_name(formatter_name ? formatter_name : ""), m_discovery_function(discovery_func) { diff --git a/source/Commands/CommandObjectVersion.cpp b/source/Commands/CommandObjectVersion.cpp index 2d950a89c9b3..70e101c22330 100644 --- a/source/Commands/CommandObjectVersion.cpp +++ b/source/Commands/CommandObjectVersion.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectVersion.h" // C Includes diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp index bef59ca30b3c..650fd253af02 100644 --- a/source/Commands/CommandObjectWatchpoint.cpp +++ b/source/Commands/CommandObjectWatchpoint.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "CommandObjectWatchpoint.h" #include "CommandObjectWatchpointCommand.h" @@ -27,6 +25,7 @@ #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Symbol/Variable.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "llvm/ADT/StringRef.h" @@ -924,10 +923,10 @@ public: "If watchpoint setting fails, consider disable/delete existing ones " "to free up resources.", NULL, - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_option_group (interpreter), m_option_watchpoint () { @@ -1131,10 +1130,10 @@ public: "If watchpoint setting fails, consider disable/delete existing ones " "to free up resources.", NULL, - eFlagRequiresFrame | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused ), + eCommandRequiresFrame | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused ), m_option_group (interpreter), m_option_watchpoint () { @@ -1211,7 +1210,7 @@ protected: if (end_options) { - Args args (raw_command, end_options - raw_command); + Args args (llvm::StringRef(raw_command, end_options - raw_command)); if (!ParseOptions (args, result)) return false; diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp index 275ee925adcc..d7d064e5fed9 100644 --- a/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/source/Commands/CommandObjectWatchpointCommand.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes // C++ Includes diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp index d449d0b21438..1cd7a7447b7f 100644 --- a/source/Core/Address.cpp +++ b/source/Core/Address.cpp @@ -468,6 +468,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum case DumpStyleResolvedDescription: case DumpStyleResolvedDescriptionNoModule: case DumpStyleResolvedDescriptionNoFunctionArguments: + case DumpStyleNoFunctionName: if (IsSectionOffset()) { uint32_t pointer_size = 4; @@ -500,7 +501,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum if (symbol_name) { s->PutCString(symbol_name); - addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress(); + addr_t delta = file_Addr - symbol->GetAddressRef().GetFileAddress(); if (delta) s->Printf(" + %" PRIu64, delta); showed_info = true; @@ -553,7 +554,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum #endif Address cstr_addr(*this); cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size); - func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true); + func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false, true, true); if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr)) { #if VERBOSE_OUTPUT @@ -636,7 +637,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum if (pointer_sc.function || pointer_sc.symbol) { s->PutCString(": "); - pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true); + pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false, true, true); } } } @@ -662,12 +663,13 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum const bool show_fullpaths = false; const bool show_inlined_frames = true; const bool show_function_arguments = (style != DumpStyleResolvedDescriptionNoFunctionArguments); + const bool show_function_name = (style != DumpStyleNoFunctionName); if (sc.function == NULL && sc.symbol != NULL) { // If we have just a symbol make sure it is in the right section if (sc.symbol->ValueIsAddress()) { - if (sc.symbol->GetAddress().GetSection() != GetSection()) + if (sc.symbol->GetAddressRef().GetSection() != GetSection()) { // don't show the module if the symbol is a trampoline symbol show_stop_context = false; @@ -684,7 +686,8 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum show_fullpaths, show_module, show_inlined_frames, - show_function_arguments); + show_function_arguments, + show_function_name); } else { @@ -719,7 +722,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum // as our address. If it isn't, then we might have just found // the last symbol that came before the address that we are // looking up that has nothing to do with our address lookup. - if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection()) + if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddressRef().GetSection() != GetSection()) sc.symbol = NULL; } sc.GetDescription(s, eDescriptionLevelBrief, target); @@ -742,10 +745,15 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum if (var && var->LocationIsValidForAddress (*this)) { s->Indent(); - s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =", + s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"", var->GetID(), - var->GetName().GetCString(), - var->GetType()->GetName().GetCString()); + var->GetName().GetCString()); + Type *type = var->GetType(); + if (type) + s->Printf(", type = \"%s\"", type->GetName().GetCString()); + else + s->PutCString(", type = <unknown>"); + s->PutCString(", location = "); var->DumpLocationForAddress(s, *this); s->PutCString(", decl = "); var->GetDeclaration().DumpStopContext(s, false); diff --git a/source/Core/AddressResolver.cpp b/source/Core/AddressResolver.cpp index 5369d960f251..aa457015b4fd 100644 --- a/source/Core/AddressResolver.cpp +++ b/source/Core/AddressResolver.cpp @@ -20,7 +20,6 @@ #include "lldb/Core/StreamString.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Target.h" -#include "lldb/lldb-private-log.h" using namespace lldb_private; diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp index 6089abd76cbc..e45076e9bfc6 100644 --- a/source/Core/AddressResolverFileLine.cpp +++ b/source/Core/AddressResolverFileLine.cpp @@ -14,7 +14,6 @@ #include "lldb/Core/StreamString.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SymbolContext.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp index 9f3b3f506fe0..1c6205fa6bdf 100644 --- a/source/Core/AddressResolverName.cpp +++ b/source/Core/AddressResolverName.cpp @@ -17,7 +17,6 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symbol.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; @@ -166,7 +165,7 @@ AddressResolverName::SearchCallback { if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress()) { - if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress()) + if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddressRef()) { sym_list.RemoveContextAtIndex(j); continue; // Don't increment j @@ -212,7 +211,7 @@ AddressResolverName::SearchCallback { if (sc.symbol && sc.symbol->ValueIsAddress()) { - func_addr = sc.symbol->GetAddress(); + func_addr = sc.symbol->GetAddressRef(); addr_t byte_size = sc.symbol->GetByteSize(); if (skip_prologue) diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index 015f76bffbb5..33cbede9ce14 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -18,7 +18,7 @@ #include "llvm/Support/COFF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Host.h" -#include "lldb/Utility/SafeMachO.h" + #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StringList.h" #include "lldb/Host/Endian.h" @@ -27,6 +27,8 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/NameMatches.h" +#include "lldb/Utility/SafeMachO.h" #include "Plugins/Process/Utility/ARMDefines.h" #include "Plugins/Process/Utility/InstructionUtils.h" @@ -87,7 +89,29 @@ static const CoreDefinition g_core_definitions[] = { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_armv8 , "armv8" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_aarch64 , "aarch64" }, - { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, + // mips32, mips32r2, mips32r3, mips32r5, mips32r6 + { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32 , "mips" }, + { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r2 , "mipsr2" }, + { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r3 , "mipsr3" }, + { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r5 , "mipsr5" }, + { eByteOrderBig , 4, 4, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r6 , "mipsr6" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32el , "mipsel" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r2el , "mipsr2el" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r3el , "mipsr3el" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r5el , "mipsr5el" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r6el , "mipsr6el" }, + + // mips64, mips64r2, mips64r3, mips64r5, mips64r6 + { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, + { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r2 , "mips64r2" }, + { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r3 , "mips64r3" }, + { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r5 , "mips64r5" }, + { eByteOrderBig , 8, 4, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r6 , "mips64r6" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64el , "mips64el" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r2el , "mips64r2el" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r3el , "mips64r3el" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r5el , "mips64r5el" }, + { eByteOrderLittle, 8, 4, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r6el , "mips64r6el" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" }, @@ -259,14 +283,25 @@ static const ArchDefinitionEntry g_elf_arch_entries[] = { { ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc { ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386 - { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_486 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 486 (deprecated) + { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_IAMCU , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel MCU // FIXME: is this correct? { ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64 { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM { ArchSpec::eCore_arm_aarch64 , llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM64 { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9 { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64 - { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS + { ArchSpec::eCore_mips32 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32 + { ArchSpec::eCore_mips32r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2 + { ArchSpec::eCore_mips32r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6 + { ArchSpec::eCore_mips32el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32el + { ArchSpec::eCore_mips32r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2el + { ArchSpec::eCore_mips32r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6el + { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64 + { ArchSpec::eCore_mips64r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2 + { ArchSpec::eCore_mips64r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6 + { ArchSpec::eCore_mips64el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64el + { ArchSpec::eCore_mips64r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2el + { ArchSpec::eCore_mips64r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6el { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA @@ -573,6 +608,32 @@ ArchSpec::GetDefaultEndian () const return eByteOrderInvalid; } +bool +ArchSpec::CharIsSignedByDefault () const +{ + switch (m_triple.getArch()) { + default: + return true; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return m_triple.isOSDarwin() || m_triple.isOSWindows(); + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + return m_triple.isOSDarwin(); + + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + case llvm::Triple::xcore: + return false; + } +} + lldb::ByteOrder ArchSpec::GetByteOrder () const { @@ -779,7 +840,7 @@ ArchSpec::MergeFrom(const ArchSpec &other) } bool -ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub) +ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os) { m_core = kCore_invalid; bool update_triple = true; @@ -800,7 +861,6 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su if (arch_type == eArchTypeMachO) { m_triple.setVendor (llvm::Triple::Apple); - switch (core_def->machine) { case llvm::Triple::aarch64: @@ -825,10 +885,22 @@ ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t su break; } } - else + else if (arch_type == eArchTypeELF) { + llvm::Triple::OSType ostype; + switch (os) + { + case llvm::ELF::ELFOSABI_AIX: ostype = llvm::Triple::OSType::AIX; break; + case llvm::ELF::ELFOSABI_FREEBSD: ostype = llvm::Triple::OSType::FreeBSD; break; + case llvm::ELF::ELFOSABI_GNU: ostype = llvm::Triple::OSType::Linux; break; + case llvm::ELF::ELFOSABI_NETBSD: ostype = llvm::Triple::OSType::NetBSD; break; + case llvm::ELF::ELFOSABI_OPENBSD: ostype = llvm::Triple::OSType::OpenBSD; break; + case llvm::ELF::ELFOSABI_SOLARIS: ostype = llvm::Triple::OSType::Solaris; break; + default: + ostype = llvm::Triple::OSType::UnknownOS; + } + m_triple.setOS (ostype); m_triple.setVendor (llvm::Triple::UnknownVendor); - m_triple.setOS (llvm::Triple::UnknownOS); } // Fall back onto setting the machine type if the arch by name failed... if (m_triple.getArch () == llvm::Triple::UnknownArch) @@ -1019,6 +1091,8 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in try_inverse = false; if (core2 == ArchSpec::eCore_arm_armv7) return true; + if (core2 == ArchSpec::eCore_arm_armv6m) + return true; } break; @@ -1027,8 +1101,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in return true; break; - case ArchSpec::eCore_arm_armv7m: case ArchSpec::eCore_arm_armv7em: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_arm_generic) + return true; + if (core2 == ArchSpec::eCore_arm_armv7m) + return true; + if (core2 == ArchSpec::eCore_arm_armv6m) + return true; + if (core2 == ArchSpec::eCore_arm_armv7) + return true; + try_inverse = true; + } + break; + + case ArchSpec::eCore_arm_armv7m: + if (!enforce_exact_match) + { + if (core2 == ArchSpec::eCore_arm_generic) + return true; + if (core2 == ArchSpec::eCore_arm_armv6m) + return true; + if (core2 == ArchSpec::eCore_arm_armv7) + return true; + if (core2 == ArchSpec::eCore_arm_armv7em) + return true; + try_inverse = true; + } + break; + case ArchSpec::eCore_arm_armv7f: case ArchSpec::eCore_arm_armv7k: case ArchSpec::eCore_arm_armv7s: @@ -1084,6 +1186,36 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in } break; + case ArchSpec::eCore_mips64: + case ArchSpec::eCore_mips64r2: + case ArchSpec::eCore_mips64r3: + case ArchSpec::eCore_mips64r5: + case ArchSpec::eCore_mips64r6: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10)) + return true; + if (core2 >= ArchSpec::kCore_mips64_first && core2 <= (core1 - 1)) + return true; + try_inverse = false; + } + break; + + case ArchSpec::eCore_mips64el: + case ArchSpec::eCore_mips64r2el: + case ArchSpec::eCore_mips64r3el: + case ArchSpec::eCore_mips64r5el: + case ArchSpec::eCore_mips64r6el: + if (!enforce_exact_match) + { + if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10)) + return true; + if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= (core1 - 1)) + return true; + try_inverse = false; + } + break; + default: break; } diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp index 1cbbde20e7f6..351487401f6b 100644 --- a/source/Core/Broadcaster.cpp +++ b/source/Core/Broadcaster.cpp @@ -16,7 +16,6 @@ #include "lldb/Core/Log.h" #include "lldb/Core/Event.h" #include "lldb/Core/StreamString.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp index ea84843fe0b3..ae579d1b00ae 100644 --- a/source/Core/Communication.cpp +++ b/source/Core/Communication.cpp @@ -11,7 +11,6 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Connection.h" #include "lldb/Core/Log.h" @@ -39,9 +38,11 @@ Communication::Communication(const char *name) : Broadcaster (NULL, name), m_connection_sp (), m_read_thread_enabled (false), + m_read_thread_did_exit (false), m_bytes(), m_bytes_mutex (Mutex::eMutexTypeRecursive), m_write_mutex (Mutex::eMutexTypeNormal), + m_synchronize_mutex (Mutex::eMutexTypeNormal), m_callback (NULL), m_callback_baton (NULL), m_close_on_eof (true) @@ -56,6 +57,7 @@ Communication::Communication(const char *name) : SetEventName (eBroadcastBitReadThreadDidExit, "read thread did exit"); SetEventName (eBroadcastBitReadThreadShouldExit, "read thread should exit"); SetEventName (eBroadcastBitPacketAvailable, "packet available"); + SetEventName (eBroadcastBitNoMorePendingInput, "no more pending input"); CheckInWithManager(); } @@ -182,7 +184,8 @@ Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connectio if (event_type & eBroadcastBitReadThreadDidExit) { - Disconnect (NULL); + if (GetCloseOnEOF ()) + Disconnect (NULL); break; } } @@ -244,6 +247,7 @@ Communication::StartReadThread (Error *error_ptr) snprintf(thread_name, sizeof(thread_name), "<lldb.comm.%s>", m_broadcaster_name.AsCString()); m_read_thread_enabled = true; + m_read_thread_did_exit = false; m_read_thread = ThreadLauncher::LaunchThread(thread_name, Communication::ReadThread, this, error_ptr); if (!m_read_thread.IsJoinable()) m_read_thread_enabled = false; @@ -376,9 +380,8 @@ Communication::ReadThread (lldb::thread_arg_t p) break; case eConnectionStatusEndOfFile: - if (comm->GetCloseOnEOF()) - done = true; - break; + done = true; + break; case eConnectionStatusError: // Check GetError() for details if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO) { @@ -392,9 +395,13 @@ Communication::ReadThread (lldb::thread_arg_t p) p, Communication::ConnectionStatusAsCString (status)); break; + case eConnectionStatusInterrupted: // Synchronization signal from SynchronizeWithReadThread() + // The connection returns eConnectionStatusInterrupted only when there is no + // input pending to be read, so we can signal that. + comm->BroadcastEvent (eBroadcastBitNoMorePendingInput); + break; case eConnectionStatusNoConnection: // No connection case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection - case eConnectionStatusInterrupted: // Interrupted done = true; // Fall through... case eConnectionStatusTimedOut: // Request timed out @@ -410,7 +417,9 @@ Communication::ReadThread (lldb::thread_arg_t p) if (log) log->Printf ("%p Communication::ReadThread () thread exiting...", p); + comm->m_read_thread_did_exit = true; // Let clients know that this thread is exiting + comm->BroadcastEvent (eBroadcastBitNoMorePendingInput); comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); return NULL; } @@ -427,6 +436,28 @@ Communication::SetReadThreadBytesReceivedCallback } void +Communication::SynchronizeWithReadThread () +{ + // Only one thread can do the synchronization dance at a time. + Mutex::Locker locker(m_synchronize_mutex); + + // First start listening for the synchronization event. + Listener listener("Communication::SyncronizeWithReadThread"); + listener.StartListeningForEvents(this, eBroadcastBitNoMorePendingInput); + + // If the thread is not running, there is no point in synchronizing. + if (!m_read_thread_enabled || m_read_thread_did_exit) + return; + + // Notify the read thread. + m_connection_sp->InterruptRead(); + + // Wait for the synchronization event. + EventSP event_sp; + listener.WaitForEvent(NULL, event_sp); +} + +void Communication::SetConnection (Connection *connection) { Disconnect (NULL); diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp index fe29814be420..e04c48905570 100644 --- a/source/Core/ConnectionMachPort.cpp +++ b/source/Core/ConnectionMachPort.cpp @@ -17,7 +17,6 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" @@ -69,7 +68,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr) ConnectionStatus status = eConnectionStatusError; - if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://"))) + if (0 == strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://"))) { s += strlen("bootstrap-checkin://"); @@ -83,7 +82,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr) error_ptr->SetErrorString ("bootstrap port name is empty"); } } - else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://"))) + else if (0 == strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://"))) { s += strlen("bootstrap-lookup://"); if (*s) diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp index d3dfa3cd8d56..77daeb14840d 100644 --- a/source/Core/ConnectionSharedMemory.cpp +++ b/source/Core/ConnectionSharedMemory.cpp @@ -26,7 +26,6 @@ // Other libraries and framework includes // Project includes #include "llvm/Support/MathExtras.h" -#include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" diff --git a/source/Core/CxaDemangle.cpp b/source/Core/CxaDemangle.cpp new file mode 100644 index 000000000000..bcc52ff39fe4 --- /dev/null +++ b/source/Core/CxaDemangle.cpp @@ -0,0 +1,5011 @@ +//---------------------------------------------------------------------- +// Inlined copy of: +// http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp +// revision 238263. +// +// Changes include: +// - Renamed the "__cxxabiv1" namespace to "lldb_private" +// - Stripped GCC attributes() +// - Removed extern "C" from the cxa_demangle function +// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning +// - Implemented missing rebind, construct, destroy in malloc_alloc +// - Replaced noexcept, constexpr, alignas with their LLVM_* equivalents +// - Included win32.h for snprintf implementation for MSVC +// - Removed constexpr member initialization for MSVC +// - Changed argument to alignas() to a literal for MSVC +//---------------------------------------------------------------------- + +#if defined(_MSC_VER) +#include "lldb/Host/windows/win32.h" // snprintf +#endif +#include "llvm/Support/Compiler.h" // LLVM_{NOEXCEPT, CONSTEXPR, ALIGNAS} +#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below + +//===-------------------------- cxa_demangle.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define _LIBCPP_EXTERN_TEMPLATE(...) +#define _LIBCPP_NO_EXCEPTIONS + +#include <vector> +#include <algorithm> +#include <string> +#include <numeric> +#include <cstdlib> +#include <cstring> +#include <cctype> + +namespace lldb_private +{ + +namespace +{ + +enum +{ + unknown_error = -4, + invalid_args = -3, + invalid_mangled_name, + memory_alloc_failure, + success +}; + +template <class C> + const char* parse_type(const char* first, const char* last, C& db); +template <class C> + const char* parse_encoding(const char* first, const char* last, C& db); +template <class C> + const char* parse_name(const char* first, const char* last, C& db, + bool* ends_with_template_args = 0); +template <class C> + const char* parse_expression(const char* first, const char* last, C& db); +template <class C> + const char* parse_template_args(const char* first, const char* last, C& db); +template <class C> + const char* parse_operator_name(const char* first, const char* last, C& db); +template <class C> + const char* parse_unqualified_name(const char* first, const char* last, C& db); +template <class C> + const char* parse_decltype(const char* first, const char* last, C& db); + +template <class C> +void +print_stack(const C& db) +{ + fprintf(stderr, "---------\n"); + fprintf(stderr, "names:\n"); + for (auto& s : db.names) + fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); + int i = -1; + fprintf(stderr, "subs:\n"); + for (auto& v : db.subs) + { + if (i >= 0) + fprintf(stderr, "S%i_ = {", i); + else + fprintf(stderr, "S_ = {"); + for (auto& s : v) + fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); + fprintf(stderr, "}\n"); + ++i; + } + fprintf(stderr, "template_param:\n"); + for (auto& t : db.template_param) + { + fprintf(stderr, "--\n"); + i = -1; + for (auto& v : t) + { + if (i >= 0) + fprintf(stderr, "T%i_ = {", i); + else + fprintf(stderr, "T_ = {"); + for (auto& s : v) + fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); + fprintf(stderr, "}\n"); + ++i; + } + } + fprintf(stderr, "---------\n\n"); +} + +template <class C> +void +print_state(const char* msg, const char* first, const char* last, const C& db) +{ + fprintf(stderr, "%s: ", msg); + for (; first != last; ++first) + fprintf(stderr, "%c", *first); + fprintf(stderr, "\n"); + print_stack(db); +} + +// <number> ::= [n] <non-negative decimal integer> + +const char* +parse_number(const char* first, const char* last) +{ + if (first != last) + { + const char* t = first; + if (*t == 'n') + ++t; + if (t != last) + { + if (*t == '0') + { + first = t+1; + } + else if ('1' <= *t && *t <= '9') + { + first = t+1; + while (first != last && std::isdigit(*first)) + ++first; + } + } + } + return first; +} + +template <class Float> +struct float_data; + +template <> +struct float_data<float> +{ + static const size_t mangled_size = 8; + static const size_t max_demangled_size = 24; + static const char* spec; +}; + +const char* float_data<float>::spec = "%af"; + +template <> +struct float_data<double> +{ + static const size_t mangled_size = 16; + static const size_t max_demangled_size = 32; + static const char* spec; +}; + +const char* float_data<double>::spec = "%a"; + +template <> +struct float_data<long double> +{ +#if defined(__arm__) + static const size_t mangled_size = 16; +#else + static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms +#endif + static const size_t max_demangled_size = 40; + static const char* spec; +}; + +const char* float_data<long double>::spec = "%LaL"; + +template <class Float, class C> +const char* +parse_floating_number(const char* first, const char* last, C& db) +{ + const size_t N = float_data<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) > N) + { + last = first + N; + union + { + Float value; + char buf[sizeof(Float)]; + }; + const char* t = first; + char* e = buf; + for (; t != last; ++t, ++e) + { + if (!isxdigit(*t)) + return first; + unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : + static_cast<unsigned>(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : + static_cast<unsigned>(*t - 'a' + 10); + *e = static_cast<char>((d1 << 4) + d0); + } + if (*t == 'E') + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[float_data<Float>::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), float_data<Float>::spec, value); + if (static_cast<std::size_t>(n) >= sizeof(num)) + return first; + db.names.push_back(typename C::String(num, static_cast<std::size_t>(n))); + first = t+1; + } + } + return first; +} + +// <source-name> ::= <positive length number> <identifier> + +template <class C> +const char* +parse_source_name(const char* first, const char* last, C& db) +{ + if (first != last) + { + char c = *first; + if (isdigit(c) && first+1 != last) + { + const char* t = first+1; + size_t n = static_cast<size_t>(c - '0'); + for (c = *t; isdigit(c); c = *t) + { + n = n * 10 + static_cast<size_t>(c - '0'); + if (++t == last) + return first; + } + if (static_cast<size_t>(last - t) >= n) + { + typename C::String r(t, n); + if (r.substr(0, 10) == "_GLOBAL__N") + db.names.push_back("(anonymous namespace)"); + else + db.names.push_back(std::move(r)); + first = t + n; + } + } + } + return first; +} + +// <substitution> ::= S <seq-id> _ +// ::= S_ +// <substitution> ::= Sa # ::std::allocator +// <substitution> ::= Sb # ::std::basic_string +// <substitution> ::= Ss # ::std::basic_string < char, +// ::std::char_traits<char>, +// ::std::allocator<char> > +// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > +// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > +// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > + +template <class C> +const char* +parse_substitution(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + if (*first == 'S') + { + switch (first[1]) + { + case 'a': + db.names.push_back("std::allocator"); + first += 2; + break; + case 'b': + db.names.push_back("std::basic_string"); + first += 2; + break; + case 's': + db.names.push_back("std::string"); + first += 2; + break; + case 'i': + db.names.push_back("std::istream"); + first += 2; + break; + case 'o': + db.names.push_back("std::ostream"); + first += 2; + break; + case 'd': + db.names.push_back("std::iostream"); + first += 2; + break; + case '_': + if (!db.subs.empty()) + { + for (const auto& n : db.subs.front()) + db.names.push_back(n); + first += 2; + } + break; + default: + if (std::isdigit(first[1]) || std::isupper(first[1])) + { + size_t sub = 0; + const char* t = first+1; + if (std::isdigit(*t)) + sub = static_cast<size_t>(*t - '0'); + else + sub = static_cast<size_t>(*t - 'A') + 10; + for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) + { + sub *= 36; + if (std::isdigit(*t)) + sub += static_cast<size_t>(*t - '0'); + else + sub += static_cast<size_t>(*t - 'A') + 10; + } + if (t == last || *t != '_') + return first; + ++sub; + if (sub < db.subs.size()) + { + for (const auto& n : db.subs[sub]) + db.names.push_back(n); + first = t+1; + } + } + break; + } + } + } + return first; +} + +// <builtin-type> ::= v # void +// ::= w # wchar_t +// ::= b # bool +// ::= c # char +// ::= a # signed char +// ::= h # unsigned char +// ::= s # short +// ::= t # unsigned short +// ::= i # int +// ::= j # unsigned int +// ::= l # long +// ::= m # unsigned long +// ::= x # long long, __int64 +// ::= y # unsigned long long, __int64 +// ::= n # __int128 +// ::= o # unsigned __int128 +// ::= f # float +// ::= d # double +// ::= e # long double, __float80 +// ::= g # __float128 +// ::= z # ellipsis +// ::= Dd # IEEE 754r decimal floating point (64 bits) +// ::= De # IEEE 754r decimal floating point (128 bits) +// ::= Df # IEEE 754r decimal floating point (32 bits) +// ::= Dh # IEEE 754r half-precision floating point (16 bits) +// ::= Di # char32_t +// ::= Ds # char16_t +// ::= Da # auto (in dependent new-expressions) +// ::= Dc # decltype(auto) +// ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) +// ::= u <source-name> # vendor extended type + +template <class C> +const char* +parse_builtin_type(const char* first, const char* last, C& db) +{ + if (first != last) + { + switch (*first) + { + case 'v': + db.names.push_back("void"); + ++first; + break; + case 'w': + db.names.push_back("wchar_t"); + ++first; + break; + case 'b': + db.names.push_back("bool"); + ++first; + break; + case 'c': + db.names.push_back("char"); + ++first; + break; + case 'a': + db.names.push_back("signed char"); + ++first; + break; + case 'h': + db.names.push_back("unsigned char"); + ++first; + break; + case 's': + db.names.push_back("short"); + ++first; + break; + case 't': + db.names.push_back("unsigned short"); + ++first; + break; + case 'i': + db.names.push_back("int"); + ++first; + break; + case 'j': + db.names.push_back("unsigned int"); + ++first; + break; + case 'l': + db.names.push_back("long"); + ++first; + break; + case 'm': + db.names.push_back("unsigned long"); + ++first; + break; + case 'x': + db.names.push_back("long long"); + ++first; + break; + case 'y': + db.names.push_back("unsigned long long"); + ++first; + break; + case 'n': + db.names.push_back("__int128"); + ++first; + break; + case 'o': + db.names.push_back("unsigned __int128"); + ++first; + break; + case 'f': + db.names.push_back("float"); + ++first; + break; + case 'd': + db.names.push_back("double"); + ++first; + break; + case 'e': + db.names.push_back("long double"); + ++first; + break; + case 'g': + db.names.push_back("__float128"); + ++first; + break; + case 'z': + db.names.push_back("..."); + ++first; + break; + case 'u': + { + const char*t = parse_source_name(first+1, last, db); + if (t != first+1) + first = t; + } + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'd': + db.names.push_back("decimal64"); + first += 2; + break; + case 'e': + db.names.push_back("decimal128"); + first += 2; + break; + case 'f': + db.names.push_back("decimal32"); + first += 2; + break; + case 'h': + db.names.push_back("decimal16"); + first += 2; + break; + case 'i': + db.names.push_back("char32_t"); + first += 2; + break; + case 's': + db.names.push_back("char16_t"); + first += 2; + break; + case 'a': + db.names.push_back("auto"); + first += 2; + break; + case 'c': + db.names.push_back("decltype(auto)"); + first += 2; + break; + case 'n': + db.names.push_back("std::nullptr_t"); + first += 2; + break; + } + } + break; + } + } + return first; +} + +// <CV-qualifiers> ::= [r] [V] [K] + +const char* +parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) +{ + cv = 0; + if (first != last) + { + if (*first == 'r') + { + cv |= 4; + ++first; + } + if (*first == 'V') + { + cv |= 2; + ++first; + } + if (*first == 'K') + { + cv |= 1; + ++first; + } + } + return first; +} + +// <template-param> ::= T_ # first template parameter +// ::= T <parameter-2 non-negative number> _ + +template <class C> +const char* +parse_template_param(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + if (*first == 'T') + { + if (first[1] == '_') + { + if (db.template_param.empty()) + return first; + if (!db.template_param.back().empty()) + { + for (auto& t : db.template_param.back().front()) + db.names.push_back(t); + first += 2; + } + else + { + db.names.push_back("T_"); + first += 2; + db.fix_forward_references = true; + } + } + else if (isdigit(first[1])) + { + const char* t = first+1; + size_t sub = static_cast<size_t>(*t - '0'); + for (++t; t != last && isdigit(*t); ++t) + { + sub *= 10; + sub += static_cast<size_t>(*t - '0'); + } + if (t == last || *t != '_' || db.template_param.empty()) + return first; + ++sub; + if (sub < db.template_param.back().size()) + { + for (auto& temp : db.template_param.back()[sub]) + db.names.push_back(temp); + first = t+1; + } + else + { + db.names.push_back(typename C::String(first, t+1)); + first = t+1; + db.fix_forward_references = true; + } + } + } + } + return first; +} + +// cc <type> <expression> # const_cast<type> (expression) + +template <class C> +const char* +parse_const_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } + } + } + return first; +} + +// dc <type> <expression> # dynamic_cast<type> (expression) + +template <class C> +const char* +parse_dynamic_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } + } + } + return first; +} + +// rc <type> <expression> # reinterpret_cast<type> (expression) + +template <class C> +const char* +parse_reinterpret_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } + } + } + return first; +} + +// sc <type> <expression> # static_cast<type> (expression) + +template <class C> +const char* +parse_static_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'c') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } + } + } + return first; +} + +// sp <expression> # pack expansion + +template <class C> +const char* +parse_pack_expansion(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'p') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + first = t; + } + return first; +} + +// st <type> # sizeof (a type) + +template <class C> +const char* +parse_sizeof_type_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 't') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// sz <expr> # sizeof (a expression) + +template <class C> +const char* +parse_sizeof_expr_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'z') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// sZ <template-param> # size of a parameter pack + +template <class C> +const char* +parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') + { + size_t k0 = db.names.size(); + const char* t = parse_template_param(first+2, last, db); + size_t k1 = db.names.size(); + if (t != first+2) + { + typename C::String tmp("sizeof...("); + size_t k = k0; + if (k != k1) + { + tmp += db.names[k].move_full(); + for (++k; k != k1; ++k) + tmp += ", " + db.names[k].move_full(); + } + tmp += ")"; + for (; k1 != k0; --k1) + db.names.pop_back(); + db.names.push_back(std::move(tmp)); + first = t; + } + } + return first; +} + +// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters + +template <class C> +const char* +parse_function_param(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && *first == 'f') + { + if (first[1] == 'p') + { + unsigned cv; + const char* t = parse_cv_qualifiers(first+2, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+1; + } + } + else if (first[1] == 'L') + { + unsigned cv; + const char* t0 = parse_number(first+2, last); + if (t0 != last && *t0 == 'p') + { + ++t0; + const char* t = parse_cv_qualifiers(t0, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+1; + } + } + } + } + return first; +} + +// sZ <function-param> # size of a function parameter pack + +template <class C> +const char* +parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') + { + const char* t = parse_function_param(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// te <expression> # typeid (expression) +// ti <type> # typeid (type) + +template <class C> +const char* +parse_typeid_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) + { + const char* t; + if (first[1] == 'e') + t = parse_expression(first+2, last, db); + else + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// tw <expression> # throw expression + +template <class C> +const char* +parse_throw_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 't' && first[1] == 'w') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "throw " + db.names.back().move_full(); + first = t; + } + } + return first; +} + +// ds <expression> <expression> # expr.*expr + +template <class C> +const char* +parse_dot_star_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 's') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += ".*" + expr; + first = t1; + } + } + } + return first; +} + +// <simple-id> ::= <source-name> [ <template-args> ] + +template <class C> +const char* +parse_simple_id(const char* first, const char* last, C& db) +{ + if (first != last) + { + const char* t = parse_source_name(first, last, db); + if (t != first) + { + const char* t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + first = t1; + } + else + first = t; + } + return first; +} + +// <unresolved-type> ::= <template-param> +// ::= <decltype> +// ::= <substitution> + +template <class C> +const char* +parse_unresolved_type(const char* first, const char* last, C& db) +{ + if (first != last) + { + const char* t = first; + switch (*first) + { + case 'T': + { + size_t k0 = db.names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.names.size(); + if (t != first && k1 == k0 + 1) + { + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + else + { + for (; k1 != k0; --k1) + db.names.pop_back(); + } + break; + } + case 'D': + t = parse_decltype(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + break; + case 'S': + t = parse_substitution(first, last, db); + if (t != first) + first = t; + else + { + if (last - first > 2 && first[1] == 't') + { + t = parse_unqualified_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "std::"); + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + } + break; + } + } + return first; +} + +// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) +// ::= <simple-id> # e.g., ~A<2*N> + +template <class C> +const char* +parse_destructor_name(const char* first, const char* last, C& db) +{ + if (first != last) + { + const char* t = parse_unresolved_type(first, last, db); + if (t == first) + t = parse_simple_id(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "~"); + first = t; + } + } + return first; +} + +// <base-unresolved-name> ::= <simple-id> # unresolved name +// extension ::= <operator-name> # unresolved operator-function-id +// extension ::= <operator-name> <template-args> # unresolved operator template-id +// ::= on <operator-name> # unresolved operator-function-id +// ::= on <operator-name> <template-args> # unresolved operator template-id +// ::= dn <destructor-name> # destructor or pseudo-destructor; +// # e.g. ~X or ~X<N-1> + +template <class C> +const char* +parse_base_unresolved_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') + { + if (first[0] == 'o') + { + const char* t = parse_operator_name(first+2, last, db); + if (t != first+2) + { + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + } + } + else + { + const char* t = parse_destructor_name(first+2, last, db); + if (t != first+2) + first = t; + } + } + else + { + const char* t = parse_simple_id(first, last, db); + if (t == first) + { + t = parse_operator_name(first, last, db); + if (t != first) + { + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + } + } + else + first = t; + } + } + return first; +} + +// <unresolved-qualifier-level> ::= <simple-id> + +template <class C> +const char* +parse_unresolved_qualifier_level(const char* first, const char* last, C& db) +{ + return parse_simple_id(first, last, db); +} + +// <unresolved-name> +// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x +// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> +// # A::x, N::y, A<T>::z; "gs" means leading "::" +// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x +// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> +// # T::N::x /decltype(p)::N::x +// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> + +template <class C> +const char* +parse_unresolved_name(const char* first, const char* last, C& db) +{ + if (last - first > 2) + { + const char* t = first; + bool global = false; + if (t[0] == 'g' && t[1] == 's') + { + global = true; + t += 2; + } + const char* t2 = parse_base_unresolved_name(t, last, db); + if (t2 != t) + { + if (global) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "::"); + } + first = t2; + } + else if (last - t > 2 && t[0] == 's' && t[1] == 'r') + { + if (t[2] == 'N') + { + t += 3; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + t = t1; + if (t == last) + { + db.names.pop_back(); + return first; + } + } + while (*t != 'E') + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + t = t1; + } + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + else + { + t += 2; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 != t) + { + t = t1; + t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + t = t1; + } + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + else + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + if (global) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "::"); + } + while (*t != 'E') + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + t = t1; + } + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + } + } + } + return first; +} + +// dt <expression> <unresolved-name> # expr.name + +template <class C> +const char* +parse_dot_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 't') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_unresolved_name(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "." + name; + first = t1; + } + } + } + return first; +} + +// cl <expression>+ E # call + +template <class C> +const char* +parse_call_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + if (t == last) + return first; + if (db.names.empty()) + return first; + db.names.back().first += db.names.back().second; + db.names.back().second = typename C::String(); + db.names.back().first.append("("); + bool first_expr = true; + while (*t != 'E') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + if (!first_expr) + { + db.names.back().first.append(", "); + first_expr = false; + } + db.names.back().first.append(tmp); + } + t = t1; + } + ++t; + if (db.names.empty()) + return first; + db.names.back().first.append(")"); + first = t; + } + } + return first; +} + +// [gs] nw <expression>* _ <type> E # new (expr-list) type +// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// [gs] na <expression>* _ <type> E # new[] (expr-list) type +// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// <initializer> ::= pi <expression>* E # parenthesized initialization + +template <class C> +const char* +parse_new_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 4) + { + const char* t = first; + bool parsed_gs = false; + if (t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) + { + bool is_array = t[1] == 'a'; + t += 2; + if (t == last) + return first; + bool has_expr_list = false; + bool first_expr = true; + while (*t != '_') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + has_expr_list = true; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + ++t; + const char* t1 = parse_type(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + bool has_init = false; + if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') + { + t += 2; + has_init = true; + first_expr = true; + while (*t != 'E') + { + t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + } + if (*t != 'E') + return first; + typename C::String init_list; + if (has_init) + { + if (db.names.empty()) + return first; + init_list = db.names.back().move_full(); + db.names.pop_back(); + } + if (db.names.empty()) + return first; + auto type = db.names.back().move_full(); + db.names.pop_back(); + typename C::String expr_list; + if (has_expr_list) + { + if (db.names.empty()) + return first; + expr_list = db.names.back().move_full(); + db.names.pop_back(); + } + typename C::String r; + if (parsed_gs) + r = "::"; + if (is_array) + r += "[] "; + else + r += " "; + if (has_expr_list) + r += "(" + expr_list + ") "; + r += type; + if (has_init) + r += " (" + init_list + ")"; + db.names.push_back(std::move(r)); + first = t+1; + } + } + return first; +} + +// cv <type> <expression> # conversion with one argument +// cv <type> _ <expression>* E # conversion with a different number of arguments + +template <class C> +const char* +parse_conversion_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') + { + bool try_to_parse_template_args = db.try_to_parse_template_args; + db.try_to_parse_template_args = false; + const char* t = parse_type(first+2, last, db); + db.try_to_parse_template_args = try_to_parse_template_args; + if (t != first+2 && t != last) + { + if (*t != '_') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t) + return first; + t = t1; + } + else + { + ++t; + if (t == last) + return first; + if (*t == 'E') + db.names.emplace_back(); + else + { + bool first_expr = true; + while (*t != 'E') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + } + ++t; + } + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; + first = t; + } + } + return first; +} + +// pt <expression> <expression> # expr->name + +template <class C> +const char* +parse_arrow_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'p' && first[1] == 't') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "->"; + db.names.back().first += tmp; + first = t1; + } + } + } + return first; +} + +// <ref-qualifier> ::= R # & ref-qualifier +// <ref-qualifier> ::= O # && ref-qualifier + +// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E + +template <class C> +const char* +parse_function_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'F') + { + const char* t = first+1; + if (t != last) + { + if (*t == 'Y') + { + /* extern "C" */ + if (++t == last) + return first; + } + const char* t1 = parse_type(t, last, db); + if (t1 != t) + { + t = t1; + typename C::String sig("("); + int ref_qual = 0; + while (true) + { + if (t == last) + { + db.names.pop_back(); + return first; + } + if (*t == 'E') + { + ++t; + break; + } + if (*t == 'v') + { + ++t; + continue; + } + if (*t == 'R' && t+1 != last && t[1] == 'E') + { + ref_qual = 1; + ++t; + continue; + } + if (*t == 'O' && t+1 != last && t[1] == 'E') + { + ref_qual = 2; + ++t; + continue; + } + size_t k0 = db.names.size(); + t1 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t1 == t || t1 == last) + return first; + for (size_t k = k0; k < k1; ++k) + { + if (sig.size() > 1) + sig += ", "; + sig += db.names[k].move_full(); + } + for (size_t k = k0; k < k1; ++k) + db.names.pop_back(); + t = t1; + } + sig += ")"; + switch (ref_qual) + { + case 1: + sig += " &"; + break; + case 2: + sig += " &&"; + break; + } + if (db.names.empty()) + return first; + db.names.back().first += " "; + db.names.back().second.insert(0, sig); + first = t; + } + } + } + return first; +} + +// <pointer-to-member-type> ::= M <class type> <member type> + +template <class C> +const char* +parse_pointer_to_member_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'M') + { + const char* t = parse_type(first+1, last, db); + if (t != first+1) + { + const char* t2 = parse_type(t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto func = std::move(db.names.back()); + db.names.pop_back(); + auto class_type = std::move(db.names.back()); + if (!func.second.empty() && func.second.front() == '(') + { + db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; + db.names.back().second = ")" + std::move(func.second); + } + else + { + db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; + db.names.back().second = std::move(func.second); + } + first = t2; + } + } + } + return first; +} + +// <array-type> ::= A <positive dimension number> _ <element type> +// ::= A [<dimension expression>] _ <element type> + +template <class C> +const char* +parse_array_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'A' && first+1 != last) + { + if (first[1] == '_') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + if (db.names.back().second.substr(0, 2) == " [") + db.names.back().second.erase(0, 1); + db.names.back().second.insert(0, " []"); + first = t; + } + } + else if ('1' <= first[1] && first[1] <= '9') + { + const char* t = parse_number(first+1, last); + if (t != last && *t == '_') + { + const char* t2 = parse_type(t+1, last, db); + if (t2 != t+1) + { + if (db.names.empty()) + return first; + if (db.names.back().second.substr(0, 2) == " [") + db.names.back().second.erase(0, 1); + db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); + first = t2; + } + } + } + else + { + const char* t = parse_expression(first+1, last, db); + if (t != first+1 && t != last && *t == '_') + { + const char* t2 = parse_type(++t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto type = std::move(db.names.back()); + db.names.pop_back(); + auto expr = std::move(db.names.back()); + db.names.back().first = std::move(type.first); + if (type.second.substr(0, 2) == " [") + type.second.erase(0, 1); + db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); + first = t2; + } + } + } + } + return first; +} + +// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) +// ::= DT <expression> E # decltype of an expression (C++0x) + +template <class C> +const char* +parse_decltype(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && first[0] == 'D') + { + switch (first[1]) + { + case 't': + case 'T': + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2 && t != last && *t == 'E') + { + if (db.names.empty()) + return first; + db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + first = t+1; + } + } + break; + } + } + return first; +} + +// extension: +// <vector-type> ::= Dv <positive dimension number> _ +// <extended element type> +// ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +// ::= p # AltiVec vector pixel + +template <class C> +const char* +parse_vector_type(const char* first, const char* last, C& db) +{ + if (last - first > 3 && first[0] == 'D' && first[1] == 'v') + { + if ('1' <= first[2] && first[2] <= '9') + { + const char* t = parse_number(first+2, last); + if (t == last || *t != '_') + return first; + const char* num = first + 2; + size_t sz = static_cast<size_t>(t - num); + if (++t != last) + { + if (*t != 'p') + { + const char* t1 = parse_type(t, last, db); + if (t1 != t) + { + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + first = t1; + } + } + else + { + ++t; + db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + first = t; + } + } + } + else + { + typename C::String num; + const char* t1 = first+2; + if (*t1 != '_') + { + const char* t = parse_expression(t1, last, db); + if (t != t1) + { + if (db.names.empty()) + return first; + num = db.names.back().move_full(); + db.names.pop_back(); + t1 = t; + } + } + if (t1 != last && *t1 == '_' && ++t1 != last) + { + const char* t = parse_type(t1, last, db); + if (t != t1) + { + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + num + "]"; + first = t; + } + } + } + } + return first; +} + +// <type> ::= <builtin-type> +// ::= <function-type> +// ::= <class-enum-type> +// ::= <array-type> +// ::= <pointer-to-member-type> +// ::= <template-param> +// ::= <template-template-param> <template-args> +// ::= <decltype> +// ::= <substitution> +// ::= <CV-qualifiers> <type> +// ::= P <type> # pointer-to +// ::= R <type> # reference-to +// ::= O <type> # rvalue reference-to (C++0x) +// ::= C <type> # complex pair (C 2000) +// ::= G <type> # imaginary (C 2000) +// ::= Dp <type> # pack expansion (C++0x) +// ::= U <source-name> <type> # vendor extended type qualifier +// extension := U <objc-name> <objc-type> # objc-type<identifier> +// extension := <vector-type> # <vector-type> starts with Dv + +// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 +// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> + +template <class C> +const char* +parse_type(const char* first, const char* last, C& db) +{ + if (first != last) + { + switch (*first) + { + case 'r': + case 'V': + case 'K': + { + unsigned cv = 0; + const char* t = parse_cv_qualifiers(first, last, cv); + if (t != first) + { + bool is_function = *t == 'F'; + size_t k0 = db.names.size(); + const char* t1 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t1 != t) + { + if (is_function) + db.subs.pop_back(); + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (is_function) + { + size_t p = db.names[k].second.size(); + if (db.names[k].second[p-2] == '&') + p -= 3; + else if (db.names[k].second.back() == '&') + p -= 2; + if (cv & 1) + { + db.names[k].second.insert(p, " const"); + p += 6; + } + if (cv & 2) + { + db.names[k].second.insert(p, " volatile"); + p += 9; + } + if (cv & 4) + db.names[k].second.insert(p, " restrict"); + } + else + { + if (cv & 1) + db.names[k].first.append(" const"); + if (cv & 2) + db.names[k].first.append(" volatile"); + if (cv & 4) + db.names[k].first.append(" restrict"); + } + db.subs.back().push_back(db.names[k]); + } + first = t1; + } + } + } + break; + default: + { + const char* t = parse_builtin_type(first, last, db); + if (t != first) + { + first = t; + } + else + { + switch (*first) + { + case 'A': + t = parse_array_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'C': + t = parse_type(first+1, last, db); + if (t != first+1) + { + if (db.names.empty()) + return first; + db.names.back().first.append(" complex"); + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'F': + t = parse_function_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'G': + t = parse_type(first+1, last, db); + if (t != first+1) + { + if (db.names.empty()) + return first; + db.names.back().first.append(" imaginary"); + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'M': + t = parse_pointer_to_member_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'O': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (!db.names[k].second.empty() && + db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + db.names[k].first.append("&&"); + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'P': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (!db.names[k].second.empty() && + db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") + { + db.names[k].first.append("*"); + } + else + { + db.names[k].first.replace(0, 11, "id"); + } + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'R': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (!db.names[k].second.empty() && + db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + db.names[k].first.append("&"); + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'T': + { + size_t k0 = db.names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.names.size(); + if (t != first) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.subs.back().push_back(db.names[k]); + if (db.try_to_parse_template_args && k1 == k0+1) + { + const char* t1 = parse_template_args(t, last, db); + if (t1 != t) + { + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t = t1; + } + } + first = t; + } + break; + } + case 'U': + if (first+1 != last) + { + t = parse_source_name(first+1, last, db); + if (t != first+1) + { + const char* t2 = parse_type(t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto type = db.names.back().move_full(); + db.names.pop_back(); + if (db.names.back().first.substr(0, 9) != "objcproto") + { + db.names.back() = type + " " + db.names.back().move_full(); + } + else + { + auto proto = db.names.back().move_full(); + db.names.pop_back(); + t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); + if (t != proto.data() + 9) + { + db.names.back() = type + "<" + db.names.back().move_full() + ">"; + } + else + { + db.names.push_back(type + " " + proto); + } + } + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t2; + } + } + } + break; + case 'S': + if (first+1 != last && first[1] == 't') + { + t = parse_name(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + else + { + t = parse_substitution(first, last, db); + if (t != first) + { + first = t; + // Parsed a substitution. If the substitution is a + // <template-param> it might be followed by <template-args>. + t = parse_template_args(first, last, db); + if (t != first) + { + if (db.names.size() < 2) + return first; + auto template_args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += template_args; + // Need to create substitution for <template-template-param> <template-args> + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + } + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'p': + { + size_t k0 = db.names.size(); + t = parse_type(first+2, last, db); + size_t k1 = db.names.size(); + if (t != first+2) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.subs.back().push_back(db.names[k]); + first = t; + return first; + } + break; + } + case 't': + case 'T': + t = parse_decltype(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + return first; + } + break; + case 'v': + t = parse_vector_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + return first; + } + break; + } + } + // drop through + default: + // must check for builtin-types before class-enum-types to avoid + // ambiguities with operator-names + t = parse_builtin_type(first, last, db); + if (t != first) + { + first = t; + } + else + { + t = parse_name(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + break; + } + } + break; + } + } + } + return first; +} + +// <operator-name> +// ::= aa # && +// ::= ad # & (unary) +// ::= an # & +// ::= aN # &= +// ::= aS # = +// ::= cl # () +// ::= cm # , +// ::= co # ~ +// ::= cv <type> # (cast) +// ::= da # delete[] +// ::= de # * (unary) +// ::= dl # delete +// ::= dv # / +// ::= dV # /= +// ::= eo # ^ +// ::= eO # ^= +// ::= eq # == +// ::= ge # >= +// ::= gt # > +// ::= ix # [] +// ::= le # <= +// ::= li <source-name> # operator "" +// ::= ls # << +// ::= lS # <<= +// ::= lt # < +// ::= mi # - +// ::= mI # -= +// ::= ml # * +// ::= mL # *= +// ::= mm # -- (postfix in <expression> context) +// ::= na # new[] +// ::= ne # != +// ::= ng # - (unary) +// ::= nt # ! +// ::= nw # new +// ::= oo # || +// ::= or # | +// ::= oR # |= +// ::= pm # ->* +// ::= pl # + +// ::= pL # += +// ::= pp # ++ (postfix in <expression> context) +// ::= ps # + (unary) +// ::= pt # -> +// ::= qu # ? +// ::= rm # % +// ::= rM # %= +// ::= rs # >> +// ::= rS # >>= +// ::= v <digit> <source-name> # vendor extended operator + +template <class C> +const char* +parse_operator_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + switch (first[0]) + { + case 'a': + switch (first[1]) + { + case 'a': + db.names.push_back("operator&&"); + first += 2; + break; + case 'd': + case 'n': + db.names.push_back("operator&"); + first += 2; + break; + case 'N': + db.names.push_back("operator&="); + first += 2; + break; + case 'S': + db.names.push_back("operator="); + first += 2; + break; + } + break; + case 'c': + switch (first[1]) + { + case 'l': + db.names.push_back("operator()"); + first += 2; + break; + case 'm': + db.names.push_back("operator,"); + first += 2; + break; + case 'o': + db.names.push_back("operator~"); + first += 2; + break; + case 'v': + { + bool try_to_parse_template_args = db.try_to_parse_template_args; + db.try_to_parse_template_args = false; + const char* t = parse_type(first+2, last, db); + db.try_to_parse_template_args = try_to_parse_template_args; + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator "); + db.parsed_ctor_dtor_cv = true; + first = t; + } + } + break; + } + break; + case 'd': + switch (first[1]) + { + case 'a': + db.names.push_back("operator delete[]"); + first += 2; + break; + case 'e': + db.names.push_back("operator*"); + first += 2; + break; + case 'l': + db.names.push_back("operator delete"); + first += 2; + break; + case 'v': + db.names.push_back("operator/"); + first += 2; + break; + case 'V': + db.names.push_back("operator/="); + first += 2; + break; + } + break; + case 'e': + switch (first[1]) + { + case 'o': + db.names.push_back("operator^"); + first += 2; + break; + case 'O': + db.names.push_back("operator^="); + first += 2; + break; + case 'q': + db.names.push_back("operator=="); + first += 2; + break; + } + break; + case 'g': + switch (first[1]) + { + case 'e': + db.names.push_back("operator>="); + first += 2; + break; + case 't': + db.names.push_back("operator>"); + first += 2; + break; + } + break; + case 'i': + if (first[1] == 'x') + { + db.names.push_back("operator[]"); + first += 2; + } + break; + case 'l': + switch (first[1]) + { + case 'e': + db.names.push_back("operator<="); + first += 2; + break; + case 'i': + { + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator\"\" "); + first = t; + } + } + break; + case 's': + db.names.push_back("operator<<"); + first += 2; + break; + case 'S': + db.names.push_back("operator<<="); + first += 2; + break; + case 't': + db.names.push_back("operator<"); + first += 2; + break; + } + break; + case 'm': + switch (first[1]) + { + case 'i': + db.names.push_back("operator-"); + first += 2; + break; + case 'I': + db.names.push_back("operator-="); + first += 2; + break; + case 'l': + db.names.push_back("operator*"); + first += 2; + break; + case 'L': + db.names.push_back("operator*="); + first += 2; + break; + case 'm': + db.names.push_back("operator--"); + first += 2; + break; + } + break; + case 'n': + switch (first[1]) + { + case 'a': + db.names.push_back("operator new[]"); + first += 2; + break; + case 'e': + db.names.push_back("operator!="); + first += 2; + break; + case 'g': + db.names.push_back("operator-"); + first += 2; + break; + case 't': + db.names.push_back("operator!"); + first += 2; + break; + case 'w': + db.names.push_back("operator new"); + first += 2; + break; + } + break; + case 'o': + switch (first[1]) + { + case 'o': + db.names.push_back("operator||"); + first += 2; + break; + case 'r': + db.names.push_back("operator|"); + first += 2; + break; + case 'R': + db.names.push_back("operator|="); + first += 2; + break; + } + break; + case 'p': + switch (first[1]) + { + case 'm': + db.names.push_back("operator->*"); + first += 2; + break; + case 'l': + db.names.push_back("operator+"); + first += 2; + break; + case 'L': + db.names.push_back("operator+="); + first += 2; + break; + case 'p': + db.names.push_back("operator++"); + first += 2; + break; + case 's': + db.names.push_back("operator+"); + first += 2; + break; + case 't': + db.names.push_back("operator->"); + first += 2; + break; + } + break; + case 'q': + if (first[1] == 'u') + { + db.names.push_back("operator?"); + first += 2; + } + break; + case 'r': + switch (first[1]) + { + case 'm': + db.names.push_back("operator%"); + first += 2; + break; + case 'M': + db.names.push_back("operator%="); + first += 2; + break; + case 's': + db.names.push_back("operator>>"); + first += 2; + break; + case 'S': + db.names.push_back("operator>>="); + first += 2; + break; + } + break; + case 'v': + if (std::isdigit(first[1])) + { + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator "); + first = t; + } + } + break; + } + } + return first; +} + +template <class C> +const char* +parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) +{ + const char* t = parse_number(first, last); + if (t != first && t != last && *t == 'E') + { + if (lit.size() > 3) + db.names.push_back("(" + lit + ")"); + else + db.names.emplace_back(); + if (*first == 'n') + { + db.names.back().first += '-'; + ++first; + } + db.names.back().first.append(first, t); + if (lit.size() <= 3) + db.names.back().first += lit; + first = t+1; + } + return first; +} + +// <expr-primary> ::= L <type> <value number> E # integer literal +// ::= L <type> <value float> E # floating literal +// ::= L <string type> E # string literal +// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") +// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) +// ::= L <mangled-name> E # external name + +template <class C> +const char* +parse_expr_primary(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && *first == 'L') + { + switch (first[1]) + { + case 'w': + { + const char* t = parse_integer_literal(first+2, last, "wchar_t", db); + if (t != first+2) + first = t; + } + break; + case 'b': + if (first[3] == 'E') + { + switch (first[2]) + { + case '0': + db.names.push_back("false"); + first += 4; + break; + case '1': + db.names.push_back("true"); + first += 4; + break; + } + } + break; + case 'c': + { + const char* t = parse_integer_literal(first+2, last, "char", db); + if (t != first+2) + first = t; + } + break; + case 'a': + { + const char* t = parse_integer_literal(first+2, last, "signed char", db); + if (t != first+2) + first = t; + } + break; + case 'h': + { + const char* t = parse_integer_literal(first+2, last, "unsigned char", db); + if (t != first+2) + first = t; + } + break; + case 's': + { + const char* t = parse_integer_literal(first+2, last, "short", db); + if (t != first+2) + first = t; + } + break; + case 't': + { + const char* t = parse_integer_literal(first+2, last, "unsigned short", db); + if (t != first+2) + first = t; + } + break; + case 'i': + { + const char* t = parse_integer_literal(first+2, last, "", db); + if (t != first+2) + first = t; + } + break; + case 'j': + { + const char* t = parse_integer_literal(first+2, last, "u", db); + if (t != first+2) + first = t; + } + break; + case 'l': + { + const char* t = parse_integer_literal(first+2, last, "l", db); + if (t != first+2) + first = t; + } + break; + case 'm': + { + const char* t = parse_integer_literal(first+2, last, "ul", db); + if (t != first+2) + first = t; + } + break; + case 'x': + { + const char* t = parse_integer_literal(first+2, last, "ll", db); + if (t != first+2) + first = t; + } + break; + case 'y': + { + const char* t = parse_integer_literal(first+2, last, "ull", db); + if (t != first+2) + first = t; + } + break; + case 'n': + { + const char* t = parse_integer_literal(first+2, last, "__int128", db); + if (t != first+2) + first = t; + } + break; + case 'o': + { + const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); + if (t != first+2) + first = t; + } + break; + case 'f': + { + const char* t = parse_floating_number<float>(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'd': + { + const char* t = parse_floating_number<double>(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'e': + { + const char* t = parse_floating_number<long double>(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case '_': + if (first[2] == 'Z') + { + const char* t = parse_encoding(first+3, last, db); + if (t != first+3 && t != last && *t == 'E') + first = t+1; + } + break; + case 'T': + // Invalid mangled name per + // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html + break; + default: + { + // might be named type + const char* t = parse_type(first+1, last, db); + if (t != first+1 && t != last) + { + if (*t != 'E') + { + const char* n = t; + for (; n != last && isdigit(*n); ++n) + ; + if (n != t && n != last && *n == 'E') + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + first = n+1; + break; + } + } + else + { + first = t+1; + break; + } + } + } + } + } + return first; +} + +template <class String> +String +base_name(String& s) +{ + if (s.empty()) + return s; + if (s == "std::string") + { + s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"; + return "basic_string"; + } + if (s == "std::istream") + { + s = "std::basic_istream<char, std::char_traits<char> >"; + return "basic_istream"; + } + if (s == "std::ostream") + { + s = "std::basic_ostream<char, std::char_traits<char> >"; + return "basic_ostream"; + } + if (s == "std::iostream") + { + s = "std::basic_iostream<char, std::char_traits<char> >"; + return "basic_iostream"; + } + const char* const pf = s.data(); + const char* pe = pf + s.size(); + if (pe[-1] == '>') + { + unsigned c = 1; + while (true) + { + if (--pe == pf) + return String(); + if (pe[-1] == '<') + { + if (--c == 0) + { + --pe; + break; + } + } + else if (pe[-1] == '>') + ++c; + } + } + const char* p0 = pe - 1; + for (; p0 != pf; --p0) + { + if (*p0 == ':') + { + ++p0; + break; + } + } + return String(p0, pe); +} + +// <ctor-dtor-name> ::= C1 # complete object constructor +// ::= C2 # base object constructor +// ::= C3 # complete object allocating constructor +// extension ::= C5 # ? +// ::= D0 # deleting destructor +// ::= D1 # complete object destructor +// ::= D2 # base object destructor +// extension ::= D5 # ? + +template <class C> +const char* +parse_ctor_dtor_name(const char* first, const char* last, C& db) +{ + if (last-first >= 2 && !db.names.empty()) + { + switch (first[0]) + { + case 'C': + switch (first[1]) + { + case '1': + case '2': + case '3': + case '5': + if (db.names.empty()) + return first; + db.names.push_back(base_name(db.names.back().first)); + first += 2; + db.parsed_ctor_dtor_cv = true; + break; + } + break; + case 'D': + switch (first[1]) + { + case '0': + case '1': + case '2': + case '5': + if (db.names.empty()) + return first; + db.names.push_back("~" + base_name(db.names.back().first)); + first += 2; + db.parsed_ctor_dtor_cv = true; + break; + } + break; + } + } + return first; +} + +// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ +// ::= <closure-type-name> +// +// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ +// +// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters + +template <class C> +const char* +parse_unnamed_type_name(const char* first, const char* last, C& db) +{ + if (last - first > 2 && first[0] == 'U') + { + char type = first[1]; + switch (type) + { + case 't': + { + db.names.push_back(typename C::String("'unnamed")); + const char* t0 = first+2; + if (t0 == last) + { + db.names.pop_back(); + return first; + } + if (std::isdigit(*t0)) + { + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + db.names.back().first.append(t0, t1); + t0 = t1; + } + db.names.back().first.push_back('\''); + if (t0 == last || *t0 != '_') + { + db.names.pop_back(); + return first; + } + first = t0 + 1; + } + break; + case 'l': + { + db.names.push_back(typename C::String("'lambda'(")); + const char* t0 = first+2; + if (first[2] == 'v') + { + db.names.back().first += ')'; + ++t0; + } + else + { + const char* t1 = parse_type(t0, last, db); + if (t1 == t0) + { + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append(tmp); + t0 = t1; + while (true) + { + t1 = parse_type(t0, last, db); + if (t1 == t0) + break; + if (db.names.size() < 2) + return first; + tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + } + t0 = t1; + } + db.names.back().first.append(")"); + } + if (t0 == last || *t0 != 'E') + { + db.names.pop_back(); + return first; + } + ++t0; + if (t0 == last) + { + db.names.pop_back(); + return first; + } + if (std::isdigit(*t0)) + { + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); + t0 = t1; + } + if (t0 == last || *t0 != '_') + { + db.names.pop_back(); + return first; + } + first = t0 + 1; + } + break; + } + } + return first; +} + +// <unqualified-name> ::= <operator-name> +// ::= <ctor-dtor-name> +// ::= <source-name> +// ::= <unnamed-type-name> + +template <class C> +const char* +parse_unqualified_name(const char* first, const char* last, C& db) +{ + if (first != last) + { + const char* t; + switch (*first) + { + case 'C': + case 'D': + t = parse_ctor_dtor_name(first, last, db); + if (t != first) + first = t; + break; + case 'U': + t = parse_unnamed_type_name(first, last, db); + if (t != first) + first = t; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + t = parse_source_name(first, last, db); + if (t != first) + first = t; + break; + default: + t = parse_operator_name(first, last, db); + if (t != first) + first = t; + break; + }; + } + return first; +} + +// <unscoped-name> ::= <unqualified-name> +// ::= St <unqualified-name> # ::std:: +// extension ::= StL<unqualified-name> + +template <class C> +const char* +parse_unscoped_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + const char* t0 = first; + bool St = false; + if (first[0] == 'S' && first[1] == 't') + { + t0 += 2; + St = true; + if (t0 != last && *t0 == 'L') + ++t0; + } + const char* t1 = parse_unqualified_name(t0, last, db); + if (t1 != t0) + { + if (St) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "std::"); + } + first = t1; + } + } + return first; +} + +// at <type> # alignof (a type) + +template <class C> +const char* +parse_alignof_type(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'a' && first[1] == 't') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// az <expression> # alignof (a expression) + +template <class C> +const char* +parse_alignof_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +template <class C> +const char* +parse_noexcept_expression(const char* first, const char* last, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + if (db.names.empty()) + return first; + db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; + first = t1; + } + return first; +} + +template <class C> +const char* +parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + if (db.names.empty()) + return first; + db.names.back().first = op + "(" + db.names.back().move_full() + ")"; + first = t1; + } + return first; +} + +template <class C> +const char* +parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) + { + if (db.names.size() < 2) + return first; + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + auto& nm = db.names.back().first; + nm.clear(); + if (op == ">") + nm += '('; + nm += "(" + op1 + ") " + op + " (" + op2 + ")"; + if (op == ">") + nm += ')'; + first = t2; + } + else + db.names.pop_back(); + } + return first; +} + +// <expression> ::= <unary operator-name> <expression> +// ::= <binary operator-name> <expression> <expression> +// ::= <ternary operator-name> <expression> <expression> <expression> +// ::= cl <expression>+ E # call +// ::= cv <type> <expression> # conversion with one argument +// ::= cv <type> _ <expression>* E # conversion with a different number of arguments +// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type +// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type +// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// ::= [gs] dl <expression> # delete expression +// ::= [gs] da <expression> # delete[] expression +// ::= pp_ <expression> # prefix ++ +// ::= mm_ <expression> # prefix -- +// ::= ti <type> # typeid (type) +// ::= te <expression> # typeid (expression) +// ::= dc <type> <expression> # dynamic_cast<type> (expression) +// ::= sc <type> <expression> # static_cast<type> (expression) +// ::= cc <type> <expression> # const_cast<type> (expression) +// ::= rc <type> <expression> # reinterpret_cast<type> (expression) +// ::= st <type> # sizeof (a type) +// ::= sz <expression> # sizeof (an expression) +// ::= at <type> # alignof (a type) +// ::= az <expression> # alignof (an expression) +// ::= nx <expression> # noexcept (expression) +// ::= <template-param> +// ::= <function-param> +// ::= dt <expression> <unresolved-name> # expr.name +// ::= pt <expression> <unresolved-name> # expr->name +// ::= ds <expression> <expression> # expr.*expr +// ::= sZ <template-param> # size of a parameter pack +// ::= sZ <function-param> # size of a function parameter pack +// ::= sp <expression> # pack expansion +// ::= tw <expression> # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= <unresolved-name> # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= <expr-primary> + +template <class C> +const char* +parse_expression(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + const char* t = first; + bool parsed_gs = false; + if (last - first >= 4 && t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + switch (*t) + { + case 'L': + first = parse_expr_primary(first, last, db); + break; + case 'T': + first = parse_template_param(first, last, db); + break; + case 'f': + first = parse_function_param(first, last, db); + break; + case 'a': + switch (t[1]) + { + case 'a': + t = parse_binary_expression(first+2, last, "&&", db); + if (t != first+2) + first = t; + break; + case 'd': + t = parse_prefix_expression(first+2, last, "&", db); + if (t != first+2) + first = t; + break; + case 'n': + t = parse_binary_expression(first+2, last, "&", db); + if (t != first+2) + first = t; + break; + case 'N': + t = parse_binary_expression(first+2, last, "&=", db); + if (t != first+2) + first = t; + break; + case 'S': + t = parse_binary_expression(first+2, last, "=", db); + if (t != first+2) + first = t; + break; + case 't': + first = parse_alignof_type(first, last, db); + break; + case 'z': + first = parse_alignof_expr(first, last, db); + break; + } + break; + case 'c': + switch (t[1]) + { + case 'c': + first = parse_const_cast_expr(first, last, db); + break; + case 'l': + first = parse_call_expr(first, last, db); + break; + case 'm': + t = parse_binary_expression(first+2, last, ",", db); + if (t != first+2) + first = t; + break; + case 'o': + t = parse_prefix_expression(first+2, last, "~", db); + if (t != first+2) + first = t; + break; + case 'v': + first = parse_conversion_expr(first, last, db); + break; + } + break; + case 'd': + switch (t[1]) + { + case 'a': + { + const char* t1 = parse_expression(t+2, last, db); + if (t1 != t+2) + { + if (db.names.empty()) + return first; + db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + + "delete[] " + db.names.back().move_full(); + first = t1; + } + } + break; + case 'c': + first = parse_dynamic_cast_expr(first, last, db); + break; + case 'e': + t = parse_prefix_expression(first+2, last, "*", db); + if (t != first+2) + first = t; + break; + case 'l': + { + const char* t1 = parse_expression(t+2, last, db); + if (t1 != t+2) + { + if (db.names.empty()) + return first; + db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + + "delete " + db.names.back().move_full(); + first = t1; + } + } + break; + case 'n': + return parse_unresolved_name(first, last, db); + case 's': + first = parse_dot_star_expr(first, last, db); + break; + case 't': + first = parse_dot_expr(first, last, db); + break; + case 'v': + t = parse_binary_expression(first+2, last, "/", db); + if (t != first+2) + first = t; + break; + case 'V': + t = parse_binary_expression(first+2, last, "/=", db); + if (t != first+2) + first = t; + break; + } + break; + case 'e': + switch (t[1]) + { + case 'o': + t = parse_binary_expression(first+2, last, "^", db); + if (t != first+2) + first = t; + break; + case 'O': + t = parse_binary_expression(first+2, last, "^=", db); + if (t != first+2) + first = t; + break; + case 'q': + t = parse_binary_expression(first+2, last, "==", db); + if (t != first+2) + first = t; + break; + } + break; + case 'g': + switch (t[1]) + { + case 'e': + t = parse_binary_expression(first+2, last, ">=", db); + if (t != first+2) + first = t; + break; + case 't': + t = parse_binary_expression(first+2, last, ">", db); + if (t != first+2) + first = t; + break; + } + break; + case 'i': + if (t[1] == 'x') + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) + { + if (db.names.size() < 2) + return first; + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + db.names.back() = "(" + op1 + ")[" + op2 + "]"; + first = t2; + } + else + db.names.pop_back(); + } + } + break; + case 'l': + switch (t[1]) + { + case 'e': + t = parse_binary_expression(first+2, last, "<=", db); + if (t != first+2) + first = t; + break; + case 's': + t = parse_binary_expression(first+2, last, "<<", db); + if (t != first+2) + first = t; + break; + case 'S': + t = parse_binary_expression(first+2, last, "<<=", db); + if (t != first+2) + first = t; + break; + case 't': + t = parse_binary_expression(first+2, last, "<", db); + if (t != first+2) + first = t; + break; + } + break; + case 'm': + switch (t[1]) + { + case 'i': + t = parse_binary_expression(first+2, last, "-", db); + if (t != first+2) + first = t; + break; + case 'I': + t = parse_binary_expression(first+2, last, "-=", db); + if (t != first+2) + first = t; + break; + case 'l': + t = parse_binary_expression(first+2, last, "*", db); + if (t != first+2) + first = t; + break; + case 'L': + t = parse_binary_expression(first+2, last, "*=", db); + if (t != first+2) + first = t; + break; + case 'm': + if (first+2 != last && first[2] == '_') + { + t = parse_prefix_expression(first+3, last, "--", db); + if (t != first+3) + first = t; + } + else + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")--"; + first = t1; + } + } + break; + } + break; + case 'n': + switch (t[1]) + { + case 'a': + case 'w': + first = parse_new_expr(first, last, db); + break; + case 'e': + t = parse_binary_expression(first+2, last, "!=", db); + if (t != first+2) + first = t; + break; + case 'g': + t = parse_prefix_expression(first+2, last, "-", db); + if (t != first+2) + first = t; + break; + case 't': + t = parse_prefix_expression(first+2, last, "!", db); + if (t != first+2) + first = t; + break; + case 'x': + t = parse_noexcept_expression(first+2, last, db); + if (t != first+2) + first = t; + break; + } + break; + case 'o': + switch (t[1]) + { + case 'n': + return parse_unresolved_name(first, last, db); + case 'o': + t = parse_binary_expression(first+2, last, "||", db); + if (t != first+2) + first = t; + break; + case 'r': + t = parse_binary_expression(first+2, last, "|", db); + if (t != first+2) + first = t; + break; + case 'R': + t = parse_binary_expression(first+2, last, "|=", db); + if (t != first+2) + first = t; + break; + } + break; + case 'p': + switch (t[1]) + { + case 'm': + t = parse_binary_expression(first+2, last, "->*", db); + if (t != first+2) + first = t; + break; + case 'l': + t = parse_binary_expression(first+2, last, "+", db); + if (t != first+2) + first = t; + break; + case 'L': + t = parse_binary_expression(first+2, last, "+=", db); + if (t != first+2) + first = t; + break; + case 'p': + if (first+2 != last && first[2] == '_') + { + t = parse_prefix_expression(first+3, last, "++", db); + if (t != first+3) + first = t; + } + else + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")++"; + first = t1; + } + } + break; + case 's': + t = parse_prefix_expression(first+2, last, "+", db); + if (t != first+2) + first = t; + break; + case 't': + first = parse_arrow_expr(first, last, db); + break; + } + break; + case 'q': + if (t[1] == 'u') + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) + { + const char* t3 = parse_expression(t2, last, db); + if (t3 != t2) + { + if (db.names.size() < 3) + return first; + auto op3 = db.names.back().move_full(); + db.names.pop_back(); + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; + first = t3; + } + else + { + db.names.pop_back(); + db.names.pop_back(); + } + } + else + db.names.pop_back(); + } + } + break; + case 'r': + switch (t[1]) + { + case 'c': + first = parse_reinterpret_cast_expr(first, last, db); + break; + case 'm': + t = parse_binary_expression(first+2, last, "%", db); + if (t != first+2) + first = t; + break; + case 'M': + t = parse_binary_expression(first+2, last, "%=", db); + if (t != first+2) + first = t; + break; + case 's': + t = parse_binary_expression(first+2, last, ">>", db); + if (t != first+2) + first = t; + break; + case 'S': + t = parse_binary_expression(first+2, last, ">>=", db); + if (t != first+2) + first = t; + break; + } + break; + case 's': + switch (t[1]) + { + case 'c': + first = parse_static_cast_expr(first, last, db); + break; + case 'p': + first = parse_pack_expansion(first, last, db); + break; + case 'r': + return parse_unresolved_name(first, last, db); + case 't': + first = parse_sizeof_type_expr(first, last, db); + break; + case 'z': + first = parse_sizeof_expr_expr(first, last, db); + break; + case 'Z': + if (last - t >= 3) + { + switch (t[2]) + { + case 'T': + first = parse_sizeof_param_pack_expr(first, last, db); + break; + case 'f': + first = parse_sizeof_function_param_pack_expr(first, last, db); + break; + } + } + break; + } + break; + case 't': + switch (t[1]) + { + case 'e': + case 'i': + first = parse_typeid_expr(first, last, db); + break; + case 'r': + db.names.push_back("throw"); + first += 2; + break; + case 'w': + first = parse_throw_expr(first, last, db); + break; + } + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return parse_unresolved_name(first, last, db); + } + } + return first; +} + +// <template-arg> ::= <type> # type or template +// ::= X <expression> E # expression +// ::= <expr-primary> # simple expressions +// ::= J <template-arg>* E # argument pack +// ::= LZ <encoding> E # extension + +template <class C> +const char* +parse_template_arg(const char* first, const char* last, C& db) +{ + if (first != last) + { + const char* t; + switch (*first) + { + case 'X': + t = parse_expression(first+1, last, db); + if (t != first+1) + { + if (t != last && *t == 'E') + first = t+1; + } + break; + case 'J': + t = first+1; + if (t == last) + return first; + while (*t != 'E') + { + const char* t1 = parse_template_arg(t, last, db); + if (t1 == t) + return first; + t = t1; + } + first = t+1; + break; + case 'L': + // <expr-primary> or LZ <encoding> E + if (first+1 != last && first[1] == 'Z') + { + t = parse_encoding(first+2, last, db); + if (t != first+2 && t != last && *t == 'E') + first = t+1; + } + else + first = parse_expr_primary(first, last, db); + break; + default: + // <type> + first = parse_type(first, last, db); + break; + } + } + return first; +} + +// <template-args> ::= I <template-arg>* E +// extension, the abi says <template-arg>+ + +template <class C> +const char* +parse_template_args(const char* first, const char* last, C& db) +{ + if (last - first >= 2 && *first == 'I') + { + if (db.tag_templates) + db.template_param.back().clear(); + const char* t = first+1; + typename C::String args("<"); + while (*t != 'E') + { + if (db.tag_templates) + db.template_param.emplace_back(db.names.get_allocator()); + size_t k0 = db.names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.names.size(); + if (db.tag_templates) + db.template_param.pop_back(); + if (t1 == t || t1 == last) + return first; + if (db.tag_templates) + { + db.template_param.back().emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.template_param.back().back().push_back(db.names[k]); + } + for (size_t k = k0; k < k1; ++k) + { + if (args.size() > 1) + args += ", "; + args += db.names[k].move_full(); + } + for (; k1 != k0; --k1) + db.names.pop_back(); + t = t1; + } + first = t + 1; + if (args.back() != '>') + args += ">"; + else + args += " >"; + db.names.push_back(std::move(args)); + + } + return first; +} + +// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E +// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E +// +// <prefix> ::= <prefix> <unqualified-name> +// ::= <template-prefix> <template-args> +// ::= <template-param> +// ::= <decltype> +// ::= # empty +// ::= <substitution> +// ::= <prefix> <data-member-prefix> +// extension ::= L +// +// <template-prefix> ::= <prefix> <template unqualified-name> +// ::= <template-param> +// ::= <substitution> + +template <class C> +const char* +parse_nested_name(const char* first, const char* last, C& db, + bool* ends_with_template_args) +{ + if (first != last && *first == 'N') + { + unsigned cv; + const char* t0 = parse_cv_qualifiers(first+1, last, cv); + if (t0 == last) + return first; + db.ref = 0; + if (*t0 == 'R') + { + db.ref = 1; + ++t0; + } + else if (*t0 == 'O') + { + db.ref = 2; + ++t0; + } + db.names.emplace_back(); + if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') + { + t0 += 2; + db.names.back().first = "std"; + } + if (t0 == last) + { + db.names.pop_back(); + return first; + } + bool pop_subs = false; + bool component_ends_with_template_args = false; + while (*t0 != 'E') + { + component_ends_with_template_args = false; + const char* t1; + switch (*t0) + { + case 'S': + if (t0 + 1 != last && t0[1] == 't') + goto do_parse_unqualified_name; + t1 = parse_substitution(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + { + db.names.back().first += "::" + name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + else + db.names.back().first = name; + pop_subs = true; + t0 = t1; + } + else + return first; + break; + case 'T': + t1 = parse_template_param(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; + else + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; + } + else + return first; + break; + case 'D': + if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T') + goto do_parse_unqualified_name; + t1 = parse_decltype(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; + else + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; + } + else + return first; + break; + case 'I': + t1 = parse_template_args(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t0 = t1; + component_ends_with_template_args = true; + } + else + return first; + break; + case 'L': + if (++t0 == last) + return first; + break; + default: + do_parse_unqualified_name: + t1 = parse_unqualified_name(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; + else + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; + } + else + return first; + } + } + first = t0 + 1; + db.cv = cv; + if (pop_subs && !db.subs.empty()) + db.subs.pop_back(); + if (ends_with_template_args) + *ends_with_template_args = component_ends_with_template_args; + } + return first; +} + +// <discriminator> := _ <non-negative number> # when number < 10 +// := __ <non-negative number> _ # when number >= 10 +// extension := decimal-digit+ + +const char* +parse_discriminator(const char* first, const char* last) +{ + // parse but ignore discriminator + if (first != last) + { + if (*first == '_') + { + const char* t1 = first+1; + if (t1 != last) + { + if (std::isdigit(*t1)) + first = t1+1; + else if (*t1 == '_') + { + for (++t1; t1 != last && std::isdigit(*t1); ++t1) + ; + if (t1 != last && *t1 == '_') + first = t1 + 1; + } + } + } + else if (std::isdigit(*first)) + { + const char* t1 = first+1; + for (; t1 != last && std::isdigit(*t1); ++t1) + ; + first = t1; + } + } + return first; +} + +// <local-name> := Z <function encoding> E <entity name> [<discriminator>] +// := Z <function encoding> E s [<discriminator>] +// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> + +template <class C> +const char* +parse_local_name(const char* first, const char* last, C& db, + bool* ends_with_template_args) +{ + if (first != last && *first == 'Z') + { + const char* t = parse_encoding(first+1, last, db); + if (t != first+1 && t != last && *t == 'E' && ++t != last) + { + switch (*t) + { + case 's': + first = parse_discriminator(t+1, last); + if (db.names.empty()) + return first; + db.names.back().first.append("::string literal"); + break; + case 'd': + if (++t != last) + { + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + t = t1 + 1; + t1 = parse_name(t, last, db, + ends_with_template_args); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append("::"); + db.names.back().first.append(name); + first = t1; + } + else + db.names.pop_back(); + } + } + break; + default: + { + const char* t1 = parse_name(t, last, db, + ends_with_template_args); + if (t1 != t) + { + // parse but ignore discriminator + first = parse_discriminator(t1, last); + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append("::"); + db.names.back().first.append(name); + } + else + db.names.pop_back(); + } + break; + } + } + } + return first; +} + +// <name> ::= <nested-name> // N +// ::= <local-name> # See Scope Encoding below // Z +// ::= <unscoped-template-name> <template-args> +// ::= <unscoped-name> + +// <unscoped-template-name> ::= <unscoped-name> +// ::= <substitution> + +template <class C> +const char* +parse_name(const char* first, const char* last, C& db, + bool* ends_with_template_args) +{ + if (last - first >= 2) + { + const char* t0 = first; + // extension: ignore L here + if (*t0 == 'L') + ++t0; + switch (*t0) + { + case 'N': + { + const char* t1 = parse_nested_name(t0, last, db, + ends_with_template_args); + if (t1 != t0) + first = t1; + break; + } + case 'Z': + { + const char* t1 = parse_local_name(t0, last, db, + ends_with_template_args); + if (t1 != t0) + first = t1; + break; + } + default: + { + const char* t1 = parse_unscoped_name(t0, last, db); + if (t1 != t0) + { + if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args> + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t0 = t1; + t1 = parse_template_args(t0, last, db); + if (t1 != t0) + { + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += tmp; + first = t1; + if (ends_with_template_args) + *ends_with_template_args = true; + } + } + else // <unscoped-name> + first = t1; + } + else + { // try <substitution> <template-args> + t1 = parse_substitution(t0, last, db); + if (t1 != t0 && t1 != last && *t1 == 'I') + { + t0 = t1; + t1 = parse_template_args(t0, last, db); + if (t1 != t0) + { + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += tmp; + first = t1; + if (ends_with_template_args) + *ends_with_template_args = true; + } + } + } + break; + } + } + } + return first; +} + +// <call-offset> ::= h <nv-offset> _ +// ::= v <v-offset> _ +// +// <nv-offset> ::= <offset number> +// # non-virtual base override +// +// <v-offset> ::= <offset number> _ <virtual offset number> +// # virtual base override, with vcall offset + +const char* +parse_call_offset(const char* first, const char* last) +{ + if (first != last) + { + switch (*first) + { + case 'h': + { + const char* t = parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') + first = t + 1; + } + break; + case 'v': + { + const char* t = parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') + { + const char* t2 = parse_number(++t, last); + if (t2 != t && t2 != last && *t2 == '_') + first = t2 + 1; + } + } + break; + } + } + return first; +} + +// <special-name> ::= TV <type> # virtual table +// ::= TT <type> # VTT structure (construction vtable index) +// ::= TI <type> # typeinfo structure +// ::= TS <type> # typeinfo name (null-terminated byte string) +// ::= Tc <call-offset> <call-offset> <base encoding> +// # base is the nominal target function of thunk +// # first call-offset is 'this' adjustment +// # second call-offset is result adjustment +// ::= T <call-offset> <base encoding> +// # base is the nominal target function of thunk +// ::= GV <object name> # Guard variable for one-time initialization +// # No <type> +// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first +// extension ::= GR <object name> # reference temporary for object + +template <class C> +const char* +parse_special_name(const char* first, const char* last, C& db) +{ + if (last - first > 2) + { + const char* t; + switch (*first) + { + case 'T': + switch (first[1]) + { + case 'V': + // TV <type> # virtual table + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "vtable for "); + first = t; + } + break; + case 'T': + // TT <type> # VTT structure (construction vtable index) + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "VTT for "); + first = t; + } + break; + case 'I': + // TI <type> # typeinfo structure + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "typeinfo for "); + first = t; + } + break; + case 'S': + // TS <type> # typeinfo name (null-terminated byte string) + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "typeinfo name for "); + first = t; + } + break; + case 'c': + // Tc <call-offset> <call-offset> <base encoding> + { + const char* t0 = parse_call_offset(first+2, last); + if (t0 == first+2) + break; + const char* t1 = parse_call_offset(t0, last); + if (t1 == t0) + break; + t = parse_encoding(t1, last, db); + if (t != t1) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "covariant return thunk to "); + first = t; + } + } + break; + case 'C': + // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first + t = parse_type(first+2, last, db); + if (t != first+2) + { + const char* t0 = parse_number(t, last); + if (t0 != t && t0 != last && *t0 == '_') + { + const char* t1 = parse_type(++t0, last, db); + if (t1 != t0) + { + if (db.names.size() < 2) + return first; + auto left = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first = "construction vtable for " + + std::move(left) + "-in-" + + db.names.back().move_full(); + first = t1; + } + } + } + break; + default: + // T <call-offset> <base encoding> + { + const char* t0 = parse_call_offset(first+1, last); + if (t0 == first+1) + break; + t = parse_encoding(t0, last, db); + if (t != t0) + { + if (db.names.empty()) + return first; + if (first[2] == 'v') + { + db.names.back().first.insert(0, "virtual thunk to "); + first = t; + } + else + { + db.names.back().first.insert(0, "non-virtual thunk to "); + first = t; + } + } + } + break; + } + break; + case 'G': + switch (first[1]) + { + case 'V': + // GV <object name> # Guard variable for one-time initialization + t = parse_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "guard variable for "); + first = t; + } + break; + case 'R': + // extension ::= GR <object name> # reference temporary for object + t = parse_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "reference temporary for "); + first = t; + } + break; + } + break; + } + } + return first; +} + +template <class T> +class save_value +{ + T& restore_; + T original_value_; +public: + save_value(T& restore) + : restore_(restore), + original_value_(restore) + {} + + ~save_value() + { + restore_ = std::move(original_value_); + } + + save_value(const save_value&) = delete; + save_value& operator=(const save_value&) = delete; +}; + +// <encoding> ::= <function name> <bare-function-type> +// ::= <data name> +// ::= <special-name> + +template <class C> +const char* +parse_encoding(const char* first, const char* last, C& db) +{ + if (first != last) + { + save_value<decltype(db.encoding_depth)> su(db.encoding_depth); + ++db.encoding_depth; + save_value<decltype(db.tag_templates)> sb(db.tag_templates); + if (db.encoding_depth > 1) + db.tag_templates = true; + switch (*first) + { + case 'G': + case 'T': + first = parse_special_name(first, last, db); + break; + default: + { + bool ends_with_template_args = false; + const char* t = parse_name(first, last, db, + &ends_with_template_args); + unsigned cv = db.cv; + unsigned ref = db.ref; + if (t != first) + { + if (t != last && *t != 'E' && *t != '.') + { + save_value<bool> sb2(db.tag_templates); + db.tag_templates = false; + const char* t2; + typename C::String ret2; + if (db.names.empty()) + return first; + const typename C::String& nm = db.names.back().first; + if (nm.empty()) + return first; + if (!db.parsed_ctor_dtor_cv && ends_with_template_args) + { + t2 = parse_type(t, last, db); + if (t2 == t) + return first; + if (db.names.size() < 2) + return first; + auto ret1 = std::move(db.names.back().first); + ret2 = std::move(db.names.back().second); + if (ret2.empty()) + ret1 += ' '; + db.names.pop_back(); + db.names.back().first.insert(0, ret1); + t = t2; + } + db.names.back().first += '('; + if (t != last && *t == 'v') + { + ++t; + } + else + { + bool first_arg = true; + while (true) + { + size_t k0 = db.names.size(); + t2 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t2 == t) + break; + if (k1 > k0) + { + typename C::String tmp; + for (size_t k = k0; k < k1; ++k) + { + if (!tmp.empty()) + tmp += ", "; + tmp += db.names[k].move_full(); + } + for (size_t k = k0; k < k1; ++k) + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + if (!first_arg) + db.names.back().first += ", "; + else + first_arg = false; + db.names.back().first += tmp; + } + } + t = t2; + } + } + if (db.names.empty()) + return first; + db.names.back().first += ')'; + if (cv & 1) + db.names.back().first.append(" const"); + if (cv & 2) + db.names.back().first.append(" volatile"); + if (cv & 4) + db.names.back().first.append(" restrict"); + if (ref == 1) + db.names.back().first.append(" &"); + else if (ref == 2) + db.names.back().first.append(" &&"); + db.names.back().first += ret2; + first = t; + } + else + first = t; + } + break; + } + } + } + return first; +} + +// _block_invoke +// _block_invoke<decimal-digit>+ +// _block_invoke_<decimal-digit>+ + +template <class C> +const char* +parse_block_invoke(const char* first, const char* last, C& db) +{ + if (last - first >= 13) + { + const char test[] = "_block_invoke"; + const char* t = first; + for (int i = 0; i < 13; ++i, ++t) + { + if (*t != test[i]) + return first; + } + if (t != last) + { + if (*t == '_') + { + // must have at least 1 decimal digit + if (++t == last || !std::isdigit(*t)) + return first; + ++t; + } + // parse zero or more digits + while (t != last && isdigit(*t)) + ++t; + } + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "invocation function for block in "); + first = t; + } + return first; +} + +// extension +// <dot-suffix> := .<anything and everything> + +template <class C> +const char* +parse_dot_suffix(const char* first, const char* last, C& db) +{ + if (first != last && *first == '.') + { + if (db.names.empty()) + return first; + db.names.back().first += " (" + typename C::String(first, last) + ")"; + first = last; + } + return first; +} + +// <block-involcaton-function> ___Z<encoding>_block_invoke +// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+ +// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+ +// <mangled-name> ::= _Z<encoding> +// ::= <type> + +template <class C> +void +demangle(const char* first, const char* last, C& db, int& status) +{ + if (first >= last) + { + status = invalid_mangled_name; + return; + } + if (*first == '_') + { + if (last - first >= 4) + { + if (first[1] == 'Z') + { + const char* t = parse_encoding(first+2, last, db); + if (t != first+2 && t != last && *t == '.') + t = parse_dot_suffix(t, last, db); + if (t != last) + status = invalid_mangled_name; + } + else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z') + { + const char* t = parse_encoding(first+4, last, db); + if (t != first+4 && t != last) + { + const char* t1 = parse_block_invoke(t, last, db); + if (t1 != last) + status = invalid_mangled_name; + } + else + status = invalid_mangled_name; + } + else + status = invalid_mangled_name; + } + else + status = invalid_mangled_name; + } + else + { + const char* t = parse_type(first, last, db); + if (t != last) + status = invalid_mangled_name; + } + if (status == success && db.names.empty()) + status = invalid_mangled_name; +} + +template <std::size_t N> +class arena +{ + static const std::size_t alignment = 16; + LLVM_ALIGNAS(16) char buf_[N]; + char* ptr_; + + std::size_t + align_up(std::size_t n) LLVM_NOEXCEPT + {return (n + (alignment-1)) & ~(alignment-1);} + + bool + pointer_in_buffer(char* p) LLVM_NOEXCEPT + {return buf_ <= p && p <= buf_ + N;} + +public: + arena() LLVM_NOEXCEPT : ptr_(buf_) {} + ~arena() {ptr_ = nullptr;} + arena(const arena&) = delete; + arena& operator=(const arena&) = delete; + + char* allocate(std::size_t n); + void deallocate(char* p, std::size_t n) LLVM_NOEXCEPT; + + static LLVM_CONSTEXPR std::size_t size() {return N;} + std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);} + void reset() {ptr_ = buf_;} +}; + +template <std::size_t N> +char* +arena<N>::allocate(std::size_t n) +{ + n = align_up(n); + if (static_cast<std::size_t>(buf_ + N - ptr_) >= n) + { + char* r = ptr_; + ptr_ += n; + return r; + } + return static_cast<char*>(std::malloc(n)); +} + +template <std::size_t N> +void +arena<N>::deallocate(char* p, std::size_t n) LLVM_NOEXCEPT +{ + if (pointer_in_buffer(p)) + { + n = align_up(n); + if (p + n == ptr_) + ptr_ = p; + } + else + std::free(p); +} + +template <class T, std::size_t N> +class short_alloc +{ + arena<N>& a_; +public: + typedef T value_type; + +public: + template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;}; + + short_alloc(arena<N>& a) LLVM_NOEXCEPT : a_(a) {} + template <class U> + short_alloc(const short_alloc<U, N>& a) LLVM_NOEXCEPT + : a_(a.a_) {} + short_alloc(const short_alloc&) = default; + short_alloc& operator=(const short_alloc&) = delete; + + T* allocate(std::size_t n) + { + return reinterpret_cast<T*>(a_.allocate(n*sizeof(T))); + } + void deallocate(T* p, std::size_t n) LLVM_NOEXCEPT + { + a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T)); + } + + template <class T1, std::size_t N1, class U, std::size_t M> + friend + bool + operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT; + + template <class U, std::size_t M> friend class short_alloc; +}; + +template <class T, std::size_t N, class U, std::size_t M> +inline +bool +operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT +{ + return N == M && &x.a_ == &y.a_; +} + +template <class T, std::size_t N, class U, std::size_t M> +inline +bool +operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) LLVM_NOEXCEPT +{ + return !(x == y); +} + +template <class T> +class malloc_alloc +{ +public: + typedef T value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + + malloc_alloc() = default; + template <class U> malloc_alloc(const malloc_alloc<U>&) LLVM_NOEXCEPT {} + + T* allocate(std::size_t n) + { + return static_cast<T*>(std::malloc(n*sizeof(T))); + } + void deallocate(T* p, std::size_t) LLVM_NOEXCEPT + { + std::free(p); + } + template<class Other> + struct rebind + { + typedef malloc_alloc<Other> other; + }; + void construct(T *p) + { + ::new (p) T(); + } + void construct(T *p, const T& t) + { + ::new (p) T(t); + } + void destroy(T *p) + { + p->~T(); + } +}; + +template <class T, class U> +inline +bool +operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) LLVM_NOEXCEPT +{ + return true; +} + +template <class T, class U> +inline +bool +operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) LLVM_NOEXCEPT +{ + return !(x == y); +} + +const size_t bs = 4 * 1024; +template <class T> using Alloc = short_alloc<T, bs>; +template <class T> using Vector = std::vector<T, Alloc<T>>; + +template <class StrT> +struct string_pair +{ + StrT first; + StrT second; + + string_pair() = default; + string_pair(StrT f) : first(std::move(f)) {} + string_pair(StrT f, StrT s) + : first(std::move(f)), second(std::move(s)) {} + template <size_t N> + string_pair(const char (&s)[N]) : first(s, N-1) {} + + size_t size() const {return first.size() + second.size();} + StrT full() const {return first + second;} + StrT move_full() {return std::move(first) + std::move(second);} +}; + +struct Db +{ + typedef std::basic_string<char, std::char_traits<char>, + malloc_alloc<char>> String; + typedef Vector<string_pair<String>> sub_type; + typedef Vector<sub_type> template_param_type; + sub_type names; + template_param_type subs; + Vector<template_param_type> template_param; + unsigned cv; + unsigned ref; + unsigned encoding_depth; + bool parsed_ctor_dtor_cv; + bool tag_templates; + bool fix_forward_references; + bool try_to_parse_template_args; + + template <size_t N> + Db(arena<N>& ar) : + names(ar), + subs(0, names, ar), + template_param(0, subs, ar) + {} +}; + +} // unnamed namespace + +char* +__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status) +{ + if (mangled_name == nullptr || (buf != nullptr && n == nullptr)) + { + if (status) + *status = invalid_args; + return nullptr; + } + size_t internal_size = buf != nullptr ? *n : 0; + arena<bs> a; + Db db(a); + db.cv = 0; + db.ref = 0; + db.encoding_depth = 0; + db.parsed_ctor_dtor_cv = false; + db.tag_templates = true; + db.template_param.emplace_back(a); + db.fix_forward_references = false; + db.try_to_parse_template_args = true; + int internal_status = success; + size_t len = std::strlen(mangled_name); + demangle(mangled_name, mangled_name + len, db, + internal_status); + if (internal_status == success && db.fix_forward_references && + !db.template_param.empty() && !db.template_param.front().empty()) + { + db.fix_forward_references = false; + db.tag_templates = false; + db.names.clear(); + db.subs.clear(); + demangle(mangled_name, mangled_name + len, db, internal_status); + if (db.fix_forward_references) + internal_status = invalid_mangled_name; + } + if (internal_status == success) + { + size_t sz = db.names.back().size() + 1; + if (sz > internal_size) + { + char* newbuf = static_cast<char*>(std::realloc(buf, sz)); + if (newbuf == nullptr) + { + internal_status = memory_alloc_failure; + buf = nullptr; + } + else + { + buf = newbuf; + if (n != nullptr) + *n = sz; + } + } + if (buf != nullptr) + { + db.names.back().first += db.names.back().second; + std::memcpy(buf, db.names.back().first.data(), sz-1); + buf[sz-1] = char(0); + } + } + else + buf = nullptr; + if (status) + *status = internal_status; + return buf; +} + +} // lldb_private diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp index 984b36e54153..ba1314448bbd 100644 --- a/source/Core/DataBufferHeap.cpp +++ b/source/Core/DataBufferHeap.cpp @@ -106,7 +106,7 @@ DataBufferHeap::CopyData (const void *src, uint64_t src_len) void DataBufferHeap::AppendData (const void *src, uint64_t src_len) { - m_data.insert(m_data.end(), (uint8_t *)src, (uint8_t *)src + src_len); + m_data.insert(m_data.end(), (const uint8_t *)src, (const uint8_t *)src + src_len); } void diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp index 4ca43b89eef1..b3211b35af85 100644 --- a/source/Core/DataBufferMemoryMap.cpp +++ b/source/Core/DataBufferMemoryMap.cpp @@ -26,7 +26,6 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostInfo.h" #include "lldb/Core/Log.h" -#include "lldb/lldb-private-log.h" using namespace lldb; using namespace lldb_private; @@ -91,7 +90,8 @@ DataBufferMemoryMap::Clear() { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP)); if (log) - log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", m_mmap_addr, (uint64_t)m_mmap_size); + log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %" PRIu64 "", (void *)m_mmap_addr, + (uint64_t)m_mmap_size); #ifdef _WIN32 UnmapViewOfFile(m_mmap_addr); #else @@ -284,9 +284,9 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, // Save the actual mmap'ed size m_mmap_size = length + page_offset; - // Our data is at an offset into the the mapped data + // Our data is at an offset into the mapped data m_data = m_mmap_addr + page_offset; - // Our pretend size is the size that was requestd + // Our pretend size is the size that was requested m_size = length; } } @@ -307,8 +307,10 @@ DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, if (log) { - log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s", - m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString()); + log->Printf( + "DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 + ", error = %s", + (void *)m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString()); } } } diff --git a/source/Core/DataEncoder.cpp b/source/Core/DataEncoder.cpp index 92a9104acc3a..d21ca423892f 100644 --- a/source/Core/DataEncoder.cpp +++ b/source/Core/DataEncoder.cpp @@ -21,36 +21,36 @@ using namespace lldb; using namespace lldb_private; static inline void -WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value) +WriteInt16(unsigned char* ptr, unsigned offset, uint16_t value) { *(uint16_t *)(ptr + offset) = value; } static inline void -WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value) +WriteInt32 (unsigned char* ptr, unsigned offset, uint32_t value) { *(uint32_t *)(ptr + offset) = value; } static inline void -WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value) +WriteInt64(unsigned char* ptr, unsigned offset, uint64_t value) { *(uint64_t *)(ptr + offset) = value; } static inline void -WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value) +WriteSwappedInt16(unsigned char* ptr, unsigned offset, uint16_t value) { *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value); } static inline void -WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value) +WriteSwappedInt32 (unsigned char* ptr, unsigned offset, uint32_t value) { *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value); } static inline void -WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value) +WriteSwappedInt64(unsigned char* ptr, unsigned offset, uint64_t value) { *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value); } @@ -153,7 +153,7 @@ DataEncoder::GetSharedDataOffset () const // any data extracted will be endian swapped. //---------------------------------------------------------------------- uint32_t -DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian) +DataEncoder::SetData (void *bytes, uint32_t length, ByteOrder endian) { m_byte_order = endian; m_data_sp.reset(); diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp index 6e1d63095cf3..b4b43ed97780 100644 --- a/source/Core/DataExtractor.cpp +++ b/source/Core/DataExtractor.cpp @@ -1710,7 +1710,7 @@ DataExtractor::Dump (Stream *s, { size_t complex_int_byte_size = item_byte_size / 2; - if (complex_int_byte_size <= 8) + if (complex_int_byte_size > 0 && complex_int_byte_size <= 8) { s->Printf("%" PRIu64, GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); s->Printf(" + %" PRIu64 "i", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index f25a3f41825f..cd41e5d65103 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/Core/Debugger.h" #include <map> @@ -39,6 +37,7 @@ #include "lldb/Host/Terminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/OptionValueSInt64.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Symbol/ClangASTContext.h" @@ -63,7 +62,6 @@ using namespace lldb; using namespace lldb_private; -static uint32_t g_shared_debugger_refcount = 0; static lldb::user_id_t g_unique_id = 1; static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024; @@ -126,7 +124,21 @@ g_language_enumerators[] = FILE_AND_LINE\ "\\n" -#define DEFAULT_DISASSEMBLY_FORMAT "${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: " +// Three parts to this disassembly format specification: +// 1. If this is a new function/symbol (no previous symbol/function), print +// dylib`funcname:\n +// 2. If this is a symbol context change (different from previous symbol/function), print +// dylib`funcname:\n +// 3. print +// address <+offset>: +#define DEFAULT_DISASSEMBLY_FORMAT "{${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }${addr-file-or-load}{ <${function.concrete-only-addr-offset-no-padding}>}: " + +// gdb's disassembly format can be emulated with +// ${current-pc-arrow}${addr-file-or-load}{ <${function.name-without-args}${function.concrete-only-addr-offset-no-padding}>}: + +// lldb's original format for disassembly would look like this format string - +// {${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}: + static PropertyDefinition g_properties[] = @@ -170,7 +182,7 @@ enum ePropertyEscapeNonPrintables }; -Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; +LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; Error Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, @@ -391,36 +403,24 @@ Debugger::GetEscapeNonPrintables () const //} // -int -Debugger::TestDebuggerRefCount () -{ - return g_shared_debugger_refcount; -} - +static bool lldb_initialized = false; void -Debugger::Initialize (LoadPluginCallbackType load_plugin_callback) +Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) { + assert(!lldb_initialized && "Debugger::Initialize called more than once!"); + + lldb_initialized = true; g_load_plugin_callback = load_plugin_callback; - if (g_shared_debugger_refcount++ == 0) - lldb_private::Initialize(); } void Debugger::Terminate () { - if (g_shared_debugger_refcount > 0) - { - g_shared_debugger_refcount--; - if (g_shared_debugger_refcount == 0) - { - lldb_private::WillTerminate(); - lldb_private::Terminate(); + assert(lldb_initialized && "Debugger::Terminate called without a matching Debugger::Initialize!"); - // Clear our master list of debugger objects - Mutex::Locker locker (GetDebuggerListMutex ()); - GetDebuggerList().clear(); - } - } + // Clear our master list of debugger objects + Mutex::Locker locker (GetDebuggerListMutex ()); + GetDebuggerList().clear(); } void @@ -553,7 +553,7 @@ DebuggerSP Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton) { DebuggerSP debugger_sp (new Debugger(log_callback, baton)); - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); GetDebuggerList().push_back(debugger_sp); @@ -570,7 +570,7 @@ Debugger::Destroy (DebuggerSP &debugger_sp) debugger_sp->Clear(); - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList (); @@ -590,7 +590,7 @@ DebuggerSP Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name) { DebuggerSP debugger_sp; - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList(); @@ -612,7 +612,7 @@ TargetSP Debugger::FindTargetWithProcessID (lldb::pid_t pid) { TargetSP target_sp; - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList(); @@ -631,7 +631,7 @@ TargetSP Debugger::FindTargetWithProcess (Process *process) { TargetSP target_sp; - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList(); @@ -682,6 +682,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : ConstString("Settings specify to debugging targets."), true, Target::GetGlobalProperties()->GetValueProperties()); + m_collection_sp->AppendProperty (ConstString("platform"), + ConstString("Platform settings."), + true, + Platform::GetGlobalPlatformProperties()->GetValueProperties()); if (m_command_interpreter_ap.get()) { m_collection_sp->AppendProperty (ConstString("interpreter"), @@ -879,34 +883,27 @@ Debugger::ClearIOHandlers () { IOHandlerSP reader_sp (m_input_reader_stack.Top()); if (reader_sp) - { - m_input_reader_stack.Pop(); - reader_sp->SetIsDone(true); - reader_sp->Cancel(); - } + PopIOHandler (reader_sp); } } void -Debugger::ExecuteIOHanders() +Debugger::ExecuteIOHandlers() { - while (1) { IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (!reader_sp) break; - reader_sp->Activate(); reader_sp->Run(); - reader_sp->Deactivate(); // Remove all input readers that are done from the top of the stack while (1) { IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); if (top_reader_sp && top_reader_sp->GetIsDone()) - m_input_reader_stack.Pop(); + PopIOHandler (top_reader_sp); else break; } @@ -920,6 +917,12 @@ Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp) return m_input_reader_stack.IsTop (reader_sp); } +void +Debugger::PrintAsync (const char *s, size_t len, bool is_stdout) +{ + lldb::StreamFileSP stream = is_stdout ? GetOutputFile() : GetErrorFile(); + m_input_reader_stack.PrintAsync(stream.get(), s, len); +} ConstString Debugger::GetTopIOHandlerControlSequence(char ch) @@ -943,25 +946,23 @@ void Debugger::RunIOHandler (const IOHandlerSP& reader_sp) { PushIOHandler (reader_sp); - + 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(); + PopIOHandler (top_reader_sp); else break; } @@ -1024,93 +1025,73 @@ Debugger::PushIOHandler (const IOHandlerSP& reader_sp) if (!reader_sp) return; - // Got the current top input reader... + Mutex::Locker locker (m_input_reader_stack.GetMutex()); + + // Get the current top input reader... IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); // 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); + if (reader_sp == top_reader_sp) + return; - // 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(); + // Push our new input reader + m_input_reader_stack.Push (reader_sp); + reader_sp->Activate(); + + // 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(); + top_reader_sp->Cancel(); } } bool Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) { - bool result = false; - + if (! pop_reader_sp) + return false; + Mutex::Locker locker (m_input_reader_stack.GetMutex()); // The reader on the stop of the stack is done, so let the next // read on the stack refresh its prompt and if there is one... - if (!m_input_reader_stack.IsEmpty()) - { - IOHandlerSP reader_sp(m_input_reader_stack.Top()); - - if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get()) - { - reader_sp->Deactivate(); - reader_sp->Cancel(); - m_input_reader_stack.Pop (); - - reader_sp = m_input_reader_stack.Top(); - if (reader_sp) - reader_sp->Activate(); - - result = true; - } - } - return result; -} - -bool -Debugger::HideTopIOHandler() -{ - Mutex::Locker locker; - - if (locker.TryLock(m_input_reader_stack.GetMutex())) - { - IOHandlerSP reader_sp(m_input_reader_stack.Top()); - if (reader_sp) - reader_sp->Hide(); - return true; - } - return false; -} + if (m_input_reader_stack.IsEmpty()) + return false; -void -Debugger::RefreshTopIOHandler() -{ IOHandlerSP reader_sp(m_input_reader_stack.Top()); + + if (pop_reader_sp != reader_sp) + return false; + + reader_sp->Deactivate(); + reader_sp->Cancel(); + m_input_reader_stack.Pop (); + + reader_sp = m_input_reader_stack.Top(); if (reader_sp) - reader_sp->Refresh(); -} + reader_sp->Activate(); + return true; +} StreamSP Debugger::GetAsyncOutputStream () { - return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(), - CommandInterpreter::eBroadcastBitAsynchronousOutputData)); + return StreamSP (new StreamAsynchronousIO (*this, true)); } StreamSP Debugger::GetAsyncErrorStream () { - return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(), - CommandInterpreter::eBroadcastBitAsynchronousErrorData)); + return StreamSP (new StreamAsynchronousIO (*this, false)); } size_t Debugger::GetNumDebuggers() { - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); return GetDebuggerList().size(); @@ -1123,7 +1104,7 @@ Debugger::GetDebuggerAtIndex (size_t index) { DebuggerSP debugger_sp; - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList(); @@ -1140,7 +1121,7 @@ Debugger::FindDebuggerWithID (lldb::user_id_t id) { DebuggerSP debugger_sp; - if (g_shared_debugger_refcount > 0) + if (lldb_initialized) { Mutex::Locker locker (GetDebuggerListMutex ()); DebuggerList &debugger_list = GetDebuggerList(); @@ -1292,8 +1273,6 @@ Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton) bool Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream) { - Log::Callbacks log_callbacks; - StreamSP log_stream_sp; if (m_log_callback_stream_sp) { @@ -1312,7 +1291,12 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l log_stream_sp = pos->second.lock(); if (!log_stream_sp) { - log_stream_sp.reset (new StreamFile (log_file)); + uint32_t options = File::eOpenOptionWrite | File::eOpenOptionCanCreate + | File::eOpenOptionCloseOnExec | File::eOpenOptionAppend; + if (! (log_options & LLDB_LOG_OPTION_APPEND)) + options |= File::eOpenOptionTruncate; + + log_stream_sp.reset (new StreamFile (log_file, options)); m_log_streams[log_file] = log_stream_sp; } } @@ -1321,33 +1305,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l if (log_options == 0) log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; - if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks)) - { - log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream); - return true; - } - else - { - LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel)); - if (log_channel_sp) - { - if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories)) - { - return true; - } - else - { - error_stream.Printf ("Invalid log channel '%s'.\n", channel); - return false; - } - } - else - { - error_stream.Printf ("Invalid log channel '%s'.\n", channel); - return false; - } - } - return false; + return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, error_stream); } SourceManager & @@ -1385,14 +1343,14 @@ Debugger::HandleBreakpointEvent (const EventSP &event_sp) if (num_new_locations > 0) { BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); - StreamFileSP output_sp (GetOutputFile()); + StreamSP output_sp (GetAsyncOutputStream()); 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(); + output_sp->Flush(); } } } @@ -1479,8 +1437,8 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) const uint32_t event_type = event_sp->GetType(); ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); - StreamString output_stream; - StreamString error_stream; + StreamSP output_stream_sp = GetAsyncOutputStream(); + StreamSP error_stream_sp = GetAsyncErrorStream(); const bool gui_enabled = IsForwardingEvents(); if (!gui_enabled) @@ -1488,47 +1446,43 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) bool pop_process_io_handler = false; assert (process_sp); - if (event_type & Process::eBroadcastBitSTDOUT || event_type & Process::eBroadcastBitStateChanged) + bool state_is_stopped = false; + const bool got_state_changed = (event_type & Process::eBroadcastBitStateChanged) != 0; + const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0; + const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0; + if (got_state_changed) { - GetProcessSTDOUT (process_sp.get(), &output_stream); + StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); + state_is_stopped = StateIsStoppedState(event_state, false); } - if (event_type & Process::eBroadcastBitSTDERR || event_type & Process::eBroadcastBitStateChanged) + // Display running state changes first before any STDIO + if (got_state_changed && !state_is_stopped) { - GetProcessSTDERR (process_sp.get(), &error_stream); + Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler); } - if (event_type & Process::eBroadcastBitStateChanged) + // Now display and STDOUT + if (got_stdout || got_state_changed) { - Process::HandleProcessStateChangedEvent (event_sp, &output_stream, pop_process_io_handler); + GetProcessSTDOUT (process_sp.get(), output_stream_sp.get()); } - if (output_stream.GetSize() || error_stream.GetSize()) + // Now display and STDERR + if (got_stderr || got_state_changed) { - StreamFileSP error_stream_sp (GetOutputFile()); - bool top_io_handler_hid = false; - - if (process_sp->ProcessIOHandlerIsActive() == false) - top_io_handler_hid = HideTopIOHandler(); - - if (output_stream.GetSize()) - { - StreamFileSP output_stream_sp (GetOutputFile()); - if (output_stream_sp) - output_stream_sp->Write (output_stream.GetData(), output_stream.GetSize()); - } - - if (error_stream.GetSize()) - { - StreamFileSP error_stream_sp (GetErrorFile()); - if (error_stream_sp) - error_stream_sp->Write (error_stream.GetData(), error_stream.GetSize()); - } + GetProcessSTDERR (process_sp.get(), error_stream_sp.get()); + } - if (top_io_handler_hid) - RefreshTopIOHandler(); + // Now display any stopped state changes after any STDIO + if (got_state_changed && state_is_stopped) + { + Process::HandleProcessStateChangedEvent (event_sp, output_stream_sp.get(), pop_process_io_handler); } + output_stream_sp->Flush(); + error_stream_sp->Flush(); + if (pop_process_io_handler) process_sp->PopProcessIOHandler(); } @@ -1547,10 +1501,7 @@ Debugger::HandleThreadEvent (const EventSP &event_sp) 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(); + thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1); } } } @@ -1644,13 +1595,11 @@ Debugger::DefaultEventHandler() const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); if (data && data[0]) { - StreamFileSP error_sp (GetErrorFile()); + StreamSP error_sp (GetAsyncErrorStream()); if (error_sp) { - HideTopIOHandler(); error_sp->PutCString(data); error_sp->Flush(); - RefreshTopIOHandler(); } } } @@ -1659,13 +1608,11 @@ Debugger::DefaultEventHandler() const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); if (data && data[0]) { - StreamFileSP output_sp (GetOutputFile()); + StreamSP output_sp (GetAsyncOutputStream()); if (output_sp) { - HideTopIOHandler(); output_sp->PutCString(data); output_sp->Flush(); - RefreshTopIOHandler(); } } } @@ -1729,7 +1676,7 @@ lldb::thread_result_t Debugger::IOHandlerThread (lldb::thread_arg_t arg) { Debugger *debugger = (Debugger *)arg; - debugger->ExecuteIOHanders(); + debugger->ExecuteIOHandlers(); debugger->StopEventHandlerThread(); return NULL; } diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp index 14fbee149a52..f96232fcceeb 100644 --- a/source/Core/Disassembler.cpp +++ b/source/Core/Disassembler.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include "lldb/Core/Disassembler.h" // C Includes @@ -421,6 +419,47 @@ Disassembler::PrintInstructions } const uint32_t scope = eSymbolContextLineEntry | eSymbolContextFunction | eSymbolContextSymbol; const bool use_inline_block_range = false; + + const FormatEntity::Entry *disassembly_format = NULL; + FormatEntity::Entry format; + if (exe_ctx.HasTargetScope()) + { + disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat (); + } + else + { + FormatEntity::Parse("${addr}: ", format); + disassembly_format = &format; + } + + // First pass: step through the list of instructions, + // find how long the initial addresses strings are, insert padding + // in the second pass so the opcodes all line up nicely. + size_t address_text_size = 0; + for (size_t i = 0; i < num_instructions_found; ++i) + { + Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get(); + if (inst) + { + const Address &addr = inst->GetAddress(); + ModuleSP module_sp (addr.GetModule()); + if (module_sp) + { + const uint32_t resolve_mask = eSymbolContextFunction | eSymbolContextSymbol; + uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc); + if (resolved_mask) + { + StreamString strmstr; + Debugger::FormatDisassemblerAddress (disassembly_format, &sc, NULL, &exe_ctx, &addr, strmstr); + size_t cur_line = strmstr.GetSizeOfLastLine(); + if (cur_line > address_text_size) + address_text_size = cur_line; + } + sc.Clear(false); + } + } + } + for (size_t i = 0; i < num_instructions_found; ++i) { Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get(); @@ -448,7 +487,7 @@ Disassembler::PrintInstructions if (offset != 0) strm.EOL(); - sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false); + sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false, false, true); strm.EOL(); if (sc.comp_unit && sc.line_entry.IsValid()) @@ -471,7 +510,7 @@ Disassembler::PrintInstructions } const bool show_bytes = (options & eOptionShowBytes) != 0; - inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL); + inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL, address_text_size); strm.EOL(); } else @@ -509,7 +548,7 @@ Disassembler::Disassemble } else if (sc.symbol && sc.symbol->ValueIsAddress()) { - range.GetBaseAddress() = sc.symbol->GetAddress(); + range.GetBaseAddress() = sc.symbol->GetAddressRef(); range.SetByteSize (sc.symbol->GetByteSize()); } else @@ -561,7 +600,8 @@ Instruction::Dump (lldb_private::Stream *s, const ExecutionContext* exe_ctx, const SymbolContext *sym_ctx, const SymbolContext *prev_sym_ctx, - const FormatEntity::Entry *disassembly_addr_format) + const FormatEntity::Entry *disassembly_addr_format, + size_t max_address_text_size) { size_t opcode_column_width = 7; const size_t operand_column_width = 25; @@ -573,6 +613,7 @@ Instruction::Dump (lldb_private::Stream *s, if (show_address) { Debugger::FormatDisassemblerAddress (disassembly_addr_format, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss); + ss.FillLastLineToColumn (max_address_text_size, ' '); } if (show_bytes) @@ -683,7 +724,7 @@ Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type dat { case OptionValue::eTypeUInt64: data_value_sp.reset (new OptionValueUInt64 (0, 0)); - data_value_sp->SetValueFromCString (value.c_str()); + data_value_sp->SetValueFromString (value); break; // Other types can be added later as needed. default: @@ -791,7 +832,7 @@ Instruction::ReadDictionary (FILE *in_file, Stream *out_stream) else if ((value[0] == '0') && (value[1] == 'x')) { value_sp.reset (new OptionValueUInt64 (0, 0)); - value_sp->SetValueFromCString (value.c_str()); + value_sp->SetValueFromString (value); } else { @@ -999,7 +1040,7 @@ InstructionList::Dump (Stream *s, { if (pos != begin) s->EOL(); - (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format); + (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format, 0); } } @@ -1018,12 +1059,13 @@ InstructionList::Append (lldb::InstructionSP &inst_sp) } uint32_t -InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const +InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, Target &target) const { size_t num_instructions = m_instructions.size(); uint32_t next_branch = UINT32_MAX; - for (size_t i = start; i < num_instructions; i++) + size_t i; + for (i = start; i < num_instructions; i++) { if (m_instructions[i]->DoesBranch()) { @@ -1031,6 +1073,52 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const break; } } + + // Hexagon needs the first instruction of the packet with the branch. + // Go backwards until we find an instruction marked end-of-packet, or + // until we hit start. + if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon) + { + // If we didn't find a branch, find the last packet start. + if (next_branch == UINT32_MAX) + { + i = num_instructions - 1; + } + + while (i > start) + { + --i; + + Error error; + uint32_t inst_bytes; + bool prefer_file_cache = false; // Read from process if process is running + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + target.ReadMemory(m_instructions[i]->GetAddress(), + prefer_file_cache, + &inst_bytes, + sizeof(inst_bytes), + error, + &load_addr); + // If we have an error reading memory, return start + if (!error.Success()) + return start; + // check if this is the last instruction in a packet + // bits 15:14 will be 11b or 00b for a duplex + if (((inst_bytes & 0xC000) == 0xC000) || + ((inst_bytes & 0xC000) == 0x0000)) + { + // instruction after this should be the start of next packet + next_branch = i + 1; + break; + } + } + + if (next_branch == UINT32_MAX) + { + // We couldn't find the previous packet, so return start + next_branch = start; + } + } return next_branch; } diff --git a/source/Core/DynamicLoader.cpp b/source/Core/DynamicLoader.cpp index 1f545b727a1e..ffd7425f5231 100644 --- a/source/Core/DynamicLoader.cpp +++ b/source/Core/DynamicLoader.cpp @@ -186,6 +186,24 @@ DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, a { UpdateLoadedSections(module_sp, link_map_addr, base_addr); } + else + { + // Try to fetch the load address of the file from the process. It can be different from the + // address reported by the linker in case of a file with fixed load address because the + // linker reports the bias between the load address specified in the file and the actual + // load address it loaded the file. + bool is_loaded; + lldb::addr_t load_addr; + Error error = m_process->GetFileLoadAddress(file, is_loaded, load_addr); + if (error.Fail() || !is_loaded) + load_addr = base_addr; + + if ((module_sp = m_process->ReadModuleFromMemory(file, load_addr))) + { + UpdateLoadedSections(module_sp, link_map_addr, base_addr); + target.GetImages().AppendIfNeeded(module_sp); + } + } return module_sp; } diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp index 5b0bbe273603..ce055826af2c 100644 --- a/source/Core/Error.cpp +++ b/source/Core/Error.cpp @@ -21,10 +21,6 @@ #include <cerrno> #include <cstdarg> -#if (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) && defined (__APPLE__) -#include <SpringBoardServices/SpringBoardServer.h> -#endif - using namespace lldb; using namespace lldb_private; diff --git a/source/Core/FastDemangle.cpp b/source/Core/FastDemangle.cpp index 53e8972e8048..0f12af2783db 100644 --- a/source/Core/FastDemangle.cpp +++ b/source/Core/FastDemangle.cpp @@ -383,10 +383,19 @@ private: char *end_m_write_ptr = m_write_ptr + content_length; if (end_m_write_ptr > m_buffer_end) { - GrowBuffer(end_m_write_ptr - m_buffer_end); + if (content >= m_buffer && content < m_buffer_end) + { + long offset = content - m_buffer; + GrowBuffer (end_m_write_ptr - m_buffer_end); + content = m_buffer + offset; + } + else + { + GrowBuffer (end_m_write_ptr - m_buffer_end); + } end_m_write_ptr = m_write_ptr + content_length; } - memcpy(m_write_ptr, content, content_length); + memcpy (m_write_ptr, content, content_length); m_write_ptr = end_m_write_ptr; } #define WRITE(x) Write(x, sizeof (x) - 1) diff --git a/source/Core/FileLineResolver.cpp b/source/Core/FileLineResolver.cpp index b1346bbdd812..e8ef87f009d9 100644 --- a/source/Core/FileLineResolver.cpp +++ b/source/Core/FileLineResolver.cpp @@ -10,7 +10,6 @@ #include "lldb/Core/FileLineResolver.h" // Project includes -#include "lldb/lldb-private-log.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" #include "lldb/Symbol/CompileUnit.h" diff --git a/source/Core/FormatEntity.cpp b/source/Core/FormatEntity.cpp index 48b2c2ddbf72..2ebe95747bc0 100644 --- a/source/Core/FormatEntity.cpp +++ b/source/Core/FormatEntity.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/Language.h" #include "lldb/Core/Module.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamString.h" @@ -20,6 +21,7 @@ #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Expression/ClangExpressionVariable.h" #include "lldb/Host/FileSpec.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Symbol/Block.h" @@ -94,7 +96,9 @@ static FormatEntity::Entry::Definition g_function_child_entries[] = ENTRY ("addr-offset" , FunctionAddrOffset , UInt64), ENTRY ("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete, UInt64), ENTRY ("line-offset" , FunctionLineOffset , UInt64), - ENTRY ("pc-offset" , FunctionPCOffset , UInt64) + ENTRY ("pc-offset" , FunctionPCOffset , UInt64), + ENTRY ("initial-function" , FunctionInitial , None), + ENTRY ("changed" , FunctionChanged , None) }; static FormatEntity::Entry::Definition g_line_child_entries[] = @@ -207,6 +211,7 @@ static FormatEntity::Entry::Definition g_top_level_entries[] = ENTRY_CHILDREN ("ansi" , Invalid , None , g_ansi_entries), ENTRY ("current-pc-arrow" , CurrentPCArrow , CString ), ENTRY_CHILDREN ("file" , File , CString , g_file_child_entries), + ENTRY ("language" , Lang , CString), ENTRY_CHILDREN ("frame" , Invalid , None , g_frame_child_entries), ENTRY_CHILDREN ("function" , Invalid , None , g_function_child_entries), ENTRY_CHILDREN ("line" , Invalid , None , g_line_child_entries), @@ -318,6 +323,7 @@ FormatEntity::Entry::TypeToCString (Type t) ENUM_TO_CSTR(ScriptTarget); ENUM_TO_CSTR(ModuleFile); ENUM_TO_CSTR(File); + ENUM_TO_CSTR(Lang); ENUM_TO_CSTR(FrameIndex); ENUM_TO_CSTR(FrameRegisterPC); ENUM_TO_CSTR(FrameRegisterSP); @@ -335,6 +341,8 @@ FormatEntity::Entry::TypeToCString (Type t) ENUM_TO_CSTR(FunctionAddrOffsetConcrete); ENUM_TO_CSTR(FunctionLineOffset); ENUM_TO_CSTR(FunctionPCOffset); + ENUM_TO_CSTR(FunctionInitial); + ENUM_TO_CSTR(FunctionChanged); ENUM_TO_CSTR(LineEntryFile); ENUM_TO_CSTR(LineEntryLineNumber); ENUM_TO_CSTR(LineEntryStartAddress); @@ -444,7 +452,8 @@ DumpAddressOffsetFromFunction (Stream &s, const ExecutionContext *exe_ctx, const Address &format_addr, bool concrete_only, - bool no_padding) + bool no_padding, + bool print_zero_offsets) { if (format_addr.IsValid()) { @@ -468,7 +477,7 @@ DumpAddressOffsetFromFunction (Stream &s, } } else if (sc->symbol && sc->symbol->ValueIsAddress()) - func_addr = sc->symbol->GetAddress(); + func_addr = sc->symbol->GetAddressRef(); } if (func_addr.IsValid()) @@ -479,10 +488,15 @@ DumpAddressOffsetFromFunction (Stream &s, { addr_t func_file_addr = func_addr.GetFileAddress(); addr_t addr_file_addr = format_addr.GetFileAddress(); - if (addr_file_addr > func_file_addr) + if (addr_file_addr > func_file_addr + || (addr_file_addr == func_file_addr && print_zero_offsets)) + { s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr); + } else if (addr_file_addr < func_file_addr) + { s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr); + } return true; } else @@ -492,10 +506,15 @@ DumpAddressOffsetFromFunction (Stream &s, { 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) + if (addr_load_addr > func_load_addr + || (addr_load_addr == func_load_addr && print_zero_offsets)) + { s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr); + } else if (addr_load_addr < func_load_addr) + { s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr); + } return true; } } @@ -750,7 +769,7 @@ DumpValue (Stream &s, ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); ValueObject::GetValueForExpressionPathOptions options; - options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren(); + options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().SetSyntheticChildrenTraversal(ValueObject::GetValueForExpressionPathOptions::SyntheticChildrenTraversal::Both); ValueObject* target = NULL; const char* var_name_final_if_array_range = NULL; size_t close_bracket_index = llvm::StringRef::npos; @@ -935,11 +954,11 @@ DumpValue (Stream &s, return false; if (log) log->Printf("[Debugger::FormatPrompt] handle as array"); + StreamString special_directions_stream; llvm::StringRef special_directions; if (close_bracket_index != llvm::StringRef::npos && subpath.size() > close_bracket_index) { ConstString additional_data (subpath.drop_front(close_bracket_index+1)); - StreamString special_directions_stream; special_directions_stream.Printf("${%svar%s", do_deref_pointer ? "*" : "", additional_data.GetCString()); @@ -1283,13 +1302,11 @@ FormatEntity::Format (const Entry &entry, // Watch for the special "tid" format... if (entry.printf_format == "tid") { - bool handled = false; Target &target = thread->GetProcess()->GetTarget(); 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)) { - handled = true; format = "%" PRIu64; } } @@ -1501,6 +1518,23 @@ FormatEntity::Format (const Entry &entry, } return false; + case Entry::Type::Lang: + if (sc) + { + CompileUnit *cu = sc->comp_unit; + if (cu) + { + Language lang(cu->GetLanguage()); + const char *lang_name = lang.AsCString(); + if (lang_name) + { + s.PutCString(lang_name); + return true; + } + } + } + return false; + case Entry::Type::FrameIndex: if (exe_ctx) { @@ -1803,7 +1837,7 @@ FormatEntity::Format (const Entry &entry, case Entry::Type::FunctionAddrOffset: if (addr) { - if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false)) + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false, false)) return true; } return false; @@ -1811,13 +1845,13 @@ FormatEntity::Format (const Entry &entry, case Entry::Type::FunctionAddrOffsetConcrete: if (addr) { - if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true)) + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true, true)) return true; } return false; case Entry::Type::FunctionLineOffset: - if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false)) + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false, false)) return true; return false; @@ -1827,12 +1861,18 @@ FormatEntity::Format (const Entry &entry, StackFrame *frame = exe_ctx->GetFramePtr(); if (frame) { - if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false)) + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false, false)) return true; } } return false; + case Entry::Type::FunctionChanged: + return function_changed == true; + + case Entry::Type::FunctionInitial: + return initial_function == true; + case Entry::Type::LineEntryFile: if (sc && sc->line_entry.IsValid()) { diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp index 747fd4411d4d..0246778b0654 100644 --- a/source/Core/IOHandler.cpp +++ b/source/Core/IOHandler.cpp @@ -8,8 +8,6 @@ //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - #include <string> #include "lldb/Breakpoint/BreakpointLocation.h" @@ -169,6 +167,17 @@ IOHandler::WaitForPop () m_popped.WaitForValueEqualTo(true); } +void +IOHandlerStack::PrintAsync (Stream *stream, const char *s, size_t len) +{ + if (stream) + { + Mutex::Locker locker (m_mutex); + if (m_top) + m_top->PrintAsync (stream, s, len); + } +} + IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger, const char *prompt, bool default_response) : @@ -380,7 +389,8 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger, m_curr_line_idx (UINT32_MAX), m_multi_line (multi_line), m_color_prompts (color_prompts), - m_interrupt_exits (true) + m_interrupt_exits (true), + m_editing (false) { SetPrompt(prompt); @@ -474,6 +484,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted) char buffer[256]; bool done = false; bool got_line = false; + m_editing = true; while (!done) { if (fgets(buffer, sizeof(buffer), in) == NULL) @@ -508,6 +519,7 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted) line.append(buffer, buffer_len); } } + m_editing = false; // We might have gotten a newline on a line by itself // make sure to return true in this case. return got_line; @@ -737,47 +749,11 @@ IOHandlerEditline::Run () } void -IOHandlerEditline::Hide () -{ -#ifndef LLDB_DISABLE_LIBEDIT - if (m_editline_ap) - m_editline_ap->Hide(); -#endif -} - - -void -IOHandlerEditline::Refresh () -{ -#ifndef LLDB_DISABLE_LIBEDIT - if (m_editline_ap) - { - m_editline_ap->Refresh(); - } - else - { -#endif - const char *prompt = GetPrompt(); - if (prompt && prompt[0]) - { - FILE *out = GetOutputFILE(); - if (out) - { - ::fprintf(out, "%s", prompt); - ::fflush(out); - } - } -#ifndef LLDB_DISABLE_LIBEDIT - } -#endif -} - -void IOHandlerEditline::Cancel () { #ifndef LLDB_DISABLE_LIBEDIT if (m_editline_ap) - m_editline_ap->Interrupt (); + m_editline_ap->Cancel (); #endif } @@ -804,6 +780,17 @@ IOHandlerEditline::GotEOF() #endif |